Often after monthly security and critical updates, a system requires a restart. System Configuration tools like SCCM provides a way to suppress the restart so that servers can be restarted in planned manner.

It would be completely fine to restart few handful of servers however, as the number increases it may become quite laborious to restart the servers manually.

My team was in similar situation where we have to restart some 40 – 50 odd servers.

Given this challenge of restart, I have written a powershell script that schedule & restart the servers.

A small 101 on the Automatic Server Restart script.

First run the following powershell commands. This will create a registry key to track server restart schedule. This needs to be done only once per system.

New-Item -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\ -Name ScheduleRestart
New-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\ScheduleRestart -Name Scheduled -Type DWord -Value 0 -Force

Next, save the below script and schedule a daily task to check if server requires reboot. If server requires reboot, the script will create 2 schedule jobs.

  1. Restart Server
  2. Restart Automatic Services

The script will then remove the above 2 jobs on next run.

<#	
  .NOTES
  ===========================================================================
   Created on:   	6/11/2018 2:41 PM
   Created by:   	Navdeep Singh
   Organization: 	Alivebits
   Filename:     	AutomaticServerRestart.ps1
  ===========================================================================
  .DESCRIPTION
    A description of the file.
#>

# Get the next Sunday Date. By default, it return time as 00:00 (start of the day)
function GetSunday
{
  [CmdletBinding()]
  param (
    [Parameter(Mandatory = $True, Position = 0)]
    [string]$Day
    
  )
  
  Switch ($Day)
  {
    Monday{ (get-date).AddDays(6).Date }
    Tuesday{ (get-date).AddDays(5).Date }
    Wednesday{ (get-date).AddDays(4).Date }
    Thursday{ (get-date).AddDays(3).Date }
    Friday{ (get-date).AddDays(2).Date }
    Saturday{ (get-date).AddDays(1).Date }
    Sunday{ (get-date).AddDays(0).Date }
  }
  
}

# Get Current Day of the Week
$Currentday = (get-date).DayOfWeek

# Check registry key for Pending Reboot. This registry key deletes itself after successful restart.
# http://ilovepowershell.com/2015/09/10/how-to-check-if-a-server-needs-a-reboot/
if (Test-Path('HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired'))
{
  if ((Get-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\ScheduleRestart -Name Scheduled).scheduled -eq 0)
  {
    
    # Define Schedule
    $JobSchedule_RestartServer = GetSunday $Currentday
    $JobSchedule_RestartService = $JobSchedule + "00:30"
    
    
    $ServerRestartSchedule = New-JobTrigger -Once -At $JobSchedule_RestartServer
    $ServiceRestartSchedule = New-JobTrigger -Once -At $JobSchedule_RestartService
    
    # Create Schedule Jobs
    $ScheduleRestart = Register-ScheduledJob -Name ScheduleRestart -ScriptBlock { shutdown /r /f } -Trigger $ServerRestartSchedule
    $RestartServices = Register-ScheduledJob -Name RestartServices -ScriptBlock { (Get-WmiObject win32_service -Filter "State='Stopped' AND StartMode='Auto'") | Start-Service } -Trigger $ServiceRestartSchedule
    
    # Capture last boot time
    $sysinfo = systeminfo | findstr /i boot
    
    # Update custom registry Key
    Set-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\ScheduleRestart -Name Scheduled -Value 1 -Force
    
    #Send Email
    Send-MailMessage -To user@domain.com -From "Server Restart Scheduled <donotreply@noreply.domain.com>" `
             -Subject "Restart Scheduled for `"$env:COMPUTERNAME`" on `"$JobSchedule_RestartServer`" " -Body $sysinfo[0].ToString() -SmtpServer SMTPServerOrFQDN
  }
  
}

# Check if server has rebooted. If yes, then remove the schedule jobs and reset the custom registry key
elseif ((Get-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\ScheduleRestart -Name Scheduled).scheduled -eq 1)
{
  $CurrentDateTime = (get-date)
  
  Unregister-ScheduledJob ScheduleRestart -Force
  Start-Sleep -Seconds 10
  Unregister-ScheduledJob RestartServices -Force
  
  $sysinfo = systeminfo | findstr /i boot
  
  #Send Email
  Send-MailMessage -To user@domain.com -From "Server Restart Completed <donotreply@noreply.domain.com>" `
           -Subject "Server Restart Completed Successfully for `"$env:COMPUTERNAME`" on `"$CurrentDateTime`" " -Body $sysinfo[0].ToString() -SmtpServer SMTPServerOrFQDN
  
  Set-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\ScheduleRestart -Name Scheduled -Value 0 -Force
  
}


else
{
  # Do Nothing
}

Now, it could be tricky if you were to run the powershell script via task scheduler. Either because system doesn’t allow unsigned PS scripts or task scheduler not executing the scripts.

I have found the following method works during most of the time.

Specify the Program to run as powershell and following as arguments

-noprofile -noexecutionpolicy bypass -file pathToPowerShellScript

here is how it looks in TaskSchedule properties.

Automatic Server Restart Schedule Task

Automatic Server Restart Schedule Task

You can further improve the script email and reporting capabilities but for now it serves the purpose.

Hope you find it useful.

Reference

http://ilovepowershell.com/2015/09/10/how-to-check-if-a-server-needs-a-reboot/