Managing laptops in certain environments can be daunting. Reboots are a must every now and then, especially for monthly windows updates. With the sleep and hibernate features being enabled, the chances of a user rebooting a laptop become far less. A laptop can go weeks and even months without a reboot. Working in the legal industry, as I do, adds to the complexity of forcing reboots as you have the issue of not causing a reboot during a hearing or during a client meeting for instance. You want to be as unobtrusive as possible. You might say that this is not needed as SCCM could be setup to automatically perform this same function on a regular schedule. That is true. Where this becomes valuable is when you don't want to force a reboot on users that regularly reboot their machines. If they are already doing this, which we have a fair number of users that do, then there is no need to reboot an additional time that will inconvenience them.
To make this process as unobtrusive as possible, I have written the following two PowerShell scripts, using Sapien's PowerShell Studio, that work in conjunction with SCCM 2012 to give users the leisure of a full business day to reboot the machine. One script is the custom detection method and the other is the installer.
The custom detection method works by reading the last event viewer 1074. It looks at the date of the ID and then sees if it is 14 days or older. This can be set to any number of days other than the 14 my firm has chosen. If it is 14 days old, the script then sets the registry key Rebooted to a DWORD value of 1 and fails the detection method. When the method fails, SCCM will then run the second PowerShell script.
The second script operates by running the same detection method. Once it detects the same values, it resets the Rebooted Key to 0 and then returns the error code 3010 back to SCCM. SCCM then reruns the detection method. The detection method sees there has been 14 days or more and the Rebooted key is set to 0. It returns and error code 0 back to SCCM with a write-host of "Success". This tells SCCM the application ran successfully and to now process with the soft reboot, which was required by the 3010 return code.
The final part is to configure the Computer Restart under the SCCM client settings. I configured ours to be 480 minutes, which is 8 hours, with a mandatory dialog window that cannot be closed the final 60 minutes.
When the system reboots, the custom detection method runs again and sees there is a new 1074 entry in the event viewer, along with the registry key Rebooted being a 0, therefor it shows successfully installed. As the days progress and SCCM reruns the custom detection method, it will rerun the application script to reboot the machine again if the machine is not rebooted in the 14 allotted days. If the user reboots the machine every week, the SCCM application will never reboot the machine.
I had a few to ask for a tutorial on setting this up. Here is a video I made on how I setup and configured the scripts in SCCM.
Here are the links to the two scripts:
Here are the two scripts below:
MandatoryRebootCustomDetection.ps1
To make this process as unobtrusive as possible, I have written the following two PowerShell scripts, using Sapien's PowerShell Studio, that work in conjunction with SCCM 2012 to give users the leisure of a full business day to reboot the machine. One script is the custom detection method and the other is the installer.
The custom detection method works by reading the last event viewer 1074. It looks at the date of the ID and then sees if it is 14 days or older. This can be set to any number of days other than the 14 my firm has chosen. If it is 14 days old, the script then sets the registry key Rebooted to a DWORD value of 1 and fails the detection method. When the method fails, SCCM will then run the second PowerShell script.
The second script operates by running the same detection method. Once it detects the same values, it resets the Rebooted Key to 0 and then returns the error code 3010 back to SCCM. SCCM then reruns the detection method. The detection method sees there has been 14 days or more and the Rebooted key is set to 0. It returns and error code 0 back to SCCM with a write-host of "Success". This tells SCCM the application ran successfully and to now process with the soft reboot, which was required by the 3010 return code.
The final part is to configure the Computer Restart under the SCCM client settings. I configured ours to be 480 minutes, which is 8 hours, with a mandatory dialog window that cannot be closed the final 60 minutes.
When the system reboots, the custom detection method runs again and sees there is a new 1074 entry in the event viewer, along with the registry key Rebooted being a 0, therefor it shows successfully installed. As the days progress and SCCM reruns the custom detection method, it will rerun the application script to reboot the machine again if the machine is not rebooted in the 14 allotted days. If the user reboots the machine every week, the SCCM application will never reboot the machine.
I had a few to ask for a tutorial on setting this up. Here is a video I made on how I setup and configured the scripts in SCCM.
Here are the links to the two scripts:
Here are the two scripts below:
MandatoryRebootCustomDetection.ps1
1: <#
2: .SYNOPSIS
3: Mandatory Reboot Custom Detection Method
4:
5: .DESCRIPTION
6: This script will read the last time a system rebooted from the event viewer logs. It then calculates the number of days since that time. If the number of days equals or exceeds the RebootThreshold variable, the script will exit with a return code 0 and no data output. No data output is read by SCCM as a failure. If the number of days is less than the RebootThreshold, then a message is written saying the system is within the threshold and the script exits with a return code of 0. SCCM reads an error code 0 with data output as a success.
7:
8: .NOTES
9: ===========================================================================
10: Created with: SAPIEN Technologies, Inc., PowerShell Studio 2016 v5.2.122
11: Created on: 6/8/2016 2:04 PM
12: Created by: Mick Pletcher
13: Organization:
14: Filename: MandatoryRebootCustomDetection.ps1
15: ===========================================================================
16: #>
17:
18: #Number of days until reboot becomes mandatory
19: $RebootThreshold = 14
20: $Today = Get-Date
21: #Returns "32-bit" or "64-bit"
22: $Architecture = Get-WmiObject -Class Win32_OperatingSystem | Select-Object OSArchitecture
23: $Architecture = $Architecture.OSArchitecture
24: #Gets the last reboot from the event viewer logs
25: $LastReboot = get-winevent -filterhashtable @{ logname = 'system'; ID = 1074 } -maxevents 1 -ErrorAction SilentlyContinue
26: #Tests if the registry key Rebooted exists and creates it if it does not. It then reads if the system has been rebooted by the value being either a 0 or 1. This determines if the reboot has occurred and is set in the MandatoryReboot.ps1 file when the custom detection method triggers its execution
27: if ($Architecture -eq "32-bit") {
28: if ((Test-Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Reboot") -eq $false) {
29: New-Item "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Reboot" | New-ItemProperty -Name Rebooted -Value 0 -Force | Out-Null
30: }
31: $Rebooted = Get-ItemProperty -Name Rebooted -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Reboot"
32: } else {
33: if ((Test-Path "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Reboot") -eq $false) {
34: New-Item "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Reboot" | New-ItemProperty -Name Rebooted -Value 0 -Force | Out-Null
35: }
36: $Rebooted = Get-ItemProperty -Name Rebooted -Path "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Reboot"
37: }
38: #Get the 0 or 1 value if a system has been rebooted within the $RebootThreshold period
39: $Rebooted = $Rebooted.Rebooted
40: #Calculate how long since last reboot. If no event viewer entries since last reboot, then trigger a reboot
41: if ($LastReboot -eq $null) {
42: $Difference = $RebootThreshold
43: } else {
44: $Difference = New-TimeSpan -Start $Today -End $LastReboot.TimeCreated
45: $Difference = [math]::Abs($Difference.Days)
46: }
47: #The first two conditions report to SCCM that the deployment is "installed" thereby not triggering a reboot. The last two report to SCCM the app is "not installed" and trigger an install
48: if (($Difference -lt $RebootThreshold) -and ($Rebooted -eq 0)) {
49: Write-Host "Success"
50: exit 0
51: }
52: if (($Difference -ge $RebootThreshold) -and ($Rebooted -eq 1)) {
53: Write-Host "Success"
54: exit 0
55: }
56: if (($Difference -ge $RebootThreshold) -and ($Rebooted -eq 0)) {
57: exit 0
58: }
59: if (($Difference -lt $RebootThreshold) -and ($Rebooted -eq 1)) {
60: exit 0
61: }
62:
MandatoryReboot.ps1
1: <#
2: .SYNOPSIS
3: Mandatory Reboot
4:
5: .DESCRIPTION
6: This script will read the last time a system rebooted from the event viewer logs. It then calculates the number of days since that time. If the number of days equals or exceeds the RebootThreshold variable, the script will change the registry key Rebooted to a 0. It then exits with an error code 3010, which tells SCCM 2012 to perform a soft reboot.
7:
8: .NOTES
9: ===========================================================================
10: Created with: SAPIEN Technologies, Inc., PowerShell Studio 2016 v5.2.122
11: Created on: 6/8/2016 1:58 PM
12: Created by: Mick Pletcher
13: Organization:
14: Filename: MandatoryReboot.ps1
15: ===========================================================================
16: #>
17:
18: #Returns "32-bit" or "64-bit"
19: $Architecture = Get-WmiObject -Class Win32_OperatingSystem | Select-Object OSArchitecture
20: $Architecture = $Architecture.OSArchitecture
21: #Tests if the registry key Rebooted exists and creates it if it does not. It then reads if the system has been rebooted by the value being either a 0 or 1. This determines if the reboot has occurred and is set in the MandatoryReboot.ps1 file when the custom detection method triggers its execution
22: if ($Architecture -eq "32-bit") {
23: if ((Test-Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Reboot") -eq $false) {
24: New-Item "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Reboot" | New-ItemProperty -Name Rebooted -Value 0 -Force | Out-Null
25: }
26: $Rebooted = Get-ItemProperty -Name Rebooted -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Reboot"
27: } else {
28: if ((Test-Path "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Reboot") -eq $false) {
29: New-Item "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Reboot" | New-ItemProperty -Name Rebooted -Value 0 -Force | Out-Null
30: }
31: $Rebooted = Get-ItemProperty -Name Rebooted -Path "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Reboot"
32: }
33: #Get the 0 or 1 value if a system has been rebooted within the $RebootThreshold period
34: $Rebooted = $Rebooted.Rebooted
35: #Number of days until reboot becomes mandatory
36: $RebootThreshold = 14
37: $Today = Get-Date
38: #Gets the last reboot from the event viewer logs
39: $LastReboot = get-winevent -filterhashtable @{ logname = 'system'; ID = 1074 } -maxevents 1 -ErrorAction SilentlyContinue
40: #Calculate how long since last reboot. If no event viewer entries since last reboot, then trigger a reboot
41: if ($LastReboot -eq $null) {
42: $Difference = $RebootThreshold
43: } else {
44: $Difference = New-TimeSpan -Start $Today -End $LastReboot.TimeCreated
45: $Difference = [math]::Abs($Difference.Days)
46: }
47: #Change the HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Reboot key to a 1 if the system is over the pre-determined threshold and $Rebooted = 0
48: if (($Difference -ge $RebootThreshold) -and ($Rebooted -eq 0)) {
49: if ((Test-Path "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Reboot") -eq $true) {
50: Set-ItemProperty -Path "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Reboot" -Name Rebooted -Value 1 -Type DWORD -Force
51: $Rebooted = Get-ItemProperty -Name Rebooted -Path "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Reboot"
52: } else {
53: Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Reboot" -Name Rebooted -Value 1 -Type DWORD -Force
54: $Rebooted = Get-ItemProperty -Name Rebooted -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Reboot"
55: }
56: }
57: $Rebooted = $Rebooted.Rebooted
58: #Change the HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Reboot key back to 0 if the system has been rebooted within the $RebootThreshold period
59: if (($Difference -lt $RebootThreshold) -and ($Rebooted -eq 1)) {
60: if ((Test-Path "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Reboot") -eq $true) {
61: Set-ItemProperty -Name Rebooted -Value 0 -Path "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Reboot" -Type DWORD -Force
62: $Rebooted = Get-ItemProperty -Name Rebooted -Path "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Reboot"
63: } else {
64: Set-ItemProperty -Name Rebooted -Value 0 -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Reboot" -Type DWORD -Force
65: $Rebooted = Get-ItemProperty -Name Rebooted -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Reboot"
66: }
67: $Rebooted = $Rebooted.Rebooted
68: Write-Host "System is within"$RebootThreshold" Day Reboot Threshold"
69: }
70: Write-Host "Reboot Threshold:"$RebootThreshold
71: Write-Host "Difference:"$Difference
72: Write-Host "Rebooted:"$Rebooted
73: Exit 3010
Thanks for sharing - just a question regarding how you set this up in SCCM. Task sequence calling one script then the other? Separate packages/deployments set to run daily? thanks
ReplyDeleteSorry for not getting back with you earlier, I have been really busy lately. I just made and posted a video on how to set it up in SCCM.
DeleteWhy is there a need for a mandatory reboot every 14 days?
ReplyDeleteThat was the chosen time period for the firm I work at. They want a reboot at least every two weeks.
DeleteCan you comment about the SCCM setup for this?
ReplyDeleteSorry for not getting back with you earlier, I have been really busy lately. I just made and posted a video on how to set it up in SCCM.
DeleteWhy didnt you use win32_operatingSystem.lastbootuptime for last reboot timestamp? Seems to be more relilable for me.
ReplyDeleteI found the registry key to be really reliable when I was looking at it. That is a good thought. I might come back and update the script using that WMI call. Thanks
DeleteThis is wonderful! Thank you for posting it. I am going to try and test it here. We need this exact same thing.
ReplyDeleteI've been testing your scripts in my lab and they're working great on Win7, 8.1 and 10 devices! Thanks for sharing this :)
ReplyDeleteI am testing this too, but am a bit confused as to the actual deployment of it. I deployed the MandatoryReboot.ps1 and set RebootCustomDetection.ps1 to run first. I set the MandatoryReboot to "SCCM Reboots computer". and am going to run this every day at 08:30. Does this sound right?
ReplyDeleteSorry for not getting back with you earlier, I have been really busy lately. I just made and posted a video on how to set it up in SCCM.
Delete