Posted On August 7, 2020

PowerShell: Update Remote Windows

kimconnect 0 comments
blog.KimConnect.com >> Codes >> PowerShell: Update Remote Windows

This script has been deprecated in favor of a more universal one here.

function invokeWindowsUpdate{ 
    [CmdletBinding()] 
    param ( 
        [parameter(Mandatory=$true,Position=0)][string]$computer,
        [parameter(Mandatory=$false,Position=1)][System.Management.Automation.PSCredential]$adminCredential,
        [parameter(Mandatory=$false,Position=2)][bool]$microsoftUpdates=$false,
        [parameter(Mandatory=$false,Position=3)][bool]$bypassWsus=$false, 
        [parameter(Mandatory=$false,Position=4)][int]$winRmPort=5985,
        [parameter(Mandatory=$false,Position=5)][string]$logFile='C:\PSWindowsUpdate.log'
        )    
    $ErrorActionPreference='stop'
    <#
    .SYNOPSIS
    This script will automatically install all avaialable windows updates on a device and will automatically reboot if needed.
    After reboots, windows updates will continue to run until all updates are installed.
    # Features: 
    # - Check WSUS settings (bypass if required by the boolean value)
    # - Prepare the targets by installing prerequisites prior to proceeding further to preemptively resolve dependency errors
    # - Include additional dedendencies such as TLS1.2, Nuget & PSGALLERY
    # - Check if server needs a reboot before issuing the reboot command, instead of just inadvertently trigger reboots
    # - Fixed the blank lines in output log causing bug in status query
    # - More thorough cleanup routine
    # Future developments:
    # - Detect and handle proxies
    #>
 
    function installPsWindowsUpdate{
        $ErrorActionPreference='stop'
        $psWindowsUpdateAvailable=Get-Module -ListAvailable -Name PSWindowsUpdate -ErrorAction SilentlyContinue;
        if (!($psWindowsUpdateAvailable)){
            try {                
                [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12;          
                Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force -Confirm:$false | Out-Null;
                Set-PSRepository -Name 'PSGallery' -InstallationPolicy Trusted | Out-Null;
                Install-Module PSWindowsUpdate -Confirm:$false -Force | Out-Null;
                Import-Module PSWindowsUpdate -force | Out-Null;
                return $true;
                }
            catch{
                "Prerequisites not met on $ENV:COMPUTERNAME.";
                return $false;
                }
        }else{
            return $true
            }
    }
   
    function checkPendingReboot([string]$computer=$ENV:computername,$session){ 
        function checkRegistry{
            if (Get-ChildItem "HKLM:\Software\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending" -EA Ignore) { return $true }
            if (Get-ChildItem "HKLM:\Software\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootInProgress" -EA Ignore) { return $true }
            if (Get-Item "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired" -EA Ignore) { return $true }
            if (Get-Item "HKLM:\Software\Microsoft\Windows\CurrentVersion\Component Based Servicing\PackagesPending" -EA Ignore) { return $true }
            if (Get-Item "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\PostRebootReporting" -EA Ignore) { return $true }
            if (Get-Item 'HKLM:\SOFTWARE\Microsoft\ServerManager\CurrentRebootAttemps' -EA Ignore) { return $true }
            if (Get-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager" -Name 'PendingFileRenameOperations' -EA Ignore) { return $true }
            if (Get-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager" -Name 'PendingFileRenameOperations2' -EA Ignore) { return $true }
            if (Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce' -Name 'DVDRebootSignal' -EA Ignore) { return $true }
            if (Get-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Services\Netlogon' -Name 'JoinDomain' -EA Ignore) { return $true }
            if (Get-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Services\Netlogon' -Name 'AvoidSpnSet' -EA Ignore) { return $true }
            try{ # This peruses CCM utility, if exists
                $util = [wmiclass]"\\.\root\ccm\clientsdk:CCM_ClientUtilities"
                $status = $util.DetermineIfRebootPending()
                if(($null -ne $status) -and $status.RebootPending){
                    $result.SCCMRebootPending = $true
                }
            }catch{
                return $false
            }                    
        }

        if ($ENV:computername -eq $computer){
            $result=checkRegistry;
        }else{
            $result=Invoke-Command -session $session -ScriptBlock{
                    param($importedFunc);
                    [ScriptBlock]::Create($importedFunc).Invoke();
                } -ArgumentList ${function:checkRegistry}
        }
        return $result;
    }
 
    function clearRebootFlags($computer,$session,$verbose=$false){
        if (checkPendingReboot $computer $session){                    
            $isLocalHost=$env:computername -eq $computer
            if($isLocalHost){
                write-warning "$computer is LOCALHOST. Please reboot manually to clear reboot flags"
                return $false
            }else{
                write-host "`nRestarting remote computer $computer to clear pending reboot flags..." 
                if($adminCredential){
                    Restart-Computer -Wait -ComputerName $computer -Credential $adminCredential -Force
                }else{
                    Restart-Computer -Wait -ComputerName $computer -Force
                    }
                write-host "$computer has been successfully restarted!" -ForegroundColor Yellow
                return $true
            }
        }else{
            if($verbose){write-host "There are no pending reboot flags to clear." -ForegroundColor Green}
            return $true
        }
    }   
    function checkWsus{
        # Check if this machine has WSUS settings configured
        $wuPath="Registry::HKLM\Software\Policies\Microsoft\Windows\WindowsUpdate\AU";
        $wuKey="UseWUServer";
        $wuIsOn=(Get-ItemProperty -path $wuPath -name $wuKey -ErrorAction SilentlyContinue).$wuKey;
        #if($wuIsOn){$GLOBAL:wsus=$True}else{$GLOBAL:wsus=$False}
        return $wuIsOn  
    }
   
    function turnoffWsus{
        # Turn WSUS settings OFF temporarily...
        $wuPath="Registry::HKLM\Software\Policies\Microsoft\Windows\WindowsUpdate\AU";
        $wuKey="UseWUServer";
        Set-Itemproperty -path $wuPath -Name $wuKey -value 0
        restart-service wuauserv;        
        }
   
    function turnonWsus{
        # Turning WSUS settings back to ON status
        $wuPath="Registry::HKLM\Software\Policies\Microsoft\Windows\WindowsUpdate\AU";
        $wuKey="UseWUServer";
        Set-Itemproperty -path $wuPath -Name $wuKey -value 1
        restart-service wuauserv;
        }
    function connectWinRm($computer,$adminCredential,$winRmPort=5985){
        if(!$computer){
            write-warning "Computer name must be specified to initiate a WinRM connection."
            return $false
        }
        # Legacy equivalent to Test-Netconnection
        function checkNetConnection($computername,$port,$timeout=1000,$verbose=$false) {
            $tcp = New-Object System.Net.Sockets.TcpClient;
            try {
                $connect=$tcp.BeginConnect($computername,$port,$null,$null)
                $wait = $connect.AsyncWaitHandle.WaitOne($timeout,$false)
                if(!$wait){
                    $null=$tcp.EndConnect($connect)
                    $tcp.Close()
                    if($verbose){
                        Write-Host "Connection Timeout" -ForegroundColor Red
                        }
                    Return $false
                }else{
                    $error.Clear()
                    $null=$tcp.EndConnect($connect) # Dispose of the connection to release memory
                    if(!$?){
                        if($verbose){
                            write-host $error[0].Exception.Message -ForegroundColor Red
                            }
                        $tcp.Close()
                        return $false
                        }
                    $tcp.Close()
                    Return $true
                }
            } catch {
                return $false
            }
        }
        function enableWinRmRemotely($remoteComputer,$winRmPort,$adminCredential){
            function Check-NetConnection($computername,$port,$timeout=1000,$verbose=$false) {
                    $tcp = New-Object System.Net.Sockets.TcpClient;
                    try {
                        $connect=$tcp.BeginConnect($computername,$port,$null,$null)
                        $wait = $connect.AsyncWaitHandle.WaitOne($timeout,$false)
                        if(!$wait){
                            $null=$tcp.EndConnect($connect)
                            $tcp.Close()
                            if($verbose){
                                Write-Host "Connection Timeout" -ForegroundColor Red
                                }
                            Return $false
                        }else{
                            $error.Clear()
                            $null=$tcp.EndConnect($connect) # Dispose of the connection to release memory
                            if(!$?){
                                if($verbose){
                                    write-host $error[0].Exception.Message -ForegroundColor Red
                                    }
                                $tcp.Close()
                                return $false
                                }
                            $tcp.Close()
                            Return $true
                        }
                    } catch {
                        return $false
                    }
            }
            if (!(get-command psexec)){
                # Install Chocolatey
                if (!(Get-Command choco.exe -ErrorAction SilentlyContinue)) {
                    [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12;
                    Set-ExecutionPolicy Bypass -Scope Process -Force; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))
                    }
                choco install sysinternals -y;  
                }
            $success=check-netconnection $remoteComputer $winRmPort
            write-host 'Attempting to use psexec to enable WinRM remotely...'
            if(!$adminCredential){ # Enable WinRM Remotely
                $null=psexec.exe \\$remoteComputer -s C:\Windows\system32\winrm.cmd qc -quiet; 
            }else{
                $username=$adminCredential.Username
                $password=$adminCredential.GetNetworkCredential().Password
                $null=psexec.exe \\$remoteComputer -u $username -p $password -s C:\Windows\system32\winrm.cmd qc -quiet
                }
            return check-netconnection $remoteComputer $winRmPort
        }

        # If machine is not pingable, wait five minutes
        $fiveMinuteTimer=[System.Diagnostics.Stopwatch]::StartNew()
        do{
            $ping = Test-Connection $computer -quiet
            if($ping -eq $false){sleep 1}
            $pastFiveMinutes=$fiveMinuteTimer.Elapsed.TotalMinutes -ge 5
        }until ($ping -eq $true -or $pastFiveMinutes)
        $fiveMinuteTimer.stop()

        $winRmAvailable=checkNetConnection $computer $winRmPort
        if(!$winRmAvailable){
            write-host "Attempting to enable WinRM on $computer" -ForegroundColor Yellow
            $enableWinRmSuccessful=enableWinRmRemotely $computer
            if($enableWinRmSuccessful){
                write-host "WinRM enabled: $enableWinRmSuccessful"
            }else{
                write-warning "WinRM could not be enabled remotely. WinRM connection aborted."
                return $false
                }
        }   
        # Wait for WinRm session prior to proceeding
        if($session.state -eq 'Opened'){remove-pssession $session}
        do{
            if($adminCredential){
                try{
                    $session=New-PSSession -ComputerName $computer -Credential $adminCredential
                }catch{
                    $session=New-PSSession -ComputerName $computer -Credential $adminCredential -SessionOption $(new-pssessionoption -IncludePortInSPN)
                }
            }else{
                try{
                    $session = New-PSSession -ComputerName $computer
                }catch{
                    $session=New-PSSession -ComputerName $computer -SessionOption $(new-pssessionoption -IncludePortInSPN)
                }
                }
            write-host "Connecting to remote computer $computer..."
            sleep -seconds 1
            if ($session){
                write-host "Connected."
                return $session
            }
        } until ($session.state -match "Opened")
    }

    # Advisories
    write-warning "$computer will go through Windows Update and will REBOOT AUTOMATICALLY (if necessary). Press Ctrl+C at anytime to cancel."
   
    $session=connectWinRm $computer $adminCredential
    # Install prerequisites
    $psWindowsUpdateAvailable=invoke-command -session $session -scriptblock {
        param($installPsWindowsUpdate);
        [ScriptBlock]::Create($installPsWindowsUpdate).Invoke();
        } -Args ${function:installPsWindowsUpdate}
        
    if(!$psWindowsUpdateAvailable){
        write-warning "$computername`t: PSWindowsUpdate installation failed."
        return $false
        }
    if($bypassWsus){
        $wsusIsOn=Invoke-Command -session $session -scriptblock{
            param($checkWsus);
            [scriptblock]::create($checkWsus).invoke()
            } -Args ${function:checkWsus}
        if($wsusIsOn){
            Invoke-Command -session $session -scriptblock{
            param($turnoffWsus);
            [scriptblock]::create($turnoffWsus).invoke()
            } -args ${function:turnoffWsus}
        }
    }
    Do{
        #retrieves a list of available updates 
        write-host "Checking for new updates on $computer..."
        $updates=invoke-command -session $session -scriptblock {
            param($microsoftUpdates)
            if($(Get-ExecutionPolicy) -ne 'RemoteSigned'){
                Set-ExecutionPolicy RemoteSigned -force
            }
            $null=Import-Module PSWindowsUpdate
            $availableUpdates=if($microsoftUpdates){
                    Get-wulist -MicrosoftUpdate -verbose
                }else{
                    Get-Wulist -verbose
                }
            write-host $($availableUpdates|out-string).trim()
            return $availableUpdates
        } -Args $microsoftUpdates
        $updatesCount=$updates.KB.count # $updates.count returns $null when count equals 1
        # If there are available updates, proceed with installing the updates and then reboot the remote machine if required
        if ($updatesCount){ 
            #Invoke-WUJob will insert a scheduled task on the remote target as a mean to bypass 2nd hop issues            
            invoke-command -Session $session {
                param($microsoftUpdates)
                $logFile='C:\PSWindowsUpdate.log'
                if(test-path $logFile){remove-item $logFile -force}                
                if($microsoftUpdates){
                    # Register Microsoft Update Service if it has not been registered
                    $microsoftUpdateId='7971f918-a847-4430-9279-4a52d1efe18d'
                    if (!($microsoftUpdateId -in (Get-WUServiceManager).ServiceID)){
                        Add-WUServiceManager -ServiceID $microsoftUpdateId -Confirm:$false
                        }
                    $invokeScript={
                        import-module PSWindowsUpdate;
                        Get-WindowsUpdate -AcceptAll -MicrosoftUpdate -Install | Out-File 'C:\PSWindowsUpdate.log'
                    }
                }else{
                    $invokeScript={
                        import-module PSWindowsUpdate;
                        Get-WindowsUpdate -AcceptAll -Install | Out-File 'C:\PSWindowsUpdate.log'
                    }
                }
                Invoke-WUjob -ComputerName $env:computername -Script $invokeScript -Confirm:$false -RunNow
                write-host "Windows Updates have been triggerred. Now checking for its log file to generate...`r`n"
                Do{
                    $logFileGenerated=if(test-path $logFile){get-content $logFile}else{$false}
                    if(!$logFileGenerated){
                        Start-Sleep -Seconds 1
                        write-host '.' -NoNewline
                    }
                }until($logFileGenerated)
            } -Args $microsoftUpdates

            #Show update status until the amount of installed updates equals the same as the count of updates being reported 
            $dotLimit=10
            $dotCount=0
            $minute=0
            $lastActivity=$null;
            $installedCount=0;
            Write-Host "There $(if($updatesCount -eq 1){'is'}else{'are'}) $updatesCount pending update(s)`r`n";
            do {                
                $getWindowsUpdateLog={param($logFile);Get-Content $logFile}
                $updatestatus=Invoke-Command -Session $session -ScriptBlock $getWindowsUpdateLog -Args $logFile
                $currentActivity=.{
                    $index=$updatestatus.count-1
                    do{
                        $value=$updatestatus[$index--]
                    }until($value)
                    return $value
                    }
                $installedCount=([regex]::Matches($updatestatus, "Installed")).count
                $failsCount=([regex]::Matches($updatestatus, "Failed")).count
                $processedCount=$installedCount+$failsCount
                if ($currentActivity -ne $lastActivity){
                    if($currentActivity -match 'Installed'){
                        Write-Host "`r`nProcessed $processedCount of $updatesCount updates: $currentActivity" -ForegroundColor Green
                    }elseif($currentActivity -match 'Failed'){
                        Write-Host "`r`nFailed item: $currentActivity" -ForegroundColor Yellow
                    }else{
                        Write-Host "`r`n$currentActivity"
                        }
                    $lastActivity=$currentActivity;
                    }else{
                        if ($dotCount++ -le $dotLimit){
                            Write-Host -NoNewline "."
                            if($processedCount -eq $updatesCount){
                                Write-Host "Processing last update: $processedCount of $updatesCount." -ForegroundColor Yellow
                            }
                        }else{
                            $minute++
                            Write-Host "`r`nMinute count: $minute"
                            $dotCount=0
                            }                                                   
                        }                
                Start-Sleep -Seconds 6                              
            }until ($processedCount -eq $updatesCount)
        }else{
            write-host "There are no available patches detected on $computer basing on current update criteria."
            }
        $localhostRebootFlag=!(clearRebootFlags $computer $session)
        if($session.State -ne 'Opened'){
            write-host "Reconnecting to $computer..." -ForegroundColor Yellow
            $session=connectWinRm $computer $adminCredential
        }
        $updatesCompleted=$installedCount -eq $updatesCount
        if($updatesCompleted){
            Write-Host "Windows is now up to date on $computer" -ForegroundColor Green
        }
    }until(($null -eq $updates) -or $updatesCompleted -or $localhostRebootFlag)
    invoke-command -Session $session -ScriptBlock {
        param($logFile)
        if (Get-ScheduledTask -TaskName "PSWindowsUpdate" -ErrorAction SilentlyContinue){
            Write-Host "Removing PSWindowsUpdate scheduled task from $env:computername..."
            Unregister-ScheduledTask -TaskName PSWindowsUpdate -Confirm:$false};
        if (Test-Path $logFile -Credential $adminCredential -ErrorAction SilentlyContinue){
            Write-Host "Deleting log to prevent collisions with subsequent runs."                    
            Write-Host "Removing $logFile."
            Remove-item $logFile
            }
        } -Args $logFile
    if($bypassWsus -and $wsusIsOn){
        write-host "Reverting WSUS registry edits"
        Invoke-Command -session $session -scriptblock{
            param($turnonWsus);
            [scriptblock]::create($turnonWsus).invoke()
        } -args ${function:turnonWsus} ;
    }    
    if($session.State -eq 'Opened'){Remove-PSSession $session}
    if($localhostRebootFlag){
        write-host "$computer requires a reboot to complete the updates"
        return $false
    }else{
        return $true
    }
}
# updateRemoteWindows_v0.0.3.ps1
# Requirement: WinRM and Internet Access must be enabled on target computer(s)
 
$computername='192.168.100.114'
$adminCredential=get-credential
 
function updateRemoteWindows{ 
    [CmdletBinding()] 
    param ( 
        [parameter(Mandatory=$true,Position=0)][string]$computer,
        [parameter(Mandatory=$false,Position=1)][System.Management.Automation.PSCredential]$adminCredential,
        [parameter(Mandatory=$false,Position=2)][bool]$microsoftUpdates=$false,
        [parameter(Mandatory=$false,Position=3)][bool]$bypassWsus=$false, 
        [parameter(Mandatory=$false,Position=4)][int]$winRmPort=5985,
        [parameter(Mandatory=$false,Position=5)][string]$logFile='C:\PSWindowsUpdate.log'
        )    
    $ErrorActionPreference='stop'
    <#
    .SYNOPSIS
    This script will automatically install all avaialable windows updates on a device and will automatically reboot if needed.
    After reboots, windows updates will continue to run until all updates are installed.
    # Features: 
    # - Check WSUS settings (bypass if required by the boolean value)
    # - Prepare the targets by installing prerequisites prior to proceeding further to preemptively resolve dependency errors
    # - Include additional dedendencies such as TLS1.2, Nuget & PSGALLERY
    # - Check if server needs a reboot before issuing the reboot command, instead of just inadvertently trigger reboots
    # - Fixed the blank lines in output log causing bug in status query
    # - More thorough cleanup routine
    # Future developments:
    # - Detect and handle proxies
    #>
 
    function installPsWindowsUpdate{
        $ErrorActionPreference='stop'
        $psWindowsUpdateAvailable=Get-Module -ListAvailable -Name PSWindowsUpdate -ErrorAction SilentlyContinue;
        if (!($psWindowsUpdateAvailable)){
            try {                
                [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12;          
                Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force -Confirm:$false | Out-Null;
                Set-PSRepository -Name 'PSGallery' -InstallationPolicy Trusted | Out-Null;
                Install-Module PSWindowsUpdate -Confirm:$false -Force | Out-Null;
                Import-Module PSWindowsUpdate -force | Out-Null;
                return $true;
                }
            catch{
                "Prerequisites not met on $ENV:COMPUTERNAME.";
                return $false;
                }
        }else{
            return $true
            }
    }
   
    function checkPendingReboot([string]$computer=$ENV:computername,$session){ 
        function checkRegistry{
            if (Get-ChildItem "HKLM:\Software\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending" -EA Ignore) { return $true }
            if (Get-ChildItem "HKLM:\Software\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootInProgress" -EA Ignore) { return $true }
            if (Get-Item "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired" -EA Ignore) { return $true }
            if (Get-Item "HKLM:\Software\Microsoft\Windows\CurrentVersion\Component Based Servicing\PackagesPending" -EA Ignore) { return $true }
            if (Get-Item "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\PostRebootReporting" -EA Ignore) { return $true }
            if (Get-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager" -Name PendingFileRenameOperations -EA Ignore) { return $true }
            if (Get-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager" -Name PendingFileRenameOperations2 -EA Ignore) { return $true }
            try{ 
                $util = [wmiclass]"\\.\root\ccm\clientsdk:CCM_ClientUtilities"
                $status = $util.DetermineIfRebootPending()
                if(($null -ne $status) -and $status.RebootPending){
                    $result.SCCMRebootPending = $true
                }
            }catch{
                return $false
            }                    
        }

        if ($ENV:computername -eq $computer){
            $result=checkRegistry;
        }else{
            $result=Invoke-Command -session $session -ScriptBlock{
                    param($importedFunc);
                    [ScriptBlock]::Create($importedFunc).Invoke();
                } -ArgumentList ${function:checkRegistry}
        }
        return $result;
    }
 
    function clearRebootFlags($computer,$session,$verbose=$false){
        if (checkPendingReboot $computer $session){                    
            write-host "`nRestarting remote computer $computer to clear pending reboot flags..." 
            if($adminCredential){
                Restart-Computer -Wait -ComputerName $computer -Credential $adminCredential -Force
            }else{
                Restart-Computer -Wait -ComputerName $computer -Force
                }
            write-host "$computer has been successfully restarted!" -ForegroundColor Yellow
        }elseif($verbose){
            write-host "Reboot flags are cleared." -ForegroundColor Green
            }
    }   
    function checkWsus{
        # Check if this machine has WSUS settings configured
        $wuPath="Registry::HKLM\Software\Policies\Microsoft\Windows\WindowsUpdate\AU";
        $wuKey="UseWUServer";
        $wuIsOn=(Get-ItemProperty -path $wuPath -name $wuKey -ErrorAction SilentlyContinue).$wuKey;
        #if($wuIsOn){$GLOBAL:wsus=$True}else{$GLOBAL:wsus=$False}
        return $wuIsOn  
    }
   
    function turnoffWsus{
        # Turn WSUS settings OFF temporarily...
        $wuPath="Registry::HKLM\Software\Policies\Microsoft\Windows\WindowsUpdate\AU";
        $wuKey="UseWUServer";
        Set-Itemproperty -path $wuPath -Name $wuKey -value 0
        restart-service wuauserv;        
        }
   
    function turnonWsus{
        # Turning WSUS settings back to ON status
        $wuPath="Registry::HKLM\Software\Policies\Microsoft\Windows\WindowsUpdate\AU";
        $wuKey="UseWUServer";
        Set-Itemproperty -path $wuPath -Name $wuKey -value 1
        restart-service wuauserv;
        }
    function connectWinRm($computer,$adminCredential,$winRmPort=5985){
        if(!$computer){
            write-warning "Computer name must be specified to initiate a WinRM connection."
            return $false
        }
        # Legacy equivalent to Test-Netconnection
        function checkNetConnection($computername,$port,$timeout=1000,$verbose=$false) {
            $tcp = New-Object System.Net.Sockets.TcpClient;
            try {
                $connect=$tcp.BeginConnect($computername,$port,$null,$null)
                $wait = $connect.AsyncWaitHandle.WaitOne($timeout,$false)
                if(!$wait){
                    $null=$tcp.EndConnect($connect)
                    $tcp.Close()
                    if($verbose){
                        Write-Host "Connection Timeout" -ForegroundColor Red
                        }
                    Return $false
                }else{
                    $error.Clear()
                    $null=$tcp.EndConnect($connect) # Dispose of the connection to release memory
                    if(!$?){
                        if($verbose){
                            write-host $error[0].Exception.Message -ForegroundColor Red
                            }
                        $tcp.Close()
                        return $false
                        }
                    $tcp.Close()
                    Return $true
                }
            } catch {
                return $false
            }
        }
        function enableWinRmRemotely($remoteComputer,$winRmPort,$adminCredential){
            function Check-NetConnection($computername,$port,$timeout=1000,$verbose=$false) {
                    $tcp = New-Object System.Net.Sockets.TcpClient;
                    try {
                        $connect=$tcp.BeginConnect($computername,$port,$null,$null)
                        $wait = $connect.AsyncWaitHandle.WaitOne($timeout,$false)
                        if(!$wait){
                            $null=$tcp.EndConnect($connect)
                            $tcp.Close()
                            if($verbose){
                                Write-Host "Connection Timeout" -ForegroundColor Red
                                }
                            Return $false
                        }else{
                            $error.Clear()
                            $null=$tcp.EndConnect($connect) # Dispose of the connection to release memory
                            if(!$?){
                                if($verbose){
                                    write-host $error[0].Exception.Message -ForegroundColor Red
                                    }
                                $tcp.Close()
                                return $false
                                }
                            $tcp.Close()
                            Return $true
                        }
                    } catch {
                        return $false
                    }
            }
            if (!(get-command psexec)){
                # Install Chocolatey
                if (!(Get-Command choco.exe -ErrorAction SilentlyContinue)) {
                    [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12;
                    Set-ExecutionPolicy Bypass -Scope Process -Force; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))
                    }
                choco install sysinternals -y;  
                }
            $success=check-netconnection $remoteComputer $winRmPort
            write-host 'Attempting to use psexec to enable WinRM remotely...'
            if(!$adminCredential){ # Enable WinRM Remotely
                $null=psexec.exe \\$remoteComputer -s C:\Windows\system32\winrm.cmd qc -quiet; 
            }else{
                $username=$adminCredential.Username
                $password=$adminCredential.GetNetworkCredential().Password
                $null=psexec.exe \\$remoteComputer -u $username -p $password -s C:\Windows\system32\winrm.cmd qc -quiet
                }
            return check-netconnection $remoteComputer $winRmPort
        }

        $fiveMinuteTimer=[System.Diagnostics.Stopwatch]::StartNew()
        do{
            $ping = Test-Connection $computer -quiet
            if($ping -eq $false){sleep 1}
            $pastFiveMinutes=$fiveMinuteTimer.Elapsed.TotalMinutes -ge 5
        }until ($ping -eq $true -or $pastFiveMinutes)
        $fiveMinuteTimer.stop()

        $winRmAvailable=checkNetConnection $computer $winRmPort
        if(!$winRmAvailable){
            write-host "Attempting to enable WinRM on $computer" -ForegroundColor Yellow
            $enableWinRmSuccessful=enableWinRmRemotely $computer
            if($enableWinRmSuccessful){
                write-host "WinRM enabled: $enableWinRmSuccessful"
            }else{
                write-warning "WinRM could not be enabled remotely. WinRM connection aborted."
                return $false
                }
        }   
        # Wait for WinRm session prior to proceeding
        if($session.state -eq 'Opened'){remove-pssession $session}
        do{
            if($adminCredential){
                $session = New-PSSession -ComputerName $computer -Credential $adminCredential
            }else{
                $session = New-PSSession -ComputerName $computer
                }
            write-host "Connecting to remote computer $computer..."
            sleep -seconds 1
            if ($session){
                write-host "Connected."
                return $session
            }
        } until ($session.state -match "Opened")
    }

    # Ensure that this function does not execute on the localhost
    if($env:computername,'localhost'|?{$_ -like "$computer*"}){
        write-warning "$computer is detected as the localhost where this program is invoked. This is out of scope of this function."
        return $false
        }
    # Advisories
    write-warning "$computer will go through Windows Update and will REBOOT AUTOMATICALLY (if necessary). Press Ctrl+C at anytime to cancel."
   
    $session=connectWinRm $computer $adminCredential
    Do{
        # Install prerequisites
        $psWindowsUpdateAvailable=invoke-command -session $session -scriptblock {
            param($installPsWindowsUpdate);
            [ScriptBlock]::Create($installPsWindowsUpdate).Invoke();
            } -Args ${function:installPsWindowsUpdate}
           
        if(!$psWindowsUpdateAvailable){
            write-warning "$computername`t: PSWindowsUpdate installation failed."
            return $false
            }
   
        #retrieves a list of available updates 
        write-host "Checking for new updates on $computer..."
        $updates=invoke-command -session $session -scriptblock {
            param($microsoftUpdates)
            if($(Get-ExecutionPolicy) -ne 'RemoteSigned'){
                Set-ExecutionPolicy RemoteSigned -force
            }
            $null=Import-Module PSWindowsUpdate
            $availableUpdates=if($microsoftUpdates){
                    Get-wulist -MicrosoftUpdate -verbose
                }else{
                    Get-Wulist -verbose
                }
            write-host $($availableUpdates|out-string).trim()
            return $availableUpdates
        } -Args $microsoftUpdates
        $updatesCount=$updates.KB.count # $updates.count returns $null when count equals 1
        # If there are available updates, proceed with installing the updates and then reboot the remote machine if required
        if ($updatesCount){ 
            if($bypassWsus){
                $wsusIsOn=Invoke-Command -session $session -scriptblock{
                    param($checkWsus);
                    [scriptblock]::create($checkWsus).invoke()
                    } -Args ${function:checkWsus}
                if($wsusIsOn){
                    Invoke-Command -session $session -scriptblock{
                    param($turnoffWsus);
                    [scriptblock]::create($turnoffWsus).invoke()
                    } -args ${function:turnoffWsus}
                }
            }
               
            #Invoke-WUJob will insert a scheduled task on the remote target as a mean to bypass 2nd hop issues            
            invoke-command -Session $session {
                param($microsoftUpdates)
                $logFile='C:\PSWindowsUpdate.log'
                if(test-path $logFile){remove-item $logFile -force}                
                if($microsoftUpdates){
                    # Register Microsoft Update Service if it has not been registered
                    $microsoftUpdateId='7971f918-a847-4430-9279-4a52d1efe18d'
                    if (!($microsoftUpdateId -in (Get-WUServiceManager).ServiceID)){
                        Add-WUServiceManager -ServiceID $microsoftUpdateId -Confirm:$false
                        }
                    $invokeScript={
                        import-module PSWindowsUpdate;
                        Get-WindowsUpdate -AcceptAll -MicrosoftUpdate -Install | Out-File 'C:\PSWindowsUpdate.log'
                    }
                }else{
                    $invokeScript={
                        import-module PSWindowsUpdate;
                        Get-WindowsUpdate -AcceptAll -Install | Out-File 'C:\PSWindowsUpdate.log'
                    }
                }
                Invoke-WUjob -ComputerName $env:computername -Script $invokeScript -Confirm:$false -RunNow
                write-host "Windows Updates have been triggerred. Now checking for its log file to generate...`r`n"
                Do{
                    $logFileGenerated=if(test-path $logFile){get-content $logFile}else{$false}
                    if(!$logFileGenerated){
                        Start-Sleep -Seconds 1
                        write-host '.' -NoNewline
                    }
                }until($logFileGenerated)
            } -Args $microsoftUpdates

            #Show update status until the amount of installed updates equals the same as the count of updates being reported 
            $dotLimit=10
            $dotCount=0
            $minute=0
            $lastActivity=$null;
            $installedCount=0;
            Write-Host "There $(if($updatesCount -eq 1){'is'}else{'are'}) $updatesCount pending update(s)`r`n";
            do {                
                $getWindowsUpdateLog={param($logFile);Get-Content $logFile}
                $updatestatus=Invoke-Command -Session $session -ScriptBlock $getWindowsUpdateLog -Args $logFile
                $currentActivity=.{
                    $index=$updatestatus.count-1
                    do{
                        $value=$updatestatus[$index--]
                    }until($value)
                    return $value
                    }
                $installedCount = ([regex]::Matches($updatestatus, "Installed")).count
                if ($currentActivity -ne $lastActivity){
                    if($currentActivity -match 'Installed'){
                        Write-Host "`r`nProcessed $installedCount of $updatesCount updates: $currentActivity" -ForegroundColor Green
                    }elseif($currentActivity -match 'Failed'){
                        Write-Host "`r`nFailed item: $currentActivity" -ForegroundColor Yellow
                    }else{
                        Write-Host "`r`n$currentActivity"
                        }
                    $lastActivity=$currentActivity;
                    }else{
                        if ($dotCount++ -le $dotLimit){
                            Write-Host -NoNewline "."
                            if($installedCount -eq $updatesCount){
                                Write-Host "Processing last update: $installedCount of $updatesCount." -ForegroundColor Yellow
                            }
                        }else{
                            $minute++
                            Write-Host "`r`nMinute count: $minute"
                            $dotCount=0
                            }                                                   
                        }                
                Start-Sleep -Seconds 6                              
            }until ($installedCount -eq $updatesCount)
        }else{
            write-host "There are no available patches detected on $computer basing on current update criteria."
            }
        clearRebootFlags $computer $session
        if($session.State -ne 'Opened'){
            write-host "Reconnecting to $computer..." -ForegroundColor Yellow
            $session=connectWinRm $computer $adminCredential
        }
    }until(($null -eq $updates) -OR ($installedCount -eq $updatesCount))   
    invoke-command -Session $session -ScriptBlock {
        param($logFile)
        if (Get-ScheduledTask -TaskName "PSWindowsUpdate" -ErrorAction SilentlyContinue){
            Write-Host "Removing PSWindowsUpdate scheduled task from $env:computername..."
            Unregister-ScheduledTask -TaskName PSWindowsUpdate -Confirm:$false};
        if (Test-Path $logFile -Credential $adminCredential -ErrorAction SilentlyContinue){
            Write-Host "Deleting log to prevent collisions with subsequent runs."                    
            Write-Host "Removing $logFile."
            Remove-item $logFile
            }
        } -Args $logFile
    if($bypassWsus -and $wsusIsOn){
        write-host "Reverting WSUS registry edits"
        Invoke-Command -session $session -scriptblock{
            param($turnonWsus);
            [scriptblock]::create($turnonWsus).invoke()
        } -args ${function:turnonWsus} ;
    }
    Write-Host "Windows is now up to date on $computer" -ForegroundColor Green
    if($session.State -eq 'Opened'){Remove-PSSession $session}
    return $true
}
  
updateRemoteWindows -computer $computername -adminCredential $adminCredential -microsoftUpdates $true
# Troubleshooting:
# Error:
#File C:\Program Files\WindowsPowerShell\Modules\PSWindowsUpdate\2.2.0.2\PSWindowsUpdate.psm1 cannot be loaded because running scripts is disabled on this
#system. For more information, see about_Execution_Policies at https:/go.microsoft.com/fwlink/?LinkID=135170.
#At line:237 char:9
#+         $updates = invoke-command -session $session -scriptblock {$nu ...
#+         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#    + CategoryInfo          : SecurityError: (:) [Import-Module], PSSecurityException
#    + FullyQualifiedErrorId : UnauthorizedAccess,Microsoft.PowerShell.Commands.ImportModuleCommand
#    + PSComputerName        : 192.168.1.54
# Resolve:
# Set-ExecutionPolicy RemoteSigned -Force
# updateRemoteWindows_v0.0.2.ps1

$computername='TEST-SERVER01'

function updateRemoteWindows{ 
    [CmdletBinding()] 
    param ( 
        [parameter(Mandatory=$true,Position=0)][string]$computer,
        [parameter(Mandatory=$false,Position=1)][bool]$bypassWsus=$false,
        [parameter(Mandatory=$false,Position=2)][System.Management.Automation.PSCredential]$adminCredential,
        [parameter(Mandatory=$false,Position=3)][int]$winRmPort=5985
        )
    $logFile="\\$computer\c$\PSWindowsUpdate.log"
    $ErrorActionPreference='stop'
    <#
    .SYNOPSIS
    This script will automatically install all avaialable windows updates on a device and will automatically reboot if needed.
    After reboots, windows updates will continue to run until all updates are installed.
    # Features: 
    # - Check WSUS settings (bypass if required by the boolean value)
    # - Prepare the targets by installing prerequisites prior to proceeding further to preemptively resolve dependency errors
    # - Include additional dedendencies such as TLS1.2, Nuget & PSGALLERY
    # - Check if server needs a reboot before issuing the reboot command, instead of just inadvertently trigger reboots
    # - Fixed the blank lines in output log causing bug in status query
    # - More thorough cleanup routine
    # Future developments:
    # - Detect and handle proxies
    #>

    function setRegKey{
        [CmdletBinding()]
        Param(
            [Parameter(Position=0, Mandatory=$True)][string]$path,
            [Parameter(Position=1, Mandatory=$True)][string]$name,
            [Parameter(Position=2, Mandatory=$True)][string]$value
        )
        Set-Itemproperty -path $path -Name $name -value $value
        }

    function installPsWindowsUpdate{
        $ErrorActionPreference='stop'
        $psWindowsUpdateAvailable=Get-Module -ListAvailable -Name PSWindowsUpdate -ErrorAction SilentlyContinue;
        if (!($psWindowsUpdateAvailable)){
            try {                
                [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12;          
                Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force -Confirm:$false | Out-Null;
                Set-PSRepository -Name 'PSGallery' -InstallationPolicy Trusted | Out-Null;
                Install-Module PSWindowsUpdate -Confirm:$false -Force | Out-Null;
                Import-Module PSWindowsUpdate -force | Out-Null;
                return $true;
                }
            catch{
                "Prerequisites not met on $ENV:COMPUTER.";
                return $false;
                }
        }else{
            return $true
            }
    }

    function checkPendingReboot{
            param([string]$computer=$ENV:computername)

            function checkRegistry{
                 if (Get-ChildItem "HKLM:\Software\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending" -EA Ignore) { return $true }
                 if (Get-Item "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired" -EA Ignore) { return $true }
                 if (Get-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager" -Name PendingFileRenameOperations -EA Ignore) { return $true }
                 try { 
                   $util = [wmiclass]"\\.\root\ccm\clientsdk:CCM_ClientUtilities"
                   $status = $util.DetermineIfRebootPending()
                   if(($status -ne $null) -and $status.RebootPending){
                     return $true
                   }
                 }catch{}
                 return $false             
            }

            $localhost=$ENV:computername
            if ($localHost -eq $computer){
                $result=checkRegistry;
             }else{
                $result=Invoke-Command -ComputerName $computer -Credential $domainAdminCred -ScriptBlock{
                                                                    param($importedFunc);
                                                                    [ScriptBlock]::Create($importedFunc).Invoke();
                                                                    } -ArgumentList ${function:checkRegistry}
                }
            return $result;
        }
    
    # Function requires 2 parameters: -computerName and -processName
    function killProcess{
        [CmdletBinding()]
        param(
          [string[]]$computerName=$ENV:COMPUTERNAME,
          [parameter(Mandatory=$true)][string]$executableName="powershell.exe"
        )
        
        # WMI querying method
        $processes = Get-WmiObject -Class Win32_Process -ComputerName $ComputerName -Credential $domainAdminCred -Filter "name='$executableName'" 
        
        if ($processes){
            foreach ($process in $processes) {
              $terminationResult = $process.terminate()
              $processid = $process.handle
 
            if($terminationResult.returnvalue -eq 0) {
              write-host "The process $executableName `($processid`) terminated successfully"
            } else {
                  write-host "The process $executableName `($processid`) termination has some problems"
                }
            }
        }else{
            "$executableName is currently not running on $computerName."
            }
    }

    function cleanup{      
        #if(check-netconnection -ComputerName $computer -port 445){
        #    if(Get-Process -ComputerName $computer powershell -ErrorAction SilentlyContinue){
        #        Write-Host "Terminating any powershell.exe processes."
        #        killProcess -ComputerName $computer -ExecutableName powershell.exe
        #        }
        #    }
        
        if (Test-Path $logFile -ErrorAction SilentlyContinue){
            Write-Host "Deleting log to prevent collisions with subsequent runs."                       
            Write-Host "Removing $logFile."
            Remove-item $logFile
            }
        
        invoke-command -computername $computer -Credential $domainAdminCred -ScriptBlock {
                            if (Get-ScheduledTask -TaskName "PSWindowsUpdate" -ErrorAction SilentlyContinue){
                                Write-Host "Removing PSWindowsUpdate scheduled task from $computer..."
                                Unregister-ScheduledTask -TaskName PSWindowsUpdate -Confirm:$false};
                            }
                        }

    function checkWsus{
        # Check if this machine has WSUS settings configured
	    $wuPath="Registry::HKLM\Software\Policies\Microsoft\Windows\WindowsUpdate\AU";
	    $wuKey="UseWUServer";
	    $wuIsOn=(Get-ItemProperty -path $wuPath -name $wuKey -ErrorAction SilentlyContinue).$wuKey;
	    if($wuIsOn){$GLOBAL:wsus=$True}else{$GLOBAL:wsus=$False}    
    }

    function turnoffWsus{
		# Turn WSUS settings OFF temporarily...
        $wuPath="Registry::HKLM\Software\Policies\Microsoft\Windows\WindowsUpdate\AU";
        $wuKey="UseWUServer";
		setRegKey -path $wuPath -name $wuKey -value 0;
		restart-service wuauserv;        
        }

    function turnonWsus{
        # Turning WSUS settings back to ON status
        $wuPath="Registry::HKLM\Software\Policies\Microsoft\Windows\WindowsUpdate\AU";
        $wuKey="UseWUServer";
		setRegKey -path $wuPath -name $wuKey -value 1;
		restart-service wuauserv;
        }
    
    function enableWinRm($remoteComputer,$winRmPort){
        function Check-NetConnection($computername, $port=5985) {
            $session = New-Object System.Net.Sockets.TcpClient;
            try {
                $session.Connect($computername, $port);
                $true;
            } catch {
                $false;
            } finally {
                $session.Close();
            }
        }
        if (!(get-command psexec)){
            # Install Chocolatey
            if (!(Get-Command choco.exe -ErrorAction SilentlyContinue)) {
                [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12;
                Set-ExecutionPolicy Bypass -Scope Process -Force; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))
                }
            choco install sysinternals -y;  
            }
        $success=check-netconnection $remoteComputer $winRmPort
        psexec.exe \\$remoteComputer -s C:\Windows\system32\winrm.cmd qc -quiet; # Enable WinRM Remotely
        return check-netconnection $remoteComputer $winRmPort
    }

    # Advisories
    write-warning "$computer will go through Windows Update and will REBOOT AUTOMATICALLY (if necessary). Press Ctrl+C at anytime to cancel."

    # Ensure that this function does not execute on the localhost
    if($env:computername,'localhost'|?{$_ -like "$computer*"}){
        write-warning "$computer is detected as the localhost where this script is invoked. Please use another method to update, instead."
        return $false
        }

    # Legacy equivalent to Test-Netconnection
    function Check-NetConnection($computername, $port) {
        $session = New-Object System.Net.Sockets.TcpClient;
        try {
            $session.Connect($computername, $port);
            $true;
        } catch {
            $false;
        } finally {
            $session.Close();
        }
    }
    $winRmAvailable=Check-NetConnection $computer $winRmPort
    if(!$winRmAvailable){
        write-warning "Attempting to enable WinRM on $computer"
        $enableWinRmSuccessful=enableWinRm $computer

        }

    Do{ 
        # Wait for WinRm session prior to proceeding
        do{
            if($adminCredential){
                $session = New-PSSession -ComputerName $computer -Credential $adminCredential
            }else{
                $session = New-PSSession -ComputerName $computer
                }
            "Connecting to remote computer $computer..."
            sleep -seconds 5
            if ($session){"Connected."}
            } until ($session.state -match "Opened")

        # Install prerequisites
        $psWindowsUpdateAvailable=invoke-command -session $session -scriptblock {
                                    param($installPsWindowsUpdate);
                                    return [ScriptBlock]::Create($installPsWindowsUpdate).Invoke();
                                    } -Args ${function:installPsWindowsUpdate}
        
        if(!$psWindowsUpdateAvailable){
            write-warning "$computername`t: PSWindowsUpdate installation failed."
            return $false
            }

        #retrieves a list of available updates 
        "Checking for new updates on $computer..." 
        $updates = invoke-command -session $session -scriptblock {Get-wulist -verbose} 

        # Count how many updates are available 
        $updatesCount = ($updates.kb).count                

        # If there are available updates proceed with installing the updates and then reboot the remote machine if required
        if ($updates -ne $null){ 
            if($bypassWsus){
                checkWsus;
                if($wsus){turnoffWsus}
                }               
            
            #Invoke-WUJob will insert a scheduled task on the remote target as a mean to bypass 2nd hop issues            
            $job=invoke-command -Session $session -AsJob {
                    $invokeScript={import-module PSWindowsUpdate; Get-WindowsUpdate -AcceptAll -Install | Out-File C:\PSWindowsUpdate.log}
                    Invoke-WUjob -ComputerName $env:computername -Script $invokeScript -Confirm:$false -RunNow}

            #Show update status until the amount of installed updates equals the same as the count of updates being reported 
            sleep -Seconds 30 # Wait for the log file to generate
            $dots=80
            $dotsCount=0
            $lastActivity="";
            $installedCount=0;
            Write-Host "There is/are $updatesCount pending update(s)`n";
                        
            do {                
                $updatestatus = Get-Content "\\$computer\c$\PSWindowsUpdate.log"            
                $currentActivity=$updatestatus | select-object -last 1
                
                if (($currentActivity -ne $lastActivity) -AND ($currentActivity -ne $Null)){
                    Write-Host "Procesing $($installedCount+1) of $updatesCount updates."
                    Write-Host "`n$currentActivity";
                    $lastActivity=$currentActivity;
                    }else{
                        if ($dotCount++ -le $dots){
                            Write-Host -NoNewline ".";
                            if($installedCount -eq $updatesCount){Write-Host "Processing last update: $installedCount of $updatesCount."}
                        }else{
                            Write-Host ".";
                            $dotCount=0;
                            }                                                   
                        }                
                sleep -Seconds 10 
                $ErrorActionPreference = 'SilentlyContinue'                 
                $ErrorActionPreference = 'Continue'
                $installedCount = ([regex]::Matches($updatestatus, "Installed")).count
                }until ($installedCount -eq $updatesCount)
 
                #restarts the remote computer and waits till it starts up again
                if (checkPendingReboot $computer){                    
                    write-host "`nReboots required.`nRestarting remote computer $computer to clear pending reboot flags." 
                    Restart-Computer -Wait -ComputerName $computer -Force;
                    write-host "$computer has been restarted."
                }else{
                    write-host "No reboots required."
                    }                        
            }    
    }until(($updates -eq $null) -OR ($installedCount -eq $updatesCount))

    # Revert WSUS registry edits, if any
    cleanup;
    if($wsus -and $bypassWsus){turnonWsus;}
    Write-Host "Windows is now up to date on $computer"
    return $true
}

updateRemoteWindows -computer $computername

Leave a Reply

Your email address will not be published. Required fields are marked *

Related Post

PowerShell: Get LastLogon Information of Computer Objects

$computernames=@( 'COMPUTER1', 'COMPUTER2' ) $computerLastLogon=foreach($computerName in $computernames){ get-adcomputer $computerName -Properties LastLogon|select Name,@{Name='LastLogon';e={[DateTime]::FromFileTime($_.LastLogon)}} } $computerLastLogon|sort -Property…

PowerShell: Windows Automated Disk Cleanup

##################################################################################     <#      This script is created to automate the cleanup activity. Doing so will benefit to reduce the size of disk.     This script will perform the following   1. Clear windows temp and user temp folder   2. Empty recycle bin   3. Disk Cleanup   4. Clear CBS cabinet log files   5. Clear downloaded patches   6. Clear downloaded driver   7. Clean download folder      Note:  …

PowerShell: Obtaining SQL Database Default Paths

# This function returns an array of 3 string values reflecting default Data, Log, and…