# Run Windows Update # iRaven # 2025-07-30 <# .SYNOPSIS Updates windows with PSWindowsUpdate .PARAMETER MDT Set this if being used with MDT so logs get put in the right place .PARAMETER Reboot Allow system reboots #> ## Initial Tasks param( [switch] $MDT, [switch] $Reboot ) $ErrorActionPreference = "Continue" $PSModulePathCU = $env:PSModulePath.split(';')[0] # CurrentUser PSModule path $PSModulePathAU = $env:PSModulePath.split(';')[1] # All Users PSModule path if ($MDT){ $MDTPath = $Global:TSEnv.Value("DeployRoot") } $WUServer = (Get-ItemProperty HKLM:\Software\Policies\Microsoft\Windows\WindowsUpdate).WUServer ## Functions Function ImportPSWindowsUpdate { Write-Host -ForegroundColor Yellow "Importing PS Windows Update module..." # Write-LogEntry -Value "Importing PS Windows Update Module..." -Severity 1 -Component "ImportPSWindowsUpdate" -FileName $ScriptLog try { if (!(Test-Path -Path $PSModulePathAU\PSWindowsUpdate -PathType Container)){ # Get from PSGallery/NuGet Write-Host -ForegroundColor Yellow "Installing PSWindowsUpdate from PSGallery" if (!(Get-PackageProvider -ListAvailable -Name 'NuGet' -ErrorAction Ignore)) { Write-Host -ForegroundColor Yellow 'Installing NuGet package provider...' Install-PackageProvider -Name 'NuGet' -Force Install-Module -Name PSWindowsUpdate -Scope AllUsers -Force } else { Install-Module -Name PSWindowsUpdate -Scope AllUsers -Force } } Import-Module PSWindowsUpdate -Force Write-Host -ForegroundColor Green "PSWindowsUpdate module imported!" Write-LogEntry -Value "PSWindowsUpdate module imported!" -Severity 1 -Component "ImportPSWindowsUpdate" -FileName $ScriptLog return $true } catch { Write-LogEntry -Value "Failed to import PSWindowsUpdate!" -Severity 3 -Component "ImportPSWindowsUpdate" -FileName $ScriptLog Write-Host -ForegroundColor Red "Failed to import PSWindowsUpdate!" return $false } } Function RunWinUpdate { # Run Windows Updates if(ImportPSWindowsUpdate){ try { Write-LogEntry -Value "Installing all available Windows Updates..." -Severity 1 -Component "RunWinUpdate" -FileName $ScriptLog Write-Host -ForegroundColor Yellow "Installing all available Windows Updates..." if ($WUServer -and !($Reboot)){ Install-WindowsUpdate -AcceptAll -IgnoreReboot #Requires -RunAsAdministrator } elseif ($WUServer -and $Reboot) { Install-WindowsUpdate -AcceptAll -AutoReboot #Requires -RunAsAdministrator } elseif (($null -eq $WUServer) -and $Reboot){ Install-WindowsUpdate -MicrosoftUpdate -AcceptAll -AutoReboot #Requires -RunAsAdministrator } else { Install-WindowsUpdate -MicrosoftUpdate -AcceptAll -IgnoreReboot #Requires -RunAsAdministrator } return $true } catch { Write-Host -ForegroundColor Red "Failed installing all available Windows updates!" Write-LogEntry -Value "Failed installing all available Windows updates!" -Severity 3 -Component "RunWinUpdate" -FileName $ScriptLog } } else { Write-LogEntry -Value "Failed to update Windows due to failed import of PSWindowsUpdate PS module." -Severity 3 -Component "RunWinUpdate" -FileName $ScriptLog return $false } } Function Write-LogEntry { #Write data to a CMTrace compatible log file. (Credit to SCConfigMgr - https://www.scconfigmgr.com/) param( [parameter(Mandatory = $true, HelpMessage = "Value added to the log file.")] [ValidateNotNullOrEmpty()] [string]$Value, [parameter(Mandatory = $true, HelpMessage = "Severity for the log entry. 1 for Informational, 2 for Warning and 3 for Error.")] [ValidateNotNullOrEmpty()] [ValidateSet("1", "2", "3")] [string]$Severity, [parameter(Mandatory = $true, HelpMessage = "Component of the log file.")] [ValidateNotNullOrEmpty()] [string]$Component, [parameter(Mandatory = $false, HelpMessage = "Name of the log file that the entry will written to.")] [ValidateNotNullOrEmpty()] [string]$FileName ) #Determine log file location $LogFilePath = $FileName #Construct time stamp for log entry if(-not(Test-Path -Path 'variable:global:TimezoneBias')) { [string]$global:TimezoneBias = [System.TimeZoneInfo]::Local.GetUtcOffset((Get-Date)).TotalMinutes if($TimezoneBias -match "^-") { $TimezoneBias = $TimezoneBias.Replace('-', '+') } else { $TimezoneBias = '-' + $TimezoneBias } } $Time = -join @((Get-Date -Format "HH:mm:ss.fff"), $TimezoneBias) #Construct date for log entry $Date = (Get-Date -Format "MM-dd-yyyy") #Construct context for log entry $Context = $([System.Security.Principal.WindowsIdentity]::GetCurrent().Name) #Construct final log entry $LogText = "" #Add value to log file try { Out-File -InputObject $LogText -Append -NoClobber -Encoding Default -FilePath $LogFilePath -ErrorAction Stop } catch [System.Exception] { Write-Warning -Message "Unable to append log entry to $FileName file. Error message at line $($_.InvocationInfo.ScriptLineNumber): $($_.Exception.Message)" } } # Main Program if ($MDT){ $ScriptLog = "$MDTPath\_Logs\$env:ComputerName-WindowsUpdate.log" } else { $ScriptLog = "$env:SystemDrive\irnh\PSWindowsUpdate.log" } RunWinUpdate