Question

Windows - Scheduled Reboot to apply updates

  • 25 November 2023
  • 2 replies
  • 117 views

Badge

Hello folks,

 

I am looking for a worklet that will reboot servers if a reboot is required. I’m using one from the Worklet catalog at the moment, but it doesn’t give any details after it has ran, and 90% of the time it gives a “COMMAND TIMEOUT” error.  Could anyone provide some insight on what they do, or if they know what may be wrong with the worklet that is causing it to timeout?

 

This is what i’m currently using:

 

evaluation script:

 

Evaluation script:

# Checks whether or not the system requires a reboot, and remediates accordingly.
$sysInfo = New-Object -ComObject "Microsoft.Update.SystemInfo"
if($sysInfo.RebootRequired)

    exit 1
}
else
{
    exit 0
}

 

 

Remediation:

 

####### EDIT WITHIN THIS BLOCK #######
######################################
# These parameters control the time of day window within which automatic reboot will be initiated (ie. 11am, 2:30pm)
[string]$rebootStartTime = "11pm"
[string]$rebootEndTime = "11:15pm"

# If there is no user input detected for $minIdleTime minutes within $rebootStartTime and $rebootEndTime, automatic reboot
# will be initiated. Set to 0 if for servers or not concerned about user input detected.
[int]$minIdleTime = 0
######################################
######################################


# .NET functionality to deteect user input.
Add-Type @'
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;

namespace PInvoke.Win32 {

public static class UserInput {

[DllImport("user32.dll", SetLastError=false)]
private static extern bool GetLastInputInfo(ref LASTINPUTINFO plii);

[StructLayout(LayoutKind.Sequential)]
private struct LASTINPUTINFO {
public uint cbSize;
public int dwTime;
}

public static DateTime LastInput {
get {
DateTime bootTime = DateTime.UtcNow.AddMilliseconds(-Environment.TickCount);
DateTime lastInput = bootTime.AddMilliseconds(LastInputTicks);
return lastInput;
}
}

public static TimeSpan IdleTime {
get {
return DateTime.UtcNow.Subtract(LastInput);
}
}

public static int LastInputTicks {
get {
LASTINPUTINFO lii = new LASTINPUTINFO();
lii.cbSize = (uint)Marshal.SizeOf(typeof(LASTINPUTINFO));
GetLastInputInfo(ref lii);
return lii.dwTime;
}
}
}
}
'@


function Trigger-TargetedReboot{
<#
.SYNOPSIS
Sends reboot signal given conditions are met.
.DESCRIPTION
Two conditions must be met for automatic reboot:
1. The local time must be between $rebootStartTime and $rebootEndTime
2. There has not been any user input for at least $idleTime minutes
.INPUTS
rebootStartTime: The beginning of the time period in which a reboot should be issued.
rebootEndTime: The ending of the time period in which a reboot should be issued.
minIdleTime: How many minutes without user input must pass before a reboot is issued.
.EXAMPLE
Trigger-TargetedReboot
.NOTES
Author: Jack Spicer
Date: February 22, 2021
#>

$boolTimeConditionMet = $False
$minTime = Get-Date $rebootStartTime
$maxTime = Get-Date $rebootEndTime
$now = Get-Date
if ($minTime.TimeOfDay -le $now.TimeOfDay -and $maxTime.TimeOfDay -ge $now.TimeOfDay)
{
$boolTimeConditionMet = $True
}

$boolIdleConditionMet = $False
$idleTime = [PInvoke.Win32.UserInput]::IdleTime
if ($idleTime.Minutes -ge $minIdleTime)
{
$boolIdleConditionMet = $True
}

# Check if a reboot is pending
$sysInfo = New-Object -ComObject "Microsoft.Update.SystemInfo"
if($sysInfo.RebootRequired)
{
if ($boolIdleConditionMet -and $boolTimeConditionMet)
{
# Wait for the computer to restart before continuing.
Restart-Computer -Force
return $True
}
return $False
}
else
{
return $True
}
}



if (Trigger-TargetedReboot)
{
# Reboot signal sent or reboot not required.
exit 0
}

# Failed to execute required reboot.
exit 1

 


2 replies

Userlevel 3

Hi @cbranum !

It looks like you are using the Targeted Reboot within Timeframe Catalog Worklet.  This worklet operates by checking to see if a device is in a required reboot state, and if so, determines if the device can be rebooted based on the defined timeframe window.

This timeframe is configured within these two variables of the remediation code:

# These parameters control the time of day window within which automatic reboot will be initiated (ie. 11am, 2:30pm)
[string]$rebootStartTime = "10:45am"
[string]$rebootEndTime = "11:00am"


With the above configuration, if a device requires a reboot and the remediation code executed within the target window of 10:45am and 11:00am, the device will restart.

If you are seeing an Exit 1 ( COMMAND TIMED OUT ) return, it means the Trigger-TargetedReboot function is failing during the worklet run.  We’d need to investigate this further via a Support ticket to see where the issue lies.


As a side note, we’ve since released an enhanced version of the worklet.
The Windows - Maintenance - Maintenance Window Reboots worklet provides more flexibility for setting the timeframe and also provides an override to reboot the device even if it is not required.

Example:

# when set to $true, the server will reboot within the maintenance window, regardless of whether a reboot is REQUIRED
$rebootForce = $false # $true


I’d recommend giving the new worklet a try and see if it meets your needs.

I hope this helps!

Have a great day!

Userlevel 3

Hi @cbranum 


My apologies!  I saw that Mark already replied to you via this separate thread:
 


His suggestion there is valid, in that you can simplify the Target Reboot within Timeframe’s remediation code to just the Restart-Computer -Force command

 

If you wanted to keep the checks for if a reboot is required, please see the worklet 

Windows - Configuration - Restart Device If Required

 
 

Reply