Last active
July 26, 2024 00:34
-
-
Save d4rkeagle65/9f6ad199188676c7cf1081d099424dcf to your computer and use it in GitHub Desktop.
This script will install any available windows updates. If a reboot is required it will setup a temporary user account and enable autologon, then reboot and rerun itself until there are no updates left. Modified gist from https://gist.github.com/joefitzgerald/8203265.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| param( | |
| $global:RestartRequired=0, | |
| $global:MoreUpdates=0, | |
| $global:MaxCycles=10 | |
| ) | |
| Function Get-StringHash { | |
| param( | |
| [String] $String, | |
| $HashName = "MD5" | |
| ) | |
| $bytes = [System.Text.Encoding]::UTF8.GetBytes($String) | |
| $algorithm = [System.Security.Cryptography.HashAlgorithm]::Create($HashName) | |
| $StringBuilder = New-Object System.Text.StringBuilder | |
| $algorithm.ComputeHash($bytes) | | |
| ForEach-Object { | |
| $null = $StringBuilder.Append($_.ToString("x2")) | |
| } | |
| $StringBuilder.ToString() | |
| } | |
| function Check-ContinueRestartOrEnd() { | |
| $RegistryKey = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run" | |
| $RegistryEntry = "InstallWindowsUpdates" | |
| $AutoLogonRegistryKey = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" | |
| 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)) { | |
| Install-WindowsUpdates | |
| } elseif ($script:Cycles -gt $global:MaxCycles) { | |
| Write-Host "Exceeded Cycle Count - Stopping" | |
| Write-Host "Removing AutoLogon and Script User" | |
| $DefaultUsername = Get-ItemProperty $AutoLogonRegistryKey | Select -Expand DefaultUsername | |
| Remove-ItemProperty $AutoLogonRegistryKey "AutoAdminLogon" -ErrorAction SilentlyContinue | |
| Remove-ItemProperty $AutoLogonRegistryKey "DefaultUsername" -ErrorAction SilentlyContinue | |
| Remove-ItemProperty $AutoLogonRegistryKey "DefaultPassword" -ErrorAction SilentlyContinue | |
| Remove-LocalUser -Name $DefaultUsername -ErrorAction SilentlyContinue | |
| Restart-Computer | |
| } else { | |
| Write-Host "Done Installing Windows Updates" | |
| Write-Host "Removing AutoLogon and Script User" | |
| $DefaultUsername = Get-ItemProperty $AutoLogonRegistryKey | Select -Expand DefaultUsername | |
| Remove-ItemProperty $AutoLogonRegistryKey "AutoAdminLogon" -ErrorAction SilentlyContinue | |
| Remove-ItemProperty $AutoLogonRegistryKey "DefaultUsername" -ErrorAction SilentlyContinue | |
| Remove-ItemProperty $AutoLogonRegistryKey "DefaultPassword" -ErrorAction SilentlyContinue | |
| Remove-LocalUser -Name $DefaultUsername -ErrorAction SilentlyContinue | |
| Restart-Computer | |
| } | |
| } | |
| 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 $($script:ScriptPath)" | |
| } else { | |
| Write-Host "Restart Registry Entry Exists Already" | |
| } | |
| If (!(Get-ItemProperty $AutoLogonRegistryKey | Select -Expand DefaultUsername -ErrorAction SilentlyContinue)) { | |
| Write-Host "Creating Script User and Enabling AutoLogon" | |
| $rand = -join ((65..90) + (97..122) | Get-Random -Count 15 | % {[char]$_}) | |
| $DefaultUsername = ("winUpUser" + $rand) | |
| $DefaultPassword = Get-StringHash -String $rand -HashName SHA256 | |
| New-LocalUser -Name $DefaultUsername -Description "Account for AutoLogon for Windows Updates" -Password $DefaultPassword | |
| Add-LocalGroupMember -Group "Administrators" -Member $DefaultUsername | |
| Set-ItemProperty $AutoLogonRegistryKey "AutoAdminLogon" -Value "1" -type String -Force | |
| Set-ItemProperty $AutoLogonRegistryKey "DefaultUsername" -Value "$DefaultUsername" -type String -Force | |
| Set-ItemProperty $AutoLogonRegistryKey "DefaultPassword" -Value "$DefaultPassword" -type String -Force | |
| } | |
| 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 = $script: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 | |
| If (!($script:ScriptPath -eq 'C:\ProgramData\winUpdate.ps1')) { | |
| Copy-Item -Destination 'C:\ProgramData\winUpdate.ps1' -LiteralPath $script:ScriptPath | |
| $script:ScriptPath = 'C:\ProgramData\winUpdate.ps1' | |
| } | |
| Check-WindowsUpdates | |
| if ($global:MoreUpdates -eq 1) { | |
| Install-WindowsUpdates | |
| } else { | |
| Check-ContinueRestartOrEnd | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I just used this... It locked me out of my computer, activated the admin account along with a password for it, obviously I won't know what that is.. that would be okay but for the fact that MY USER is not availabe on the logon screen and none of the fixes I've tried have helped..
Like, it's probably me being dumb but I've tried enough fixes to have realised by now,, Is there anything in your script that would cause that and you know how to undo it?
Don't take this as me sayingn you are malicious in any way it's proall a bug of some sort but damn it's a bad bug...
Also I changed the admin account password in safe mod and it didn't work, when I leave it blank it still says wrong password, when I typ in "123" which is what I set, it says "your account has been disabled".
Edit: @d4rkeagle65
Yeah that fucked my system up in a way I;'ve nevber seen... currently reinstalling Windows on the laptop I used it on so not the worst thing.. but using it on my main would have been disastrous if it did the same thing.
@d4rkeagle65 Actually, I'm using Win11 Enterprise IoT so maybe there was some weird user interaction there ... ?