Public/Get-ITFDeviceLapsPassword.ps1
|
<# .SYNOPSIS Retrieves the active Windows LAPS local administrator password for a specific device. .DESCRIPTION This function queries Entra ID (Azure AD) to retrieve the current Windows LAPS (Local Administrator Password Solution) credential for a given device. It utilizes the native Microsoft Graph SDK cmdlets. It requires the 'DeviceLocalCredential.Read.All' Graph API scope. .PARAMETER DeviceName The display name of the device in Entra ID/Intune. .PARAMETER PasswordAgeDays The number of days before the LAPS password expires, based on your Intune policy. Defaults to 7 days. This is used to calculate the ExpirationDateTime. .EXAMPLE Get-ITFDeviceLapsPassword -DeviceName "WPS-12345" Retrieves the local admin password and calculates expiration based on a 7-day policy. .EXAMPLE Get-ITFDeviceLapsPassword -DeviceName "WPS-12345" -PasswordAgeDays 14 Retrieves the local admin password and calculates expiration based on a 14-day policy. #> function Get-ITFDeviceLapsPassword { [CmdletBinding()] param ( [Parameter(Mandatory = $true, Position = 0)] [ValidateNotNullOrEmpty()] [string]$DeviceName, [Parameter(Mandatory = $false)] [int]$PasswordAgeDays = 7 ) try { Write-Verbose "Searching for device '$DeviceName' in Entra ID..." # 1. Retrieve the device (including both Object ID and Azure AD Device ID) $entraDevice = Get-MgDevice -Filter "displayName eq '$DeviceName'" -Property "id,deviceId,displayName" -ErrorAction Stop if ($null -eq $entraDevice) { Write-Warning "Device '$DeviceName' not found in Entra ID." return } if ($entraDevice.Count -gt 1) { Write-Warning "Multiple devices found with the name '$DeviceName'. Please ensure the device name is unique." return } Write-Host "Retrieving active LAPS password for $($entraDevice.DisplayName)..." -ForegroundColor Cyan $lapsInfo = $null $foundPassword = $false # 2. Try the Object ID first (Microsoft Standard) try { $lapsInfo = Get-MgDirectoryDeviceLocalCredential -DeviceLocalCredentialInfoId $entraDevice.Id -Property "credentials" -ErrorAction Stop } catch { # Catch the specific Graph error if the Object ID fails if ($_.Exception.Message -match "could not be found" -or $_.Exception.Message -match "NotFound") { # Plan B: Try using the Azure AD Device ID try { $lapsInfo = Get-MgDirectoryDeviceLocalCredential -DeviceLocalCredentialInfoId $entraDevice.DeviceId -Property "credentials" -ErrorAction Stop } catch { if ($_.Exception.Message -match "could not be found" -or $_.Exception.Message -match "NotFound") { Write-Warning "LAPS password record not found in Entra ID for this device." return } throw $_ } } else { throw $_ } } # 3. Extract credentials, sort by date, convert timezone, and decode the newest one if ($null -ne $lapsInfo -and $null -ne $lapsInfo.Credentials) { # Collect all valid credentials into an array $validCredentials = @() foreach ($credential in $lapsInfo.Credentials) { if (-not [string]::IsNullOrWhiteSpace($credential.PasswordBase64)) { $validCredentials += $credential } } if ($validCredentials.Count -gt 0) { $foundPassword = $true # Sort the array by BackupDateTime (newest first) and select the top 1 $activeCredential = $validCredentials | Sort-Object BackupDateTime -Descending | Select-Object -First 1 # Decode Base64 password $plainTextPassword = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($activeCredential.PasswordBase64)) # Convert UTC to Local Timezone $localBackupTime = ([datetime]$activeCredential.BackupDateTime).ToLocalTime() # Calculate the Expiration Date using the local time $expirationDate = $localBackupTime.AddDays($PasswordAgeDays) [PSCustomObject]@{ DeviceName = $entraDevice.DisplayName AccountName = $activeCredential.AccountName Password = $plainTextPassword BackupDateTime = $localBackupTime ExpirationDateTime = $expirationDate } } } if (-not $foundPassword) { Write-Warning "No LAPS password found inside the credentials container for '$DeviceName'." } } catch { $errorMessage = $_.Exception.Message if ($errorMessage -match "Authorization_RequestDenied" -or $errorMessage -match "Forbidden" -or $errorMessage -match "Insufficient privileges") { Write-Error "Access Denied. You are missing the 'DeviceLocalCredential.Read.All' scope. Please run Connect-IntuneTaskForce to re-authenticate and consent." } else { Write-Error "Graph SDK Error: $errorMessage" } } } |