<# .SYNOPSIS Forces Windows LAPS to rotate the managed local admin password on this computer right now. .DESCRIPTION Finds which Windows LAPS policy applies (Intune/CSP, Group Policy, or local config), confirms password backup is turned on, and calls Reset-LapsPassword. LAPS generates the new password, stores it in Active Directory or Microsoft Entra ID, and sets it locally. No password ever passes through this script. If LAPS isn't configured, the script stops and says so rather than falling back to anything. Exit codes: 0 = rotated; 1 = rotation failed; 2 = Windows LAPS not available on this build; 4 = no active Windows LAPS policy. .EXAMPLE .\Invoke-LapsPasswordRotation.ps1 .EXAMPLE .\Invoke-LapsPasswordRotation.ps1 -WhatIf -Verbose #> [CmdletBinding(SupportsShouldProcess)] param() # Windows LAPS reads policy from these keys, highest precedence first. $policyRoots = [ordered]@{ 'CSP (Intune)' = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\LAPS' 'Group Policy' = 'HKLM:\SOFTWARE\Microsoft\Policies\LAPS' 'Local configuration' = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\LAPS\Config' } $legacyRoot = 'HKLM:\SOFTWARE\Policies\Microsoft Services\AdmPwd' $directories = @{ 0 = 'Disabled'; 1 = 'Microsoft Entra ID'; 2 = 'Active Directory' } $result = [ordered]@{ ComputerName = $env:COMPUTERNAME; PolicySource = 'None'; BackupDirectory = '' ManagedAccount = ''; Status = ''; Detail = '' } function Complete-Run { param([int]$Code) [pscustomobject]$result; exit $Code } if (-not (Get-Command -Name Reset-LapsPassword -ErrorAction SilentlyContinue)) { $result.Status = 'NotAvailable' $result.Detail = 'Windows LAPS is not on this build. Patch to a supported cumulative update first.' Complete-Run 2 } $policy = $null foreach ($source in $policyRoots.Keys) { $values = Get-ItemProperty -Path $policyRoots[$source] -ErrorAction SilentlyContinue if ($values -and $null -ne $values.BackupDirectory) { $policy = $values; $result.PolicySource = $source break } } if (-not $policy) { $result.Status = 'NoPolicy' $result.Detail = if (Test-Path -Path $legacyRoot) { 'Only legacy Microsoft LAPS (AdmPwd) policy found. Migrate to Windows LAPS.' } else { 'No Windows LAPS policy applies to this device.' } Complete-Run 4 } $backup = [int]$policy.BackupDirectory $result.BackupDirectory = if ($directories.ContainsKey($backup)) { $directories[$backup] } else { "Unknown ($backup)" } $result.ManagedAccount = if ($policy.AutomaticAccountManagementEnabled -eq 1) { $name = if ($policy.AutomaticAccountManagementNameOrPrefix) { $policy.AutomaticAccountManagementNameOrPrefix } else { 'WLapsAdmin' } "$name (automatic account management)" } elseif ($policy.AdministratorAccountName) { $policy.AdministratorAccountName } else { 'Built-in Administrator' } Write-Verbose "Policy from $($result.PolicySource): backup to $($result.BackupDirectory), account $($result.ManagedAccount)" if ($backup -eq 0) { $result.Status = 'NoPolicy'; $result.Detail = 'A LAPS policy exists but password backup is disabled.' Complete-Run 4 } if (-not $PSCmdlet.ShouldProcess($env:COMPUTERNAME, "Rotate the LAPS password for '$($result.ManagedAccount)'")) { $result.Status = 'WhatIf'; Complete-Run 0 } try { Reset-LapsPassword -ErrorAction Stop $result.Status = 'Rotated' Complete-Run 0 } catch { # Usually means the device can't reach a domain controller or Entra right now. LAPS retries on its own cycle. $result.Status = 'Failed'; $result.Detail = $_.Exception.Message Complete-Run 1 }