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 serverhttps://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. |