Configurations/PowerShellLab/PostSetup/Run-WindowsUpdate.ps1
#requires -version 5.1 #install all Windows updates on a Hyper-V VM #you must be running Hyper-V on Windows 10 or Windows Server 2016 [CmdletBinding(DefaultParameterSetName="VM")] Param( [Parameter(Mandatory,ParameterSetName='VM')] #specify the name of a VM [string[]]$VMName, [Parameter(Mandatory,ParameterSetName='VM')] #Specify the user credential [pscredential]$Credential, [Parameter(Mandatory,ParameterSetName="session")] #specify an existing PSSession object [System.Management.Automation.Runspaces.PSSession[]]$Session, [switch]$AsJob ) Write-Host "Be aware that running Windows Update may take some time to complete, especially for multiple virtual machines." -ForegroundColor yellow #define a script block to be run on each virtual machine via Invoke-Command $sb = { Write-Host "[$env:computername] Create update session objects" $updateSession = New-Object -ComObject "Microsoft.Update.Session" $updateSearcher = $updateSession.CreateupdateSearcher() $updatesToDownload = New-Object -ComObject "Microsoft.Update.UpdateColl" $updatesToInstall = New-Object -ComObject "Microsoft.Update.UpdateColl" $downloader = $updateSession.CreateUpdateDownloader() $installer = $updateSession.CreateUpdateInstaller() #get the collection of available updates Write-Host "[$env:computername] Retrieving available updates" $results=$updateSearcher.Search("IsInstalled=0 and Type='Software'") Write-Host "[$env:computername] Retrieved $($results.updates.count) updates" #initialize $updates=@() # get by severity $updates+=$results.updates if ($updates) { write-Host "[$env:computername] Processing $($updates.count) updates" #download updates if needed $updates | Where-Object {-not $_.IsDownloaded} | ForEach-Object { [void]$updatesToDownload.Add($_) } if ($updatesToDownload.count -gt 0) { Write-host "[$env:computername] Downloading $($updatesToDownload.count) updates" $downloader.Updates = $updatesToDownload $downloader.Download() } Write-Host "[$env:computername] Installing $($updates.count) updates" foreach ($item in $updates) { [void]$updatesToInstall.add($item) } $installer.Updates = $updatesToInstall foreach ($update in $updates) { #uncomment the next line for troubleshooting or debugging #write-host "[$env:computername] $($update | out-string)" #accept EULAs if ($update.EULAAccepted -eq $false) { $update.AcceptEULA=$True } #install the updates Write-Host "[$env:computername] Installing $($update.title)" $installationResult = $installer.Install() #decode results Switch ($installationResult.ResultCode) { 0 {$result="Not Started"} 1 {$result="In Progress"} 2 {$result="Success" } 3 {$result="Success with errors"} 4 {$result="Failed"} 5 {$result="Process stopped before completing" } default {$result="Unknown"} } #switch #determine if any updates require a reboot if ($installationResult.RebootRequired) { $RebootRequired=$True } #create a custom result object New-Object PSObject -Property @{ Computername=$env:computername Title=$update.title Result=$result RebootRequired=$installationResult.RebootRequired Severity=$update.msrcSeverity InstallDate=Get-Date } #new-object } #end foreach if ($rebootRequired) { write-host "[$env:computername] One or more updates requires a reboot." -ForegroundColor Red -BackgroundColor Black } } #if $updates else { Write-Warning "[$env:computername] No matching updates found" } } #close scriptblock Try { if ($PSCmdlet.ParameterSetName -eq 'VM') { Write-Host "Creating PSSession to $VMName" -ForegroundColor cyan if ($PSBoundParameters.ContainsKey("AsJob")) { [void]$PSBoundParameters.Remove("AsJob") } $session = New-PSSession @PSBoundParameters -ErrorAction stop } if ($AsJob) { Write-Host "Creating background jobs" -ForegroundColor cyan $session | ForEach-Object { Invoke-Command -ScriptBlock $sb -Session $_ -AsJob -JobName "WinUp-$($_.Computername)" } write-Host "You may need to manually remove PSSessions after the jobs complete." -ForegroundColor yellow } else { Invoke-Command -ScriptBlock $sb -Session $session } if ($PSCmdlet.ParameterSetName -eq 'VM' -AND (-Not $AsJob)) { Write-Host "Removing PSSession" -ForegroundColor cyan $Session | Remove-PSSession } } Catch { Throw $_ } |