Ever wanted to reboot a Windows box at a specific time? How hard could it be? Unforunately way too hard.
The Restart-Computer cmdlet in Powershell unfortunately does not seem to have an option to schedule a for a later time or delay a restart. The old school “shutdown” command, does though. Unfortunately:
/t xxx Set the time-out period before shutdown to xxx seconds. The valid range is 0-315360000 (10 years), with a default of 30. If the timeout period is greater than 0, the /f parameter is implied.
The functionality is there but it’s a pain to use. I don’t want to have to do math to calculate the number of seconds until shutdown. That’s why we have computers after all!
PowerShell to the rescue after all! Consider the following example:
shutdown /r /t ([math]::ceiling((New-TimeSpan -End "2016-11-15 22:00").TotalSeconds)) /d p:1:1
This example will restart the server at 22:00 on 2016-11-15, with the reason of “Hardware: Maintenance (Planned)”.
Picking apart the command
As before, I like to take apart the command to show what makes it tick.
The command shutdown will call the “old school” shutdown command found at C:\Windows\System32\Shutdown.exe.
The /r parameter specifies that we want to do a reboot.
The /t parameter specifies that the next parameter is the number of seconds until restart.
The next parameter, ([math]::ceiling((New-TimeSpan -End "2016-11-15 22:00").TotalSeconds)) calculates the number of seconds until the desired shutdown time. We’ll take a deeper look at this further down.
The /d p:1:1 parameter specifies the shutdown code. For a full list of valid reason codes, run shutdown /?.
Picking apart that magic parameter
All the magic of calculating the number of seconds happens here:
([math]::ceiling((New-TimeSpan -End "2016-11-15 22:00").TotalSeconds))
In order to better understand this, let’s unpack the full command into a longer script.
# Generate a TimeSpan measuring the amount of time between now # (the default when the "Start" parameter is omitted) and the # end time (the desired shutdown time) $timespan = New-TimeSpan -End "2016-11-15 22:00" # Get the amount of time as seconds. We use TotalSeconds here # and not Seconds, because Seconds only contains the seconds # part of the time span. E.g. if the time span is 10 minutes # 30 seconds, Seconds would be 30, and TotalSeconds would be # 630. $seconds = $timespan.TotalSeconds # Unfornately, $seconds contains a lot of unneccessary decimals. # Here, we're rounding it up to the nearest integer. $seconds = [math]::ceiling($seconds) # Finally, we're invoking the shutdown command with the desired # parameters. shutdown /r /t $seconds /d p:1:1
I hope this is clear. Happy rebooting!
Hey, bit of a longer one line but to save you having to edit the script each time and it not being a copy/paste/enter job try the below which will auto work out the time difference between now and 3AM or your preferred reboot time and set the shutdown accordingly.
$StartDate=(GET-DATE); $EndDate=(Get-Date -Hour 3 -Minute 00 -Second 00).AddDays(+1); shutdown /r /t ([math]::ceiling((New-Timespan -Start $StartDate -End $EndDate).TotalSeconds))
Cool! Although watch out if you run that after midnight, because it’ll run on midnight on the next calendar day. So if you run that script on Monday at 00.30, you’ll reboot on Tuesday at 03:00, which might not be what you want.
Something like this is probably better (split up into multiple lines, so it’s not really a one-liner… also, warning, I have not tested this)
$StartDate = Get-Date
$EndDate = Get-Date -Hour 3 -Minute 0 -Second 0
if ($EndDate -lt $StartDate) {
$EndDate = $EndDate.AddDays(1)
}
$DelaySeconds = [math]::ceiling((New-Timespan -Start $StartDate -End $EndDate).TotalSeconds)
shutdown /r /t $DelaySeconds