The following PowerShell script creates a dialog window which performs an automated device reboot after a pre-specified timeout period. The dialog window has buttons for Cancel and Reboot Now. If the users selects Cancel the script terminates with immediate effect. Should the user select Reboot Now the device will reboot immediately. If no action is taken by the user the code contains a countdown timer object which will countdown and then reboot the device automatically once the timeout period has been met.
The two important variables are $nTimeout which contains the timeout period in seconds and $debug_mode which can be set to $true when testing so that no actual reboot takes place.
The routine is designed to be called as a Windows scheduled task and can be used to automatically reboot workstations at a specified day and time. This is useful for devices that are left on permanently and can often go for weeks or even months without a shutdown or restart.
The .ps1 code is presented below; The code has been tested and works on Windows 10/11.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 |
#----------------------------------------------------------------------------# # Program Copyright : Mike Wilcock. # Program Name : device_reboot.ps1. #----------------------------------------------------------------------------# # Program Created : 23rd May 2023. # Program Code Type : PowerShell Script (version 5.1.22621.436). # Author : Michael Wilcock, IT Technician. #----------------------------------------------------------------------------# # Version : 2.10 #----------------------------------------------------------------------------# # Purpose : Reboot PC with user confirmation dialog box and timeout. #----------------------------------------------------------------------------# # Timeout in seconds. $nTimeout = 30 # If set to true the reboot will not happen. Set to false for production. $debug_mode = $true # Countdown timer. Variable MUST be global in scope. $global:nCountdown = $nTimeout #----------------------------------------------------------------------------# # Elegantly perform reboot. #----------------------------------------------------------------------------# # Notes: Function is called by the timer object and the reboot button click event. # # If memvar $debug_mode is $true perform a simulated reboot #----------------------------------------------------------------------------# function close_and_reboot() { # Simulate reboot for testing. if($debug_mode -eq $true) { Restart-Computer -whatIf } # Production. else { Restart-Computer } # Close dialog window. $oDlg.Close() } #----------------------------------------------------------------------------# # Update countdown timer label. #----------------------------------------------------------------------------# # Notes: Function is called every second by the timer object. Uses globaly # scoped variable to store the seconds left until reboot happens. #----------------------------------------------------------------------------# function updCountdown() { # Decrement countdown timer global variable. $global:nCountdown-- # Update countdown label. $lbl_countdown.text = "Time To Restart: " + $global:nCountdown } #----------------------------------------------------------------------------# # Main code. Create dialog window, timer object and form components. #----------------------------------------------------------------------------# # Load windows forms class. Add-Type -assembly System.Windows.Forms $cMessage = "Device: " + $env:computername + " Requires A Reboot`n`nPlease select Cancel to delay the restart until further notice.`n`nIf no selection is made the device will restart after $nTimeout seconds!" $cTitle = "[" + $env:computername + "] - " + "Automatic Device Restart" $CenterScreen = [System.Windows.Forms.FormStartPosition]::CenterScreen; # Button row in pixels. $nBtnRow = 170 # Create our dialog window. $oDlg = New-Object System.Windows.Forms.Form $oDlg.Text = $cTitle $oDlg.Width = 475 $oDlg.Height = 235 $oDlg.FormBorderStyle = 'Fixed3D' $oDlg.MaximizeBox = $false $oDlg.MinimizeBox = $false $oDlg.StartPosition = $CenterScreen; $oDlg.AutoSize = $true # Create a timer. $timer_reboot = New-Object System.Windows.Forms.Timer $timer_reboot.Interval = $nTimeout * 1000 # Set up the event handler for the timer. $timer_reboot.Add_Tick({close_and_reboot}) # Panel object. $panel = New-Object System.Windows.Forms.Panel $panel.Left = 0 $panel.Top = 0 $panel.Width = $oDlg.Width $panel.Height = 61 $panel.BackColor = '255, 255, 255' $panel.Dock = "top" # Add panel to our form. $oDlg.Controls.Add($panel) # Add an image to the form using Base64. $base64ImageString = "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" $imageBytes = [Convert]::FromBase64String($base64ImageString) $ms = New-Object IO.MemoryStream($imageBytes, 0, $imageBytes.Length) $ms.Write($imageBytes, 0, $imageBytes.Length); $nhs_logo = [System.Drawing.Image]::FromStream($ms, $true) # picturebox object. $pictureBox = new-object Windows.Forms.PictureBox $pictureBox.Width = $nhs_logo.Size.Width; $pictureBox.Height = $nhs_logo.Size.Height; $pictureBox.Location = New-Object System.Drawing.Size(360,0) $pictureBox.Image = $nhs_logo; # Add picturebox to our form. $oDlg.Controls.Add($pictureBox) # User message label. $lbl_message = New-Object System.Windows.Forms.Label $lbl_message.Text = $cMessage $lbl_message.Location = New-Object System.Drawing.Point(10,80) $lbl_message.AutoSize = $true # Add label to our form. $oDlg.Controls.Add($lbl_message) # Countdown timer label. $lbl_countdown = New-Object System.Windows.Forms.Label $lbl_countdown.Text = "Time To Restart: " + $nCountdown $lbl_countdown.Location = New-Object System.Drawing.Point(10, $nBtnRow) $lbl_countdown.ForeColor = "red" $lbl_countdown.AutoSize = $true # Add label to our form. $oDlg.Controls.Add($lbl_countdown) # Create a timer. $timer_countdown = New-Object System.Windows.Forms.Timer $timer_countdown.Interval = 1000 # Set up the event handler for the timer. $timer_countdown.Add_Tick({updCountdown}) # Reboot button. $btn_reboot = New-Object System.Windows.Forms.Button $btn_reboot.Location = New-Object System.Drawing.Size(355, $nBtnRow) $btn_reboot.Size = New-Object System.Drawing.Size(100, 23) $btn_reboot.Text = "REBOOT NOW" # Add button to our form. $oDlg.Controls.Add($btn_reboot) # Capture click event. $btn_reboot.Add_Click({close_and_reboot}) # Cancel button. $btn_cancel = New-Object System.Windows.Forms.Button $btn_cancel.Location = New-Object System.Drawing.Size(255, $nBtnRow) $btn_cancel.Size = New-Object System.Drawing.Size(100, 23) $btn_cancel.Text = "Cancel" $oDlg.Controls.Add($btn_cancel) # Add button to our form. $btn_cancel.Add_Click({$oDlg.Close()}) # IMPORTANT. Order items for correct display. $oDlg.Controls.SetChildIndex($panel, 1) # Start both timers. $timer_reboot.Start() $timer_countdown.Start() # Let's do this thing! $oDlg.ShowDialog() # Dispose (stop) the timer. Doing this here instead of in the tick # event handler ensures that the timer is stopped even when the form # was closed by the user. $timer_reboot.Dispose() $timer_countdown.Dispose() # Dispose the form and its controls. Skip, if you want to redisplay the form later. $oDlg.Dispose() |