Skip to content

Instantly share code, notes, and snippets.

@d4rkeagle65
Last active July 26, 2024 00:34
Show Gist options
  • Save d4rkeagle65/9f6ad199188676c7cf1081d099424dcf to your computer and use it in GitHub Desktop.
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.
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
}
@Wateraga
Copy link

Wateraga commented Jun 10, 2024

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment