Files
management-scripts/Set-RebootSchedule2.ps1
T
2019-11-11 19:22:39 -05:00

281 lines
10 KiB
PowerShell

<#
.SYNOPSIS
Provides friendly messages reminding a user to restart their computer based on events that require it.
.DESCRIPTION
The Set-RebootSchedule script is called from any computer management software to notify a user of a required restart.
This script accepts several different parameters which change the messages displayed to the user.
.PARAMETER SysPerf
The -SysPerf parameter will remind the user to restart due to system performance.
This parameter should be called if the computer has had consistently high memory usage, recurring application hangs, or stuck processes.
If this parameter is used it will simply tell the user that a restart is needed to improve overall stability.
.PARAMETER OSUpdate
The -OSUpdate parameter will remind the user to restart due to operating system updates.
.PARAMETER Uptime
The -Uptime parameter will remind the user to restart due to long uptimes.
This script does not define the length of time the computer has been on, but will display the number of days to the end user.
If the computer has been on for 10 days and this parameter is used, it will tell the user this computer has been on for 10 days.
.PARAMETER AllowMinimize
The -AllowMinimize parameter will let the prompt be minimized by the user.
By default, the user is not allowed to minimize the window.
.EXAMPLE
Set-RebootSchedule -SysPerf
Prompt the user to restart because you've seen problems in multiple areas of the computer.
.EXAMPLE
Set-RebootSchedule -OSUpdate
Prompt the user to restart because Windows was recently updated.
.EXAMPLE
Set-RebootSchedule -Uptime
Prompt the user to restart because the computer has been up for a long time.
.NOTES
Calling this script with no parameters does nothing, the script will just exit without prompting the user for anything.
#>
## Define parameters
Param(
[switch]$SysPerf=$false,
[switch]$OSUpdate=$false,
[switch]$Uptime=$false,
[switch]$AllowMinimize=$false
)
## Get the name of this script
$ScriptName = $MyInvocation.MyCommand.Name
## Get a list of running PowerShell scripts
$RUnningPSScripts = Get-WmiObject Win32_Process -Filter "Name='powershell.exe'" | Select-Object ProcessId,CommandLine
## Loop through all other running instances of this script and kill each one that isn't the current instance.
ForEach ( $script in $RUnningPSScripts ) {
$OtherPID = $script.ProcessId
$OtherCMD = $script.CommandLine
## Check for other instances of this script that might be running
If ( ($OtherCMD -like "*${ScriptName}*") -and ($OtherPID -ne $PID) ) {
## Kill the other instance
Stop-Process -Id $script.ProcessId -Force
}
}
## Add Windows Forms support to this script
Add-Type -AssemblyName System.Windows.Forms
[System.Windows.Forms.Application]::EnableVisualStyles()
## Functions and subroutines
#region begin FUNCTIONS {
## Gets the number of days the system has been up.
Function Get-UptimeDays {
## Get a new instance of the Win32_OperatingSystem WMI object
$WMIOS = Get-WmiObject Win32_OperatingSystem
## Get the last boot time and convert it to a DateTime value
$LastBootTime = $WMIOS.ConvertToDateTime($WMIOS.LastBootUpTime)
## Get the number of days since the last time the system was powered on
[string]$Uptime = (New-TimeSpan -Start $LastBootTime -End $(Get-Date)).Days.ToString()
Return $Uptime
}
## Determines whether the logo can be downloaded or not
Function IsLogoDownloadable {
## Create a web request
$HTTPRequest = [System.Net.WebRequest]::Create($LogoURL)
## Get the response
Try { $HTTPResponse = $HTTPRequest.GetResponse() }
## Catch any error2 when trying to connect to the resource (including 404)
Catch [System.Net.WebException] { $HTTPResponse = $_.Exception.Response }
## Save the status code
$HTTPStatus = [int]$HTTPResponse.StatusCode
## Close the connection, because we're done with it
$HTTPResponse.Close()
## Test to make sure we received a status of 200 "OK" from the resource
If ($HTTPStatus -eq 200) { Return $true }
## If the status code is anything other than 200, return $false so we can do something else
Else { Return $false }
}
## Returns the local path of a file downloaded from a URL
Function Get-LogoPath {
## Get the file name from $url
$filename = [System.IO.Path]::GetFileName($LogoURL)
## Set the destination to download to
$localpath = "${Env:TEMP}\${filename}"
## Make sure the file is downloadable
If ( IsLogoDownloadable ) {
## Try downloading the file
Try { (New-Object Net.WebClient).DownloadFile($LogoURL, $localpath) }
## If you want to handle any download errors, put that code in here
Catch { $_ }
}
## Now that the file *may* be downloaded, check to make sure it exists
If ( Test-Path $localpath ) {
## Return $localpath to the caller
Return $localpath
}
## If $localpath doesn't exist (ie: from a previous execution of this script) then return $false
Else { Return $false }
}
## Builds the Windows form to display to the user
Function Display-Prompt([string]$message) {
## Set the form's overall parameters
$Form = New-Object System.Windows.Forms.Form
$Form.ClientSize = '400,360'
$Form.Text = $WindowTitle
$Form.TopMost = $true
$Form.MaximizeBox = $false
$Form.MinimizeBox = $AllowMinimize
$Form.FormBorderStyle = 'FixedDialog'
$Form.StartPosition = 'CenterScreen'
## Download the logo
$Logo = (Get-LogoPath)
## Add a picturebox to the form
If ( $Logo ) {
$pbLogo = New-Object system.Windows.Forms.PictureBox
$pbLogo.Width = $Form.ClientSize.Width - 20
$pbLogo.Height = 90
$pbLogo.Anchor = [System.Windows.Forms.AnchorStyles]::None
$pbLogo.Location = New-Object System.Drawing.Point(10,10)
$pbLogo.ImageLocation = $Logo
$pbLogo.SizeMode = [System.Windows.Forms.PictureBoxSizeMode]::CenterImage
$Form.Controls.Add($pbLogo)
}
## If the logo isn't available, add label to the form instead of a picturebox
Else {
$lblCompany = New-Object System.Windows.Forms.Label
$lblCompany.Text = $CompanyName
$lblCompany.AutoSize = $false
## The TextAlign enumerations can be found here:
## https://docs.microsoft.com/en-us/dotnet/api/system.drawing.contentalignment?view=netframework-2.0
$lblCompany.TextAlign = 32
$lblCompany.Width = $Form.ClientSize.Width - 20
$lblCompany.Height = 60
$lblCompany.Location = New-Object System.Drawing.Point(10,10)
$lblCompany.Font = 'Microsoft Sans Serif,24,style=Bold'
$Form.Controls.Add($lblCompany)
}
## This is the label that contains the reason for the restart
$lblReason = New-Object System.Windows.Forms.Label
$lblReason.Text = $message
$lblReason.AutoSize = $false
$lblReason.TextAlign = 1
$lblReason.Width = $Form.ClientSize.Width - 50
$lblReason.Height = 180
$lblReason.Location = New-Object System.Drawing.Point(25,100)
$lblReason.Font = 'Microsoft Sans Serif,11'
$Form.Controls.Add($lblReason)
## This is the label that contains a static message about how to proceed
$lblProceed = New-Object System.Windows.Forms.Label
$lblProceed.Text = $ProceedText
$lblProceed.AutoSize = $true
$lblProceed.TextAlign = 1
$lblProceed.Location = New-Object System.Drawing.Point(25,280)
$lblProceed.Font = 'Microsoft Sans Serif,11'
$Form.Controls.Add($lblProceed)
## This is the button that displays the nearest time to schedule a reboot
$btnRestartNow = New-Object System.Windows.Forms.Button
$btnRestartNow.Text = $RestartNowText
$btnRestartNow.Width = 130
$btnRestartNow.Height = 30
$btnRestartNow.Location = New-Object System.Drawing.Point(45,310)
$btnRestartNow.Font = 'Microsoft Sans Serif,11'
$btnRestartNow.Add_Click({
## Restart the computer
Restart-Computer
## We're done for now, just close the window.
$Form.Close()
})
$Form.AcceptButton = $btmRestartNow
$Form.Controls.Add($btnRestartNow)
## This is the placebo button, it just closes the form when clicked.
## The reminder schedule has already been created, so this button doesn't need to do anything.
$btnCancel = New-Object System.Windows.Forms.Button
$btnCancel.Text = $CancelText
$btnCancel.Width = 130
$btnCancel.Height = 30
$btnCancel.Location = New-Object System.Drawing.Point(225,310)
$btnCancel.Font = 'Microsoft Sans Serif,11'
$btnCancel.Add_Click({ $Form.Close() })
$Form.Controls.Add($btnCancel)
[void]$Form.ShowDialog()
}
#endregion FUNCTIONS }
## Define custom company name, logo, window title, and messages
#region begin CUSTOMIZATIONS {
## The following 2 settings are specific to your company
## This is the name of your company.
$CompanyName = "Emberkom"
## This is the URL to your company logo.
## If your company logo cannot be downloaded, $CompanyName will be used instead.
## If the image you specify is larger than 380x90, it will be centered in that area (clipping will occur).
$LogoURL = 'https://emberkom.s3.amazonaws.com/management/scripts/resources/small-web-logo.png'
## The following 7 settings control text displayed on the form when prompting the user to choose a time to restart their computer
## The title of the window
$WindowTitle = "Restart Required - ${CompanyName}"
## The message displayed to the user when -SysPerf is called.
$SysPerfText = "It looks like your computer isn't performing like it should.`n`nRestarting it will help to resolve some of the problems its been having."
## The message displayed to the user when -OSUpdate is called.
$OSUpdateText = "Good news!`n`nYour computer has recently installed some updates and it needs to be restarted soon."
## The message displayed to the user when -Uptime is called.
$UptimeText = "It looks like your computer has been on for more than $(Get-UptimeDays) days.`n`nIt's probably best to restart soon so it doesn't start causing problems for you."
## This is the message displayed just above the buttons - it should ask the user how they want to proceed
$ProceedText = "Can we make this happen?"
## This is the text for the cancel button. Clicking this button will just close the form
$CancelText = "Remind me later"
## The message on the button that immediately restarts the computer
$RestartNowText = "Restart Now"
#endregion CUSTOMIZATIONS }
## Display the form
If ( $SysPerf ) { Display-Prompt $SysPerfText }
ElseIf ( $OSUpdate ) { Display-Prompt $OSUpdateText }
ElseIF ( $Uptime ) { Display-Prompt $UptimeText }