Detect Windows LAPS Configuration Issues with PowerShell · CloudEngineerHub
Detection & Remediation9 min read4 views
Detecting Windows LAPS Configuration Issues with PowerShell
A read-only Intune detection script that proves Windows LAPS policy landed and processed, flags unsupported builds, and finds legacy LAPS migration leftovers.
C
CloudEngineerHub Team
Published: September 11, 2026· Last Updated: September 28, 2026·9 min read
Windows LAPS solved an old problem elegantly: the local administrator password rotates automatically, the plaintext never sits on the device, and the encrypted copy lands in Entra ID or Active Directory where only authorized admins can read it. What it did not remove is the configuration gap between "we assigned a LAPS policy" and "this device is actually rotating its password". Policy sync can fail silently, unsupported builds ignore the policy entirely, legacy LAPS clients keep running alongside the new stack, and the device looks perfectly managed in every report that does not specifically check.
Visual Walkthrough
The engine behind every “Detect with PowerShell” runbook on this site.
Exit 1 flips the device into the remediation queue for this package.
remediate
3
Remediation executes
Fix script runs silently as SYSTEM with a 5-minute budget.
verify
4
Re-run detection
The same detection script must now exit 0 — proof, not hope.
telemetry
5
Results report
Per-device outcome lands in Reports → Remediations for trend analysis.
6
Repeat on schedule
The loop continues — drift gets caught the day it appears.
Continuous cycle
Proactive Remediations — The Detect → Fix → Verify Loop. 1. Detection script runs: Scheduled (daily/hourly): exit 0 healthy, exit 1 unhealthy — nothing more. — 2. Verdict: unhealthy: Exit 1 flips the device into the remediation queue for this package. — 3. Remediation executes: Fix script runs silently as SYSTEM with a 5-minute budget. — 4. Re-run detection: The same detection script must now exit 0 — proof, not hope. — 5. Results report: Per-device outcome lands in Reports → Remediations for trend analysis. — 6. Repeat on schedule: The loop continues — drift gets caught the day it appears.
C
CloudEngineerHub Team
Author
The CloudEngineerHub editorial team — Microsoft endpoint management and cloud engineers writing hands-on guides on Intune, Azure, Entra ID, Autopilot, Defender and PowerShell. Every article is reviewed against current Microsoft documentation.
Detection closes that gap. This article builds an Intune detection script that verifies the Windows LAPS policy actually reached the device, confirms the client has processed it at least once, probes whether the build supports Windows LAPS at all, and flags legacy LAPS leftovers that belong in a migration plan. It is read-only end to end, and it never touches password material, which lives encrypted in your directory, not in the places this script inspects.
Symptoms
Devices report compliant everywhere, but retrieving a LAPS password from Entra ID or AD fails with "no password found" for specific machines.
Some devices rotate on schedule while others keep the same password for months, and nothing in the portal explains the difference.
A migration from legacy Microsoft LAPS stalls: the old password keeps changing on some machines while Windows LAPS policy seems ignored.
After an OS deployment, newly built devices never appear in your LAPS password retrieval workflow at all.
Possible Causes
The policy never reached the device
LAPS settings arrive like any other Intune policy. Assignment mistakes, filters, and sync failures leave devices with no policy, which the device expresses by doing nothing at all. No error, no rotation, no state.
The build does not support Windows LAPS
Windows LAPS ships with specific Windows versions and servicing levels. Older builds without it ignore the policy completely; some intermediate builds accept pieces of it. Mixed-OS fleets show partial coverage that looks random unless you check build support explicitly.
Policy processing or backup blocked
The client processes policy, rotates the password, and backs it up. Any step can fail: the configured backup target is unreachable, the device lacks directory permissions, or the account the policy targets does not exist locally. Config lands, state never appears.
Legacy LAPS still installed
The legacy client and Windows LAPS use different mechanisms. A device running both can rotate a password through the old stack while you read the new one, or vice versa, which is worse than either alone. Migration cleanup is a real task, not a formality.
Wrong local account targeted
Windows LAPS manages the account its policy names. Renamed administrators, images with custom local accounts, and localized account names create devices where the client is healthy but manages an account nobody expected.
Detection Script
The script below is read-only and runs in 64-bit SYSTEM context, finishing in seconds. It checks build-support signals, scans for legacy LAPS remnants, verifies the LAPS\Config policy mirror, and confirms that LAPS\State shows the client has completed at least one processing cycle.
PowerShell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#Requires -RunAsAdministrator
[CmdletBinding()]
param()
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
<#
.SYNOPSIS
Detection script: reports Windows LAPS configuration health: policy
presence, processed state, build support, and legacy LAPS leftovers.
.NOTES
Intended for Intune Scripts and Remediations, 64-bit SYSTEM context.
Read-only; the script never reads or displays password material. Exit
0 = Windows LAPS policy present and processed; 1 = policy present but
not yet processed, or a legacy LAPS migration signal; 2 = no LAPS
management detected / state cannot be determined; 3 = unexpected error.
#>$logDir = 'C:\ProgramData\Company\Logs'$logFile = Join-Path $logDir'LapsDetection.log'$lapsRoot = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\LAPS'$lapsConfig = Join-Path $lapsRoot'Config'$lapsState = Join-Path $lapsRoot'State'$legacyCseDll = 'C:\Program Files\LAPS\CSE\Admpwd.dll'$gpExtensions = 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\GPExtensions'function Write-DetectionLog {
param([Parameter(Mandatory)][string] $Level, [Parameter(Mandatory)][string] $Message)
if (-not (Test-Path $logDir)) { New-Item -Path$logDir -ItemType Directory -Force | Out-Null }
"$([DateTime]::UtcNow.ToString('o')) [$Level] $Message" | Out-File -FilePath$logFile -Append -Encoding utf8
}
try {
Write-DetectionLog 'INFO''Windows LAPS configuration detection run started.' # ---- Check 0: build support signals ----$lapsEventLog = Get-WinEvent -ListLog'Microsoft-Windows-LAPS/Operational' -ErrorAction SilentlyContinue
if ($null -ne$lapsEventLog) {
Write-DetectionLog 'INFO''Microsoft-Windows-LAPS/Operational event log present - this build supports Windows LAPS.'
}
else {
Write-DetectionLog 'WARN''Microsoft-Windows-LAPS/Operational event log not found - this Windows build may predate Windows LAPS. Registry and cmdlet behavior can differ on older builds.'
}
$lapsCmdlet = $nulltry { $lapsCmdlet = Get-Command -Name'Get-LapsDiagnostics' -ErrorAction SilentlyContinue }
catch { $lapsCmdlet = $null }
if ($null -ne$lapsCmdlet) {
Write-DetectionLog 'INFO'"LAPS PowerShell module present ($($lapsCmdlet.Source))."
}
else {
Write-DetectionLog 'INFO''LAPS PowerShell module not available on this build - registry checks remain authoritative.'
}
# ---- Check 1: legacy LAPS client (migration signal) ----$legacyDetected = $falseif (Test-Path $legacyCseDll) {
$legacyDetected = $true
Write-DetectionLog 'WARN'"Legacy LAPS client detected ($legacyCseDll)."
}
if (Test-Path $gpExtensions) {
foreach ($keyin @(Get-ChildItem -Path$gpExtensions -ErrorAction SilentlyContinue)) {
$prop = Get-ItemProperty -Path$key.PSPath -ErrorAction SilentlyContinue
if ($null -eq$prop) { continue }
$displayName = $prop.PSObject.Properties['(default)']
if ($null -ne$displayName -and$displayName.Value -match'LAPS') {
$legacyDetected = $true
Write-DetectionLog 'WARN'"Legacy LAPS GP extension registered: $($key.PSChildName)."
}
}
}
# ---- Check 2: Windows LAPS policy mirror ----if (-not (Test-Path $lapsConfig)) {
if ($legacyDetected) {
Write-DetectionLog 'ERROR''Legacy LAPS is active but no Windows LAPS policy has landed - migration to Windows LAPS is pending.'
}
else {
Write-DetectionLog 'WARN'"No Windows LAPS policy found under $lapsConfig - either no LAPS policy is assigned to this device, or policy sync has not landed it yet."
}
exit 2
}
$configKey = Get-Item -Path$lapsConfig -ErrorAction SilentlyContinue
$configValueCount = 0if ($null -ne$configKey) { $configValueCount = $configKey.ValueCount }
if ($configValueCount -eq0) {
Write-DetectionLog 'WARN''LAPS\Config exists but holds no values - policy state is incomplete.'
exit 2
}
$valueNames = @($configKey.GetValueNames() | Sort-Object)
Write-DetectionLog 'INFO'"LAPS\Config present with $configValueCount value(s): $($valueNames -join ', ')"$backupDirectory = $configKey.GetValue('BackupDirectory')
if ($null -ne$backupDirectory) {
Write-DetectionLog 'INFO'"Configured BackupDirectory=$backupDirectory (confirm this matches your intended backup target)."
}
# ---- Check 3: processed state ----if (-not (Test-Path $lapsState)) {
Write-DetectionLog 'ERROR''LAPS policy is present but LAPS\State does not exist yet - the client has not completed a policy processing or backup cycle.'
exit 1
}
$stateKey = Get-Item -Path$lapsState -ErrorAction SilentlyContinue
$stateValueCount = 0if ($null -ne$stateKey) { $stateValueCount = $stateKey.ValueCount }
if ($stateValueCount -eq0) {
Write-DetectionLog 'ERROR''LAPS\State exists but holds no values - no successful policy processing cycle has been recorded.'
exit 1
}
Write-DetectionLog 'INFO'"LAPS\State present with $stateValueCount value(s) - the client has processed policy at least once."if ($legacyDetected) {
Write-DetectionLog 'WARN''Windows LAPS is healthy, but a legacy LAPS client is still installed - plan the migration cleanup.'
}
Write-DetectionLog 'INFO''Windows LAPS configuration looks healthy.'
exit 0
}
catch {
Write-DetectionLog 'ERROR'"Unexpected failure: $($_.Exception.Message)"
exit 3
}
Detection Logic
Build support signals. The script probes the Microsoft-Windows-LAPS/Operational event log with Get-WinEvent -ListLog. Its presence means the build ships Windows LAPS; its absence is a WARN, not a verdict, because the registry checks that follow remain the authority and cmdlet availability varies by build. The script also probes for the LAPS PowerShell module, which only exists on builds where Windows LAPS shipped, and logs the finding without treating it as proof.
Legacy LAPS scan. Two real fingerprints of the legacy client: the file C:\Program Files\LAPS\CSE\Admpwd.dll, and a Group Policy extension registered under HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\GPExtensions whose display name contains LAPS. Either finding is logged as a WARN. If Windows LAPS policy is absent while the legacy client runs, the script calls the migration pending, because that device's local admin password is still being managed by the old stack.
Policy mirror. When a LAPS policy is assigned and synced, the device mirrors its configuration under HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\LAPS\Config. The script verifies the key exists and holds values, logs the value names (policy settings only, no secrets), and records the configured BackupDirectory so a mismatch with your intended backup target is visible. No key, or an empty key, exits 2: from the device you cannot distinguish "no policy assigned" from "policy not synced yet".
Processed state.HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\LAPS\State appears once the client has processed policy, and its values record the outcome of that processing. A device with Config but no State has been assigned policy but has never completed a cycle, which is the classic "assigned but not working" signature and exits 1. State with values exits 0, healthy.
Remediation Script
There is no remediation script, and the reasons are practical rather than squeamish. Every meaningful fix here is external to the device: correcting the policy assignment, upgrading the build, repairing directory permissions for the backup target, or removing the legacy client as part of a planned migration. A script could delete the legacy client, but ripping a client-side password manager out of devices whose backup target may still be the legacy one is a migration decision with sequencing requirements, not a remediation loop. This package gives you the fleet-wide evidence to sequence that migration safely: which devices are healthy, which never processed policy, and which still run the old client.
Deploying Through Intune
Deploy as a detection-only package:
In the Microsoft Intune admin center, open Devices → Scripts and remediations and select + Add under Windows 10/11.
On Basics, name it, for example Detect - Windows LAPS configuration, and describe it as a read-only configuration review that never touches password material.
On Detection script, upload detect.ps1. Set Run script in 64-bit PowerShell: Yes and Run this script using signed-on credentials: No; the registry tree under HKLM requires SYSTEM or elevated context.
On the Remediation script step, choose No remediation script.
On Schedule, run Daily during a LAPS rollout or migration, then relax to Weekly. Configuration state changes only with policy or build changes, so weekly is ample steady-state.
On Assignments, target the device groups covered by your LAPS policy so the report reflects the managed population. For migration projects, also assign to the legacy-LAPS device group to track progress.
Review and create.
Post-specific notes:
Run this before your first LAPS policy assignment to establish a baseline; the code 2 population then shows you exactly which devices the policy has not reached.
Pair the log's BackupDirectory line with your directory-side review: a device can be healthy locally and still back up to the wrong target.
The legacy-LAPS findings are migration input, not incidents. Feed the WARN lines into your migration tracker.
Visual Walkthrough
Per-device local admin passwords: rotate, store, authorize, audit.
Interactive FlowWindows LAPS — Rotation to Retrieval6/6
1
LAPS policy assigned
Rotation days, password complexity, admin account name set.
rotate
2
Password rotated locally
Device generates a unique random password per schedule.
escrow
3
Escrowed to Entra / AD
Password stored on the computer object / Entra device.
retrieve
4
Authorized retrieval
RBAC role + scope decides who may read which device.
audit
5
Every read audited
Retrieval events logged — accountability by design.
6
Cycle continues
Next rotation invalidates any leaked secret automatically.
Windows LAPS — Rotation to Retrieval. 1. LAPS policy assigned: Rotation days, password complexity, admin account name set. — 2. Password rotated locally: Device generates a unique random password per schedule. — 3. Escrowed to Entra / AD: Password stored on the computer object / Entra device. — 4. Authorized retrieval: RBAC role + scope decides who may read which device. — 5. Every read audited: Retrieval events logged — accountability by design. — 6. Cycle continues: Next rotation invalidates any leaked secret automatically.
Exit Codes
Code
Meaning
0
Windows LAPS policy present and processed at least once (healthy)
1
Policy present but never processed, or a legacy LAPS migration signal on an otherwise policy-less device
2
No LAPS policy detected on the device, or the configuration state is incomplete or unreadable
3
Unexpected script error — inspect the log
Logging
The script writes to C:\ProgramData\Company\Logs\LapsDetection.log. Each line carries a UTC timestamp, a level (INFO, WARN, ERROR), and a message. Build-support findings, legacy fingerprints, the policy value names, and the BackupDirectory setting all appear as their own lines, so the log answers "why is this device flagged" without a follow-up session. The script logs no password material anywhere; it inspects configuration only. Three to eight lines per run; monthly rotation is plenty.
Troubleshooting the Script
Exit 2 across a newly assigned group. Policy sync lag. Check the LAPS policy's assignment status and device check-in times before assuming devices are broken.
Exit 2 with the empty-Config message. The policy landed but carries no settings. Verify the LAPS policy profile in Intune is fully populated and targeted at the right platform.
Exit 1 with the no-State message on supported builds. The client processed nothing. Read the Microsoft-Windows-LAPS/Operational event log on that device; backup failures and target-account errors explain most cases.
Legacy LAPS warnings on machines you thought were migrated. The uninstall step was skipped or reverted. Plan a cleanup wave; both stacks running is the state migration guides warn about.
No event log and no LAPS module on specific devices. Those builds likely predate Windows LAPS. Route them to an OS upgrade track; no policy change will fix them.
No log file appears. The script never ran. Verify assignment, check-in, and that no policy pins the run to a user context that never signs in.
How to Validate the Fix
On a device with an assigned LAPS policy, run the script manually in an elevated 64-bit PowerShell console. A healthy device exits 0 with the Config value names and State line logged.
On a device deliberately excluded from the LAPS policy, expect exit code 2 with the "no policy" line, proving the script separates "not in scope" from "broken".
For a flagged device, retrieve its password through your normal admin workflow after fixing the root cause, then re-run the script and confirm exit code 0.
In the admin center, review the package's Device status after the first scheduled runs and reconcile the code 1 and code 2 populations against your rollout plan.
During a legacy migration, watch the legacy WARN lines disappear as you uninstall the old client, and confirm each device still reports code 0 afterwards.
Production Considerations
Execution context. SYSTEM in 64-bit Windows PowerShell. Registry reads under HKLM and the legacy CSE path checks need elevation; no user state is read.
Idempotency. Pure read. The script can run at any frequency without side effects and without interacting with the LAPS client's own processing.
Privacy and secrets. The script never reads, displays, or moves password material. It inspects configuration keys and state, which is the correct boundary for fleet automation; password retrieval stays in your directory-side, audited workflow.
Build honesty. Cmdlet and event-log availability depend on the Windows build, which is why the script treats them as signals and keeps the registry checks authoritative. Expect the WARN lines on older builds.
Security review and test ring. No credentials appear in the script and nothing is changed, but your PowerShell automation SME and security team should review it and validate it in a test ring before broad production rollout, as with every script in this series.
Does this script read or expose the local administrator password?
No. The password itself is stored encrypted in Entra ID or Active Directory, and this script never contacts the directory. It reads the device's configuration mirror and processing state under the LAPS registry root, which contains policy settings and cycle outcomes, not credentials. Retrieving passwords stays in your audited, role-restricted admin workflow.
Why does a missing policy exit code 2 instead of 1?
From the device alone, "no policy assigned" and "policy not synced yet" look identical. Exit code 1 is reserved for a state the device can act on, like policy present but never processed. Exit code 2 sends you to the Intune side, where assignment records settle the question. That split keeps the triage path honest.
We still run legacy LAPS everywhere. Is this script useful before the migration?
Yes, and that is one of its main uses. The legacy fingerprints let you track which devices still run the old stack, while the Windows LAPS checks show migration progress device by device. Assign it during the migration, and the log becomes your per-device migration evidence.
Comments
0No comments yet — be the first to share your thoughts.