From Worklet: Predictable Reboot Notifications for Windows
RebootNotifications.pdf (133.8 KB)
Any chance you can post screenshots of what the popup prompts look like?
any chance we could see the eval/rem code in a non-PDF format?
Sure. Sorry I didn’t post earlier. I have been very busy working with OAuth 2. 🙂
Hidden.vbs
CreateObject("Wscript.Shell").Run """" & WScript.Arguments(0) & """", 0, False
Runtoasthidden.cmd
powershell.exe -executionpolicy Unrestricted -file "C:\ProgramData\amagent\rebootNotification\RebootToastNotification.ps1"
Runreboothidden.cmd
powershell.exe -executionpolicy Unrestricted -file "C:\ProgramData\amagent\rebootNotification\RebootWithoutNotification.ps1"
Rebootwithoutnotification.ps1
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
}
}
Reboottoastnotification.ps1
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 SaveToastLogo
{
param([string]$strImageFile)
$Base64Image = "......replace with your own image....."
if (!(Test-Path $strImageFile))
{
# Create an image file from base64 string and save to user temp location
[byte[]]$Bytes = [convert]::FromBase64String($Base64Image)
[System.IO.File]::WriteAllBytes($strImageFile,$Bytes)
}
}
Function ClearToastNotification
{
param([string]$toastAppID)
[Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType = WindowsRuntime] | Out-Null
[Windows.UI.Notifications.ToastNotification, Windows.UI.Notifications, ContentType = WindowsRuntime] | Out-Null
[Windows.UI.Notifications.ToastNotificationManager]::History.Clear($appID)
}
Function ShowToastNotification
{
param([string]$rebootStartTime, [string]$rebootEndTime)
[xml]$Toast = @"
<toast scenario="reminder">
<visual>
<binding template="ToastGeneric">
<text>BW IT Notice</text>
<text>Your computer was recently patched. Please restart manually, or automatic restart will occur between $rebootStartTime and $rebootEndTime.</text>
<image placement="appLogoOverride" hint-crop="circle" src="$ImageFile"/>
<group>
<subgroup>
<text hint-style="captionSubtle">If you need assistance, contact Help Desk.</text>
</subgroup>
</group>
</binding>
</visual>
<actions>
<action activationType="system"
arguments="dismiss"
content="Dismiss"
/>
</actions>
<audio src="ms-winsoundevent:Notification.Looping.Alarm3"/>
</toast>
"@
$Load = [Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType = WindowsRuntime]
$Load = [Windows.Data.Xml.Dom.XmlDocument, Windows.Data.Xml.Dom.XmlDocument, ContentType = WindowsRuntime]
# Load the notification into the required format
$ToastXml = New-Object -TypeName Windows.Data.Xml.Dom.XmlDocument
$ToastXml.LoadXml($Toast.OuterXml)
[Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier($appID).Show($ToastXml)
}
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
}
Function IsTimeForReminder
{
param([int]$intMinutesBetweenReminders, [string]$registryPath)
$doReminder = $False
$intLastReminder = GetMinutesSinceLastReminder($registryPath)
if ($intLastReminder -ge $intMinutesBetweenReminders)
{
$doReminder = $True
UpdateReminderTracker($registryPath)
}
return $doReminder
}
Function GetMinutesSinceLastReminder
{
param([string]$registryPath)
$minutesSinceLastReminder = 999999
$boolReturnVal = VerifyReminderTracker($registryPath)
if ($boolReturnVal -eq $False)
{
$lastReminder = (Get-ItemProperty -Path $registryPath -Name "LastNotified").LastNotified
$lastReminder = [datetime]$lastReminder
$tempDate = New-TimeSpan -Start $lastReminder -End (Get-Date)
$minutesSinceLastReminder = $tempDate.TotalMinutes
}
return ($minutesSinceLastReminder)
}
Function UpdateReminderTracker
{
param([string]$registryPath)
VerifyReminderTracker($registryPath)
$now = [string](Get-Date)
Set-ItemProperty -Path $registryPath -Name "LastNotified" -Value $now | Out-Null
}
Function VerifyReminderTracker
{
param([string]$registryPath)
$boolFirstTimeRunning = $False
InitializeReminderTracker($registryPath)
$lastReminder = (Get-ItemProperty -Path $registryPath -Name "LastNotified").LastNotified
if (!([string]$lastReminder -as [DateTime]))
{
$now = [string](Get-Date)
Set-ItemProperty -Path $registryPath -Name "LastNotified" -Value $now | Out-Null
$boolFirstTimeRunning = $True
}
return $boolFirstTimeRunning
}
#--- Never call this function directly
Function InitializeReminderTracker
{
param([string]$registryPath)
$Now = (Get-Date)
$Now = $Now.AddMonths(-3)
$Now = [string]$now
if (!(Test-Path $registryPath))
{
New-Item -Path $registryPath -Force | Out-Null
New-ItemProperty -Path $registryPath -Name "LastNotified" -Value $Now -PropertyType STRING -Force | Out-Null
}
try
{
$lastReminder = (Get-ItemProperty -Path $registryPath -Name "LastNotified" -ErrorAction Stop).LastNotified
}
catch
{
New-ItemProperty -Path $registryPath -Name "LastNotified" -Value $Now -PropertyType STRING -Force | Out-Null
}
}
#---------------------------------------------------------------------------------------
[string]$appID = "{1AC14E77-02E7-4E5D-B744-2EB1AE5198B7}\WindowsPowerShell\v1.0\powershell.exe"
# Note: These next two variables work because this script is run as a scheduled task configured to execute as the currently logged on user.
# This is needed so that user is able to see the toast notification. If the task runs under the SYSTEM context, the toast notification
# will not show.
[string]$ImageFile = "$env:TEMP\BWToastLogo.png"
[string]$NotificationRegistryPath = "HKCU:\Software\BW\RebootNotification"
# 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
# How many times per day to show reboot reminder toast notification
[int]$reminderTimesPerDay = 1
# Dump the base-64 image into a file on disk. This image is used in the toast notification.
# If the image is missing, the toast notification will not show.
SaveToastLogo($ImageFile)
# Clear any previous toast notifications generated by Powershell. This will ensure we don't have notifications that are stacked (they show one at a time
# immediately after you dismiss one). This may confuse / irritate a user.
ClearToastNotification($appID)
# Check registry key exists. Create if it doesn't exist.
VerifyReminderTracker($NotificationRegistryPath)
[int]$minutesBetweenReminders = [int]((24 / $reminderTimesPerDay) * 60)
# Check if a reboot is pending
$sysInfo = New-Object -ComObject "Microsoft.Update.SystemInfo"
if($sysInfo.RebootRequired)
{
if (IsAutomaticReboot)
{
RebootComputer
}
else
{
if (IsTimeForReminder $minutesBetweenReminders $NotificationRegistryPath)
{
ShowToastNotification $rebootStartTime $rebootEndTime
}
}
}
5 likes
1 like
1 like
No account yet? Create an account
Enter your E-mail address. We'll send you an e-mail with instructions to reset your password.
Sorry, we're still checking this file's contents to make sure it's safe to download. Please try again in a few minutes.
OKSorry, our virus scanner detected that this file isn't safe to download.
OKWe use cookies to enhance and personalize your experience. If you accept you agree to our full cookie policy. Learn more about our cookies.
We use 3 different kinds of cookies. You can choose which cookies you want to accept. We need basic cookies to make this site work, therefore these are the minimum you can select. Learn more about our cookies.