Skip to main content

Custom Reboot Notifications

  • September 14, 2020
  • 5 replies
  • 476 views

Forum|alt.badge.img

5 replies

Any chance you can post screenshots of what the popup prompts look like?


Forum|alt.badge.img
  • Author
  • Power User
  • 52 replies
  • September 14, 2020

image


any chance we could see the eval/rem code in a non-PDF format?


Forum|alt.badge.img
  • Author
  • Power User
  • 52 replies
  • July 12, 2021

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

    }

  }

}

you da man!


Reply


Cookie policy

We use cookies to enhance and personalize your experience. If you accept you agree to our full cookie policy. Learn more about our cookies.

 
Cookie settings