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'HHss")
$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'HHss")
$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'HHss")
$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."}