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 = ePInvoke.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(pstring]$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 = tconvert]::FromBase64String($Base64Image)
System.IO.File]::WriteAllBytes($strImageFile,$Bytes)
}
}
Function ClearToastNotification
{
param(pstring]$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(pstring]$rebootStartTime, Tstring]$rebootEndTime)
bxml]$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 = oWindows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType = WindowsRuntime]
$Load = oWindows.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 = iPInvoke.Win32.UserInput]::IdleTime
if ($idleTime.Minutes -ge $minIdleTime)
{
$boolIdleConditionMet = $True
}
return ($boolIdleConditionMet -and $boolTimeConditionMet)
}
Function RebootComputer
{
Restart-Computer -Force
}
Function IsTimeForReminder
{
param(pint]$intMinutesBetweenReminders, dstring]$registryPath)
$doReminder = $False
$intLastReminder = GetMinutesSinceLastReminder($registryPath)
if ($intLastReminder -ge $intMinutesBetweenReminders)
{
$doReminder = $True
UpdateReminderTracker($registryPath)
}
return $doReminder
}
Function GetMinutesSinceLastReminder
{
param(pstring]$registryPath)
$minutesSinceLastReminder = 999999
$boolReturnVal = VerifyReminderTracker($registryPath)
if ($boolReturnVal -eq $False)
{
$lastReminder = (Get-ItemProperty -Path $registryPath -Name "LastNotified").LastNotified
$lastReminder = ddatetime]$lastReminder
$tempDate = New-TimeSpan -Start $lastReminder -End (Get-Date)
$minutesSinceLastReminder = $tempDate.TotalMinutes
}
return ($minutesSinceLastReminder)
}
Function UpdateReminderTracker
{
param(pstring]$registryPath)
VerifyReminderTracker($registryPath)
$now = nstring](Get-Date)
Set-ItemProperty -Path $registryPath -Name "LastNotified" -Value $now | Out-Null
}
Function VerifyReminderTracker
{
param(pstring]$registryPath)
$boolFirstTimeRunning = $False
InitializeReminderTracker($registryPath)
$lastReminder = (Get-ItemProperty -Path $registryPath -Name "LastNotified").LastNotified
if (!(istring]$lastReminder -as rDateTime]))
{
$now = nstring](Get-Date)
Set-ItemProperty -Path $registryPath -Name "LastNotified" -Value $now | Out-Null
$boolFirstTimeRunning = $True
}
return $boolFirstTimeRunning
}
#--- Never call this function directly
Function InitializeReminderTracker
{
param(pstring]$registryPath)
$Now = (Get-Date)
$Now = $Now.AddMonths(-3)
$Now = Nstring]$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
}
}
#---------------------------------------------------------------------------------------
bstring]$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.
bstring]$ImageFile = "$env:TEMP\BWToastLogo.png"
bstring]$NotificationRegistryPath = "HKCU:\Software\BW\RebootNotification"
# These parameters control the time of day window within which automatic reboot will be initiated
bstring]$rebootStartTime = "1am"
bstring]$rebootEndTime = "5am"
# If there is no user input detected for $minIdleTime minutes within $rebootStarTime and $rebootEndTime, automatic reboot
# will be initiated
bint]$minIdleTime = 30
# How many times per day to show reboot reminder toast notification
bint]$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)
bint]$minutesBetweenReminders = eint]((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
}
}
}
you da man!
No account yet? Create an account
Enter your E-mail address. We'll send you an e-mail with instructions to reset your password.