The LAPS: Reloaded / Revolutions

Last Updated on January 28, 2022 by rudyooms

First, A shout out to Peter Rising | LinkedIn for delivering the blog title. We had a nice movie discussion, which movie is better: Terminator 1 and 2…. We also talked about the Matrix… Guess where the blog name came from.

This blog will be about an Idea I had to use proactive remediations to create a sort of LAPS (Local administrator password solution).

I have mentioned it a lot, you will need to make sure your end-users do not have local admin permissions by default. There are a lot of options how you could make sure they are never a local admin when their device is enrolled. Before we proceed I recommend reading this blog first:

You don’t want to have local administrators who are also global admin. But having no local admin on the device is not great at all. So making sure you always have a device admin with local admin permission is always a smart thing to do. When you need to troubleshoot the device or when you need to install some software manually you will need to have a user with local admin permissions.

I am going to divide this blog into  3 parts.

Part 1: In the first part I will show you how you could add a local admin to the device.

Part 2: I will show you how to deal with the device local admin password

Part 3: will show you some best practices

(don’t forget to read the third part, as it’s very very important!)

Part 1. Adding a local Administrator

In my opinion, the device administrator role is not what you want to use. Most of the time when a customer calls, he wants to be helped immediately. Waiting before the PRT (primary refresh token) is renewed could take up to 4 hours. So a better solution would be making sure there is always a dedicated local admin available.

You could do so by creating two CSP (I hoped to see it in the setting catalog… but unfortunately it’s not there…. Yet)

When configuring this CSP, on each device a local admin would be created with the same password. Please read This blog on how to deal with the remediation errors

And there comes the trouble. You really don’t want to have the same password on each device.

In one of my older blogs I showed you, PowerShell could be used in the first stage in the Hacking/Cyber Kill Chain: Reconnaissance.

When each device has the same local admin with the same password you are vulnerable to lateral movement. Lateral movement is the 5th stage in the Cyber Kill Chain.

With lateral movement, the attacker could impersonate a legitimate user (the local admin) and move through multiple systems in the network.

Part 2. Dealing with the local admin password

If you want to prevent lateral movement you will need to implement LAPS. LAPS will make sure the local admin passwords are being rotated each month/specified days. With LAPS each device has its own local admin with a unique password.

Implementing LAPS in a normal active directory is very easy, but implementing a LAPS solution in a cloud-only environment can be a pain. Tim Hermie created a great solution.

Serverless LAPS with Intune, Function App and Key Vault (

Some time ago I also created a LAPS solution.

The LAPS and the furious! – Call4Cloud Deploy Laps to intune right now!

With this solution, a third-party RMM tool was needed and when you are sticking to the Microsoft products only, this solution is not going to work for you.

After some projects dealing with proactive remediations, I was curious if I could create a local admin password solution with some proactive remediations. Changing the password when it’s 30 days old is no problem of course. But reporting back the password with proactive remediations was a little bit more difficult.

But after some late hours, I managed to get some good reporting. I have created 2 solutions.

  • *The first solution will store the password in the registry
  • *The second solution will store the password in a custom event log

But before I will show you the solutions you will need to add/remove some columns in the proactive remediation report.

Please note: You will need to open the Proactive Remediation itself and click on DeviceStatus otherwise these columns above are not possible to add

Here is an example how it looks

You will notice a column with some output:

Pre-remediation detection output:

This output will show you the output of the detection script when the password does not have to be changed. Of course, when the password is changed by the remediation script the detection script output will show you the new Password.

Please make sure you configure the remediation script to run in a 64 bits context.

The LocalAccounts Module (get-localuser) is not going to work in a 32-bits PowerShell on a 64-bit system

Option 1: Registry

Just like I did with my first LAPS project I am using the registry to store the password. If you make sure the end-user could not open Regedit or has no permissions to read the registry key you are safe.

Of course, you could upload the password to SharePoint/teams or azure key vault but I wanted to keep it a little bit more simple. Just one detection and one remediation script, nothing more. So I created proactive remediation that runs each hour, to be sure you will get the new up to date password when it’s changed)

Detection script:

$currentdate = Get-Date -Format g
$username = "admin"
$maxtimebetweenreset = "30"
$lastPasswordReset = Get-LocalUser -name $username | Select-Object -ExpandProperty PasswordLastSet | Out-String
$lastPasswordResetdate = Get-Date $lastPasswordReset -Format g
$timeSpan = New-TimeSpan -Start $lastPasswordResetdate -End $currentDate
if($timeSpan.Days -ge $maxtimebetweenreset)
    Write-Host "Password needs to be reset. Password is older than $maxtimebetweenreset days"
    Exit 1
    $regPath = "HKLM:\SOFTWARE\Microsoft\DCLAPS"
    $regVal = "lapsww"
    $regData = Get-ItemProperty $regPath -Name $regVal -ErrorAction Stop  
    $lapsww = $regdata.lapsww
    Write-Host "Password does not have to be changed. Current password: $lapsww" 
    Exit 0

Of course, the detection script can’t read the existing local admin password, because it wasn’t stored in the registry key yet. To make sure all the passwords were going to be changed, I changed the maxtimebetweenreset to “0”.

Remediation script

$currentdate = Get-Date -Format g
$username = "admin"

function Get-RandomCharacters($length, $characters) {
    $random = 1..$length | ForEach-Object { Get-Random -Maximum $characters.length }
    return [String]$characters[$random]

$password = Get-RandomCharacters -length 8 -characters  'abcdefghiklmnoprstuvwxyz'
$password += Get-RandomCharacters -length 2 -characters  'ABCDEFGHKLMNOPRSTUVWXYZ'
$password += Get-RandomCharacters -length 3 -characters '1234567890'
$password += Get-RandomCharacters -length 1 -characters '!$%&/()=?@#*+'

Try {
    	net user admin $password | out-null
	$registryPath = "HKLM:\SOFTWARE\Microsoft\DCLAPS"
	new-Item -Path $registryPath -force | out-null
	$name = "lapsww"
	$value = $password
	New-ItemProperty -Path $registryPath -Name $name -Value $value -Force | Out-Null
	$path = 'HKLM:\software\microsoft\DClaps'
	$acl = (Get-Item $path).GetAccessControl('Access')
	set-acl $path -AclObject $acl
	$acl = (Get-Item $path).GetAccessControl('Access')
	$acl.Access |where {$_.IdentityReference -eq 'BUILTIN\Users'} |%{$acl.RemoveAccessRule($_)}
	set-acl $path -AclObject $acl

	$regVal = "lapsww"
	$lapsww = $regdata.lapsww
	$regData = Get-ItemProperty $registryPath -Name $regVal -ErrorAction Stop  
    $lastPasswordReset = Get-LocalUser -name $username | Select-Object -ExpandProperty PasswordLastSet | Out-String
    $lastPasswordResetdate = Get-Date $lastPasswordReset -Format g
    $timeSpan = New-TimeSpan -Start $lastPasswordResetdate -End $currentDate
    if($timeSpan.Days -eq 0)
    Write-Output "Password has been reset to $lapsww"
    Exit 0
Write-Output $password
   Exit 1
Write-Warning "Value Missing"
Exit 1

The remediation script will be executed when the detection script will exit with the Statuscode: 1. It will change the “admin” user his password to a random password. After the password has been changed, the script will force the password to be stored in a registry key. To be sure no other users are able to read the registry keys I made sure I changed the ACL.

Please make sure you change the ‘BUILTIN\Users‘ part to fit the device its language. So for me (dutch), it would be ingebouwd\gebruikers.

After the remediation script is executed, the detection script will read the registry key and will show it in the output!

Option 2: The Event Log

I guess some people just don’t like the admin password to be stored in a registry key (of course…). Storing passwords is always a difficult thing, especially when it’s not encrypted. Luckily a normal user can’t read the event log.

So you might have guessed it with this solution, I will create a new event log with the new password in it when the password needs to be changed. I will also create a scheduled task to make sure the sensitive information is removed from the log file and the registry. More information later on!

Detection Script and Remediation Script

And now for the results:Open the LAPS event log and take a look!

Of course, you could choose to store the password in an existing event log. As an example, if you are storing the password in the System event log you could also retrieve the Password with the Collect Diagnostics feature.

If you want to have some more info about this feature please look at this blog.

Part 3: Best Practices

1.Speeding things up!

I decided to remove this part from this blog and create a separate blog for it. Why? because it deserves it 🙂

2.Implementing RBAC

When you need to make sure not everyone needs to have access to these passwords you could begin to implement RBAC.

In this blog I will show you how to do this:

3. Securing your Logs and Reports

Of course, we are totally not done! Because when using this LAPS, you will end up with some sensitive information in your logs. Please read this blog how you could make sure it’s removed properly!


This is the first version of this idea, I still need to deploy/test it with some more test tenants. I hope it showed you how you could use Proactive remediations for some reporting and LAPS. For now, you have got 2 options to choose from… hopefully I can add a completely new third option tomorrow.

Maybe in the near future, Microsoft will come up with their own solution but for now, go and deploy a LAPS solution to prevent lateral movement attacks!

(hopefully you would test out my idea and provide me some feedback on how to improve it)

2 thoughts on “The LAPS: Reloaded / Revolutions

  1. Great Idea!
    I suggest to store the passwords in a KeyVault instead of the returncodes.
    There’s already a (quite old, where the printscreens are outdated) tutorial in the web for that:
    That script could get updated to use it as detection / remediationscript.

    1. HI,

      If you have read the blog you will notice I also mentioned the blog from Tim Hermie 🙂 and to quote:

      “Of course, you could upload the password to SharePoint/teams or azure key vault but I wanted to keep it a little bit more simple. Just one detection and one remediation script, nothing more.”

Leave a Reply

Your email address will not be published. Required fields are marked *

9  +  1  =