NPSD/NPSAM better 2gether

Overview

If you have NPS-AM and NPS-D monitoring your organization, you will find that using Protect Mode in NPS-D will start to remove your local administrator accounts you are managing with NPS-AM. This article talks about a couple of strategies that you can use to help.

Use AD Group

For NPS-D you can add a specific AD Group to the resources with standing privilege. This approach has the advantage that it is something you can use bulk actions in NPS-D to add that Group to your computers. NPS-AM can manage the group membership for this group using Activity Sessions and you don’t have competition.

The downside is that the group membership is less focused, you end up giving your users temporary access to ALL the machines that allow that group. You can mitigate it by using multiple AD Groups for different security tiers. The short lifespan of an Activity Token user and the fact that the requesting user doesn’t have the password can also prevent the user from moving laterally.

Even using a Managed Account for this has the same effect if you limit the user’s ability to view the password. They would need to create an NPS AM session for every resource they want direct access to, and then use the UI to download the RDP file to access the resource.

Use a Custom PowerShell Step

This approach allows you to dynamically grant access to the resource using NPS-AM which in turn calls the NPS-D API to grant local admin rights for the user. This approach allows you to monitor the access from both products, and ensures that NPS-D is the source of truth for local administrator access for your endpoints.

The other advantage to this approach is that if you have workstations that don’t have PowerShell access, you can still grant your user Local Admin rights using NPS-D via MSRPC or leverage your EDR/XDR solution.

The downside to this, is you are using a custom PowerShell step to accomplish this and you have to create an API account.

Setting up NPS-D API account

Create an API key for an Administrator account following the instructions https://helpcenter.netwrix.com/bundle/PrivilegeSecureForDiscovery_2.22/page/Content/PrivilegeSecure/Discovery/Integrations/API/APIKeyManagement.html

Creating Custom PowerShell for NPS-AM

In the activity that grants your user local admin rights in NPS-AM, add a new Custom PowerShell step. Delete the boiler plate (CTRL-A + DELETE). Insert the following code:

# NPS-D 
# Update with values from your NPSD
$AppUserId = "XXX" # TODO
$AppApiKey = "XXX" # TODO

# URL to NPS-D
# Update with your NPSD Server
$BaseUrl = "https://npsd-host.example.com" # TODO

# This is from the NPS-AM Session
if (![string]::IsNullOrEmpty($UserId)) {
    $targetUser = Get-SbPAMUser -Id $UserId
    if ($null -ne $targetUser) { $JitaUser = $targetUser.sAMAccountName }
    if ([string]::IsNullOrEmpty($JitaUser)) {
        Write-Error "Unable to find user."
        exit 1
    }
    Write-Host (ConvertTo-Json $targetUser)
}

if (![string]::IsNullOrEmpty($HostId)) {
    $targetHost = Get-SbPAMHost -Id $HostId
    if ($null -eq $targetHost -or [string]::IsNullOrEmpty($targetHost.DnsHostName)) {
        Write-Error "Unable to find host."
        exit 2
    }
    $dnsHostName = $targetHost.DnsHostName
}

# Login using API Key
$response = Invoke-RestMethod -Method POST -Uri "$($BaseUrl)/api/v1/api-keys/auth" -Body "token=$AppApiKey&userId=$AppUserId"  -ContentType "application/x-www-form-urlencoded" -SkipCertificateCheck
Add-SbPAMActionLog -Type Info -Message "Login with API Key: $($response.Message)"

$Headers = @{
    "Authorization" = "Bearer $($response.Token)"
}
Add-SbPAMActionLog -Type Info -Message "Starting JITA Session for $JitaUser on $dnsHostName"

# Find the system
$url = "$($BaseUrl)/api/v1/computers?advanced&dNSHostName=~$($dnsHostName)&limit=15&scoreBy=cn&sort=matchScore%2Ccn&select=domain_netbios%2Ccn%2Cos_type%2Clast_ip%2CdNSHostName"
$system = Invoke-RestMethod -Method GET -Uri $url -Headers $Headers -SkipCertificateCheck
Add-SbPAMActionLog -Type Info -Message "System: $($system.id) CN: $($system.cn) DNSHostName: $($system.dNSHostName) OS: $($system.os_type) IP: $($system.last_ip)"

# Get the NPS-D User info from flattened Admins
$queryValue = [uri]::EscapeDataString($JitaUser.Split("\")[1])
$url = "$($BaseUrl)/api/v1/computers/$($system.id)/flattened-accounts?accountTypes=user&sAMAccountName=$queryValue&userId"
$foundUser = Invoke-RestMethod -Method GET -Uri $url -Headers $Headers -SkipCertificateCheck
$foundUser = $foundUser | Where-Object { $_.sAMAccountName -eq $JitaUser.Split("\")[1]  -and $_.domain_netbios -eq $JitaUser.Split("\")[0] }
Add-SbPAMActionLog -Type Info -Message "User: $($foundUser.id) $($foundUser.sAMAccountName) SID: $($foundUser.objectSid)"

$JitaUserId = $foundUser._id
if ($null -eq $foundUser._id) {
    Add-SbPAMActionLog -Type Info -Message "Adding User $JitaUser to admins on $dnsHostName"
    $queryValue = [uri]::EscapeDataString($JitaUser)
    $url = "$($BaseUrl)/api/v1/users?advanced=true&limit=5&sAMAccountName=~$($queryValue)&scoreBy=sAMAccountName&select=domain_netbios,sAMAccountName,objectSid&sort=matchScore,sAMAccountName"
    $foundUser = Invoke-RestMethod -Method GET -Uri $url -Headers $Headers -SkipCertificateCheck
    if ($null -ne $foundUser) {
        $JitaUserId = $foundUser.id
        $url = "$($BaseUrl)/api/v1/computers/$($system.id)/admins"
        $body = @{ id = $foundUser.Id; persistent = $false } | ConvertTo-Json
        $response = Invoke-RestMethod -Method POST -Uri $url -Headers $Headers -Body $body -SkipCertificateCheck
            
    }
    else {
        Add-SbPAMActionLog -Type Warn -Message "User $JitaUser not found - Unable to start JITA Session"
        return
    }
}
else {
    Add-SbPAMActionLog -Type Info -Message "User $JitaUser is already an admin: $($JitaUserId)"
}

# Start JITA Session
$url = "$($BaseUrl)/api/v1/computers/$($system.id)/access"
$body = @{  t = 15; userId = $($foundUser._id) } | ConvertTo-Json
$response = Invoke-RestMethod -Method POST -Uri $url -Headers $Headers -SkipCertificateCheck -Body $body
Add-SbPAMActionLog -Type Info -Message "JITA Session Response: $($response.Message)"

Make sure to update the Variables with TODO labels

$AppUserId - the UserId associated with your API Key

$AppApiKey - The NPS-D ApiKey

$BaseUrl - The URL for your NPS-D server https://host.example.com (NO trailing slash!)

Example Activity

The Start JITA Session is my custom step. I put that before the Add to Administrators step to ensure that NPS-D doesn’t remove my user from the Local Administrators. I didn’t add a Stop JITA because NPS-AM will remove the user from the Local Administrators group at the end of the session.

Logs from Session

Line Number Date Log Level Message
1 5/22/2025 1:44:58 PM Info Create user started, SessionId: b734edd7-7e63-40fb-bc35-6698d8484c97.
2 5/22/2025 1:44:59 PM Info Create/Enable Windows user.
3 5/22/2025 1:44:59 PM Info Find or Create Domain user CN=kevinh-NPS,OU=SbPAM Users,DC=example,DC=com, SessionId: b734edd7-7e63-40fb-bc35-6698d8484c97.
4 5/22/2025 1:44:59 PM Info Creating/Enabling domain user EXAMPLE\kevinh-NPS DC: pamdc001.example.com
5 5/22/2025 1:44:59 PM Info Set-SbPAMDomainUserStatus: UserName: kevinh-NPS DomainController: pamdc001.example.com DomainServiceAccount: s1admin Create: True Enable: True
6 5/22/2025 1:44:59 PM Info Setting password for domain user EXAMPLE\kevinh-NPS
7 5/22/2025 1:44:59 PM Info Updated password for AD User: ‘CN=kevinh-NPS,OU=SbPAM Users,DC=example,DC=com’ using DC: ‘pamdc001.example.com’ SvcAccount: ‘s1admin’
8 5/22/2025 1:44:59 PM Info Create user finished, SessionId: b734edd7-7e63-40fb-bc35-6698d8484c97.
9 5/22/2025 1:45:00 PM Info Login with API Key: Access granted.
10 5/22/2025 1:45:00 PM Info Starting JITA Session for EXAMPLE\kevinh-NPS on nps-app004.example.com
11 5/22/2025 1:45:02 PM Info System: 6407a4abd907a4834dbb27aa CN: nps-app004 DNSHostName: nps-app004.example.com OS: windows IP: 10.0.0.11
12 5/22/2025 1:45:02 PM Info User: kevinh-NPS SID: S-1-5-21-1876278665-3860928811-4030506457-476933
13 5/22/2025 1:45:02 PM Info User EXAMPLE\kevinh-NPS is already an admin: 657218809d95e9e073340e79
14 5/22/2025 1:45:02 PM Info JITA Session Response: Session requested.
15 5/22/2025 1:45:03 PM Info Add-SbPAMLocalGroupUser script started, SessionId: b734edd7-7e63-40fb-bc35-6698d8484c97.
16 5/22/2025 1:45:03 PM Info Performing Add-SbPAMLocalGroupUser script for EXAMPLE\kevinh-NPS on nps-app004.example.com, LeaveInGroup: False, SessionId: b734edd7-7e63-40fb-bc35-6698d8484c97.
17 5/22/2025 1:45:03 PM Info Found 0 references for user EXAMPLE\kevinh-NPS in group Administrators on host nps-app004.example.com.
18 5/22/2025 1:45:03 PM Info Found 1 activity sessions for user EXAMPLE\kevinh-NPS.
19 5/22/2025 1:45:03 PM Info Found 1 activity sessions for user EXAMPLE\kevinh-NPS on host nps-app004.example.com.
20 5/22/2025 1:45:04 PM Info Adding user: EXAMPLE\kevinh-NPS to Administrators, SessionId: b734edd7-7e63-40fb-bc35-6698d8484c97.
21 5/22/2025 1:45:11 PM Info Added user: EXAMPLE\kevinh-NPS to Administrators, SessionId: b734edd7-7e63-40fb-bc35-6698d8484c97.
22 5/22/2025 1:45:11 PM Info EXAMPLE\kevinh-NPS will NOT be left in group: Administrators on nps-app004.example.com at end of session
23 5/22/2025 1:45:12 PM Info Add-SbPAMLocalGroupUser script completed for EXAMPLE\kevinh-NPS on nps-app004.example.com, SessionId: b734edd7-7e63-40fb-bc35-6698d8484c97.
24 5/22/2025 2:10:15 PM Info Remove-SbPAMLocalGroupUser script started, SessionId: b734edd7-7e63-40fb-bc35-6698d8484c97.
25 5/22/2025 2:10:15 PM Info Performing Remove-SbPAMLocalGroupUserDemote script for EXAMPLE\kevinh-NPS on nps-app004.example.com, SessionId: b734edd7-7e63-40fb-bc35-6698d8484c97.
26 5/22/2025 2:10:15 PM Info Found 1 references for user EXAMPLE\kevinh-NPS in group Administrators on host nps-app004.example.com.
27 5/22/2025 2:10:15 PM Info Found 1 activity sessions for user EXAMPLE\kevinh-NPS.
28 5/22/2025 2:10:15 PM Info Found 1 activity sessions for user EXAMPLE\kevinh-NPS on host nps-app004.example.com.
29 5/22/2025 2:10:16 PM Info Removing user: EXAMPLE\kevinh-NPS from Administrators, SessionId: b734edd7-7e63-40fb-bc35-6698d8484c97.
30 5/22/2025 2:10:23 PM Info Removed user: EXAMPLE\kevinh-NPS from Administrators, SessionId: b734edd7-7e63-40fb-bc35-6698d8484c97.
31 5/22/2025 2:10:23 PM Info Remove-SbPAMLocalGroupUser script completed for EXAMPLE\kevinh-NPS on nps-app004.example.com, SessionId: b734edd7-7e63-40fb-bc35-6698d8484c97.
32 5/22/2025 2:10:24 PM Info No Builtin Account on Platform: Active Directory.
33 5/22/2025 2:10:25 PM Info Account: kevinh-NPS in use in 1 sessions.
34 5/22/2025 2:10:26 PM Info Disable Domain user EXAMPLE\kevinh-NPS, SessionId: b734edd7-7e63-40fb-bc35-6698d8484c97.
35 5/22/2025 2:10:26 PM Info Set-SbPAMDomainUserStatus: UserName: kevinh-NPS DomainController: pamdc001.example.com DomainServiceAccount: s1admin Create: False Enable: False
36 5/22/2025 2:10:26 PM Info Disabled managed account: EXAMPLE\kevinh-NPS, SessionId: b734edd7-7e63-40fb-bc35-6698d8484c97.
37 5/22/2025 2:10:26 PM Info DisableUser: Rotating password.
38 5/22/2025 2:10:27 PM Info Getting new password for credential
39 5/22/2025 2:10:27 PM Info Setting password for kevinh-NPS
40 5/22/2025 2:10:27 PM Info Setting password for domain user EXAMPLE\kevinh-NPS using DC: pamdc001.example.com
41 5/22/2025 2:10:27 PM Info Updated password for AD User: ‘CN=kevinh-NPS,OU=SbPAM Users,DC=example,DC=com’ using DC: ‘pamdc001.example.com’ SvcAccount: ‘s1admin’
42 5/22/2025 2:10:27 PM Info Password set for domain user EXAMPLE\kevinh-NPS on try 1 of 10
43 5/22/2025 2:10:28 PM Info Updated password for Active Directory User: ‘EXAMPLE\kevinh-NPS’ Domain: ‘example.com
44 5/22/2025 2:10:28 PM Info Updated password for Active Directory User: ‘kevinh-NPS’ Host: ‘nps-app004.example.com
45 5/22/2025 2:10:28 PM Info DisableUser completed, SessionId: b734edd7-7e63-40fb-bc35-6698d8484c97.
46 5/22/2025 2:10:29 PM Info ActivityCheckin script started.
47 5/22/2025 2:10:29 PM Info Found 1 domain activity sessions for user EXAMPLE\kevinh-NPS.
48 5/22/2025 2:10:29 PM Info Found 1 activity sessions for user EXAMPLE\kevinh-NPS on host example\nps-app004.
49 5/22/2025 2:10:29 PM Info ActivityCheckin script complete.
5 Likes