Hi everyone,
I’m currently working with Netwrix Privilege Secure for Access Management and setting up integration with LAPS for local credential management.
I noticed that the official documentation still refers to the legacy LAPS download link:
However, in our environment we are using the modern version of Windows LAPS, which is natively integrated into Windows 11 and Windows Server 2022 and managed via Group Policy.
Does anyone know if integration with this modern version of LAPS is officially supported in Netwrix Privilege Secure ?
Specifically, I would like to understand:
Does the LAPS connector work with the new attributes introduced by modern Windows LAPS?
Is there anything different that needs to be configured compared to the legacy version?
Are there any best practices or known limitations?
Thanks in advance for any insights or experiences you can share!
Thanks for reaching out. We currently don’t natively support Windows LAPS but it is on the roadmap. Until then you can leverage the BYOV integration connector with custom pwsh code to access Windows LAPS accounts/passwords. I have scripts to do this in Azure but it is specific to Azure only or azure accounts with password writeback enabled. Also, outside of Windows LAPS you can utilize resource groups within NPS-AM that can automatically manage local administrator accounts. This would be used instead of LAPS. Are you just looking to have access to these accounts/passwords in NPS-AM? If so a BYOV connector and pwsh can checkout/checkin these accounts and accomplish this. Below is my checkout script for working with LAPS in azure.
param(
[Parameter(Mandatory = $true)]
$Options,
[Parameter(Mandatory = $true)]
$Credential
)
# Extract the Azure vault information
$azureTenantId = $Options.Connector.Options.APIUrl
$azureAppId = $Options.Connector.Options.AppId
$CertificateThumbprint = $Options.Connector.Options.ClientCertificate
$AZApp = $Options.Connector.Name
if ($null -ne $CertificateThumbprint) {
Add-SbPAMActionLog -Type Info -Message "Using certificate thumbprint: '$CertificateThumbprint'"
$azureCert = Get-ChildItem Cert:\LocalMachine\ -Recurse | Where-Object { $_.Thumbprint -eq $CertificateThumbprint } | Select-Object -First 1
if ($null -eq $azureCert) {
throw "Unable to find certificate '$CertificateThumbprint'"
}
}
$TargetHost = $Options.TargetHost
if ($null -eq $targetHost -or [string]::IsNullOrEmpty($targetHost.DnsHostName)) {
Throw "Unable to find host."
}
Add-SbPAMActionLog -Type Info -Message "Checking out LAPS password for $($credential.username) from $AZApp" -RestApiUri $Options.RestApiUri -RestApiToken $Options.RestApiToken | Out-Null
Add-SbPAMActionLog -Type Info -Message "Connecting to AZ with AppId '$azureAppID' TenantId '$azureTenantId'"
$graphConn = $null
try {
$graphConn = Connect-MgGraph -ClientId $azureAppId -TenantId $azureTenantId -Certificate $azureCert -NoWelcome -ErrorAction Stop
# Connecting to MS Graph
Write-Host "Connected to MS Graph using application '$azureAppID' in tenant '$azureTenantId'"
if ($null -ne $Options.ActivitySession) {
$Username = $Options.ActivitySession.LoginAccountName
$Hostname = $TargetHost.DnsHostName
}
#OR
#$hostname = $Whatever I need to pull the hostname from the AppOnlyAuthGraph secret vault.
# Get the Azure LAPS Password
Write-Host "Getting Azure LAPS password for $hostname"
# Get the LAPS password for the specified device
$passwordInfo = Get-LapsAADPassword -DeviceIds $hostname -IncludePasswords -AsPlainText -ErrorAction Stop
# Extract the password
$secret = $passwordInfo.Password
if($null -eq $secret) {
throw "Password for $hostname not found"
}
# Set the credential password
$Credential.Username = $Username
$credential.password = $secret
##Need alternative if I can't map to a credential???
Add-SbPAMActionLog -Type Info -Message "Checked out Azure LAPS password for $($Hostname) using $AZApp" -RestApiUri $Options.RestApiUri -RestApiToken $Options.RestApiToken | Out-Null
# Return the credential so the wrapper can save it
return $credential
}
catch {
Add-SbPAMActionLog -Type Error -Message "Error checking out LAPS password for $($Hostname) using $AZApp : $($_)" -RestApiUri $Options.RestApiUri -RestApiToken $Options.RestApiToken | Out-Null
return $null
}
finally {
if ($null -ne $graphConn) {
Add-SbPAMActionLog -Type Info -Message "Disconnect Microsoft Graph"
Disconnect-MgGraph | Out-Null
}
}
Thank you for sharing this Adam, in order to use this all the ActionServices would need to have that certificate installed, right? And is that a certificate that you created and uploaded? Or is that a certificate that is generated in Azure?
Just curious what the setup for this BYOV script would be.
Yes, like anything utilizing app-only access and the MS Graph powershell module, a valid certificate is needed for client – server authentication between NPS-AM Action Service servers and EntraID. The Base64 Public Key file is used by the Azure registered app to authenticate. Also, the Azure App Registration requires permission to use Microsoft.Graph and read device permissions and read device local credential passwords.
Thanks so much for the detailed responses and for sharing the script!
Just to clarify our environment: we are not using Azure , but rather a fully on-premises Active Directory setup on Domain Controllers. The modern version of Windows LAPS is already deployed and working in our infrastructure, managed via Group Policy.
Our goal is to integrate this modern Windows LAPS with Netwrix Privilege Secure (NPS-AM), so we can retrieve the local admin credentials managed by LAPS directly within NPS-AM.
If anyone has already implemented this integration or has tips I’d really appreciate any advice or best practices!
Hey Again Josephine. I had a feeling you needed to pull this directly from AD but wanted to get you something so you could get a feel for how the integrations work. I put this together for Windows LAPS in AD too. It works in my lab but that’s no guarantte so please test thoroughly if you do want to use this in a production environment. Hopefully this is closer to what you are looking for.
First, go to Integration Connectors and create a BYOV connector using the same setting here:
For the checkout script copy and past the following:
param(
[Parameter(Mandatory = $true)]
$Options,
[Parameter(Mandatory = $true)]
$Credential
)
# Extract the connector information
$connectorName = $Options.Connector.Name
# Get target host information
$TargetHost = $Options.TargetHost
if ($null -eq $TargetHost -or [string]::IsNullOrEmpty($TargetHost.DnsHostName)) {
Throw "Unable to find host."
}
$Hostname = $TargetHost.DnsHostName
# Get the ServiceAccount credential using CredentialId
$ServiceAccountCredentialId = $Options.TargetHost.CredentialId
if ($null -eq $ServiceAccountCredentialId -or [string]::IsNullOrEmpty($ServiceAccountCredentialId)) {
Add-SbPAMActionLog -Type Error -Message "ServiceAccount CredentialId not found in Options.TargetHost.CredentialId" -RestApiUri $Options.RestApiUri -RestApiToken $Options.RestApiToken | Out-Null
return $null
}
# Retrieve the ServiceAccount credential using the GUID
$ServiceAccountCredential = Get-SbPAMCredential -Id $ServiceAccountCredentialId -RestApiUri $Options.RestApiUri -RestApiToken $Options.RestApiToken
if ($null -eq $ServiceAccountCredential) {
Add-SbPAMActionLog -Type Error -Message "Failed to retrieve ServiceAccount credential with ID: $ServiceAccountCredentialId" -RestApiUri $Options.RestApiUri -RestApiToken $Options.RestApiToken | Out-Null
return $null
}
# Convert to PSCredential using manual method
$username = "$($ServiceAccountCredential.Domain)\$($ServiceAccountCredential.Username)"
$securePassword = ConvertTo-SecureString -String $ServiceAccountCredential.Password -AsPlainText -Force
$PSCredential = New-Object System.Management.Automation.PSCredential($username, $securePassword)
Add-SbPAMActionLog -Type Info -Message "Checking out Windows LAPS password for $Hostname from $connectorName using service account: $($PSCredential.UserName)" -RestApiUri $Options.RestApiUri -RestApiToken $Options.RestApiToken | Out-Null
try {
Add-SbPAMActionLog -Type Info -Message "Running LAPS query on domain controller " -RestApiUri $Options.RestApiUri -RestApiToken $Options.RestApiToken | Out-Null
# Dynamically discover domain controllers
try {
Add-SbPAMActionLog -Type Info -Message "Discovering domain controllers for $($ServiceAccountCredential.Domain)" -RestApiUri $Options.RestApiUri -RestApiToken $Options.RestApiToken | Out-Null
# Try to get domain controllers using DNS SRV queries
$domainControllers = @()
try {
$dnsResult = Resolve-DnsName -Name "_ldap._tcp.$($ServiceAccountCredential.Domain)" -Type SRV -ErrorAction Stop
foreach ($record in $dnsResult) {
if ($record.NameTarget) {
$domainControllers += $record.NameTarget
}
}
Add-SbPAMActionLog -Type Info -Message "Found domain controllers via DNS: $($domainControllers -join ', ')" -RestApiUri $Options.RestApiUri -RestApiToken $Options.RestApiToken | Out-Null
} catch {
Add-SbPAMActionLog -Type Error -Message "DNS SRV lookup failed: $($_.Exception.Message)" -RestApiUri $Options.RestApiUri -RestApiToken $Options.RestApiToken | Out-Null
throw "Unable to discover domain controllers for $($ServiceAccountCredential.Domain). DNS SRV lookup failed."
}
if ($domainControllers.Count -eq 0) {
throw "No domain controllers found for $($ServiceAccountCredential.Domain)"
}
}
catch {
Add-SbPAMActionLog -Type Error -Message "Domain controller discovery failed: $($_.Exception.Message)" -RestApiUri $Options.RestApiUri -RestApiToken $Options.RestApiToken | Out-Null
return $null
}
$lapsInfo = $null
$dcUsed = $null
foreach ($dc in $domainControllers) {
try {
Add-SbPAMActionLog -Type Info -Message "Trying LAPS query on domain controller: $dc" -RestApiUri $Options.RestApiUri -RestApiToken $Options.RestApiToken | Out-Null
$result = Invoke-Command -ComputerName $dc -Credential $PSCredential -ScriptBlock {
param($TargetComputer)
try {
Import-Module LAPS -ErrorAction SilentlyContinue
# Try FQDN first
$lapsResult = Get-LapsADPassword -Identity $TargetComputer -AsPlainText -ErrorAction Stop
return $lapsResult
}
catch {
# Try with computer name suffix
$computerName = $TargetComputer + "$"
$lapsResult = Get-LapsADPassword -Identity $computerName -AsPlainText -ErrorAction Stop
return $lapsResult
}
} -ArgumentList $Hostname
if ($null -ne $result -and $null -ne $result.Password) {
$lapsInfo = $result
$dcUsed = $dc
Add-SbPAMActionLog -Type Info -Message "LAPS password successfully retrieved from domain controller: $dc" -RestApiUri $Options.RestApiUri -RestApiToken $Options.RestApiToken | Out-Null
break
}
}
catch {
Add-SbPAMActionLog -Type Info -Message "Domain controller $dc failed: $($_.Exception.Message)" -RestApiUri $Options.RestApiUri -RestApiToken $Options.RestApiToken | Out-Null
}
}
# Extract the password
if ($null -ne $lapsInfo -and $null -ne $lapsInfo.Password) {
$secret = $lapsInfo.Password
# Set the credential with administrator username and LAPS password
$userName = if ($null -ne $Options.ActivitySession) { $Options.ActivitySession.LoginAccountName } else { $Credentials.Username }
if ($userName.Contains("\")) {
$domain, $userName = $userName -Split "\\"
}
$Credential.Domain = $domain
$Credential.Username = $UserName
$Credential.Password = $secret
# Log the expiration time if available
if ($null -ne $lapsInfo.ExpirationTimestamp) {
Add-SbPAMActionLog -Type Info -Message "LAPS password expires: $($lapsInfo.ExpirationTimestamp)" -RestApiUri $Options.RestApiUri -RestApiToken $Options.RestApiToken | Out-Null
}
Add-SbPAMActionLog -Type Info -Message "Successfully checked out Windows LAPS password for $Hostname using domain controller $dcUsed" -RestApiUri $Options.RestApiUri -RestApiToken $Options.RestApiToken | Out-Null
# Return the credential so PAM can save it
return $Credential
} else {
Add-SbPAMActionLog -Type Error -Message "All domain controllers failed to retrieve LAPS password for $Hostname" -RestApiUri $Options.RestApiUri -RestApiToken $Options.RestApiToken | Out-Null
return $null
}
}
catch {
Add-SbPAMActionLog -Type Error -Message "Error checking out Windows LAPS password for $Hostname - $($_.Exception.Message)" -RestApiUri $Options.RestApiUri -RestApiToken $Options.RestApiToken | Out-Null
return $null
}
Leave the checkin field blank.
Then create an Activity that uses the integration connector we just created and the settings here (If you have changed your local administrator account names replace the value to match in the Login Account Template field):
Finally, tie everything together via an Access Policy that is using a connection profile that allows for password viewing (alternatively you can require this only be used with the RDP files through the proxy service and not allow for the password to be viewed)
Created an Activity using the connector and applied the settings, including adjusting the Login Account Template to match our local administrator account name.
statusString,status,logMessage,lineNumber,timestamp,version,id
"Warn",2,"DisableUser script finished with errors, [REDACTED]: 8ae5f530-b9aa-436f-b8f3-ee167b6c7ffb.",18,"2025-07-02T09:48:00.690472Z","4.2.1632.0","18"
"Error",3,"Unable to find user to Disable.",17,"2025-07-02T09:48:00.662966Z","4.2.1632.0","17"
"Error",3,"Failed to checkout user from [REDACTED]: Failed to checkout user from [REDACTED].",16,"2025-07-02T09:47:59.779386Z",,"16"
"Error",3,"[[REDACTED].[REDACTED]] Connecting to remote server [REDACTED].[REDACTED] failed with the following error message : The WinRM client cannot process the request...",15,"2025-07-02T09:47:59.759057Z",,"15"
...
"Info",1,"Trying LAPS query on domain controller: [REDACTED].[REDACTED]",9,"2025-07-02T09:47:59.620116Z","4.2.1632.0","9"
"Info",1,"Checking out Windows LAPS password for [REDACTED].[REDACTED] from LAPS using service account: [REDACTED]\\[REDACTED]",3,"2025-07-02T09:47:59.311206Z","4.2.1632.0","3"
Let me know if you’d like me to share any specific configuration details or if you have suggestions on what to check next.
It looks to be a permissions issue. Do your windows resources use the same service account as Active Directory? You need to make sure that account has the following permissions:
Domain Controller Access Permissions:
Remote PowerShell Access: The service account must be a member of a group that has “Log on as a service” and “Access this computer from the network” rights on the DC
WinRM/PowerShell Remoting: Typically requires membership in the Remote Management Users group or Administrators group on the target DC
LAPS-Specific Permissions:
Read permissions on the LAPS password attribute in Active Directory
The account needs to be granted “All extended rights” or specifically ms-LAPS-Password attribute permission on the computer objects whose LAPS passwords you want to retrieve. Typically done via a group.
You can use this to set permissions for the account
Hi Josephine,
Sorry, we couldn’t get this to work! With how deep into the weeds it was getting, I had high hopes!
As Adam noted above, this feature is on the roadmap, though!. If you want to create an Idea in Privilege Secure Ideas, the product team will give updates as it gets rolled into NPS