Worklet: Predictable Reboot Notifications for Windows

  • 25 September 2019
  • 34 replies
  • 1554 views


Show first post

34 replies

Userlevel 4
Badge

Would you be willing to share this with us?

Userlevel 4
Badge

Here you go. Feel freer to reach out if you need help


.RebootNotifications.pdf (133.8 KB)

Userlevel 4
Badge

impressive script, kudo’s! Just curious why base encode an image and not use another file attached to the worklet?

Userlevel 4
Badge

Just an old habit. 🙂 You can definitely use the method you mentioned - that’s probably easier 🙂

Userlevel 4
Badge

Hi everyone. I recently made a change to this worklet. It now installs 2 scheduled tasks.


Here is the new reboot powershell script:


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 IsAutomaticReboot
{
<#

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

#>

$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
}

return ($boolIdleConditionMet -and $boolTimeConditionMet)
}

Function RebootComputer
{
Restart-Computer -Force
}

#---------------------------------------------------------------------------------------
# These parameters control the time of day window within which automatic reboot will be initiated
[string]$rebootStartTime = "1am"
[string]$rebootEndTime = "5am"

# If there is no user input detected for $minIdleTime minutes within $rebootStarTime and $rebootEndTime, automatic reboot
# will be initiated
[int]$minIdleTime = 30

# Check if a reboot is pending
$sysInfo = New-Object -ComObject "Microsoft.Update.SystemInfo"
if($sysInfo.RebootRequired)
{
if (IsAutomaticReboot)
{
RebootComputer
}
}

This scheduled job needs to be installed with certain properties for it to work. And here is the powershell script to do this:


$action = New-ScheduledTaskAction -Execute wscript.exe -Argument "//B C:\ProgramData\amagent\rebootNotification\Hidden.vbs C:\ProgramData\amagent\rebootNotification\RunToastHidden.cmd" 
$trigger = New-ScheduledTaskTrigger -Daily -At 9am
$principal = New-ScheduledTaskPrincipal -UserID "NT AUTHORITY\SYSTEM" -LogonType ServiceAccount -RunLevel Highest
$settings = New-ScheduledTaskSettingsSet -MultipleInstances Parallel
$task = Register-ScheduledTask -TaskName "Reboot No Reminder" -Trigger $trigger -Action $action -User "NT AUTHORITY\SYSTEM"
$task.Triggers.Repetition.Interval = "PT1H"
$task.Triggers.Repetition.Duration = "P1D"
$task.Settings.StartWhenAvailable = $True
$task | Set-ScheduledTask -ErrorAction SilentlyContinue
Userlevel 4
Badge

The reason for the change is this: the previous script would not reboot the computer between 1am and 5am if there is no user logged on.

would it be possible to share this in a non-PDF output?

Maybe implement it directly in Automox ?

Userlevel 1
Badge

I think it would be helpful to include all dependencies, like this will require Toast notifications to be enabled or the user will never see these alerts (which is kinda a big deal).  You’d want to build some checks at the head of the script like the following, to a) check if notifications are enabled, and b) enable them.

function Test-WindowsPushNotificationsEnabled() {
$ToastEnabledKey = (Get-ItemProperty "HKCU:\Software\Microsoft\Windows\CurrentVersion\PushNotifications" -Name ToastEnabled -ErrorAction Ignore).ToastEnabled
if ($ToastEnabledKey -eq "1") {
Write-Host "Toast notifications for the logged on user are enabled in Windows"
$true
}
elseif ($ToastEnabledKey -eq "0") {
Write-Host "Toast notifications for the logged on user are not enabled in Windows. The script will try to enable toast notifications for the logged on user"
$false
}
}

# Create Enable-WindowsPushNotifications
# This is used to re-enable toast notifications if the user disabled them generally in Windows
function Enable-WindowsPushNotifications() {
$ToastEnabledKeyPath = "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\PushNotifications"
Write-Host "Trying to enable toast notifications for the logged on user"
try {
Set-ItemProperty -Path $ToastEnabledKeyPath -Name ToastEnabled -Value 1 -Force
Get-Service -Name WpnUserService** | Restart-Service -Force
Write-Host "Successfully enabled toast notifications for the logged on user"
}
catch {
Write-Host "Failed to enable toast notifications for the logged on user. Toast notifications will probably not be displayed"
}
}

 

Reply