Powershell - SILENT WINDOWS PATCHING AND CONTROLLED REBOOTS

SILENT WINDOWS PATCHING AND CONTROLLED REBOOTS



updating windows and control when the system restarts.
Thanks to Rönnkvist
Copy the following files to %ProgramFiles%\RebootIfNeeded
RebootIfNeeded.ps1 – Copy script below
hstart64.exe – Download from http://www.ntwind.com/software/hstart.html (needed to hide the scheduled task completely)
ShutdownTool.exe – Download from http://blog.coretech.dk/kea/new-version-of-the-coretech-shutdown-tool/ (you can find the latest version in the comments)
Create a Scheduled Task that runs once or twice every day (I have it set at 08:00 and 13:00 every weekday), and on that task create an with the following configuration:
Program: %ProgramFiles%\RebootIfNeeded\hstart64.exe
Arguments: /NOCONSOLE /WAIT “”%SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe” -NoLogo -NoProfile -NonInteractive -File “%ProgramFiles%\RebootIfNeeded\RebootIfNeeded.ps1″”

[CmdletBinding()]
PARAM (
    $maxBootAgeDays = 35,
    $restartTimeOut = (9 * 60), # 9 hours
    $restartMaxPostpone = (48 * 60), # 48 hours
    $restartDescriptions = @{
        "en-US" = "Your computer needs to restart to receive the latest updates.";
    },
    $defaultLanguage = "en-US"
)
 
 
Function Get-PendingReboot {
    # Local HKLM
    $HKLM = [UInt32] "0x80000002"
    $wmiRegistry = [WMIClass] "\\.\root\default:StdRegProv"
 
    #Default
    $PendingReboot = $false
 
    # CBS - Reboot Required ?
    $RegSubKeysCBS = $wmiRegistry.EnumKey($HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\")
    if ($RegSubKeysCBS.sNames -contains "RebootPending") {
        Write-Verbose "Component Based Servicing have a reboot pending"
        $PendingReboot = $true
    }
                             
    # Windows Update - Reboot Required?
    $RegistryWUAU = $wmiRegistry.EnumKey($HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\")
    if ($RegistryWUAU.sNames -contains "RebootRequired") {
        Write-Verbose "Windows Update have a reboot required"
        $PendingReboot = $true
    }
 
    ## Pending FileRenameOperations ?
    $RegSubKeySM = $wmiRegistry.GetMultiStringValue($HKLM,"SYSTEM\CurrentControlSet\Control\Session Manager\","PendingFileRenameOperations")
    If ($RegSubKeySM.sValue) {
        $RegSubKeySM.sValue | ForEach-Object { 
            If ($_.Trim() -ne '') {
                Write-Verbose "Pending FileRename operation: $($_)"
            }
        }
        $PendingReboot = $true
    }
 
    # ConfigMgr - Pending reboot ?
    TRY {
        $CCMClientSDK = Invoke-WmiMethod -NameSpace "ROOT\ccm\ClientSDK" -Class "CCM_ClientUtilities" -Name "DetermineIfRebootPending" -ErrorAction Stop
 
        If ($CCMClientSDK.IsHardRebootPending -or $CCMClientSDK.RebootPending) {
            Write-Verbose "ConfigMgr have reboot pending"
            $PendingReboot = $true
        }
    } CATCH {
        Write-Verbose "Cant talk to ConfigMgr Agent"
    }
 
    Write-Verbose "Pending reboot: $($PendingReboot)"
    Return $PendingReboot
}
 
Function Check-OldBootAge {
    PARAM (
        $maxAgeDays = 35
    )
 
    $BootTime = Get-WmiObject  Win32_Operatingsystem
    [Int]$days = (New-TimeSpan -Start $boottime.ConvertToDateTime($boottime.LastBootUpTime) -End (Get-Date)).TotalDays
 
    if ($days -ge $maxAgeDays) {
        Write-Verbose "Boot age is $($days) days (more than $($maxBootAgeDays)), reboot required"
        Return $true
    } else {
        Write-Verbose "Boot age is $($days) days (less than $($maxBootAgeDays))"
        Return $false
    }
 
    Return $days
}
 
Function Get-UserLanguage {
    Return [String] ([System.Threading.Thread]::CurrentThread).CurrentUICulture.Name
}
 
# ------------------------------------------------------------------------------------------------------------
# Main script
 
if ( (Get-WmiObject -Query "SELECT ProductType FROM Win32_OperatingSystem").ProductType -eq 1) {
 
    If ( (Get-Process "ShutdownTool" -ErrorAction SilentlyContinue) ) {
        Write-Host "Already running ShutdownTool"
    } else {
        If ((Check-OldBootAge -maxAgeDays $maxBootAgeDays) -or (Get-PendingReboot)) {
            Write-Host "Reboot is required, calling restart utility"
 
            $userLanguage = Get-UserLanguage
            Write-Verbose "Language: $($userLanguage)"
 
            # Find description
            $Description = $restartDescriptions[$userLanguage]
            if ($Description -eq $null) {
                $Description = $restartDescriptions[$defaultLanguage]
            }
 
            $timeOutSeconds = ($restartTimeOut*60) - 1
 
            Write-Verbose "Restart timeout: $($timeOutSeconds) seconds"
            Write-Verbose "Max postpone: $($restartMaxPostpone) minutes"
            Write-Verbose "Description: $($Description)"
 
 
            If ((Test-Path ".\ShutdownTool.exe") -eq $false) {
                Throw "Cant find ShutdownTool.exe"
            } else {
                Write-Verbose "Calling restart with ShutdownTool"
                .\ShutdownTool.exe /g:$userLanguage /d:"$Description" /t:$timeOutSeconds /m:$restartMaxPostpone /r /c
            }
 
            # /g - Language
            # /d - description
            # /t - countdown in sec
            # /m - max postpone in min
            # /r - reboot instead of shutdown
            # /c - force & remove abort-btn
        }
    }
 
} else {
    Write-Verbose "Not a client OS"
}
# Done!


Spiceworks Link
https://community.spiceworks.com/scripts/show/3706-silent-windows-patching-and-controlled-reboots