SILENT WINDOWS PATCHING AND CONTROLLED REBOOTS
updating windows and control when the system restarts.
Thanks to Rönnkvist
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″”
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