mikeglover Posted January 18, 2022 Posted January 18, 2022 Hi, To help be a bit more efficient in doing server windows updates and scheduling reboots of a night I found this script that asks for a date and time and then works out the shutdown -r -t time for and runs the command. I would like to just enter the time and for it to automatically know that I want tomorrows date as I'll set a time after 0:00. I don't know that much about powershell but i think i need to get the current date and +1 and inject it into my $RestartDate Can anyone help with modifying the code below? Thank you [CmdletBinding()] Param( [Parameter(Mandatory=$true,HelpMessage="RestartDate Format: dd-MM-yyyy HH:mm")] [ValidateScript({[DateTime]::ParseExact($_, "dd-MM-yyyy HH:mm", $null)})] $RestartDate, [Parameter(Mandatory=$true)] [string]$Reason ) $now = get-date $PostponeTo = get-date($RestartDate) $secToRestartTimeFromNow = $PostponeTo - $now $sec = [math]::round($secToRestartTimeFromNow.TotalSeconds) $cmd = "shutdown /r /t $sec /d P:0:0 /c '$reason'" Write-Host "Running:" $cmd Invoke-Expression -Command $cmd -Verbose Write-Host Write-Host "Use following command to cancel: " Write-Host "shutdown /a"
Rob_D Posted January 18, 2022 Posted January 18, 2022 (edited) This spits out tomorrows date for me. $RestartDate = [DateTime]::Today.AddDays(+1).ToString([font=inherit]"dd-MM-yyyy"[/font]) Is there any reason you don't just use the task scheduler? Edited January 18, 2022 by Rob_D
Boredguy Posted January 18, 2022 Posted January 18, 2022 I have a scheduled task on most of the servers to do this. It's a Basic task that runs Powershell.exe, with the additional arguments restart-computer -Force I set the trigger to be once only at a specific time, and then alter the date I want it to run based on when I've applied the patches.
mikeglover Posted January 18, 2022 Author Posted January 18, 2022 This spits out tomorrows date for me. $RestartDate = [DateTime]::Today.AddDays(+1).ToString([font=inherit]"dd-MM-yyyy"[/font]) Is there any reason you don't just use the task scheduler? Thanks I'll give that a go. The network manager who has since left would use an app called PC Sleep and I'm not sure how good this tool is. It's extremely slow to start up and I had in mind something fast that I just double click on the desktop to schedule reboot. Task scheduler would take longer setting up on each server, if I understand it correct? I have about 28 VM I have to run windows updates on every month.
DalekSec Posted January 18, 2022 Posted January 18, 2022 Used to use Right Click Tools in SCCM, but now we are decommissioning it i use a mix of Windows Update on the server and just setting a restart time, or via Windows Admin Center and just entering a time
howartp Posted January 18, 2022 Posted January 18, 2022 https://www.faqforge.com/windows-server-2016/configure-scheduled-task-item-using-group-policy/ Set the tasks up with that initially, then you just need to change the time either in the task (per server) or in the GPO (global) when you want reboots to happen - being careful your DCs don't all go down at once. 1
HPlum78 Posted January 18, 2022 Posted January 18, 2022 Just a couple of observations here, in your code @mikeglover the write-host no use what so ever,unless someone is sat running the script but the you would not be looking to automate this. The second is a note about just letting servers reboot you should define matanance windows and ensure that the servers are rebooted within those windows and as already noted don't reboot your DC's/ highly available services within one matanance window! And make sure you are capturing when servers are rebooting and why if at all possible.
HPlum78 Posted January 19, 2022 Posted January 19, 2022 So the code below is what we have in place we use a function (Get-PendingReboot - by Brian Wilhite) this is distributed as a schedule task to our servers and is run at the end of the maintenance window (we have a similar script that runs each night that just emails the list of servers that require a reboot). The script also has a reg key that is updated via group policy if we want the script to not reboot a server/ group of servers. By using this we are capturing the reboots of servers and this helps us identify servers that are rebooted outside of their maintenance window. The next update to this is to write out an event to the application log so that we can surface these reboots in our other monitoring tools. Function Get-PendingReboot { <# .SYNOPSIS Gets the pending reboot status on a local or remote computer. .DESCRIPTION This function will query the registry on a local or remote computer and determine if the system is pending a reboot, from either Microsoft Patching or a Software Installation. For Windows 2008+ the function will query the CBS registry key as another factor in determining pending reboot state. "PendingFileRenameOperations" and "Auto Update\RebootRequired" are observed as being consistant across Windows Server 2003 & 2008. CBServicing = Component Based Servicing (Windows 2008) WindowsUpdate = Windows Update / Auto Update (Windows 2003 / 2008) CCMClientSDK = SCCM 2012 Clients only (DetermineIfRebootPending method) otherwise $null value PendFileRename = PendingFileRenameOperations (Windows 2003 / 2008) .PARAMETER ComputerName A single Computer or an array of computer names. The default is localhost ($env:COMPUTERNAME). .PARAMETER ErrorLog A single path to send error data to a log file. .EXAMPLE PS C:\> Get-PendingReboot -ComputerName (Get-Content C:\ServerList.txt) | Format-Table -AutoSize Computer CBServicing WindowsUpdate CCMClientSDK PendFileRename PendFileRenVal RebootPending -------- ----------- ------------- ------------ -------------- -------------- ------------- DC01 False False False False DC02 False False False False FS01 False False False False This example will capture the contents of C:\ServerList.txt and query the pending reboot information from the systems contained in the file and display the output in a table. The null values are by design, since these systems do not have the SCCM 2012 client installed, nor was the PendingFileRenameOperations value populated. .EXAMPLE PS C:\> Get-PendingReboot Computer : WKS01 CBServicing : False WindowsUpdate : True CCMClient : False PendComputerRename : False PendFileRename : False PendFileRenVal : RebootPending : True This example will query the local machine for pending reboot information. .EXAMPLE PS C:\> $Servers = Get-Content C:\Servers.txt PS C:\> Get-PendingReboot -Computer $Servers | Export-Csv C:\PendingRebootReport.csv -NoTypeInformation This example will create a report that contains pending reboot information. .LINK Component-Based Servicing: http://technet.microsoft.com/en-us/library/cc756291(v=WS.10).aspx PendingFileRename/Auto Update: http://support.microsoft.com/kb/2723674 http://technet.microsoft.com/en-us/library/cc960241.aspx http://blogs.msdn.com/b/hansr/archive/2006/02/17/patchreboot.aspx SCCM 2012/CCM_ClientSDK: http://msdn.microsoft.com/en-us/library/jj902723.aspx .NOTES Author: Brian Wilhite Email: bcwilhite (at) live.com Date: 29AUG2012 PSVer: 2.0/3.0/4.0/5.0 Updated: 01DEC2014 UpdNote: Added CCMClient property - Used with SCCM 2012 Clients only Added ValueFromPipelineByPropertyName=$true to the ComputerName Parameter Removed $Data variable from the PSObject - it is not needed Bug with the way CCMClientSDK returned null value if it was false Removed unneeded variables Added PendFileRenVal - Contents of the PendingFileRenameOperations Reg Entry Removed .Net Registry connection, replaced with WMI StdRegProv Added ComputerPendingRename #> [CmdletBinding()] param( [Parameter(Position=0,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)] [Alias("CN","Computer")] [string[]]$ComputerName="$env:COMPUTERNAME", [string]$ErrorLog ) Begin { }## End Begin Script Block Process { Foreach ($Computer in $ComputerName) { Try { ## Setting pending values to false to cut down on the number of else statements $CompPendRen,$PendFileRename,$Pending,$SCCM = $false,$false,$false,$false ## Setting CBSRebootPend to null since not all versions of Windows has this value $CBSRebootPend = $null ## Querying WMI for build version $WMI_OS = Get-WmiObject -Class Win32_OperatingSystem -Property BuildNumber, CSName -ComputerName $Computer -ErrorAction Stop ## Making registry connection to the local/remote computer $HKLM = [uInt32] "0x80000002" $WMI_Reg = [WMIClass] "\\$Computer\root\default:StdRegProv" ## If Vista/2008 & Above query the CBS Reg Key If ([int32]$WMI_OS.BuildNumber -ge 6001) { $RegSubKeysCBS = $WMI_Reg.EnumKey($HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\") $CBSRebootPend = $RegSubKeysCBS.sNames -contains "RebootPending" } ## Query WUAU from the registry $RegWUAURebootReq = $WMI_Reg.EnumKey($HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\") $WUAURebootReq = $RegWUAURebootReq.sNames -contains "RebootRequired" ## Query PendingFileRenameOperations from the registry $RegSubKeySM = $WMI_Reg.GetMultiStringValue($HKLM,"SYSTEM\CurrentControlSet\Control\Session Manager\","PendingFileRenameOperations") #$RegValuePFRO = $RegSubKeySM.sValue $RegValuePFRO = @($RegSubKeySM.sValue).Where({$_ -ne ""}) ## Query ComputerName and ActiveComputerName from the registry $ActCompNm = $WMI_Reg.GetStringValue($HKLM,"SYSTEM\CurrentControlSet\Control\ComputerName\ActiveComputerName\","ComputerName") $CompNm = $WMI_Reg.GetStringValue($HKLM,"SYSTEM\CurrentControlSet\Control\ComputerName\ComputerName\","ComputerName") If ($ActCompNm -ne $CompNm) { $CompPendRen = $true } ## If PendingFileRenameOperations has a value set $RegValuePFRO variable to $true $PendFileRename = $false $noRebootFiles = @() If ($RegValuePFRO) { foreach($regValue in $RegValuePFRO) { If ($RegValue -like "*\C:\windows\system32\spool\*" -or $RegValue -like "*\C:\Program Files (x86)\Google\*" -or $RegValue -like "*\C:\Users\*") { $noRebootFiles += $regValue } else { $PendFileRename = $true } } } $manualReboot = $false If (Test-Path c:\temp\RebootRequired.txt) { $loops = 0 Do{ Start-Sleep -Seconds 5 Remove-Item c:\temp\RebootRequired.txt -Force $loops++ } Until (!(Test-Path c:\temp\RebootRequired.txt) -or $loops -gt 12) $manualReboot = $true } ## Determine SCCM 2012 Client Reboot Pending Status ## To avoid nested 'if' statements and unneeded WMI calls to determine if the CCM_ClientUtilities class exist, setting EA = 0 $CCMClientSDK = $null $CCMSplat = @{ NameSpace='ROOT\ccm\ClientSDK' Class='CCM_ClientUtilities' Name='DetermineIfRebootPending' ComputerName=$Computer ErrorAction='Stop' } ## Try CCMClientSDK Try { $CCMClientSDK = Invoke-WmiMethod @CCMSplat } Catch [system.UnauthorizedAccessException] { $CcmStatus = Get-Service -Name CcmExec -ComputerName $Computer -ErrorAction SilentlyContinue If ($CcmStatus.Status -ne 'Running') { Write-Warning "$Computer`: Error - CcmExec service is not running." $CCMClientSDK = $null } } Catch { $CCMClientSDK = $null } If ($CCMClientSDK) { If ($CCMClientSDK.ReturnValue -ne 0) { Write-Warning "Error: DetermineIfRebootPending returned error code $($CCMClientSDK.ReturnValue)" } If ($CCMClientSDK.IsHardRebootPending -or $CCMClientSDK.RebootPending) { $SCCM = $true } } Else { $SCCM = $null } ## Creating Custom PSObject and Select-Object Splat $SelectSplat = @{ Property=( 'Computer', 'CBServicing', 'WindowsUpdate', 'CCMClientSDK', 'PendComputerRename', 'PendFileRename', 'PendFileRenVal', 'NoRebootFiles', 'RebootPending' )} New-Object -TypeName PSObject -Property @{ Computer=$WMI_OS.CSName CBServicing=$CBSRebootPend WindowsUpdate=$WUAURebootReq CCMClientSDK=$SCCM PendComputerRename=$CompPendRen PendFileRename=$PendFileRename PendFileRenVal=$RegValuePFRO NoRebootFiles=$noRebootFiles #PendFileRenVal=$noRebootFiles RebootPending=($CompPendRen -or $CBSRebootPend -or $WUAURebootReq -or $SCCM -or $PendFileRename -or $manualReboot) } | Select-Object @SelectSplat } Catch { Write-Warning "$Computer`: $_" ## If $ErrorLog, log the file to a user specified location/path If ($ErrorLog) { Out-File -InputObject "$Computer`,$_" -FilePath $ErrorLog -Append } } }## End Foreach ($Computer in $ComputerName) }## End Process End { }## End End }## End Function Get-PendingReboot ################# test server for reboot status and restart if true ######################################## ################# Set Mail server SMTP Address ############################################################# $PSEmailServer = '%YourMAilServerHere%' ############################################################################################################ ###################################### Vars ################################################################ $rb = Get-PendingReboot $strSrv = $env:COMPUTERNAME $strDate = Get-Date -Format dd/MM/yy-h:mm:ss $props = @{ CBServicing = "$($RB.CBServicing)" WindowsUpdate = "$($RB.WindowsUpdate)" PendComputerRename = "$($RB.PendComputerRename)" PendFileRename = "$($RB.PendFileRename)" PendFileRenVal = "$($RB.PendFileRenVal)" NoRebootFiles = "$($RB.NoRebootFiles)" RebootPending = "$($RB.rebootpending)" ManualRebootReq = "$manualReboot" } $objRBP = new-object psobject -Property $props $strMailB1 = $objRBPList | ? {$_.RebootPending -eq "True"} | select RebootPending,CBServicing,WindowsUpdate,PendComputerRename,PendFileRename,PendFileRenVal $strMailB = $strSrv + " Server was restarted by the Restart Computer with Reg Check script at " + $strDate + "`n" + "Restart Reason `n" + "CBServicing : " + $objRBP.CBServicing + "`n" + "Windows Update : " + $objRBP.WindowsUpdate + "`n" + "Pending Computer Rename : " + $objRBP.PendComputerRename + "`n" + "Pending File Rename : " + $objRBP.PendFileRename + "`n" + "Pending File Rename Value : " + $objRBP.PendFileRenVal $strMailSub = $strSrv + " restarted by script" $strMailSubNoReboot = $strSrv + " has not restarted (pending file rename operation)" $strMailBNoReboot = $strSrv + " Server was not restarted by the Restart Computer with Reg Check script at " + $strDate + "`n" + "`n" + "Pending File Rename Value : " + "`n" + $objRBP.NoRebootFiles $strMailBMan = $strSrv + " Server has not deleted its Manual Reboot File, please investigate at " + $strDate $strMailSubMan = $strSrv + " rebooted but didn't remove its Manual Reboot File" $strMailBForceNoReboot = $strSrv + " Server was not restarted by the Restart Computer with Reg Check script at " + $strDate + "`n" + "`n" + "Pending reboot Reason `n" + "CBServicing : " + $objRBP.CBServicing + "`n" + "Windows Update : " + $objRBP.WindowsUpdate + "`n" + "Pending Computer Rename : " + $objRBP.PendComputerRename + "`n" + "Pending File Rename : " + $objRBP.PendFileRename + "`n" + "Pending File Rename Value : " + $objRBP.PendFileRenVal + "`n" + "`n" + "This was due to the No Reboot registry value being set" $strMailSubForceNoReboot = $strSrv + " has not restarted (registry entry)" if ($rb.RebootPending -eq $true){ If(Test-Path -Path Registry::HKEY_LOCAL_MACHINE\SOFTWARE\PendingRebootCheck\PendingReboot){ $AutoRebootDisabledReg = Get-Item -Path Registry::HKEY_LOCAL_MACHINE\SOFTWARE\PendingRebootCheck\PendingReboot $AutoRebootDisabled = $AutoRebootDisabledReg.GetValue('AutoRebootDisabled') If($AutoRebootDisabled -eq '1'){ Send-MailMessage -to "YourITTeamHere" -from "[email protected]" -Subject $strMailSubForceNoReboot -Body $strMailBForceNoReboot Exit } } #the line below determines the number of seconds to sleep between the value after minimum and the value after maximum $sleepval = get-random -minimum 0 -maximum 600 #the line below sleeps the script for a number of seconds equal to sleep value Start-sleep -Seconds $sleepval Send-MailMessage -to "YourITTeamHere" -from "[email protected]" -Subject $strMailSub -Body $strMailB If($loops -gt 12) { Send-MailMessage -to "YourITTeamHere" -from "[email protected]" -Subject $strMailSubMan -Body $strMailBMan } Start-Sleep -Seconds 3 Restart-Computer -Force } elseif ($rb.PendFileRenVal) { Send-MailMessage -to "YourITTeamHere" -from "[email protected]" -Subject $strMailSubNoReboot -Body $strMailBNoReboot } 1
mikeglover Posted January 20, 2022 Author Posted January 20, 2022 The second is a note about just letting servers reboot you should define matanance windows and ensure that the servers are rebooted within those windows and as already noted don't reboot your DC's/ highly available services within one matanance window! And make sure you are capturing when servers are rebooting and why if at all possible. Erm, I'm trying to script reboots by a defining a time when I set so I see that as maintenance rather than "just letting servers reboot". Pretty much every cumulative update I've seen on a server always wants a reboot afterwards so I don't see this as strange behaviour to need to reboot a server.
HPlum78 Posted January 21, 2022 Posted January 21, 2022 Sorry the point I was trying to make there is when you might not have control of the server as some tools/ ransome ware requires a reboot and being able to identify reboots outside of your knowns as it were is useful...
mikeglover Posted January 22, 2022 Author Posted January 22, 2022 Sorry the point I was trying to make there is when you might not have control of the server as some tools/ ransome ware requires a reboot and being able to identify reboots outside of your knowns as it were is useful... Thanks HPlum78. Due to circumstances I've ended up solely managing and updating these servers and the program that was was used before was a PC Sleep app tool installed on all the servers that basically did a reboot at a defined time. I think I need to take a step back and look at how others deploy Windows Updates on servers then as I don't think I have maintenance windows setup. Currently I remote into a server set windows updates off manually and then schedule a reboot at say 3:00am the next day (DC's are different) and then I wait for the next 2nd Tuesday, doing this 28 times is time consuming and was looking at ways of better managing it. I like to script things which is why I went down this avenue. I like your idea about it emailing what servers need reboots so I'm going to gave a good look.
HPlum78 Posted January 22, 2022 Posted January 22, 2022 Happy to share what we do, as we are a little larger than you are @ ~600 Windows servers. Also if I can help script wise ping me.
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now