Worklet Deploy Microsoft LAPS and Compliance Check

  • 11 February 2022
  • 0 replies
  • 628 views

Userlevel 5
Badge +1

Add as many details as possible, by providing details you’ll make it easier for others to reply

 

How to Deploy LAPS

  1. Download LAPS to a domain controller

  2. Create security group called “LAPS Admins” and populate appropriate users or groups

  3. Install LAPS x64 and add all Management Tools

  4. Extend AD Schema

    Import-Module AdmPwd.PS 2Update-AdmPwdADSchema
  5. Provide permissions to workstation administrators

    Set-AdmPwdReadPasswordPermission -OrgUnit "Workstations" -AllowedPrincipals "Workstation-Admins"
  6. Set self permissions (what OU the Workstation-Admins can lookup passwords on)

    Set-AdmPwdComputerSelfPermission -OrgUnit "Workstations"
  7. Open Group Policy Management Wizard

  8. Create new policy under Workstations OU called “Microsoft LAPS”

  9. Edit new policy at Computer Configuration > Policies > Administrative Templates > LAPS

  10. Enable “Enable local admin password management”

  11. Enable “Password Settings”

    1. Set Password Complexity

    2. Set Password Length X+ characters

    3. Set Password Age X days

  12. Update policy on domain connected PC

 

Deploying LAPS with Automox Worklet

 

Evaluation Code

  • Validates if LAPS is installed → Runs Remediation if not
  • Was local admin password reset in last 30 days → Runs Remediation if not
# Check LAPS as installed (Need to extract from 64-bit registry hive so using 64-bit powershell as Automox runs in 32-bit)
$scriptblock = {Get-ItemProperty 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*' | where-object {$_.DisplayName -eq 'Local Administrator Password Solution'}}
$software = & "$env:SystemRoot\sysnative\WindowsPowerShell\v1.0\powershell.exe" -ExecutionPolicy Bypass -WindowStyle Hidden -NoProfile -NonInteractive -Command $scriptblock

If(-not ($software)){
# LAPS NOT INSTALLED
exit 1
}else{
# LAPS detected. Determine if local admin was set in last 30 days.
$scriptblock = {Get-LocalUser}
$users = & "$env:SystemRoot\sysnative\WindowsPowerShell\v1.0\powershell.exe" -ExecutionPolicy Bypass -WindowStyle Hidden -NoProfile -NonInteractive -Command $scriptblock

$admin = $users | Where-Object Name -eq Administrator
[regex]$regex = '(0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])[- /.](19|20)'
$PasswordLastSet = ($admin.PasswordLastSet | Select-String -Pattern $regex).matches.value

# Validate LAPS reset password in last month
$expires = (Get-Date).AddMonths(-1)
IF($admin.PasswordLastSet -lt $expires){
# Non-Compliant
Exit 1
}elseif($admin.PasswordLastSet -ge $expires){
# Compliant
Exit 0
}
}

Remediation Code - 

  • Installs LAPS
  • Writes output to Activity Log if Non-Compliant.
# Check LAPS as installed (Need to extract from 64-bit registry hive so using 64-bit powershell as Automox runs in 32-bit)
$scriptblock = {Get-ItemProperty 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*' | where-object {$_.DisplayName -eq 'Local Administrator Password Solution'}}
$software = & "$env:SystemRoot\sysnative\WindowsPowerShell\v1.0\powershell.exe" -ExecutionPolicy Bypass -WindowStyle Hidden -NoProfile -NonInteractive -Command $scriptblock

If(-not ($software)){
# Install LAPS
[void](Start-Process -FilePath 'msiexec.exe' -ArgumentList ('/qn', '/i', '"LAPS.x64.msi"') -Wait -Passthru)

# Check Results of install
if ($? -eq "True"){
Write-Output "LAPS client successfully installed. "
}else{
Write-Output "Failed to install LAPS client! "
}
}

Write-Host "Determine if local admin was set in last 30 days. "
# Get Local Users (using script block because Automox runs 32-bit and Get-LocalUser only works with 64-bit powershell on 64-bit system)
$scriptblock = {Get-LocalUser}
$users = & "$env:SystemRoot\sysnative\WindowsPowerShell\v1.0\powershell.exe" -ExecutionPolicy Bypass -WindowStyle Hidden -NoProfile -NonInteractive -Command $scriptblock

$admin = $users | Where-Object Name -eq Administrator
[regex]$regex = '(0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])[- /.](19|20)'
$PasswordLastSet = ($admin.PasswordLastSet | Select-String -Pattern $regex).matches.value

# Validate LAPS reset password in last month
$expires = (Get-Date).AddMonths(-1)
IF($admin.PasswordLastSet -lt $expires){
Write-Output "Administrator password last set $PasswordLastSet. Non-Complaint. "
exit 1
}elseif($admin.PasswordLastSet -ge $expires){
Write-Output "Administrator password last set $PasswordLastSet. Complaint. "
exit 0
}

 

Checking for Compliance

 

Using Active Directory

This proved to be a slow way of getting compliance. I’m certain this could be tweaked for larger environments to produce a faster answer.

$DaysInactive = 31
$searchbase = "OU=Workstations,DC=LapkoSoft,DC=local"

$InactiveDate = (Get-Date).Adddays(-($DaysInactive))
$computers = Get-ADComputer -Filter {(LastLogonDate -gt $InactiveDate -and Enabled -eq $true)} -SearchBase $searchbase -Properties LastLogonDate,whenCreated,OperatingSystem,ms-MCS-AdmPwdExpirationTime

$results = $computers | % {

# Check Compliance
IF($null -eq $_.'ms-Mcs-AdmPwdExpirationTime'){
# no time-stamp, LAPS likely has not run
$compliance = $false
}else{
# Get Timestamp for password last set
$PwExp = $([datetime]::FromFileTime([convert]::ToInt64($_."ms-MCS-AdmPwdExpirationTime",10)))

# Password last set longer than inactivity date, report non-compliance
IF($pwExp -gt $InactiveDate){
$compliance = $false
}else{
$complinace = $true
}
}

# Build object with results
[pscustomobject]@{
Compliance = $compliance
Name = $_.Name
"LAPS PW Expiration Time" = $PwExp
DistinguishedName = $_.DistinguishedName
DNSHostName = $_.DNSHostName
LastLogonDate = $_.LastLogonDate
OperatingSystem = $_.OperatingSystem
whenCreated = $_.whenCreated
}
}

# Get compliant and non-compliant
$compliant = $results | where Compliance -eq $true
$noncompliant = $results | where Compliance -eq $false

# Get percentage of compliant systems.
$compliance = "{0:p2}" -f (($compliant.count)/($compliant.count + $noncompliant.count))
Write-Output "LAPS Compliance at $compliance ($($compliant.count) Compliant out of $($compliant.count + $noncompliant.count) )"

Automox API

This proved to be a faster method but limited in source of truth of does it include every workstation or not.

$apiKey = Read-Host "api-key "
$outcsv = 'C:\temp\Microsoft-LAPS-Audit.csv'
$orgID = 'your-org-id'
$headers = @{ "Authorization" = "Bearer $apiKey" }
$policy = 000000 # policy # for worklet used to deploy LAPS
$start = Get-Date 1/1/2022 -f 'yyyy-MM-dd'
$end = Get-Date 1/31/2022 -f 'yyyy-MM-dd'
$i = 0

$data = do{

$url = "https://console.automox.com/api/events?o=$orgID&policyId=$policy&limit=500&page=$i&startDate=$start&endDate=$end"
$response = (Invoke-WebRequest -Method Get -Uri $url -Headers $headers).Content | ConvertFrom-Json

$response | % {
$nc = 0
$text = IF($_.data.text -match 'Non-Compliant'){$nc -eq 1}
$name = $_.server_name
[regex]$regex = '(0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])[- /.](19|20)'
$PasswordLastSet = ($_.data.text | Select-String -Pattern $regex).matches.value
[pscustomobject] @{
name = $name
LAPS = IF($nc -eq 0){"Compliant"}else{"Non-Compliant"}
PasswordLastSet = $PasswordLastSet
}
}
$i++
}
while ($response)

# Save output
$data | Export-Csv $outcsv -NoTypeInformation -Verbose

# Use Out-Gridview to display the results
$data | ogv

 


0 replies

Be the first to reply!

Reply