Function Invoke-WUInstall { <# .SYNOPSIS Invoke Get-WUInstall remotely. .DESCRIPTION Use Invoke-WUInstall to invoke Windows Update install remotly. It Based on TaskScheduler because CreateUpdateDownloader() and CreateUpdateInstaller() methods can't be called from a remote computer - E_ACCESSDENIED. Note: Because we do not have the ability to interact, is recommended use -AcceptAll with WUInstall filters in script block. .PARAMETER ComputerName Specify computer name. .PARAMETER TaskName Specify task name. Default is PSWindowsUpdate. .PARAMETER Script Specify PowerShell script block that you what to run. Default is {ipmo PSWindowsUpdate; Get-WUInstall -AcceptAll | Out-File C:\PSWindowsUpdate.log} .EXAMPLE PS C:\> $Script = {ipmo PSWindowsUpdate; Get-WUInstall -AcceptAll -AutoReboot | Out-File C:\PSWindowsUpdate.log} PS C:\> Invoke-WUInstall -ComputerName pc1.contoso.com -Script $Script ... PS C:\> Get-Content \\pc1.contoso.com\c$\PSWindowsUpdate.log .NOTES Author: Michal Gajda Blog : http://commandlinegeeks.com/ .LINK Get-WUInstall #> [CmdletBinding( SupportsShouldProcess=$True, ConfirmImpact="High" )] param ( [Parameter(ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)] [String[]]$ComputerName, [String]$TaskName = "PSWindowsUpdate", [ScriptBlock]$Script = {ipmo PSWindowsUpdate; Get-WUInstall -AcceptAll | Out-File C:\PSWindowsUpdate.log}, [Switch]$OnlineUpdate ) Begin { $User = [Security.Principal.WindowsIdentity]::GetCurrent() $Role = (New-Object Security.Principal.WindowsPrincipal $user).IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator) if(!$Role) { Write-Warning "To perform some operations you must run an elevated Windows PowerShell console." } #End If !$Role $PSWUModule = Get-Module -Name PSWindowsUpdate -ListAvailable Write-Verbose "Create schedule service object" $Scheduler = New-Object -ComObject Schedule.Service $Task = $Scheduler.NewTask(0) $RegistrationInfo = $Task.RegistrationInfo $RegistrationInfo.Description = $TaskName $RegistrationInfo.Author = $User.Name $Settings = $Task.Settings $Settings.Enabled = $True $Settings.StartWhenAvailable = $True $Settings.Hidden = $False $Action = $Task.Actions.Create(0) $Action.Path = "powershell" $Action.Arguments = "-Command $Script" $Task.Principal.RunLevel = 1 } Process { ForEach($Computer in $ComputerName) { If ($pscmdlet.ShouldProcess($Computer,"Invoke WUInstall")) { if(Test-Connection -ComputerName $Computer -Quiet) { Write-Verbose "Check PSWindowsUpdate module on $Computer" Try { $ModuleTest = Invoke-Command -ComputerName $Computer -ScriptBlock {Get-Module -ListAvailable -Name PSWindowsUpdate} -ErrorAction Stop } #End Try Catch { Write-Warning "Can't access to machine $Computer. Try use: winrm qc" Continue } #End Catch $ModulStatus = $false if($ModuleTest -eq $null -or $ModuleTest.Version -lt $PSWUModule.Version) { if($OnlineUpdate) { Update-WUModule -ComputerName $Computer } #End If $OnlineUpdate else { Update-WUModule -ComputerName $Computer -LocalPSWUSource (Get-Module -ListAvailable -Name PSWindowsUpdate).ModuleBase } #End Else $OnlineUpdate } #End If $ModuleTest -eq $null -or $ModuleTest.Version -lt $PSWUModule.Version #Sometimes can't connect at first time $Info = "Connect to scheduler and register task on $Computer" for ($i=1; $i -le 3; $i++) { $Info += "." Write-Verbose $Info Try { $Scheduler.Connect($Computer) Break } #End Try Catch { if($i -ge 3) { Write-Error "Can't connect to Schedule service on $Computer" -ErrorAction Stop } #End If $i -ge 3 else { sleep -Seconds 1 } #End Else $i -ge 3 } #End Catch } #End For $i=1; $i -le 3; $i++ $RootFolder = $Scheduler.GetFolder("\") $SendFlag = 1 if($Scheduler.GetRunningTasks(0) | Where-Object {$_.Name -eq $TaskName}) { $CurrentTask = $RootFolder.GetTask($TaskName) $Title = "Task $TaskName is curretly running: $($CurrentTask.Definition.Actions | Select-Object -exp Path) $($CurrentTask.Definition.Actions | Select-Object -exp Arguments)" $Message = "What do you want to do?" $ChoiceContiniue = New-Object System.Management.Automation.Host.ChoiceDescription "&Continue Current Task" $ChoiceStart = New-Object System.Management.Automation.Host.ChoiceDescription "Stop and Start &New Task" $ChoiceStop = New-Object System.Management.Automation.Host.ChoiceDescription "&Stop Task" $Options = [System.Management.Automation.Host.ChoiceDescription[]]($ChoiceContiniue, $ChoiceStart, $ChoiceStop) $SendFlag = $host.ui.PromptForChoice($Title, $Message, $Options, 0) if($SendFlag -ge 1) { ($RootFolder.GetTask($TaskName)).Stop(0) } #End If $SendFlag -eq 1 } #End If !($Scheduler.GetRunningTasks(0) | Where-Object {$_.Name -eq $TaskName}) if($SendFlag -eq 1) { $RootFolder.RegisterTaskDefinition($TaskName, $Task, 6, "SYSTEM", $Null, 1) | Out-Null $RootFolder.GetTask($TaskName).Run(0) | Out-Null } #End If $SendFlag -eq 1 #$RootFolder.DeleteTask($TaskName,0) } #End If Test-Connection -ComputerName $Computer -Quiet else { Write-Warning "Machine $Computer is not responding." } #End Else Test-Connection -ComputerName $Computer -Quiet } #End If $pscmdlet.ShouldProcess($Computer,"Invoke WUInstall") } #End ForEach $Computer in $ComputerName Write-Verbose "Invoke-WUInstall complete." } End {} }