-
Notifications
You must be signed in to change notification settings - Fork 235
Various fixes, optimizations and code formatting #13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -47,9 +47,8 @@ | |
| # require the user to log back in manually after the reboot before | ||
| # continuing. | ||
| # | ||
| # A log of this process is created in | ||
| # $env:SystemDrive\temp\upgrade_powershell.log which is usually C:\temp\. This | ||
| # log can used to see how the script faired after an automatic reboot. | ||
| # A log of this process is created in '$env:temp\upgrade_powershell.log'. | ||
| # This log can be used to see how did the script worked after an automatic reboot. | ||
| # | ||
| # See https://github.com/jborean93/ansible-windows/tree/master/scripts for more | ||
| # details. | ||
|
|
@@ -64,11 +63,15 @@ | |
| # [string] - The username of a local admin user that will be automatically | ||
| # logged in after a reboot to continue the script install. The 'password' | ||
| # parameter is also required if this is set. | ||
| # .PARAMETER domain | ||
| # [string] - fully qualified domain name (FQDN) of the computer domain. | ||
| # .PARAMETER password | ||
| # [string] - The password for 'username', this is required if the 'username' | ||
| # parameter is also set. | ||
| # .PARAMETER Verbose | ||
| # [switch] - Whether to display Verbose logs on the console | ||
| # .PARAMETER force | ||
| # [switch] - Forces script to reboot automatically without user confirmation | ||
| # .EXAMPLE | ||
| # # upgrade from powershell 1.0 to 3.0 with automatic login and reboots | ||
| # Set-ExecutionPolicy Unrestricted -Force | ||
|
|
@@ -83,9 +86,12 @@ | |
| Param( | ||
| [string]$version = "5.1", | ||
| [string]$username, | ||
| [string]$domain, | ||
| [string]$password, | ||
| [switch]$verbose = $false | ||
| [switch]$verbose = $false, | ||
| [switch]$force | ||
| ) | ||
|
|
||
| $ErrorActionPreference = 'Stop' | ||
| if ($verbose) { | ||
| $VerbosePreference = "Continue" | ||
|
|
@@ -100,15 +106,15 @@ Function Write-Log($message, $level="INFO") { | |
| # Poor man's implementation of Log4Net | ||
| $date_stamp = Get-Date -Format s | ||
| $log_entry = "$date_stamp - $level - $message" | ||
| $log_file = "$tmp_dir\upgrade_powershell.log" | ||
| $log_file = Join-Path -Path "$tmp_dir" -ChildPath 'upgrade_powershell.log' | ||
| Write-Verbose -Message $log_entry | ||
| Add-Content -Path $log_file -Value $log_entry | ||
| } | ||
|
|
||
| Function Reboot-AndResume { | ||
| Write-Log -message "adding script to run on next logon" | ||
| $script_path = $script:MyInvocation.MyCommand.Path | ||
| $ps_path = "$env:SystemDrive\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" | ||
| $ps_path = Join-Path -Path "$PSHOME" -ChildPath 'powershell.exe' | ||
| $arguments = "-version $version" | ||
| if ($username -and $password) { | ||
| $arguments = "$arguments -username `"$username`" -password `"$password`"" | ||
|
|
@@ -117,27 +123,24 @@ Function Reboot-AndResume { | |
| $arguments = "$arguments -Verbose" | ||
| } | ||
|
|
||
| $command = "$ps_path -ExecutionPolicy ByPass -File $script_path $arguments" | ||
| $command = "$ps_path -ExecutionPolicy ByPass -File `"$script_path`" $arguments" | ||
| $reg_key = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce" | ||
| $reg_property_name = "ps-upgrade" | ||
| Set-ItemProperty -Path $reg_key -Name $reg_property_name -Value $command | ||
|
|
||
| if ($username -and $password) { | ||
| $reg_winlogon_path = "HKLM:\Software\Microsoft\Windows NT\CurrentVersion\Winlogon" | ||
| Set-ItemProperty -Path $reg_winlogon_path -Name AutoAdminLogon -Value 1 | ||
| Set-ItemProperty -Path $reg_winlogon_path -Name DefaultUserName -Value $username | ||
| Set-ItemProperty -Path $reg_winlogon_path -Name DefaultPassword -Value $password | ||
| Write-Log -message "rebooting server to continue powershell upgrade" | ||
| } else { | ||
| Write-Log -message "need to reboot server to continue powershell upgrade" | ||
| Set-AutoLogon -Enable | ||
| } | ||
| if ($Force -eq $false) { | ||
| $reboot_confirmation = Read-Host -Prompt "need to reboot server to continue powershell upgrade, do you wish to proceed (y/n)" | ||
| if ($reboot_confirmation -ne "y") { | ||
| $error_msg = "please reboot server manually and login to continue upgrade process, the script will restart on the next login automatically" | ||
| Write-Log -message $error_msg -level "ERROR" | ||
| throw $error_msg | ||
| $msg = "please reboot server manually to continue upgrade process, the script will restart on the next login automatically" | ||
| Write-Log -Message $msg | ||
| exit 0 | ||
| } | ||
| } | ||
|
|
||
|
|
||
| Write-Log -Message 'rebooting server to continue powershell upgrade' | ||
| if (Get-Command -Name Restart-Computer -ErrorAction SilentlyContinue) { | ||
| Restart-Computer -Force | ||
| } else { | ||
|
|
@@ -152,9 +155,9 @@ Function Run-Process($executable, $arguments) { | |
| $psi.FileName = $executable | ||
| $psi.Arguments = $arguments | ||
| Write-Log -message "starting new process '$executable $arguments'" | ||
| $process.Start() | Out-Null | ||
| $process.Start() > $null | ||
|
|
||
| $process.WaitForExit() | Out-Null | ||
| $process.WaitForExit() > $null | ||
| $exit_code = $process.ExitCode | ||
| Write-Log -message "process completed with exit code '$exit_code'" | ||
|
|
||
|
|
@@ -167,62 +170,68 @@ Function Download-File($url, $path) { | |
| $client.DownloadFile($url, $path) | ||
| } | ||
|
|
||
| Function Clear-AutoLogon { | ||
| $reg_winlogon_path = "HKLM:\Software\Microsoft\Windows NT\CurrentVersion\Winlogon" | ||
| Write-Log -message "clearing auto logon registry properties" | ||
| Set-ItemProperty -Path $reg_winlogon_path -Name AutoAdminLogon -Value 0 | ||
| Remove-ItemProperty -Path $reg_winlogon_path -Name DefaultUserName -ErrorAction SilentlyContinue | ||
| Remove-ItemProperty -Path $reg_winlogon_path -Name DefaultPassword -ErrorAction SilentlyContinue | ||
| Function Set-AutoLogon { | ||
| param ( | ||
| [switch] $Enable, | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would probably just have the 1 switch, if set then enable AutoLogon, if not then remove AutoLogon. That way you don't need the ambiguous if case and Enable/Disable are opposites of each other.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In that case, maybe a better way would be to make two separate functions - |
||
| [switch] $Disable | ||
| ) | ||
| $reg_winlogon_path = 'HKLM:\Software\Microsoft\Windows NT\CurrentVersion\Winlogon' | ||
|
|
||
| if ($Enable) { | ||
| Write-Log -Message 'setting auto logon registry properties' | ||
| Set-ItemProperty -Path $reg_winlogon_path -Name AutoAdminLogon -Value 1 | ||
| Set-ItemProperty -Path $reg_winlogon_path -Name DefaultUserName -Value $username | ||
| Set-ItemProperty -Path $reg_winlogon_path -Name DefaultPassword -Value $password | ||
| if ($domain) { | ||
| Set-ItemProperty -Path $reg_winlogon_path -Name DefaultDomain -Value $domain | ||
| } | ||
| } elseif ($Disable) { | ||
| Write-Log -Message 'clearing auto logon registry properties' | ||
| Set-ItemProperty -Path $reg_winlogon_path -Name AutoAdminLogon -Value 0 | ||
| Remove-ItemProperty -Path $reg_winlogon_path -Name DefaultUserName -ErrorAction SilentlyContinue | ||
| Remove-ItemProperty -Path $reg_winlogon_path -Name DefaultPassword -ErrorAction SilentlyContinue | ||
| Remove-ItemProperty -Path $reg_winlogon_path -Name DefaultDomain -ErrorAction SilentlyContinue | ||
| } else { | ||
| $error_msg = 'ambiguous calling of Set-Autolon: expecting a parameter -Enable or -Disable, none has been provided' | ||
| Write-Log -Message $error_msg -Level 'ERROR' | ||
| throw $error_msg | ||
| } | ||
| } | ||
|
|
||
| Function Download-Wmf5Server2008($architecture) { | ||
| if ($architecture -eq "x64") { | ||
| $zip_url = "http://download.microsoft.com/download/6/F/5/6F5FF66C-6775-42B0-86C4-47D41F2DA187/Win7AndW2K8R2-KB3191566-x64.zip" | ||
| $file = "$tmp_dir\Win7AndW2K8R2-KB3191566-x64.msu" | ||
| $zip_url = [uri]"http://download.microsoft.com/download/6/F/5/6F5FF66C-6775-42B0-86C4-47D41F2DA187/Win7AndW2K8R2-KB3191566-x64.zip" | ||
| } else { | ||
| $zip_url = "http://download.microsoft.com/download/6/F/5/6F5FF66C-6775-42B0-86C4-47D41F2DA187/Win7-KB3191566-x86.zip" | ||
| $file = "$tmp_dir\Win7-KB3191566-x86.msu" | ||
| $zip_url = [uri]"http://download.microsoft.com/download/6/F/5/6F5FF66C-6775-42B0-86C4-47D41F2DA187/Win7-KB3191566-x86.zip" | ||
| } | ||
| $filename = $zip_url.Segments[-1] | ||
| $file = Join-Path -Path "$tmp_dir" -ChildPath $filename.Replace('.zip', '.msu') | ||
| if (Test-Path -Path $file) { | ||
| return $file | ||
| } | ||
|
|
||
| $filename = $zip_url.Split("/")[-1] | ||
| $zip_file = "$tmp_dir\$filename" | ||
| $zip_file = Join-Path -Path "$tmp_dir" -ChildPath "$filename" | ||
| Download-File -url $zip_url -path $zip_file | ||
|
|
||
| Write-Log -message "extracting '$zip_file' to '$tmp_dir'" | ||
| try { | ||
| Add-Type -AssemblyName System.IO.Compression.FileSystem > $null | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please keep this in here, Server 2008/R2 probably won't include .NET 4.5 which is when
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You are correct that .NET 4.5 isn't available in clean Server 2008 R2, and you definitely found a bug in my code, but my intentions was to get rid of the So, after .NET installation we could add DWORD that forces usage of the latest CRL, respawn script and load assembly like this: [Reflection.Assembly]::LoadWithPartialName("System.IO.Compression.Filesystem")Also, this could allow us to get rid of What do you think? |
||
| $legacy = $false | ||
| } catch { | ||
| $legacy = $true | ||
| } | ||
|
|
||
| if ($legacy) { | ||
| $shell = New-Object -ComObject Shell.Application | ||
| $zip_src = $shell.NameSpace($zip_file) | ||
| $zip_dest = $shell.NameSpace($tmp_dir) | ||
| $zip_dest.CopyHere($zip_src.Items(), 1044) | ||
| } else { | ||
| [System.IO.Compression.ZipFile]::ExtractToDirectory($zip_file, $tmp_dir) | ||
| } | ||
| Add-Type -AssemblyName System.IO.Compression.FileSystem > $null | ||
| [System.IO.Compression.ZipFile]::ExtractToDirectory($zip_file, $tmp_dir) | ||
|
|
||
| return $file | ||
| } | ||
|
|
||
| Write-Log -message "starting script" | ||
| # on PS v1.0, upgrade to 2.0 and then run the script again | ||
| if ($PSVersionTable -eq $null) { | ||
| if ($null -eq $PSVersionTable) { | ||
| Write-Log -message "upgrading powershell v1.0 to v2.0" | ||
| $architecture = $env:PROCESSOR_ARCHITECTURE | ||
| if ($architecture -eq "AMD64") { | ||
| $url = "https://download.microsoft.com/download/2/8/6/28686477-3242-4E96-9009-30B16BED89AF/Windows6.0-KB968930-x64.msu" | ||
| $url = [uri]"https://download.microsoft.com/download/2/8/6/28686477-3242-4E96-9009-30B16BED89AF/Windows6.0-KB968930-x64.msu" | ||
| } else { | ||
| $url = "https://download.microsoft.com/download/F/9/E/F9EF6ACB-2BA8-4845-9C10-85FC4A69B207/Windows6.0-KB968930-x86.msu" | ||
| $url = [uri]"https://download.microsoft.com/download/F/9/E/F9EF6ACB-2BA8-4845-9C10-85FC4A69B207/Windows6.0-KB968930-x86.msu" | ||
| } | ||
| $filename = $url.Split("/")[-1] | ||
| $file = "$tmp_dir\$filename" | ||
| $filename = $url.Segments[-1] | ||
| $file = Join-Path -Path "$tmp_dir" -ChildPath "$filename" | ||
| Download-File -url $url -path $file | ||
| $exit_code = Run-Process -executable $file -arguments "/quiet /norestart" | ||
| if ($exit_code -ne 0 -and $exit_code -ne 3010) { | ||
|
|
@@ -237,7 +246,7 @@ if ($PSVersionTable -eq $null) { | |
| $current_ps_version = [version]"$($PSVersionTable.PSVersion.Major).$($PSVersionTable.PSVersion.Minor)" | ||
| if ($current_ps_version -eq [version]$version) { | ||
| Write-Log -message "current and target PS version are the same, no action is required" | ||
| Clear-AutoLogon | ||
| Set-AutoLogon -Disable | ||
| exit 0 | ||
| } | ||
|
|
||
|
|
@@ -289,20 +298,8 @@ switch ($version) { | |
|
|
||
| # detect if .NET 4.5.2 is not installed and add to the actions | ||
| $dotnet_path = "HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full" | ||
| if (-not (Test-Path -Path $dotnet_path)) { | ||
| $dotnet_upgrade_needed = $true | ||
| } else { | ||
| $dotnet_version = Get-ItemProperty -Path $dotnet_path -Name Release -ErrorAction SilentlyContinue | ||
| if ($dotnet_version) { | ||
| # 379893 == 4.5.2 | ||
| if ($dotnet_version.Release -lt 379893) { | ||
| $dotnet_upgrade_needed = $true | ||
| } | ||
| } else { | ||
| $dotnet_upgrade_needed = $true | ||
| } | ||
| } | ||
| if ($dotnet_upgrade_needed) { | ||
| $dotnet_version = Get-ItemProperty -Path $dotnet_path -Name Release -ErrorAction SilentlyContinue | ||
| if ($dotnet_version.Release -lt 379893) { | ||
| $actions = @("dotnet") + $actions | ||
| } | ||
|
|
||
|
|
@@ -315,7 +312,7 @@ foreach ($action in $actions) { | |
| switch ($action) { | ||
| "dotnet" { | ||
| Write-Log -message "running .NET update to 4.5.2" | ||
| $url = "https://download.microsoft.com/download/E/2/1/E21644B5-2DF2-47C2-91BD-63C560427900/NDP452-KB2901907-x86-x64-AllOS-ENU.exe" | ||
| $url = [uri]"https://download.microsoft.com/download/E/2/1/E21644B5-2DF2-47C2-91BD-63C560427900/NDP452-KB2901907-x86-x64-AllOS-ENU.exe" | ||
| $error_msg = "failed to update .NET to 4.5.2" | ||
| $arguments = "/q /norestart" | ||
| break | ||
|
|
@@ -334,19 +331,19 @@ foreach ($action in $actions) { | |
| "3.0" { | ||
| Write-Log -message "running powershell update to version 3" | ||
| if ($os_version.Minor -eq 1) { | ||
| $url = "https://download.microsoft.com/download/E/7/6/E76850B8-DA6E-4FF5-8CCE-A24FC513FD16/Windows6.1-KB2506143-$($architecture).msu" | ||
| $url = [uri]"https://download.microsoft.com/download/E/7/6/E76850B8-DA6E-4FF5-8CCE-A24FC513FD16/Windows6.1-KB2506143-$($architecture).msu" | ||
| } else { | ||
| $url = "https://download.microsoft.com/download/E/7/6/E76850B8-DA6E-4FF5-8CCE-A24FC513FD16/Windows6.0-KB2506146-$($architecture).msu" | ||
| $url = [uri]"https://download.microsoft.com/download/E/7/6/E76850B8-DA6E-4FF5-8CCE-A24FC513FD16/Windows6.0-KB2506146-$($architecture).msu" | ||
| } | ||
| $error_msg = "failed to update Powershell to version 3" | ||
| break | ||
| } | ||
| "4.0" { | ||
| Write-Log -message "running powershell update to version 4" | ||
| if ($os_version.Minor -eq 1) { | ||
| $url = "https://download.microsoft.com/download/3/D/6/3D61D262-8549-4769-A660-230B67E15B25/Windows6.1-KB2819745-$($architecture)-MultiPkg.msu" | ||
| $url = [uri]"https://download.microsoft.com/download/3/D/6/3D61D262-8549-4769-A660-230B67E15B25/Windows6.1-KB2819745-$($architecture)-MultiPkg.msu" | ||
| } else { | ||
| $url = "https://download.microsoft.com/download/3/D/6/3D61D262-8549-4769-A660-230B67E15B25/Windows8-RT-KB2799888-x64.msu" | ||
| $url = [uri]"https://download.microsoft.com/download/3/D/6/3D61D262-8549-4769-A660-230B67E15B25/Windows8-RT-KB2799888-x64.msu" | ||
| } | ||
| $error_msg = "failed to update Powershell to version 4" | ||
| break | ||
|
|
@@ -358,13 +355,13 @@ foreach ($action in $actions) { | |
| $file = Download-Wmf5Server2008 -architecture $architecture | ||
| } elseif ($os_version.Minor -eq 2) { | ||
| # Server 2012 | ||
| $url = "http://download.microsoft.com/download/6/F/5/6F5FF66C-6775-42B0-86C4-47D41F2DA187/W2K12-KB3191565-x64.msu" | ||
| $url = [uri]"http://download.microsoft.com/download/6/F/5/6F5FF66C-6775-42B0-86C4-47D41F2DA187/W2K12-KB3191565-x64.msu" | ||
| } else { | ||
| # Server 2012 R2 and Windows 8.1 | ||
| if ($architecture -eq "x64") { | ||
| $url = "http://download.microsoft.com/download/6/F/5/6F5FF66C-6775-42B0-86C4-47D41F2DA187/Win8.1AndW2K12R2-KB3191564-x64.msu" | ||
| $url = [uri]"http://download.microsoft.com/download/6/F/5/6F5FF66C-6775-42B0-86C4-47D41F2DA187/Win8.1AndW2K12R2-KB3191564-x64.msu" | ||
| } else { | ||
| $url = "http://download.microsoft.com/download/6/F/5/6F5FF66C-6775-42B0-86C4-47D41F2DA187/Win8.1-KB3191564-x86.msu" | ||
| $url = [uri]"http://download.microsoft.com/download/6/F/5/6F5FF66C-6775-42B0-86C4-47D41F2DA187/Win8.1-KB3191564-x86.msu" | ||
| } | ||
| } | ||
| break | ||
|
|
@@ -375,16 +372,16 @@ foreach ($action in $actions) { | |
| } | ||
| } | ||
|
|
||
| if ($file -eq $null) { | ||
| $filename = $url.Split("/")[-1] | ||
| $file = "$tmp_dir\$filename" | ||
| if ($null -eq $file) { | ||
| $filename = $url.Segments[-1] | ||
| $file = Join-Path -Path "$tmp_dir" -ChildPath "$filename" | ||
| } | ||
| if ($url -ne $null) { | ||
| if ($null -ne $url) { | ||
| Download-File -url $url -path $file | ||
| } | ||
|
|
||
| $exit_code = Run-Process -executable $file -arguments $arguments | ||
| if ($exit_code -ne 0 -and $exit_code -ne 3010) { | ||
| if (@(0, 3010) -notcontains $exit_code) { | ||
| $log_msg = "$($error_msg): exit code $exit_code" | ||
| Write-Log -message $log_msg -level "ERROR" | ||
| throw $log_msg | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you not specify the domain as part of the
$username, likeDOMAIN\useroruser@DOMAIN.COM?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually I don't know and haven't got domain controller at my disposal to check it. Nevertheless in my opinion separate parameter for domain name is more clear and less obscure way for users to login using their domain accounts.