Skip to content

Instantly share code, notes, and snippets.

@anuriq
Last active February 3, 2016 09:52
Show Gist options
  • Save anuriq/ecbd675d4a680f06afce to your computer and use it in GitHub Desktop.
Save anuriq/ecbd675d4a680f06afce to your computer and use it in GitHub Desktop.
function Get-PendingReboot {
<#
.SYNOPSIS
Gets the pending reboot status on a local or remote computer.
.DESCRIPTION
This function will query the registry on a local or remote computer and determine if the
system is pending a reboot, from either Microsoft Patching or a Software Installation.
For Windows 2008+ the function will query the CBS registry key as another factor in determining
pending reboot state. "PendingFileRenameOperations" and "Auto Update\RebootRequired" are observed
as being consistent across Windows Server 2003 & 2008.
CBServicing = Component Based Servicing (Windows 2008)
WindowsUpdate = Windows Update / Auto Update (Windows 2003 / 2008)
PendFileRename = PendingFileRenameOperations (Windows 2003 / 2008)
.PARAMETER ComputerName
A single Computer or an array of computer names. The default is localhost ($env:COMPUTERNAME).
.PARAMETER ErrorLog
A single path to send error data to a log file.
.EXAMPLE
PS C:\> Get-PendingReboot -ComputerName (Get-Content C:\ServerList.txt) | Format-Table -AutoSize
Computer CBServicing WindowsUpdate PendFileRename RebootPending
-------- ----------- ------------- -------------- -------------
DC01 False False False False
DC02 False False False False
FS01 False True True True
This example will capture the contents of C:\ServerList.txt and query the pending reboot
information from the systems contained in the file and display the output in a table
.EXAMPLE
PS C:\> Get-PendingReboot
Computer : WKS01
CBServicing : False
WindowsUpdate : True
PendFileRename : False
RebootPending : True
This example will query the local machine for pending reboot information.
.EXAMPLE
PS C:\> $Servers = Get-Content C:\Servers.txt
PS C:\> Get-PendingReboot -Computer $Servers | Export-Csv C:\PendingRebootReport.csv -NoTypeInformation
This example will create a report that contains pending reboot information.
.LINK
Component-Based Servicing:
http://technet.microsoft.com/en-us/library/cc756291(v=WS.10).aspx
PendingFileRename/Auto Update:
http://support.microsoft.com/kb/2723674
http://technet.microsoft.com/en-us/library/cc960241.aspx
http://blogs.msdn.com/b/hansr/archive/2006/02/17/patchreboot.aspx
.NOTES
Author: Brian Wilhite
Email: bwilhite1@carolina.rr.com
Date: 08/29/2012
PSVer: 2.0/3.0
#>
[CmdletBinding()]
param(
[Parameter(Position=0,ValueFromPipeline=$true)]
[Alias("CN","Computer")]
[String[]]$ComputerName="$env:COMPUTERNAME"
)
Begin
{
#Adjusting ErrorActionPreference to stop on all errors
$TempErrAct = $ErrorActionPreference
$ErrorActionPreference = "Stop"
}#End Begin Script Block
Process
{
foreach ($Computer in $ComputerName) {
$Computer = $Computer.ToUpper().Trim()
try {
#Setting pending values to false to cut down on the number of else statements
$CBS,$WUAU,$PendFileRename,$Pending = $false, $false, $false, $false
#Querying WMI for build version
$WMI_OS = Get-WmiObject -Class Win32_OperatingSystem -ComputerName $Computer
#Making registry connection to the local/remote computer
$RegCon = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey([Microsoft.Win32.RegistryHive]"LocalMachine",$Computer)
#If Vista/2008 & Above query the CBS Reg Key
If ($WMI_OS.BuildNumber -ge 6001) {
$RegSubKeysCBS = $RegCon.OpenSubKey("SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\").GetSubKeyNames()
$CBSRebootPend = $RegSubKeysCBS -contains "RebootPending"
If ($CBSRebootPend) {
$CBS = $true
}
}
#Query WUAU from the registry
$RegWUAU = $RegCon.OpenSubKey("SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\")
if($RegWUAU -ne $null) {
$RegWUAURebootReq = $RegWUAU.GetSubKeyNames()
$WUAURebootReq = $RegWUAURebootReq -contains "RebootRequired"
}
#Query PendingFileRenameOperations from the registry
$RegSubKeySM = $RegCon.OpenSubKey("SYSTEM\CurrentControlSet\Control\Session Manager\")
$RegValuePFRO = $RegSubKeySM.GetValue("PendingFileRenameOperations",$null)
#Closing registry connection
$RegCon.Close()
#If values from the registry are present, setting each respective variable to $true
If ($WUAURebootReq) {
$WUAU = $true
}
If ($RegValuePFRO) {
$PendFileRename = $true
}
If ($CBS -or $WUAU -or $PendFileRename) {
$Pending = $true
}
#Creating $Data Custom PSObject
$Data = New-Object -TypeName PSObject -Property @{
Computer=$Computer
CBServicing=$CBS
WindowsUpdate=$WUAU
PendFileRename=$PendFileRename
RebootPending=$Pending
}#End $Data Custom object
#Returning $Data object in a selected order to the user
$Data | Select-Object -Property Computer, CBServicing, WindowsUpdate, PendFileRename, RebootPending
}
catch {
Write-Warning "$Computer`: $_"
}
}#End Foreach ($Computer in $ComputerName)
}#End Process
End
{
#Resetting ErrorActionPref
$ErrorActionPreference = $TempErrAct
}#End End
}
function Test-PendingReboot {
<#
.SYNOPSIS
Checks to see if Windows is pending a reboot
.DESCRIPTION
Uses a script from Brian Wilhite
http://gallery.technet.microsoft.com/scriptcenter/Get-PendingReboot-Query-bdb79542
that queries the registry, Windows Update and System
Configuration Manager to determine if a pending reboot is
required.
One may want to check this before installing software
or doing anything that may fail if there is a pending
reboot. If this command returns $true, one may want to
call Invoke-Reboot to restart the local machine.
.LINK
http://boxstarter.org
http://gallery.technet.microsoft.com/scriptcenter/Get-PendingReboot-Query-bdb79542
Invoke-Reboot
about_boxstarter_bootstrapper
#>
$rebootPending = Get-PendingReboot
if($rebootPending.RebootPending) {
echo "Detected Pending reboot" -Verbose
echo "$rebootPending"
return $true
}
return $false
}
function Invoke-Reboot {
Restart-Computer -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue
}
function Install-WindowsUpdate {
<#
.SYNOPSIS
Downloads and installs updates via Windows Update
.DESCRIPTION
This uses the windows update service to search, download and install updates. By default, only critical updates are included and a reboot will be induced if required.
.PARAMETER GetUpdatesFromMS
If this switch is set, the default windows update server, if any, is bypassed and windows update requests go to the public Microsoft Windows update service.
.PARAMETER AcceptEula
If any update requires a Eula acceptance, setting this switch will accept the Eula and allow the update to be installed.
.PARAMETER SuppressReboots
Setting this switch will suppress a reboot in the event that any update requires one.
.PARAMETER Criteria
The criteria used for searching updates. The default criteria is "IsHidden=0 and IsInstalled=0 and Type='Software'" which is effectively just critical updates.
.LINK
http://boxstarter.org
#>
param(
[switch]$getUpdatesFromMS,
[switch]$acceptEula,
[switch]$SuppressReboots,
[string]$criteria="IsHidden=0 and IsInstalled=0 and Type='Software' and BrowseOnly=0"
)
try{
$updateSession =new-object -comobject "Microsoft.Update.Session"
$Downloader =$updateSession.CreateUpdateDownloader()
$Installer =$updateSession.CreateUpdateInstaller()
$Searcher =$updatesession.CreateUpdateSearcher()
if($getUpdatesFromMS) {
$Searcher.ServerSelection = 2 #2 is the Const for the Windows Update server
}
$wus=Get-WmiObject -Class Win32_Service -Filter "Name='wuauserv'"
$origStatus=$wus.State
$origStartupType=$wus.StartMode
echo "Update service is in the $origStatus state and its startup type is $origStartupType" -verbose
if($origStartupType -eq "Auto"){
$origStartupType = "Automatic"
}
if($origStatus -eq "Stopped"){
if($origStartupType -eq "Disabled"){
Set-Service wuauserv -StartupType Automatic
}
echo "Starting windows update service" -verbose
Start-Service -Name wuauserv
}
else {
# Restart in case updates are running in the background
echo "Restarting windows update service" -verbose
try {
Restart-Service -Name wuauserv -Force -WarningAction SilentlyContinue
}
catch {}
}
$Result = $Searcher.Search($criteria)
$totalUpdates = $Result.updates.count
If ($totalUpdates -ne 0)
{
echo "$($Result.updates.count) Updates found"
$currentCount = 0
foreach($update in $result.updates) {
++$currentCount
if(!($update.EulaAccepted)){
if($acceptEula) {
$update.AcceptEula()
}
else {
echo " * $($update.title) has a user agreement that must be accepted. Call Install-WindowsUpdate with the -AcceptEula parameter to accept all user agreements. This update will be ignored."
continue
}
}
$Result= $null
if ($update.isDownloaded -eq "true" -and ($update.InstallationBehavior.CanRequestUserInput -eq $false )) {
echo " * $($update.title) already downloaded"
$result = Install-Update $update $currentCount $totalUpdates
}
elseif($update.InstallationBehavior.CanRequestUserInput -eq $true) {
echo " * $($update.title) Requires user input and will not be downloaded"
}
else {
Download-Update $update
$result = Install-Update $update $currentCount $totalUpdates
}
}
if($result -ne $null -and $result.rebootRequired) {
if($SuppressReboots) {
echo "A Restart is Required."
} else {
$Rebooting=$true
echo "Restart Required. Restarting now..."
if(test-path function:\Invoke-Reboot) {
return Invoke-Reboot
} else {
Restart-Computer -force
}
}
}
}
else {
echo "There is no update applicable to this machine"
}
}
catch {
echo "There were problems installing updates: $($_.ToString())"
throw
}
finally {
if($origAUVal){
Set-ItemProperty -Path HKLM:\Software\Policies\Microsoft\Windows\WindowsUpdate\AU -Name UseWuServer -Value $origAUVal -ErrorAction SilentlyContinue
}
if($origStatus -eq "Stopped")
{
echo "Stopping win update service and setting its startup type to $origStartupType" -verbose
Set-Service wuauserv -StartupType $origStartupType
try {
stop-service wuauserv -WarningAction SilentlyContinue
}
catch {}
}
}
}
function Download-Update($update) {
$updates= new-Object -com "Microsoft.Update.UpdateColl"
$updates.Add($update) | out-null
$Downloader.Updates = $updates
$Downloader.Download() | Out-Null
}
function Install-Update($update, $currentCount, $totalUpdates) {
$updates=new-Object -com "Microsoft.Update.UpdateColl"
$updates.Add($update) | out-null
$Installer.updates = $Updates
try { $result = $Installer.Install() }
catch {
if(!($SuppressReboots) -and (test-path function:\Invoke-Reboot)){
if(Test-PendingReboot) {
$global:error.RemoveAt(0)
Invoke-Reboot
}
}
# Check for WU_E_INSTALL_NOT_ALLOWED
if($_.Exception.HResult -eq -2146233087) {
echo "There is either an update in progress or there is a pending reboot blocking the install."
$global:error.RemoveAt(0)
}
else { throw }
}
return $result
}
function Set-WindowsExplorerOptions {
<#
.SYNOPSIS
Sets options on the Windows Explorer shell
.PARAMETER EnableShowHiddenFilesFoldersDrives
If this flag is set, hidden files will be shown in Windows Explorer
.PARAMETER DisableShowHiddenFilesFoldersDrives
Disables the showing on hidden files in Windows Explorer, see EnableShowHiddenFilesFoldersDrives
.PARAMETER EnableShowProtectedOSFiles
If this flag is set, hidden Operating System files will be shown in Windows Explorer
.PARAMETER DisableShowProtectedOSFiles
Disables the showing of hidden Operating System Files in Windows Explorer, see EnableShowProtectedOSFiles
.PARAMETER EnableShowFileExtensions
Setting this switch will cause Windows Explorer to include the file extension in file names
.PARAMETER DisableShowFileExtensions
Disables the showing of file extension in file names, see EnableShowFileExtensions
.PARAMETER EnableShowFullPathInTitleBar
Setting this switch will cause Windows Explorer to show the full folder path in the Title Bar
.PARAMETER DisableShowFullPathInTitleBar
Disables the showing of the full path in Windows Explorer Title Bar, see EnableShowFullPathInTitleBar
.LINK
http://boxstarter.org
#>
[CmdletBinding()]
param(
[switch]$EnableShowHiddenFilesFoldersDrives,
[switch]$DisableShowHiddenFilesFoldersDrives,
[switch]$EnableShowProtectedOSFiles,
[switch]$DisableShowProtectedOSFiles,
[switch]$EnableShowFileExtensions,
[switch]$DisableShowFileExtensions,
[switch]$EnableShowFullPathInTitleBar,
[switch]$DisableShowFullPathInTitleBar
)
$PSBoundParameters.Keys | % {
if($_-like "En*") {
$other="Dis" + $_.Substring(2)
}
if($_-like "Dis*") {
$other="En" + $_.Substring(3)
}
if($PSBoundParameters[$_] -and $PSBoundParameters[$other]) {
throw new-Object -TypeName ArgumentException "You may not set both $_ and $other. You can only set one."
}
}
$key = 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer'
$advancedKey = "$key\Advanced"
$cabinetStateKey = "$key\CabinetState"
echo "Setting Windows Explorer options..."
if(Test-Path -Path $advancedKey) {
if($EnableShowHiddenFilesFoldersDrives) {Set-ItemProperty $advancedKey Hidden 1}
if($DisableShowHiddenFilesFoldersDrives) {Set-ItemProperty $advancedKey Hidden 0}
if($EnableShowFileExtensions) {Set-ItemProperty $advancedKey HideFileExt 0}
if($DisableShowFileExtensions) {Set-ItemProperty $advancedKey HideFileExt 1}
if($EnableShowProtectedOSFiles) {Set-ItemProperty $advancedKey ShowSuperHidden 1}
if($DisableShowProtectedOSFiles) {Set-ItemProperty $advancedKey ShowSuperHidden 0}
}
if(Test-Path -Path $cabinetStateKey) {
if($EnableShowFullPathInTitleBar) {Set-ItemProperty $cabinetStateKey FullPath 1}
if($DisableShowFullPathInTitleBar) {Set-ItemProperty $cabinetStateKey FullPath 0}
}
}
function Stop-UpdateServices {
echo "Disabling Automatic Updates from Windows Update"
$winUpdateKey = "HKLM:SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\au"
if(!(Test-Path $winUpdateKey)) {
New-Item $winUpdateKey -Type Folder -Force | Out-Null
}
try {
New-ItemProperty -Path $winUpdateKey -name 'NoAutoUpdate' -value '1' -propertyType "DWord" -force -ErrorAction Stop | Out-Null
}
catch { $global:error.RemoveAt(0) }
try {
New-ItemProperty -Path $winUpdateKey -name 'NoAutoRebootWithLoggedOnUsers' -value '1' -propertyType "DWord" -force -ErrorAction Stop | Out-Null
}
catch { $global:error.RemoveAt(0) }
}
function InstallChocolatey {
echo "Installing chocolatey..."
if(-not $env:ChocolateyInstall -or -not (Test-Path "$env:ChocolateyInstall")) {
$env:ChocolateyInstall = "$env:programdata\chocolatey"
New-Item $env:ChocolateyInstall -Force -type directory | Out-Null
$wc=New-Object Net.WebClient
$wp=[System.Net.WebProxy]::GetDefaultProxy()
$wp.UseDefaultCredentials=$true
$wc.Proxy=$wp
iex ($wc.DownloadString("https://chocolatey.org/install.ps1"))
$env:path="$env:path;$env:ChocolateyInstall\bin"
}
}
function InstallWinFeatures {
echo "Installing Windows features..."
$tries = 3
for ($i = 1; $i -le $tries; $i++) {
try {
$wc=New-Object Net.WebClient
$wp=[System.Net.WebProxy]::GetDefaultProxy()
$wp.UseDefaultCredentials=$true
$wc.Proxy=$wp
$features=$wc.DownloadString("https://gist.githubusercontent.com/anuriq/5a0ae450305e9d790736/raw/e8370f2f3682932682ebe916a646696eb13f512f/windowsfeatures2.xml")
Set-Content -Path $env:bootstrap\windowsfeatures.xml -Value $features
Install-WindowsFeature -ConfigurationFilePath $env:bootstrap\windowsfeatures.xml
break;
}
catch {
echo "Error during access to gist.github.com page."
if ($i -eq $tries) { throw $_.Exception; }
sleep 2;
}
}
}
function ConfigureWinFeatures {
echo "Configuring Windows features..."
NewDir "$env:systemdrive\share"
ICACLS "$env:systemdrive\share" /Grant IUSR:R /T
New-WebFtpSite -Name "FtpSite" -IPAddress "0.0.0.0" -Port 21 -PhysicalPath "$env:systemdrive\share" -Force
# Allow SSL connections
Set-ItemProperty "IIS:\Sites\FtpSite" -Name ftpServer.security.ssl.controlChannelPolicy -Value 0
Set-ItemProperty "IIS:\Sites\FtpSite" -Name ftpServer.security.ssl.dataChannelPolicy -Value 0
# Enable Basic Authentication
Set-ItemProperty "IIS:\Sites\FtpSite" -Name ftpServer.security.authentication.basicAuthentication.enabled -Value $true
# Give Authorization to All Users and grant "read"/"write" privileges
Add-WebConfiguration "/system.ftpServer/security/authorization" -value @{accessType="Allow";roles="Administrators";permissions="Read,Write"} -PSPath IIS:\ -location "FtpSite"
# Restart the FTP site for all changes to take effect
Restart-WebItem "IIS:\Sites\FtpSite"
}
function CleanSxs {
echo "Cleaning SxS and other cache..."
Dism.exe /online /Cleanup-Image /StartComponentCleanup /ResetBase
@(
"$env:localappdata\Nuget",
"$env:localappdata\temp\*",
"$env:windir\logs",
"$env:windir\panther",
"$env:windir\temp\*",
"$env:windir\winsxs\manifestcache"
) | % {
if(Test-Path $_) {
echo "Removing $_"
Takeown /d Y /R /f $_ | Out-Null
Icacls $_ /GRANT:r administrators:F /T /c /q 2>&1 | Out-Null
Remove-Item $_ -Recurse -Force -ErrorAction SilentlyContinue | Out-Null
}
}
}
function NewDir ($dirpath) {
New-Item $dirpath -ItemType dir -Force -ErrorAction SilentlyContinue;
}
function NewFile ($filepath) {
New-Item $filepath -ItemType file -Force -ErrorAction SilentlyContinue;
}
$ErrorActionPreference = "Continue";
$n = NewDir "$env:systemdrive\bootstrap";
[Environment]::SetEnvironmentVariable("bootstrap", "$env:systemdrive\bootstrap", "Machine");
$env:bootstrap = "$env:systemdrive\bootstrap";
if (Test-Path "$env:bootstrap\__shutdown") {
exit 0;
}
# Install-WindowsUpdate -AcceptEula
if(Test-PendingReboot) { Invoke-Reboot }
if (-not (Test-Path "$env:bootstrap\__chocoinstall")) {
InstallChocolatey
$step1 = NewFile "$env:bootstrap\__chocoinstall";
}
if (-not (Test-Path "$env:bootstrap\__packageinstall")) {
#cinst "dotnet4.5.1" -y
#cinst jre8 -y
#cinst adobereader -y
cinst tightvnc -y
$step2 = NewFile "$env:bootstrap\__packageinstall";
}
if (-not (Test-Path "$env:bootstrap\__winfeatureinstall")) {
InstallWinFeatures
ConfigureWinFeatures
echo "Removing unused features..."
Remove-WindowsFeature -Name 'Powershell-ISE'
Get-WindowsFeature | ? { $_.InstallState -eq 'Available' } | Uninstall-WindowsFeature -Remove
$step3 = NewFile "$env:bootstrap\__winfeatureinstall";
}
if (-not (Test-Path "$env:bootstrap\__winoptions")) {
echo "Disabling display turning off..."
powercfg -change -monitor-timeout-ac 0
powercfg -change -monitor-timeout-dc 0
Set-ItemProperty -Path "HKCU:\Control Panel\Desktop" -Name "ScreenSaveActive" -Value 0
Set-ItemProperty -Path "HKCU:\Control Panel\Desktop" -Name "SCRNSAVE.EXE" -Value ""
echo "Disabling UAC..."
New-ItemProperty -Path HKLM:Software\Microsoft\Windows\CurrentVersion\policies\system -Name EnableLUA -PropertyType DWord -Value 0 -Force
Set-WindowsExplorerOptions -EnableShowHiddenFilesFoldersDrives -EnableShowFileExtensions -EnableShowFullPathInTitleBar
$step4 = NewFile "$env:bootstrap\__winoptions";
}
if(Test-PendingReboot) { Invoke-Reboot }
Stop-UpdateServices
CleanSxs
echo "Enabling RDP configuration in EC2Config..."
$ec2configfile = "$env:programfiles\Amazon\Ec2ConfigService\Settings\config.xml"
$xml = [xml](Get-Content $ec2configfile)
foreach ($element in $xml.get_DocumentElement().Plugins.Plugin) {
if ($element.Name -eq "Ec2ConfigureRDP") { $element.State = "Enabled" }
if ($element.Name -eq "Ec2SetPassword") { $element.State = "Enabled" }
}
$xml.Save($ec2configfile)
Copy-Item -Path "$env:programfiles\Amazon\Ec2ConfigService\Logs\*" -Destination $env:bootstrap;
NewFile "$env:bootstrap\__done"
NewFile "$env:bootstrap\__shutdown"
& "$env:programfiles\Amazon\Ec2ConfigService\ec2config.exe" -sysprep
# Stop-Computer -Confirm:$false -Force
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment