PowerShell Scripting - Update Windows 10 USB install media

    PowerShell Scripting - Update Windows 10 USB install media

    How to keep Windows 10 USB install media up to date using a PowerShell script
    Published by Category: Installation & Upgrade
    04 Nov 2017
    Designer Media Ltd

    Published by


    Kari's Avatar
    Finnish but not finished


    Location: A Finnish expat in Germany
    Posts: 12,965

    Show Printable Version 


    information   Information
    A few weeks after release of Windows 10 version 1703 (Creators Update), Microsoft in April 2017 officially announced that Windows in the future will get biannual feature upgrades:

    Windows is committing to a predictable twice-per-year feature release schedule, targeting September and March of each year, aligning with Office 365 ProPlus. The next Windows 10 feature update will be targeted for September 2017.

    Each Windows 10 feature release will be serviced and supported for 18 months.
    Read more: Windows and Office align feature release schedules to benefit customers - Windows Blogs

    Half a year later we got the first of these biannual feature upgrades, current Windows 10 version 1709 Fall Creators Update. Next will be still unnamed version 1803 late March or early April 2018. Until version1803 will be released we will see several cumulative updates, version 1709 has already been updated from build 16299.15 to 16299.19.

    What this means for us Windows users is that when we create install media for a new version, it will be to at least some extent outdated quite some time before the next version is released. This tutorial will show how to keep your USB install media up to date by applying cumulative, critical and security updates to it to assure that Windows 10 when installed from the media is always up to date.

    To start with, create a USB install media for current version of Windows 10. Here on Ten Forums we have several tutorials to show you how:





    PowerShell Scripting - Update Windows 10 USB install media Contents PowerShell Scripting - Update Windows 10 USB install media
     


    Part One: Windows Update Download Windows Update packages
    Part Two: Run the Script Apply updates to Windows install media
    Part Three: What does Script do? Script explained step by step

    Note   Note
    Do parts One & Two to update your Windows 10 install media. Part Three is optional, for those interested in how the script was built. It is not required for the USB update process.




    PowerShell Scripting - Update Windows 10 USB install media Part One: Windows Update PowerShell Scripting - Update Windows 10 USB install media
     Download Windows Update packages


    1.1) Go to Microsoft Update Catalog: https://www.catalog.update.microsoft.com/

    1.2) Search updates for Windows 10 version of your install media you want to update. I have created a USB install media for unattended hands-free install of Windows 10 version 1709 (tutorial), I will search updates for version 1709:
    Click image for larger version. 

Name:	image.png 
Views:	22 
Size:	670.8 KB 
ID:	161250

    (Click screenshots to enlarge.)

    Search found a cumulative update and a security update for Flash Player for both 64 bit systems (highlighted blue) and 32 bit systems (yellow), and cumulative update for systems with ARM64 processor (green). Some device specific updates for Windows 10 S version 1709 were also found (red), I'm not interest in them because I do not have Windows 10 S installed nor do I have install media for it
    Note   Note
    Sometimes, depending on Windows version and how long since it was released, Update Catalog finds more than one cumulative update. In this case it is enough to download the most recent cumulative update and all critical updates and security updates released after it.

    1.3) In my case, wanting to update 64 bit install media, I will download both x64 updates:
    Name:  image.png
Views: 366
Size:  159.6 KB
    Note   Note
    Be sure to download Windows Updates for correct bit version, x64 if you will update a 64 bit Windows install media and x86 if updating 32 bit install media.

    1.4) I saved the updates in folder H:\WindowsUpdate which I created specifically to store Windows Update files:
    Click image for larger version. 

Name:	image.png 
Views:	11 
Size:	75.1 KB 
ID:	161258





    PowerShell Scripting - Update Windows 10 USB install media Part Two: Run the Script PowerShell Scripting - Update Windows 10 USB install media
     Apply updates to Windows install media


    2.1) Plug in your Windows 10 install USB flash drive. Alternatively, if you want to update an ISO image instead, mount the ISO (right click > select 'Mount') and copy its content (all files and folders) to a folder on hard disk, for instance D:\ISO_Files

    2.2) Download USBUpdate.ps1 script from OneDrive, save it to local PC selecting Save or Save As. Do not select Open or Run:

    download

    2.3) Right click downloaded file, select Properties:
    Click image for larger version. 

Name:	image.png 
Views:	10 
Size:	173.1 KB 
ID:	161423

    2.4) Select Unblock (tick the box), click OK:
    Name:  image.png
Views: 362
Size:  182.1 KB

    2.5) Open Settings app, select Update & Security, select For developers, click Apply under PowerShell to allow local unblocked scripts to be run:
    Click image for larger version. 

Name:	image.png 
Views:	11 
Size:	156.3 KB 
ID:	161427
    Note   Note
    The Apply button will be greyed out if this setting is already applied:
    Name:  image.png
Views: 364
Size:  31.4 KB

    2.6) Run USBUpdate.ps1 script by right clicking it and selecting Run with PowerShell:
    Name:  image.png
Views: 483
Size:  120.8 KB

    You can of course run script if you so prefer manually from PowerShell or from PowerShell ISE using both normal user mode or elevated PowerShell, script will be automatically elevated if started from user mode.

    To run script from PS, enter following command, replacing path X:\Scripts with actual path to folder where script is stored:

    & "X:\Scripts\USBUpdate.ps1"

    If script is in current PS working folder, use following command:

    .\"USBUpdate.ps1"

    2.7) Depending on your current execution policy level (read more) you might get a notification as shown in screenshot. Press Y and Enter to accept:
    Click image for larger version. 

Name:	image.png 
Views:	9 
Size:	180.9 KB 
ID:	161434

    If you will get an error message in red telling running scripts is disabled, you've forgot either step 2.4 or step 2.5:
    Click image for larger version. 

Name:	image.png 
Views:	11 
Size:	177.8 KB 
ID:	161441

    2.8) Script will be run:
    Name:  image.png
Views: 360
Size:  467.4 KB

    2.9 ) If script was started with right click > Run in PowerShell, or if it was started manually from a normal user mode PS, a new elevated "Run as administrator" PS process will be started.

    In this case, depending on your UAC settings, you will be asked to allow PS to be elevated. Click Yes:
    Name:  image.png
Views: 361
Size:  85.4 KB

    2.10) Follow on-screen instructions to update Windows install media, a USB flash drive or an ISO image





    PowerShell Scripting - Update Windows 10 USB install media Part Three: What does script do? PowerShell Scripting - Update Windows 10 USB install media
     Script explained step by step


    3.1) OK, let's go shortly through the modules in this script. In this part we'll look at each screen user will see and the code for it.

    I have used a lot of remarks to make script more readable. Lines starting with a hash sign are ignored when script is run and can be used for remarks and notes.

    Here's the script to start with, all almost 400 lines of it, including remarks and empty lines to separate modules:

    Code:
    ########################################################## 
    # 
    # USBUpdate.ps1
    #
    # A PS Script to update Windows 10 install USB. 
    # 
    # You are free to edit & share this script as long as
    # source TenForums.com is mentioned.
    #
    # *** Twitter.com/TenForums *** Facebook.com/TenForums ***
    # 
    # Script by Kari 
    # - TenForums.com/members/kari.html
    # - Twitter.com/KariTheFinn
    # - YouTube.com/KariTheFinn
    #
    # 'Use-RunAs' function to check if script was launched
    # in normal user mode and elevating it if necessary by
    # Matt Painter (Microsoft TechNet Script Center)
    # https://gallery.technet.microsoft.com/scriptcenter/ 
    #
    ##########################################################
    
    ##########################################################
    # Checking if PS is running elevated. If not, elevating it
    ##########################################################   
    
    function Use-RunAs 
    {    
        # Check if script is running as Administrator and if not elevate it
        # Use Check Switch to check if admin 
         
        param([Switch]$Check) 
         
        $IsAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()` 
            ).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator") 
             
        if ($Check) { return $IsAdmin }   
          
        if ($MyInvocation.ScriptName -ne "") 
        {  
            if (-not $IsAdmin)  
              {  
                try 
                {  
                    $arg = "-file `"$($MyInvocation.ScriptName)`"" 
                    Start-Process "$psHome\powershell.exe" -Verb Runas -ArgumentList $arg -ErrorAction 'stop'  
                } 
                catch 
                { 
                    Write-Warning "Error - Failed to restart script elevated"  
                    break               
                } 
                exit 
            }  
        }  
    } 
    
    Use-RunAs 
    
    ##########################################################
    # Show short instructions to user
    ##########################################################   
    
    cls
    Write-Host                                                                       
    Write-Host ' This script will update Windows 10 install media with updates '
    Write-Host ' downloaded from http://www.catalog.update.microsoft.com'
    Write-Host 
    Write-Host ' Please notice that the process will take quite some time, depending'
    Write-Host ' on amount and size of updates being applied to Windows image. '
    Write-Host
    Write-Host ' If you already have a bootable Windows 10 install media on USB '
    Write-Host ' flash drive, plug it in now.'
    Write-Host 
    Write-Host ' If you want to upgrade an ISO instead, mount (double click) a Windows'
    Write-Host ' ISO image and copy its content to a folder on local PC, for instance'
    Write-Host ' "D:\ISO_Files". Make sure the folder has no other content.'
    Write-Host 
    Write-Host ' When ISO files have been copied to a hard disk folder, or USB drive'
    Write-Host ' has been plugged in, press Enter to start.'
    Write-Host 
    Write-Host '                                                                      ' -ForegroundColor DarkBlue -BackgroundColor White
    Write-Host ' Notice that you cannot use this script to update an ESD based install' -ForegroundColor DarkBlue -BackgroundColor White
    Write-Host ' media like for instance ISO / USB made with Media Creation Tool.     ' -ForegroundColor DarkBlue -BackgroundColor White
    Write-Host ' You must first convert "install.esd" file to "install.wim". See      ' -ForegroundColor DarkBlue -BackgroundColor White
    Write-Host ' TenForums tutorial "Convert ESD to WIM":' -ForegroundColor DarkBlue -BackgroundColor White -NoNewline
    Write-Host ' http://w10g.eu/esd2wim      ' -ForegroundColor DarkCyan -BackgroundColor White
    Write-Host '                                                                      ' -ForegroundColor DarkBlue -BackgroundColor White
    Write-Host
    Write-Host ' ' -NoNewline
    pause
     
    ##########################################################
    # Delete possible old log files from previous runs
    ##########################################################
    
    if (Test-Path C:\WUSuccess.log) {Remove-Item C:\WUSuccess.log}
    if (Test-Path C:\WUFail.log) {Remove-Item C:\WUFail.log}
    
    ##########################################################
    # Prompt user for path to install media (USB drive) or 
    # folder where ISO content was copied to.
    #
    # Using 'while' loop to check that source given by user 
    # contains a Windows image, if not user is asked to chek
    # path and try again
    ##########################################################
    
    $WimCount = 0
    while ($WimCount -eq 0) {
    cls
    Write-Host 
    Write-Host ' Enter source path. In case you are using a plugged in USB flash'
    Write-Host ' drive, simply enter its drive letter followed by : (colon).'
    Write-Host
    Write-Host ' If the source you are using is a Windows 10 ISO or DVD, enter.'
    Write-Host ' path to folder where you copied ISO / DVD content.'
    Write-Host 
    Write-Host ' Notice please: If your source contains both 32 (x86) and 64 (x64)'
    Write-Host ' bit versions, add \x86 or \x64 to source depending on which'
    Write-Host ' bit version you want to update.'
    Write-Host 
    Write-Host ' Examples:'
    Write-Host ' - A USB drive, enter its drive letter with colon (D: or F:)'
    Write-Host ' - A USB drive with both bit versions, enter D:\x86 or D:\x64'
    Write-Host ' - ISO files copied to folder, enter path (D:\ISO_Files)'
    Write-Host ' - Dual bit version ISO copied to folder, enter path with bit version'
    Write-Host '   (W:\MyISOFolder\x86 or W:\MyISOFolder\x64)' 
    Write-Host
    
    $ISOFolder = Read-Host -Prompt ' Enter source, press Enter'
    $WimFolder = $ISOFolder
       
        if (Test-Path $WimFolder\Sources\install.wim)
            {
            $WimCount = 1
                if (($WIMFolder -match "x86") -or ($WIMFolder -match "x64"))
                {
                $ISOFolder = $ISOFolder -replace "....$" 
                }
            }
        elseif (Test-Path $WimFolder)
            {
            $WimCount = 0
            cls
            Write-Host
            Write-Host ' No Windows image (install.wim file) found'
            Write-Host ' Please check path and try again.'
            Write-Host
            Pause
            }
        else
            {
            $FileCount = 0
            cls
            Write-Host
            Write-Host ' Path'$ISOFolder 'does not exist.'
            Write-Host
            Write-Host ' ' -NoNewline
            Pause
            }
        }
    
    $WimFile = Join-Path $WimFolder '\Sources\install.wim'
    
    ##########################################################
    # List Windows editions on image, prompt user for
    # edition to be updated
    ##########################################################
    
    cls
    Get-WindowsImage -ImagePath $WimFile | Format-Table ImageIndex, ImageName
    Write-Host 
    Write-Host ' The install.wim file contains above listed Windows editions.'
    Write-Host ' Which edition should be updated?'
    Write-Host  
    Write-Host ' Enter the ImageIndex number of correct edition and press Enter.'
    Write-Host ' If this is a single edition Windows image, enter 1.'                                                                     
    Write-Host
    $Index = Read-Host -Prompt ' Select edition (ImageIndex)'
            
    
    ##########################################################
    # Prompt user for folder containing downloaded WU files
    # (*.cab and / or *.msu). Again, a 'while' loop is used to
    # check folder contains Windows Update files, if not user
    # is asked to check path and try again
    ##########################################################
    
    $FileCount = 0
    while ($FileCount -eq 0) {
    cls
    Write-Host 
    Write-Host '  Enter path to folder containing downloaded Windows Update'
    Write-Host '  *.cab and / or *.msu files.'
    Write-Host 
    Write-Host '  Be sure to enter correct path / folder!'
    Write-Host                                                                       
    
    $WUFolder = Read-Host -Prompt ' Path to folder containing downloaded Windows Update files'
    
    if (Test-Path $WUFolder)
        {
        $FileCount = (Get-ChildItem $WUFolder\* -Include *.msu,*.cab).Count
        if ($FileCount -eq 0)
            {
            Write-Host
            Write-Host ' No Windows Update files found in given folder.' 
            Write-Host ' Check the path and try again.'
            Write-Host
            Write-Host ' ' -NoNewline
            pause
            }
        }
        else
            {
            $FileCount = 0
            cls
            Write-Host
            Write-Host ' Path'$WUFolder 'does not exist.'
            Write-Host
            Write-Host ' ' -NoNewline
            Pause
            }
      }
    $WUFiles = Get-ChildItem -Path "$WUFolder" -Recurse -Include *.cab, *.msu | Sort LastWriteTime 
    Write-Host
    Write-Host ' Found following' $FileCount 'Windows Update files:'
    Write-Host
    ForEach ($File in $WUFiles)
        {Write-Host ' '$File}
    Write-Host
    Write-Host ' ' -NoNewline
    pause    
    
    ##########################################################
    # Ask user which drive should be used for temporary 
    # working folder 'Mount'. If 'Mount' exists on selected
    # drive, delete and recreate it.
    ##########################################################
    
    cls
    Write-Host
    [System.IO.DriveInfo]::GetDrives() | Where-Object {$_.DriveType -eq 'Fixed'} | Format-Table @{n='Drive ID';e={($_.Name)}}, @{n='Label';e={($_.VolumeLabel)}}, @{n='Free (GB)';e={[int]($_.AvailableFreeSpace/1GB)}}
    Write-Host
    Write-Host ' Above is a list of all hard disk partitions showing available'
    Write-Host ' free space on each of them. Select a partition for temporary'
    Write-Host ' folder to mount Windows image. Selected partition must have at'
    Write-Host ' least 15 GB available free space. Folder will be removed when'
    Write-Host ' image has been updated.'
    Write-Host
    $Drive = Read-Host -Prompt ' Enter drive letter and press Enter'
    $Mount = $Drive.SubString(0,1) + ':\Mount'
    
    if (Test-Path $Mount) {Remove-Item $Mount}
    $Mount = New-Item -ItemType Directory -Path $Mount
    
    ##########################################################
    # Mount Windows image in temporary mount folder.
    #
    # Adding eight empty lines to $EmptySpace variable to be
    # used as placeholder to push output below PowerShell
    # progressbar which is shown on top. Five empty lines would
    # be enough for PowerShell ISE but standard PowerShell will
    # need eight lines, otherwise output remains hidden
    ##########################################################
    
    cls
    $EmptySpace = @"
    
    
    
      
     
    
    
    
    "@
    
    Write-Host $EmptySpace
    Write-Host ' Mounting Windows image. This will take a few minutes.'
    Mount-WindowsImage -ImagePath $WimFolder\Sources\install.wim -Index $Index -Path $Mount | Out-Null
    Write-Host
    Write-Host ' Image mounted, applying updates.'
    Write-Host
    
    ##########################################################
    # Write updates one by one to Windows image. If OK, add
    # update name including KB number to 'WUSuccess.log' file,
    # if failed add to 'WUFail.log'
    ##########################################################
    
    ForEach ($File in $WUFiles)
        {
        Write-Host ' Applying'$File
        Add-WindowsPackage -Path $Mount -PackagePath $File.FullName | Out-Null
        if ($? -eq $TRUE)
            {$File.Name | Out-File -FilePath C:\WUSuccess.log -Append}
         else     
            {$File.Name | Out-File -FilePath C:\WUFail.log -Append}
        }
    
    ##########################################################
    # Dismount Windows image saving updated install.wim. Using
    # $EmptySpace variable again to push output from under
    # PowerShell progressbar to visible area under it
    ##########################################################
    
    cls
    Write-Host $EmptySpace
    Write-Host ' Dismounting Windows image, saving updated install.wim.'
    Write-Host ' This will take a minute or two.'
    Dismount-WindowsImage -Path $Mount -Save | Out-Null
    cls
    
    ##########################################################
    # Show updates added to Windows image
    ##########################################################
    
    if (Test-Path C:\WUSuccess.log)
        {
        Write-Host
        Write-Host ' Following updates successfully added to Windows image: '
        Write-Host
        $LogContent = Get-Content 'C:\WUSuccess.log'
        foreach ($Line in $LogContent)
            {Write-Host ' - '$Line}
        } 
        else
        {
        Write-Host
        Write-Host ' All updates failed, nothing added to Windows image.'
        Write-Host
        Write-Host ' ' -NoNewline
        pause
        exit
        }
    
    ##########################################################
    # Show failed updates
    ##########################################################
    
    if (Test-Path C:\WUFail.log)
        {
        Write-Host
        Write-Host ' Following updates could not be added to Windows image: '
        $LogContent = Get-Content 'C:\WUfail.log'
        foreach ($Line in $LogContent)
            {Write-Host ' - '$Line}
        } 
        else
        {
        Write-Host
        Write-Host ' No failed updates.'}
    
    ##########################################################
    # Delete temporary mount folder
    ##########################################################
    
    if (Test-Path $Mount) {Remove-Item $Mount}
    
    ##########################################################
    # End credits
    ##########################################################
    
    Write-Host                                                                        
    Write-Host ' Windows image (install.wim) has been updated.'
    Write-Host 
    Write-Host ' If your source was a bootable USB drive, it is now updated.'
    Write-Host  
    Write-Host ' If you started this script by copying Windows install files'
    Write-Host ' from an ISO or DVD to a folder on hard disk, it now contains.'
    Write-Host ' everything required to create updated ISO image.'
    Write-Host 
    Write-Host ' Creating ISO tutorial on TenForums:'
    Write-Host ' w10g.eu/iso' -ForegroundColor Yellow
    Write-Host   
    Write-Host ' More Windows 10 tips, tricks, videos & tutorials at'
    Write-Host ' TenForums.com' -ForegroundColor Yellow
    Write-Host
    Write-Host ' * Twitter.com/TenForums * Facebook.com/TenForums * ' -ForegroundColor Yellow
    Write-Host 
    Write-Host ' Script by Kari'
    Write-Host ' - TenForums.com/members/kari.html'
    Write-Host ' - Twitter.com/KariTheFinn'
    Write-Host ' - YouTube.com/KariTheFinn'
    Write-Host  
    Write-Host ' Logs were saved on C: drive. They can be opened with Notepad:'
    Write-Host ' - C:\WUSuccess.log > lists applied updates'
    Write-Host ' - C:\WUFail.log > lists failed updates'
    Write-Host
    Write-Host ' Press Enter to exit.' 
    $Quit = Read-Host 
    
    ##########################################################
    # End of script
    ##########################################################

    3.2) In my opinion one of the characteristics of good code, be it a batch file or script or an application is clear and precise on-screen instructions to end user. I recommend both adding enough remarks for those reading the source code, and really doing your best to make output clear, understandable and readable.

    To increase readability I add a leading space to any text output line because PS has this annoying non-existing left margin. Two screenshots to show what I mean:

    With a leading space in every line of output:
    Name:  image.png
Views: 444
Size:  242.2 KB

    Without leading space:
    Name:  image.png
Views: 433
Size:  241.6 KB

    Notice that command PAUSE which I use to give user time to read instructions will automatically output text string Press Enter to continue... which will by default have no leading space. To add one, I'll write a line only containing a single space with -NoNewline switch at the end of the command line which tells PS not to start new line after string (single space in this case) has been written (highlighted in code extract):

    Code:
    Write-Host ' Notice that you cannot use this script to update an ESD based install' -ForegroundColor DarkBlue -BackgroundColor White
    Write-Host ' media like for instance ISO / USB made with Media Creation Tool.     ' -ForegroundColor DarkBlue -BackgroundColor White
    Write-Host ' You must first convert "install.esd" file to "install.wim". See      ' -ForegroundColor DarkBlue -BackgroundColor White
    Write-Host ' TenForums tutorial "Convert ESD to WIM":' -ForegroundColor DarkBlue -BackgroundColor White -NoNewline
    Write-Host ' http://w10g.eu/esd2wim      ' -ForegroundColor DarkCyan -BackgroundColor White
    Write-Host '                                                                      ' -ForegroundColor DarkBlue -BackgroundColor White
    Write-Host
    Write-Host ' Notice please: If this script was not started from elevated PowerShell,'
    Write-Host ' PowerShell process will be closed and restarted in elevated mode.'
    Write-Host ' If restarted, this screen will be shown again and you must press Enter'
    Write-Host ' one more time to start.'
    Write-Host
    Write-Host ' ' -NoNewline
    pause

    Now the next line, command PAUSE will not write its output to a new line without leading space but will instead continue on previous line after that single space.

    Also notice in above code extract how warning about ESD file is shown using other colors, inverting them with -ForegroundColor DarkBluesetting the text color to blue and -BackgroundColor White as the name says setting the background color to white. To make it look better, character count (including spaces) in each line is the same to show white background exactly as long in each line.

    Opening screen looks like this:
    Name:  image.png
Views: 439
Size:  469.9 KB

    3.3) Already before showing opening screen, we have checked if script has been started elevated and if not, we will start a new elevated PS process.

    Beauty of modular structure of a PS script is in how easy it is to reuse parts of it, even borrow code from other geeks. In this case I use a function by Matt Painter I found on TechNet Script Center:

    Code:
    function Use-RunAs 
    {    
        # Check if script is running as Administrator and if not elevate it
        # Use Check Switch to check if admin 
         
        param([Switch]$Check) 
         
        $IsAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()` 
            ).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator") 
             
        if ($Check) { return $IsAdmin }   
          
        if ($MyInvocation.ScriptName -ne "") 
        {  
            if (-not $IsAdmin)  
              {  
                try 
                {  
                    $arg = "-file `"$($MyInvocation.ScriptName)`"" 
                    Start-Process "$psHome\powershell.exe" -Verb Runas -ArgumentList $arg -ErrorAction 'stop'  
                } 
                catch 
                { 
                    Write-Warning "Error - Failed to restart script elevated"  
                    break               
                } 
                exit 
            }  
        }  
    } 
    
    Use-RunAs

    Microsoft TechNet Script Center: Powershell, VB Script, SQL and JavaScript - TechNet IT Pros and Scripting Guys
    "Use-RunAs" function: Re-launch Powershell Script Elevated

    3.4) After opening screen we will check if old log files from previous runs of this script exist, if yes we will remove them, then ask user path to source which can be either a USB drive or a folder where ISO content has been copied:

    Code:
    ##########################################################
    # Delete possible old log files from previous runs
    ##########################################################
    
    if (Test-Path C:\WUSuccess.log) {Remove-Item C:\WUSuccess.log}
    if (Test-Path C:\WUFail.log) {Remove-Item C:\WUFail.log}
    
    ##########################################################
    # Prompt user for path to install media (USB drive) or 
    # folder where ISO content was copied to.
    #
    # Using 'while' loop to check that source given by user 
    # contains a Windows image, if not user is asked to chek
    # path and try again
    ##########################################################
    
    $WimCount = 0
    while ($WimCount -eq 0) {
    cls
    Write-Host 
    Write-Host ' Enter source path. In case you are using a plugged in USB flash'
    Write-Host ' drive, simply enter its drive letter followed by : (colon).'
    Write-Host
    Write-Host ' If the source you are using is a Windows 10 ISO or DVD, enter.'
    Write-Host ' path to folder where you copied ISO / DVD content.'
    Write-Host 
    Write-Host ' Notice please: If your source contains both 32 (x86) and 64 (x64)'
    Write-Host ' bit versions, add \x86 or \x64 to source depending on which'
    Write-Host ' bit version you want to update.'
    Write-Host 
    Write-Host ' Examples:'
    Write-Host ' - A USB drive, enter its drive letter with colon (D: or F:)'
    Write-Host ' - A USB drive with both bit versions, enter D:\x86 or D:\x64'
    Write-Host ' - ISO files copied to folder, enter path (D:\ISO_Files)'
    Write-Host ' - Dual bit version ISO copied to folder, enter path with bit version'
    Write-Host '   (W:\MyISOFolder\x86 or W:\MyISOFolder\x64)' 
    Write-Host
    $ISOFolder = Read-Host -Prompt ' Enter source, press Enter'
    $WimFolder = $ISOFolder
       
        if (Test-Path $WimFolder\Sources\install.wim)
            {
            $WimCount = 1
                if (($WIMFolder -match "x86") -or ($WIMFolder -match "x64"))
                {
                $ISOFolder = $ISOFolder -replace "....$" 
                }
            }
        elseif (Test-Path $WimFolder)
            {
            $WimCount = 0
            cls
            Write-Host
            Write-Host ' No Windows image (install.wim file) found'
            Write-Host ' Please check path and try again.'
            Write-Host
            Pause
            }
        else
            {
            $FileCount = 0
            cls
            Write-Host
            Write-Host ' Path'$ISOFolder 'does not exist.'
            Write-Host
            Write-Host ' ' -NoNewline
            Pause
            }
        }
    $WimFile = Join-Path $WimFolder '\Sources\install.wim'

    What user will see:
    Name:  image.png
Views: 438
Size:  339.5 KB

    Alternatively, if source path does not contain valid Windows image:
    Name:  image.png
Views: 426
Size:  67.0 KB

    Or, if given source path does not exist:
    Name:  image.png
Views: 436
Size:  47.3 KB


    3.5) Next step is to check install.wim, show user which editions it contains and ask which edition should be updated:

    Code:
    ##########################################################
    # List Windows editions on image, prompt user for
    # edition to be updated
    ##########################################################
    
    cls
    Get-WindowsImage -ImagePath $WimFile | Format-Table ImageIndex, ImageName
    Write-Host 
    Write-Host ' The install.wim file contains above listed Windows editions.'
    Write-Host ' Which edition should be updated?'
    Write-Host  
    Write-Host ' Enter the ImageIndex number of correct edition and press Enter.'
    Write-Host ' If this is a single edition Windows image, enter 1.'                                                                     
    Write-Host
    $Index = Read-Host -Prompt ' Select edition (ImageIndex)'

    What user will see:
    Name:  image.png
Views: 432
Size:  223.2 KB

    3.6) Time to prompt user for path to folder containing downloaded Windows update .msu and / or .cab files:

    Code:
    ##########################################################
    # Prompt user for folder containing downloaded WU files
    # (*.cab and / or *.msu). Again, a 'while' loop is used to
    # check folder contains Windows Update files, if not user
    # is asked to check path and try again
    ##########################################################
    
    $FileCount = 0
    while ($FileCount -eq 0) {
    cls
    Write-Host 
    Write-Host '  Enter path to folder containing downloaded Windows Update'
    Write-Host '  *.cab and / or *.msu files.'
    Write-Host 
    Write-Host '  Be sure to enter correct path / folder!'
    Write-Host                                                                       
    $WUFolder = Read-Host -Prompt ' Path to folder containing downloaded Windows Update files'
    if (Test-Path $WUFolder)
        {
        $FileCount = (Get-ChildItem $WUFolder\* -Include *.msu,*.cab).Count
        if ($FileCount -eq 0)
            {
            Write-Host
            Write-Host ' No Windows Update files found in given folder.' 
            Write-Host ' Check the path and try again.'
            Write-Host
            Write-Host ' ' -NoNewline
            pause
            }
        }
            $FileCount = 0
            cls
            Write-Host
            Write-Host ' Path'$WUFolder 'does not exist.'
            Write-Host
            Write-Host ' ' -NoNewline
            Pause
      }
    $WUFiles = Get-ChildItem -Path "$WUFolder" -Recurse -Include *.cab, *.msu | Sort LastWriteTime 
    Write-Host
    Write-Host ' Found following' $FileCount 'Windows Update files:'
    Write-Host
    ForEach ($File in $WUFiles)
        {Write-Host ' '$File}
    Write-Host
    Write-Host ' ' -NoNewline
    pause

    User will see this:
    Click image for larger version. 

Name:	image.png 
Views:	7 
Size:	217.9 KB 
ID:	161473

    Again, we are prepared for two possible errors:
    Click image for larger version. 

Name:	image.png 
Views:	7 
Size:	177.0 KB 
ID:	161497
    Name:  image.png
Views: 439
Size:  49.0 KB

    3.7) To mount a Windows image we need some space. A compressed image (install.wim) is under 4 GB but needs over triple that space when mounted. Mounting a standard v. 1709 W10 PRO install.wim takes over 12 GB

    We will now check all hard disk partitions and list them to user showing how much free space each of them has available and let user to pick drive where temporary mount folder will be created:

    Code:
    ##########################################################
    # Ask user which drive should be used for temporary 
    # working folder 'Mount'. If 'Mount' exists on selected
    # drive, delete and recreate it.
    ##########################################################
    
    cls
    Write-Host
    [System.IO.DriveInfo]::GetDrives() | Where-Object {$_.DriveType -eq 'Fixed'} | Format-Table @{n='Drive ID';e={($_.Name)}}, @{n='Label';e={($_.VolumeLabel)}}, @{n='Free (GB)';e={[int]($_.AvailableFreeSpace/1GB)}}
    Write-Host
    Write-Host ' Above is a list of all hard disk partitions showing available'
    Write-Host ' free space on each of them. Select a partition for temporary'
    Write-Host ' folder to mount Windows image. Selected partition must have at'
    Write-Host ' least 15 GB available free space. Folder will be removed when'
    Write-Host ' image has been updated.'
    Write-Host
    $Drive = Read-Host -Prompt ' Enter drive letter and press Enter'
    $Mount = $Drive.SubString(0,1) + ':\Mount'
    if (Test-Path $Mount) {Remove-Item $Mount}
    $Mount = New-Item -ItemType Directory -Path $Mount
    Name:  image.png
Views: 430
Size:  208.8 KB

    3.8) That's it, we have collected all required information. Script starts working.
    Name:  image.png
Views: 436
Size:  61.2 KB

    Image will be mounted:
    Code:
    ##########################################################
    # Mount Windows image in temporary mount folder.
    #
    # Adding eight empty lines to $EmptySpace variable to be
    # used as placeholder to push output below PowerShell
    # progressbar which is shown on top. Five empty lines would
    # be enough for PowerShell ISE but standard PowerShell will
    # need eight lines, otherwise output remains hidden
    ##########################################################
    
    
    cls
    $EmptySpace = @"
    
    
     
     
    
    
    
    
    
    
    
    "@
    Write-Host $EmptySpace
    Write-Host ' Mounting Windows image. This will take a few minutes.'
    Mount-WindowsImage -ImagePath $WimFolder\Sources\install.wim -Index $Index -Path $Mount | Out-Null
    Write-Host
    Write-Host ' Image mounted, applying updates.'
    Write-Host

    3.9) Updates will be written (applied) to image:

    Code:
    ##########################################################
    # Write updates one by one to Windows image. If OK, add
    # update name including KB number to 'WUSuccess.log' file,
    # if failed add to 'WUFail.log'
    ##########################################################
    
    ForEach ($File in $WUFiles)
        {
        Write-Host ' Applying'$File
        Add-WindowsPackage -Path $Mount -PackagePath $File.FullName | Out-Null
        if ($? -eq $TRUE)
            {$File.Name | Out-File -FilePath C:\WUSuccess.log -Append}
         else     
            {$File.Name | Out-File -FilePath C:\WUFail.log -Append}
        }
    Click image for larger version. 

Name:	image.png 
Views:	8 
Size:	141.8 KB 
ID:	161502

    3.10) Dismounting the image, saving changes to install.wim (applied updates):

    Code:
    ##########################################################
    # Dismount Windows image saving updated install.wim. Using
    # $EmptySpace variable again to push output from under
    # PowerShell progressbar to visible area under it
    ##########################################################
    
    cls
    Write-Host $EmptySpace
    Write-Host ' Dismounting Windows image, saving updated install.wim.'
    Write-Host ' This will take a minute or two.'
    Dismount-WindowsImage -Path $Mount -Save | Out-Null
    cls
    Name:  image.png
Views: 435
Size:  80.3 KB

    3.11) Show user which updates were applied, delete temporary mount folder, show end credits:
    Code:
    ##########################################################
    # Show updates added to Windows image
    ##########################################################
    
    if (Test-Path C:\WUSuccess.log)
        {
        Write-Host
        Write-Host ' Following updates successfully added to Windows image: '
        Write-Host
        $LogContent = Get-Content 'C:\WUSuccess.log'
        foreach ($Line in $LogContent)
            {Write-Host ' - '$Line}
        } 
        else
        {
        Write-Host
        Write-Host ' All updates failed, nothing added to Windows image.'
        Write-Host
        Write-Host ' ' -NoNewline
        pause
        exit
        }
    
    ##########################################################
    # Show failed updates
    ##########################################################
    
    if (Test-Path C:\WUFail.log)
        {
        Write-Host
        Write-Host ' Following updates could not be added to Windows image: '
        $LogContent = Get-Content 'C:\WUfail.log'
        foreach ($Line in $LogContent)
            {Write-Host ' - '$Line}
        } 
        else
        {
        Write-Host
        Write-Host ' No failed updates.'}
    
    ##########################################################
    # Delete temporary mount folder
    ##########################################################
    
    if (Test-Path $Mount) {Remove-Item $Mount}
    
    ##########################################################
    # End credits
    ##########################################################
    
    Write-Host                                                                        
    Write-Host ' Windows image (install.wim) has been updated.'
    Write-Host 
    Write-Host ' If your source was a bootable USB drive, it is now updated.'
    Write-Host  
    Write-Host ' If you started this script by copying Windows install files'
    Write-Host ' from an ISO or DVD to a folder on hard disk, it now contains.'
    Write-Host ' everything required to create updated ISO image.'
    Write-Host 
    Write-Host ' Creating ISO tutorial on TenForums:'
    Write-Host ' w10g.eu/iso' -ForegroundColor Yellow
    Write-Host   
    Write-Host ' More Windows 10 tips, tricks, videos & tutorials at'
    Write-Host ' TenForums.com' -ForegroundColor Yellow
    Write-Host
    Write-Host ' * Twitter.com/TenForums * Facebook.com/TenForums * ' -ForegroundColor Yellow
    Write-Host 
    Write-Host ' Script by Kari'
    Write-Host ' - TenForums.com/members/kari.html'
    Write-Host ' - Twitter.com/KariTheFinn'
    Write-Host ' - YouTube.com/KariTheFinn'
    Write-Host  
    Write-Host ' Logs were saved on C: drive. They can be opened with Notepad:'
    Write-Host ' - C:\WUSuccess.log > lists applied updates'
    Write-Host ' - C:\WUFail.log > lists failed updates'
    Write-Host
    Write-Host ' Press Enter to exit.' 
    $Quit = Read-Host 
    
    ##########################################################
    # End of script
    ##########################################################
    Click image for larger version. 

Name:	image.png 
Views:	10 
Size:	494.8 KB 
ID:	161504


    That's it this time!

    Kari
  1.    2 Weeks Ago #1
    Join Date : Nov 2013
    Chicagoland
    Posts : 33,820
    Dual boot Windows 10 FCU Pro x 64 & Insider 10 Pro

    Another great method, PS script, and tutorial Kari.

    That's it this time!
    What is it? Are you taking a break?
      My ComputersSystem Spec
  2.    2 Weeks Ago #2
    Join Date : Oct 2013
    A Finnish expat in Germany
    Posts : 12,965
    Windows 10 Pro
    Thread Starter

    Quote Originally Posted by HippsieGypsie View Post
    Another great method, PS script, and tutorial Kari.
    Thanks Tony.

    Especially if you clean install every now and then or have multiple machines to install, it's quite practical to keep install media up to date, not having to run Windows Update every time on newly installed Windows. When those updates have been "injected" to install media, your clean install is up to date as soon as it enters desktop.
      My ComputerSystem Spec

 


Similar Threads
Tutorial Category
General Tips PowerShell Scripting - The Basics
A PowerShell script is a collection of commands and cmdlets to be run in logical order, previous lines in script determining values and variables in command lines thereafter. The principle is the same than in Command Prompt batch files (.bat or...
Tutorials
Installation & Upgrade PowerShell Scripting - Create USB Install Media for Windows 10
The way Windows operating system is delivered and installed has changed quite a lot from days when Windows 3.0 was delivered on 6 floppy disks. To install, you booted PC from floppy 1, which in its turn asked you to eject it and insert floppy 2 to...
Tutorials
Install apps via Powershell cmd line OR via Chocholatey GUI App (easy)
Despite the abundance of endless text here, it's just my way of being very clear and yes sometimes redundant. The actual 'labor' lol required to install this takes a whopping 1 minute if that. I just provided a tad more info than might be...
Software and Apps
Installation & Upgrade PowerShell PackageManagement (OneGet) - Install Apps from Command Line
If you are not familiar with package managers I recommend you read first the short Chocolatey package manager tutorial at our sister site Windows Eight Forums as an introduction to this tutorial: Chocolatey - Install Apps from Command Line. Although...
Tutorials
Solved How do I force Win10 update to re-install Windows Media Player 12
Hi, I'm not sure whether this issue should be listed under the Programs and Apps category. Perhaps you could put me right here. I'm finding my WMP is not able to play my Audible .aa and .aax audiobooks, and will not import them. This has been...
Windows Updates and Activation
Our Sites
Site Links
About Us
Windows 10 Forums is an independent web site and has not been authorized, sponsored, or otherwise approved by Microsoft Corporation. "Windows 10" and related materials are trademarks of Microsoft Corp.

Designer Media Ltd
All times are GMT -5. The time now is 23:44.
Find Us
Twitter Facebook Google+ Ten Forums iOS App Ten Forums Android App



Windows 10 Forums