What Problem Does This Solve?
Creating Resource Groups based on LDAP Queries or other external information is a topic that comes up on occasion. There isn’t a way to this natively within Privilege Secure, but we can manage Groups with the API and consult the external source.
Kudos to @kevin.horvatin for this approach!
Installing Privilege Secure’s PowerShell Module
First, we need to install Privilege Secure’s PowerShell module if it’s not already. We can do so by navigating to the Extras folder that’s included with each Privilege Secure download and running SbPAMPowershellModules.msi
as an administrator.
The PowerShell module needs to be installed on the computer where the PowerShell script will be run. This can be the Privilege Secure server itself, or any computer that can access Privilege Secure via a web browser.
The PowerShell Script
The following is going to consult a CSV file, for resources that are already on-boarded. The match is performed on the DnsHostName
attribute.
The ResourceGroup
column of the CSV is used to assign the existing resource to a group.
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[string]$NPSUri,
[Parameter(Mandatory=$true)]
[PSCredential]$userCred,
[Parameter(Mandatory=$true)]
[string]$userCode,
[Parameter(Mandatory=$true)]
[string]$CsvFile
)
### Map the computers to the resource group found in the CSV
### Expected CSV Format
### dnsHostName,ResourceGroup
if (-not (Test-Path $CsvFile)) {
Write-Error "Could not find $CsvFile"
return
}
$ComputerAttrs = Import-Csv -Path $CsvFile
if ($null -eq $ComputerAttrs) {
Write-Error "No computer attributes found in $CsvFile"
return
}
Import-Module SbPAMAPI -Force -ErrorAction Stop
# create the web session
$WebSession = New-Object Microsoft.PowerShell.Commands.WebRequestSession
# grab the user token
$global:UserToken = Get-SbPAMToken -Credential $userCred -Uri $NPSUri -WebSession $WebSession -SkipCertificateCheck -ErrorAction Stop
$global:UserToken = Get-SbPAMMfaToken -Uri $NPSUri -Token $global:UserToken -Code $userCode -WebSession $WebSession -SkipCertificateCheck -ErrorAction Stop
## Renew Token
function Get-RenewToken
{
[CmdletBinding()]
param (
[string]
$UserToken,
[string]
$Uri
)
$mfaObj = Convert-SbPAMToken $userToken
$expiration = Get-Date -UnixTimeSeconds $mfaObj.exp
if ($expiration -lt (Get-Date).AddMinutes(7)) {
Write-Host "$(Get-Date) Refreshing token"
$userToken = Invoke-SbPAMRest -Uri "$Uri/api/v1/UserToken" -Token $userToken -ErrorAction Stop -SkipCertificateCheck
}
return $UserToken
}
function Add-ResourceToGroup
{
param(
[string]
$Uri,
[string]
$Token,
[string]
$ResourceId,
[string]
$ResourceGroupId
)
# POST /api/v1/ManagedResourceGroup/21fcdfd9-d15a-4ff8-9bec-a6ac7acf7e19/AddResources
# ["20d0039a-a471-4133-8736-5b722fa4cc83"]
$apiUrl = "$Uri/api/v1/ManagedResourceGroup/$ResourceGroupId/AddResources"
$body = (ConvertTo-Json @( $ResourceId ))
Invoke-SbPAMRest -Uri $apiUrl -Token $Token -Body $body -Method POST -ErrorAction Stop -SkipCertificateCheck
}
## Get all Group Members
function Get-AllResourceGroupMembers {
param (
$Uri,
$ResourceGroupId
)
# Get /api/v1/ManagedResource/InGroup/ad073f32-d909-408e-9c48-af58f6b88de2?skip=0&take=30&refresh=true&showAll=false
$skip = 0
$take = 10000
$MRCache = @{};
do {
$global:UserToken = Get-RenewToken -UserToken $global:UserToken -Uri $NPSUri
$result = Invoke-SbPAMRest -Uri "$Uri/api/v1/ManagedResource/InGroup/$ResourceGroupId?skip=$skip&take=$take" -Token $global:UserToken -ErrorAction Stop -SkipCertificateCheck
# Found an existing record
$result.Data | ForEach-Object {
if ($null -ne $_.dnsHostName -and (-not $MRCache.ContainsKey($_.dnsHostName))) {
$MRCache.Add($_.dnsHostName,$_.Id)
}
}
$skip += $take
}
while ($result.Data.Count -eq $take)
return $MRCache;
}
## Get all Managed Resources
function Get-AllManagedResources
{
param(
[string]
$Uri
)
$skip = 0
$take = 10000
$MRCache = @{};
do {
$global:UserToken = Get-RenewToken -UserToken $global:UserToken -Uri $NPSUri
$result = Invoke-SbPAMRest -Uri "$Uri/api/v1/ManagedResource/Search?skip=$skip&take=$take" -Token $global:UserToken -ErrorAction Stop -SkipCertificateCheck
# Found an existing record
$result.Data | ForEach-Object {
if ($null -ne $_.dnsHostName -and (-not $MRCache.ContainsKey($_.dnsHostName))) {
$MRCache.Add($_.dnsHostName,$_.Id)
}
}
$skip += $take
}
while ($result.Data.Count -eq $take)
return $MRCache;
}
function Add-ResourceGroup
{
param(
[string]
$Uri,
[string]
$Token,
[string]
$ResourceGroupId,
[string]
$ResourceGroupName,
[string]
$Description
)
$apiUrl = "$Uri/api/v1/ManagedResourceGroup"
$ResourceGroup = @{
Name = $ResourceGroupName
Type = 0
manageAccounts = 1
}
$body = ConvertTo-Json $ResourceGroup
$result = Invoke-SbPAMRest -Uri $apiUrl -Token $Token -Body $body -Method POST -ErrorAction Stop -SkipCertificateCheck
return $result
}
function Get-AllResourceGroups
{
param(
[string]
$Uri
)
$ResourceGroups = @{}
$apiUrl = "$Uri/api/v1/ManagedResourceGroup/Names"
$groups = Invoke-SbPAMRest -Uri $apiUrl -Token $global:UserToken -ErrorAction Stop -SkipCertificateCheck
foreach ($item in $groups.Data)
{
$ResourceGroups[$item.name] = $item.id
}
return $ResourceGroups
}
$ResourceGroups = Get-AllResourceGroups -Uri $NPSUri
if ($null -eq $ResourceGroups) {
Write-Error "Could not find any Resource Groups"
return
}
$ManagedReources = Get-AllManagedResources -Uri $NPSUri
if ($null -eq $ManagedReources) {
Write-Error "Could not find any Managed Resources"
return
}
$ComputerAttrs | ForEach-Object {
$currentComputer = $_
if ($null -eq $currentComputer.dnsHostName) {
Write-Host "Skipping empty line"
return
}
if ($null -eq $currentComputer.ResourceGroup) {
Write-Host "Skipping $($currentComputer.dnsHostName)"
return
}
## Lookup Managed Resource - if it exists in NPS then add it
## to the Resource Group
if ($ManagedReources.ContainsKey($currentComputer.dnsHostName)) {
$resourceId = $ManagedReources[$currentComputer.dnsHostName]
$resourceGroup = $currentComputer.ResourceGroup
Write-Host "Assigning $resourceId to $resourceGroup"
$global:UserToken = Get-RenewToken -UserToken $global:UserToken -Uri $NPSUri
$resourceGroupId = $ResourceGroups[$resourceGroup]
## Lookup Resource Group
## If it does not exist then create it
if ($null -eq $resourceGroupId) {
Write-Host "Creating Resource Group $resourceGroup"
$ResourceGroupObj = Add-ResourceGroup -Uri $NPSUri -Token $global:UserToken -ResourceGroupName $resourceGroup
$ResourceGroups[$resourceGroup] = $ResourceGroupObj.Id
$resourceGroupId = $ResourceGroupObj.Id
}
## Lookup Resource Members
## If it we don't have them then get them
if ($null -eq $ResourceMembers[$resourceGroupId])
{
$ResourceMembers[$resourceGroupId] = Get-AllResourceGroupMembers -Uri $NPSUri -ResourceGroupId $resourceGroupId
}
## Check if the resource is in the group
## If not then add it
if ($null -eq $ResourceMembers[$resourceGroupId][$resourceId]) {
Write-Host "Adding $resourceId to $resourceGroup"
Add-ResourceToGroup -Uri $NPSUri -Token $global:UserToken -ResourceId $resourceId -ResourceGroupId $resourceGroupId
}
}
else {
## Managed Resource does not exist - report it
Write-Host "Could not find Managed Resource for $($currentComputer.dnsHostName)"
}
}