Commit 76373bef authored by Joe Fitzgerald's avatar Joe Fitzgerald

Windows Updates Now Handle Reboots Until All Updates Are Installed

parent dcb2f1d2
......@@ -116,93 +116,93 @@
<Order>2</Order>
<RequiresUserInput>true</RequiresUserInput>
</SynchronousCommand>
<SynchronousCommand wcm:action="add">
<CommandLine>cmd.exe /c powershell -NoProfile -NonInteractive -File a:\Get-WindowsUpdates.ps1 -Install -EulaAccept -Verbose | a:\mtee.exe /+ c:\windowsupdate.log</CommandLine>
<Description>Install Windows Updates</Description>
<Order>3</Order>
<RequiresUserInput>true</RequiresUserInput>
</SynchronousCommand>
<SynchronousCommand wcm:action="add">
<CommandLine>cmd.exe /c a:\install-cygwin-sshd.bat</CommandLine>
<Description>Install Cygwin SSH</Description>
<Order>4</Order>
<Order>3</Order>
<RequiresUserInput>true</RequiresUserInput>
</SynchronousCommand>
<SynchronousCommand wcm:action="add">
<CommandLine>cmd.exe /c winrm quickconfig -q</CommandLine>
<Description>winrm quickconfig -q</Description>
<Order>5</Order>
<Order>4</Order>
<RequiresUserInput>true</RequiresUserInput>
</SynchronousCommand>
<SynchronousCommand wcm:action="add">
<CommandLine>cmd.exe /c winrm quickconfig -transport:http</CommandLine>
<Description>winrm quickconfig -transport:http</Description>
<Order>6</Order>
<Order>5</Order>
<RequiresUserInput>true</RequiresUserInput>
</SynchronousCommand>
<SynchronousCommand wcm:action="add">
<CommandLine>cmd.exe /c winrm set winrm/config @{MaxTimeoutms="1800000"}</CommandLine>
<Description>Win RM MaxTimoutms</Description>
<Order>7</Order>
<Order>6</Order>
<RequiresUserInput>true</RequiresUserInput>
</SynchronousCommand>
<SynchronousCommand wcm:action="add">
<CommandLine>cmd.exe /c winrm set winrm/config/winrs @{MaxMemoryPerShellMB="300"}</CommandLine>
<Description>Win RM MaxMemoryPerShellMB</Description>
<Order>8</Order>
<Order>7</Order>
<RequiresUserInput>true</RequiresUserInput>
</SynchronousCommand>
<SynchronousCommand wcm:action="add">
<CommandLine>cmd.exe /c winrm set winrm/config/service @{AllowUnencrypted="true"}</CommandLine>
<Description>Win RM AllowUnencrypted</Description>
<Order>9</Order>
<Order>8</Order>
<RequiresUserInput>true</RequiresUserInput>
</SynchronousCommand>
<SynchronousCommand wcm:action="add">
<CommandLine>cmd.exe /c winrm set winrm/config/service/auth @{Basic="true"}</CommandLine>
<Description>Win RM auth Basic</Description>
<Order>10</Order>
<Order>9</Order>
<RequiresUserInput>true</RequiresUserInput>
</SynchronousCommand>
<SynchronousCommand wcm:action="add">
<CommandLine>cmd.exe /c winrm set winrm/config/client/auth @{Basic="true"}</CommandLine>
<Description>Win RM client auth Basic</Description>
<Order>11</Order>
<Order>10</Order>
<RequiresUserInput>true</RequiresUserInput>
</SynchronousCommand>
<SynchronousCommand wcm:action="add">
<CommandLine>cmd.exe /c winrm set winrm/config/listener?Address=*+Transport=HTTP @{Port="5985"} </CommandLine>
<Description>Win RM listener Address/Port</Description>
<Order>12</Order>
<Order>11</Order>
<RequiresUserInput>true</RequiresUserInput>
</SynchronousCommand>
<SynchronousCommand wcm:action="add">
<CommandLine>cmd.exe /c netsh advfirewall firewall set rule group="remote administration" new enable=yes </CommandLine>
<Description>Win RM adv firewall enable</Description>
<Order>13</Order>
<Order>12</Order>
<RequiresUserInput>true</RequiresUserInput>
</SynchronousCommand>
<SynchronousCommand wcm:action="add">
<CommandLine>cmd.exe /c netsh firewall add portopening TCP 5985 "Port 5985" </CommandLine>
<Description>Win RM port open</Description>
<Order>14</Order>
<Order>13</Order>
<RequiresUserInput>true</RequiresUserInput>
</SynchronousCommand>
<SynchronousCommand wcm:action="add">
<CommandLine>cmd.exe /c net stop winrm </CommandLine>
<Description>Stop Win RM Service </Description>
<Order>15</Order>
<Order>14</Order>
<RequiresUserInput>true</RequiresUserInput>
</SynchronousCommand>
<SynchronousCommand wcm:action="add">
<CommandLine>cmd.exe /c sc config winrm start= auto</CommandLine>
<Description>Win RM Autostart</Description>
<Order>16</Order>
<Order>15</Order>
<RequiresUserInput>true</RequiresUserInput>
</SynchronousCommand>
<SynchronousCommand wcm:action="add">
<CommandLine>cmd.exe /c net start winrm </CommandLine>
<Description>Start Win RM Service</Description>
<Order>16</Order>
<RequiresUserInput>true</RequiresUserInput>
</SynchronousCommand>
<SynchronousCommand wcm:action="add">
<CommandLine>C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -File a:\vagrant\scripts\Install-WindowsUpdates.ps1</CommandLine>
<Description>Install Windows Updates</Description>
<Order>17</Order>
<RequiresUserInput>true</RequiresUserInput>
</SynchronousCommand>
......
<#
.SYNOPSIS
Get and optionally install Windows Updates
.DESCRIPTION
This script will get all available udpates for the computer it is run on.
It will then optionally install those updates, provided they do not require
user input.
This script was based off the original vbs that appeared on the MSDN site.
Please see the Related Links section for the URL.
Without any parameters the script will return the title of each update that
is currently available.
.PARAMETER Install
When present the script will download and install each update. If the EulaAccept
param has not been passed, only updates that don't have a Eula will be applied.
.PARAMETER EulaAccept
When present will allow the script to download and install all updates that are
currently available.
.EXAMPLE
.\Get-WindowsUpdates.ps1
There are no applicable updates
Description
-----------
This system is currently patched and up to date.
.NOTES
ScriptName : Get-WindowsUpdates.ps1
Created By : jspatton
Date Coded : 08/29/2012 13:06:31
ScriptName is used to register events for this script
ErrorCodes
100 = Success
101 = Error
102 = Warning
104 = Information
.LINK
https://code.google.com/p/mod-posh/wiki/Production/Get-WindowsUpdates.ps1
.LINK
http://msdn.microsoft.com/en-us/library/windows/desktop/aa387102(v=vs.85).aspx
#>
[CmdletBinding()]
Param
(
[switch]$Install,
[switch]$EulaAccept
)
Begin
{
$ScriptName = $MyInvocation.MyCommand.ToString()
$ScriptPath = $MyInvocation.MyCommand.Path
$Username = $env:USERDOMAIN + "\" + $env:USERNAME
New-EventLog -Source $ScriptName -LogName 'Windows Powershell' -ErrorAction SilentlyContinue
$Message = "Script: " + $ScriptPath + "`nScript User: " + $Username + "`nStarted: " + (Get-Date).toString()
Write-EventLog -LogName 'Windows Powershell' -Source $ScriptName -EventID "104" -EntryType "Information" -Message $Message
# Dotsource in the functions you need.
$UpdateSession = New-Object -ComObject 'Microsoft.Update.Session'
$UpdateSession.ClientApplicationID = 'MSDN PowerShell Sample'
}
Process
{
$UpdateSearcher = $UpdateSession.CreateUpdateSearcher()
$SearchResult = $UpdateSearcher.Search("IsInstalled=0 and Type='Software' and IsHidden=0")
if ($Install)
{
Write-Verbose 'Creating a collection of updates to download:'
$UpdatesToDownload = New-Object -ComObject 'Microsoft.Update.UpdateColl'
foreach ($Update in $SearchResult.Updates)
{
[bool]$addThisUpdate = $false
if ($Update.InstallationBehavior.CanRequestUserInput)
{
Write-Verbose "> Skipping: $($Update.Title) because it requires user input"
}
else
{
if (!($Update.EulaAccepted))
{
Write-Verbose "> Note: $($Update.Title) has a license agreement that must be accepted:"
if ($EulaAccept)
{
$Update.AcceptEula()
[bool]$addThisUpdate = $true
}
else
{
Write-Verbose "> Skipping: $($Update.Title) because the license agreement was declined"
}
}
else
{
[bool]$addThisUpdate = $true
}
}
if ([bool]$addThisUpdate)
{
Write-Verbose "Adding: $($Update.Title)"
$UpdatesToDownload.Add($Update) |Out-Null
}
}
if ($UpdatesToDownload.Count -eq 0)
{
Write-Verbose 'All applicable updates were skipped.'
break
}
Write-Verbose 'Downloading updates...'
$Downloader = $UpdateSession.CreateUpdateDownloader()
$Downloader.Updates = $UpdatesToDownload
$Downloader.Download()
$UpdatesToInstall = New-Object -ComObject 'Microsoft.Update.UpdateColl'
[bool]$rebootMayBeRequired = $false
Write-Verbose 'Successfully downloaded updates:'
foreach ($Update in $SearchResult.Updates)
{
if ($Update.IsDownloaded)
{
Write-Verbose "> $($Update.Title)"
$UpdatesToInstall.Add($Update) |Out-Null
if ($Update.InstallationBehavior.RebootBehavior -gt 0)
{
[bool]$rebootMayBeRequired = $true
}
}
}
if ($UpdatesToInstall.Count -eq 0)
{
Write-Verbose 'No updates were succsesfully downloaded'
}
if ($rebootMayBeRequired)
{
Write-Verbose 'These updates may require a reboot'
}
Write-Verbose 'Installing updates...'
$Installer = $UpdateSession.CreateUpdateInstaller()
$Installer.Updates = $UpdatesToInstall
$InstallationResult = $Installer.Install()
Write-Verbose "Installation Result: $($InstallationResult.ResultCode)"
Write-Verbose "Reboot Required: $($InstallationResult.RebootRequired)"
Write-Verbose 'Listing of updates installed and individual installation results'
for($i=0; $i -lt $UpdatesToInstall.Count; $i++)
{
New-Object -TypeName PSObject -Property @{
Title = $UpdatesToInstall.Item($i).Title
Result = $InstallationResult.GetUpdateResult($i).ResultCode
}
}
}
else
{
if ($SearchResult.Updates.Count -ne 0)
{
$SearchResult.Updates |Select-Object -Property Title, Description, SupportUrl, UninstallationNotes, RebootRequired |Format-List
}
else
{
Write-Host 'There are no applicable updates'
}
}
}
End
{
$Message = "Script: " + $ScriptPath + "`nScript User: " + $Username + "`nFinished: " + (Get-Date).toString()
Write-EventLog -LogName 'Windows Powershell' -Source $ScriptName -EventID "104" -EntryType "Information" -Message $Message
}
\ No newline at end of file
param($global:RestartRequired=0,
$global:MoreUpdates=0,
$global:MaxCycles=5)
function Check-ContinueRestartOrEnd() {
$RegistryKey = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run"
$RegistryEntry = "InstallWindowsUpdates"
switch ($global:RestartRequired) {
0 {
$prop = (Get-ItemProperty $RegistryKey).$RegistryEntry
if ($prop) {
Write-Host "Restart Registry Entry Exists - Removing It"
Remove-ItemProperty -Path $RegistryKey -Name $RegistryEntry -ErrorAction SilentlyContinue
}
Write-Host "No Restart Required"
Check-WindowsUpdates
if (($global:MoreUpdates -eq 1) -and ($script:Cycles -le $global:MaxCycles)) {
Stop-Service $script:ServiceName -Force
Set-Service -Name $script:ServiceName -StartupType Disabled Status Stopped
Install-WindowsUpdates
} else {
Write-Host "Done Installing Windows Updates"
Set-Service -Name $script:ServiceName -StartupType Automatic Status Running
}
}
1 {
$prop = (Get-ItemProperty $RegistryKey).$RegistryEntry
if (-not $prop) {
Write-Host "Restart Registry Entry Does Not Exist - Creating It"
Set-ItemProperty -Path $RegistryKey -Name $RegistryEntry -Value "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -File C:\vagrant\scripts\Install-WindowsUpdates.ps1"
} else {
Write-Host "Restart Registry Entry Exists Already"
}
Write-Host "Restart Required - Restarting..."
Restart-Computer
}
default {
Write-Host "Unsure If A Restart Is Required";
break;
}
}
}
function Install-WindowsUpdates() {
$script:Cycles++
Write-Host 'Evaluating Available Updates:'
$UpdatesToDownload = New-Object -ComObject 'Microsoft.Update.UpdateColl'
foreach ($Update in $SearchResult.Updates) {
if (($Update -ne $null) -and (!$Update.IsDownloaded)) {
[bool]$addThisUpdate = $false
if ($Update.InstallationBehavior.CanRequestUserInput) {
Write-Host "> Skipping: $($Update.Title) because it requires user input"
}
else {
if (!($Update.EulaAccepted)) {
Write-Host "> Note: $($Update.Title) has a license agreement that must be accepted. Accepting the license."
$Update.AcceptEula()
[bool]$addThisUpdate = $true
}
else {
[bool]$addThisUpdate = $true
}
}
if ([bool]$addThisUpdate) {
Write-Host "Adding: $($Update.Title)"
$UpdatesToDownload.Add($Update) |Out-Null
}
}
}
if ($UpdatesToDownload.Count -eq 0) {
Write-Host "No Updates To Download..."
} else {
Write-Host 'Downloading Updates...'
$Downloader = $UpdateSession.CreateUpdateDownloader()
$Downloader.Updates = $UpdatesToDownload
$Downloader.Download()
}
$UpdatesToInstall = New-Object -ComObject 'Microsoft.Update.UpdateColl'
[bool]$rebootMayBeRequired = $false
Write-Host 'The following updates are downloaded and ready to be installed:'
foreach ($Update in $SearchResult.Updates) {
if (($Update.IsDownloaded)) {
Write-Host "> $($Update.Title)"
$UpdatesToInstall.Add($Update) |Out-Null
if ($Update.InstallationBehavior.RebootBehavior -gt 0){
[bool]$rebootMayBeRequired = $true
}
}
}
if ($UpdatesToInstall.Count -eq 0) {
Write-Host 'No updates available to install...'
$global:MoreUpdates=0
$global:RestartRequired=0
break
}
if ($rebootMayBeRequired) {
Write-Host 'These updates may require a reboot'
$global:RestartRequired=1
}
Write-Host 'Installing updates...'
$Installer = $UpdateSession.CreateUpdateInstaller()
$Installer.Updates = $UpdatesToInstall
$InstallationResult = $Installer.Install()
Write-Host "Installation Result: $($InstallationResult.ResultCode)"
Write-Host "Reboot Required: $($InstallationResult.RebootRequired)"
Write-Host 'Listing of updates installed and individual installation results:'
if ($InstallationResult.RebootRequired) {
$global:RestartRequired=1
} else {
$global:RestartRequired=0
}
for($i=0; $i -lt $UpdatesToInstall.Count; $i++) {
New-Object -TypeName PSObject -Property @{
Title = $UpdatesToInstall.Item($i).Title
Result = $InstallationResult.GetUpdateResult($i).ResultCode
}
}
Check-ContinueRestartOrEnd
}
function Check-WindowsUpdates() {
Write-Host "Checking For Windows Updates"
$Username = $env:USERDOMAIN + "\" + $env:USERNAME
New-EventLog -Source $ScriptName -LogName 'Windows Powershell' -ErrorAction SilentlyContinue
$Message = "Script: " + $ScriptPath + "`nScript User: " + $Username + "`nStarted: " + (Get-Date).toString()
Write-EventLog -LogName 'Windows Powershell' -Source $ScriptName -EventID "104" -EntryType "Information" -Message $Message
Write-Host $Message
$script:UpdateSearcher = $script:UpdateSession.CreateUpdateSearcher()
$script:SearchResult = $script:UpdateSearcher.Search("IsInstalled=0 and Type='Software' and IsHidden=0")
if ($SearchResult.Updates.Count -ne 0) {
$script:SearchResult.Updates |Select-Object -Property Title, Description, SupportUrl, UninstallationNotes, RebootRequired, EulaAccepted |Format-List
$global:MoreUpdates=1
}
else {
Write-Host 'There are no applicable updates'
$global:RestartRequired=0
$global:MoreUpdates=0
}
}
$script:ScriptName = $MyInvocation.MyCommand.ToString()
$script:ScriptPath = $MyInvocation.MyCommand.Path
$script:UpdateSession = New-Object -ComObject 'Microsoft.Update.Session'
$script:UpdateSession.ClientApplicationID = 'Packer Windows Update Installer'
$script:UpdateSearcher = $script:UpdateSession.CreateUpdateSearcher()
$script:SearchResult = New-Object -ComObject 'Microsoft.Update.UpdateColl'
$script:Cycles = 0
$script:ServiceName = "sshd"
Stop-Service $script:ServiceName -Force
Set-Service -Name $script:ServiceName -StartupType Disabled Status Stopped
Check-WindowsUpdates
if ($global:MoreUpdates -eq 1) {
Install-WindowsUpdates
} else {
Check-ContinueRestartOrEnd
}
......@@ -3,7 +3,7 @@ REM http://webcache.googleusercontent.com/search?q=cache:SjoPPpuQxuoJ:www.tcm.ph
REM create the cygwin directory
cmd /c mkdir %SystemDrive%\cygwin
cmd /c bitsadmin /transfer CygwinSetupExe /download /priority normal http://www.cygwin.com/setup.exe %SystemDrive%\cygwin\cygwin-setup.exe
cmd /c bitsadmin /transfer CygwinSetupExe /download /priority normal http://www.cygwin.com/setup-x86_64.exe %SystemDrive%\cygwin\cygwin-setup.exe
REM goto a temp directory
cd %SystemDrive%\windows\temp
......@@ -32,7 +32,7 @@ cmd /c if exist %Systemroot%\system32\netsh.exe netsh advfirewall firewall add r
%SystemDrive%\cygwin\bin\sleep 2
net start sshd
# net start sshd
# Fix corrupt recycle bin
# http://www.winhelponline.com/blog/fix-corrupted-recycle-bin-windows-7-vista/
......
......@@ -17,8 +17,7 @@
"floppy_files": [
"Autounattend.xml",
"./scripts/install-cygwin-sshd.bat",
"./scripts/Get-WindowsUpdates.ps1",
"./scripts/mtee.exe"
"./scripts/Install-WindowsUpdates.ps1"
],
"vmx_data": {
"RemoteDisplay.vnc.enabled": "false",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment