Worklet - Enforced Reboots with Notifications using Scheduled Tasks

The idea behind this worklet is to display balloon tip in the taskbar once every 5 hours and then every 15 minutes to warn end users of an upcoming reboot and when.

If an end user reboots during the notification stages, there is a scheduled task that triggers upon restart that will run another powershell script that was written to cancel out running any future events built by this worklet.

The notification is using a custom icon file I built using a company logo.

Please do a lot of testing beforehand as the code is not professionally written to accommodate for every scenario one could encounter. Enjoy!

Evaluation Code

# Cleanup prior reboot task
Unregister-ScheduledTask -TaskName 'RebootMsg*' -Confirm:$false | Out-Null

# Establish Reboot Data Points
$uptime = (get-date) - (gcim Win32_OperatingSystem).LastBootUpTime
$sysInfo = New-Object -ComObject "Microsoft.Update.SystemInfo"

if($sysInfo.RebootRequired -or $uptime.Days -gt 28)
    { 
    exit 1}
else
    {
    exit 0}

Remediation Code

Unregister-ScheduledTask -TaskName 'RebootMsg*' -Confirm:$false | Out-Null

# Establish Reboot Data Points
$uptime = (get-date) - (gcim Win32_OperatingSystem).LastBootUpTime
$sysInfo = New-Object -ComObject "Microsoft.Update.SystemInfo"

if($sysInfo.RebootRequired -or $uptime.Days -gt 28)
{

# Balloon tip pop-up
$title = 'Company'
$icon = 'C:\Users\Public\Pictures\Company.ico'
$date = Get-Date ([datetime]::Now.AddMinutes(360)) -Format 'h:mm tt'
$msg = "As part of keeping Company safe, please save your work and reboot your computer. Automatic reboot at $date"
IF(!(Test-Path $icon)){Copy-Item Company.ico $icon | Out-Null}
$workdir = "C:\ProgramData\amagent"
IF(!(Test-Path $workdir)){mkdir $workdir | Out-Null}

# Cleanup Prior Scheduled tasks if they exist
Unregister-ScheduledTask -TaskName 'RebootMsg*' -Confirm:$false | Out-Null

function Build-Scripts{
# Build script that will send message
$vbs = @"
command = "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy Bypass -windowstyle hidden -File C:\ProgramData\Amagent\message.ps1 -Force"
 set shell = CreateObject("WScript.Shell")
 shell.Run command,0
"@
New-Item -Path "$workdir" -Name "message.vbs" -ItemType "file" -Value $vbs -force | Out-Null

$script = @"
`$BalloonTipText = ("$msg")
`$BalloonTipTitle = "$title"
`$BalloonTipTime = 1000
`$BalloonTipIcon = 'None'

Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
[Windows.Forms.ToolTipIcon]`$BalloonTipIcon = `$BalloonTipIcon
`$ContextMenu = New-Object System.Windows.Forms.ContextMenu
`$MenuItem = New-Object System.Windows.Forms.MenuItem
        
`$NotifyIcon = New-Object Windows.Forms.NotifyIcon -Property @{
    BalloonTipIcon = `$BalloonTipIcon
    BalloonTipText = `$BalloonTipText
    BalloonTipTitle = `$BalloonTipTitle
    ContextMenu = `$ContextMenu
    Icon = "C:\Users\Public\Pictures\Company.ico"
    Text = -join `$BalloonTipText[0..62]
    Visible = `$false
}
`$NotifyIcon.contextMenu.MenuItems.AddRange(`$MenuItem)
`$NotifyIcon.Visible = `$True
`$MenuItem.Text = "Exit"
`$MenuItem.add_Click({
    `$NotifyIcon.Visible = `$true
    `$NotifyIcon.ShowInTaskbar = `$true
})
`$NotifyIcon.ShowBalloonTip(`$BalloonTipTime)
"@
New-Item -Path "$workdir" -Name "message.ps1" -ItemType "file" -Value $script -force | Out-Null

$script = @"
# Cleanup Prior Scheduled tasks if they exist
Unregister-ScheduledTask -TaskName 'RebootMsg*' -Confirm:`$false
Remove-Item $workdir\message* -Confirm:`$false -Force
"@
New-Item -Path "C:\windows\temp\" -Name "message-stop.ps1" -ItemType "file" -Value $script -force | Out-Null

}
Build-Scripts

# Schedule actual Reboot
Function Schedule-Reboot{
    # This will create a scheduled task for SYSTEM REBOOT
    $TaskStartTime = [datetime]::Now.AddMinutes(360) # Six hours
    $SchedService = New-Object -ComObject Schedule.Service
    $SchedService.Connect()
    $Task = $SchedService.NewTask(0)
    $Task.RegistrationInfo.Description = 'Balloon tip pop-up'
    $Task.Settings.Enabled = $true
    $Task.Settings.AllowDemandStart = $true
    $trigger = $Task.triggers.Create(1) # https://docs.microsoft.com/en-us/windows/win32/taskschd/triggercollection-create
    $trigger.StartBoundary = $TaskStartTime.ToString("yyyy-MM-dd'T'HH:mm:ss")
    $trigger.Enabled = $true
    $action = $Task.Actions.Create(0)
    $action.Path = 'C:\Windows\System32\Shutdown.exe'
    $action.Arguments = "/r /t 900"
    $taskFolder = $SchedService.GetFolder('\')
    $taskFolder.RegisterTaskDefinition("RebootMsgReboot", $Task , 6, 'SYSTEM', $null, 4) | out-null
}
Schedule-Reboot

Function Stop-Reboot{
    # This will create a scheduled task for SYSTEM REBOOT
    $TaskStartTime = [datetime]::Now.AddMinutes(0) # Six hours
    $SchedService = New-Object -ComObject Schedule.Service
    $SchedService.Connect()
    $Task = $SchedService.NewTask(0)
    $Task.RegistrationInfo.Description = 'Balloon tip pop-up'
    $Task.Settings.Enabled = $true
    $Task.Settings.AllowDemandStart = $true
    $trigger = $Task.triggers.Create(8) # https://docs.microsoft.com/en-us/windows/win32/taskschd/triggercollection-create
    $trigger.StartBoundary = $TaskStartTime.ToString("yyyy-MM-dd'T'HH:mm:ss")
    $trigger.Enabled = $true
    $action = $Task.Actions.Create(0)
    $action.Path = "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"
    $action.Arguments = "-NoProfile -NoLogo -NonInteractive -ExecutionPolicy Bypass -File C:\windows\temp\message-stop.ps1 -Force"
    $taskFolder = $SchedService.GetFolder('\')
    $taskFolder.RegisterTaskDefinition("RebootMsgStop", $Task , 6, 'SYSTEM', $null, 4) | out-null
}
Stop-Reboot

# Sets up multiple scheduled tasks to run once every hour up to five hours, then every 15min there after
Function Schedule-RebootMsg {
    $i = 0 # Minutes
    $a = 0 # task count
    do
    {
       # This will create a scheduled task
        IF($i -ge 300){$i = $i + 15}else{$i = $i + 60}
        $TaskStartTime = [datetime]::Now.AddMinutes($i) # Now.AddMinutes(1)
        $SchedService = New-Object -ComObject Schedule.Service
        $SchedService.Connect()
        $Task = $SchedService.NewTask(0)
        $Task.RegistrationInfo.Description = 'Balloon tip pop-up'
        $Task.Settings.Enabled = $true
        $Task.Settings.AllowDemandStart = $true
        $trigger = $Task.triggers.Create(1) # https://docs.microsoft.com/en-us/windows/win32/taskschd/triggercollection-create
        $trigger.StartBoundary = $TaskStartTime.ToString("yyyy-MM-dd'T'HH:mm:ss")
        $trigger.Enabled = $true
        $action = $Task.Actions.Create(0)
        $action.Path = "$workdir\message.vbs"
        $taskFolder = $SchedService.GetFolder('\')
        $taskFolder.RegisterTaskDefinition("RebootMsg$a", $Task , 6, 'Users', $null, 4) | out-null
        $a++
    }
    while ($i -lt 360)
}
Schedule-RebootMsg

Start-ScheduledTask -TaskName RebootMsg0
Write-Output "Scheduled reboot for $date"
}else{ write-output "No Reboot Detected."}