25 February 2016

Laptop Mandatory Reboot Management

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
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  

12 comments:

  1. 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

    ReplyDelete
    Replies
    1. Sorry 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
  2. Why is there a need for a mandatory reboot every 14 days?

    ReplyDelete
    Replies
    1. That was the chosen time period for the firm I work at. They want a reboot at least every two weeks.

      Delete
  3. Can you comment about the SCCM setup for this?

    ReplyDelete
    Replies
    1. Sorry 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
  4. Why didnt you use win32_operatingSystem.lastbootuptime for last reboot timestamp? Seems to be more relilable for me.

    ReplyDelete
    Replies
    1. I 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

      Delete
  5. This is wonderful! Thank you for posting it. I am going to try and test it here. We need this exact same thing.

    ReplyDelete
  6. I've been testing your scripts in my lab and they're working great on Win7, 8.1 and 10 devices! Thanks for sharing this :)

    ReplyDelete
  7. I 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?

    ReplyDelete
    Replies
    1. Sorry 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