[Howto] Using the PowerShell Samples for Centrify Infrastructure Service - OU to Set Example

[Howto] Using the PowerShell Samples for Centrify Infrastructure Service - OU to Set Example

By Centrify Guru I 2 weeks ago - last edited 2 weeks ago


The Centrify Developers website (https://developer.centrify.com) provides resources for developers to accelerate their productivity.  A very popular asset that builds on the Centrify Identity Platform's APIs is the Centrify PowerShell samples in GitHub (https://github.com/centrify/centrify-samples-powershell).  In this article, we walk you through an example and discuss the steps we took to get the information needed to accomplish this goal.


What you need

To follow along with this post you'll need:

  • A Centrify Infrastructure Services SaaS or On-Premises instance.
  • A User with System Administrator rights.
  • Basic SQL knowledge (e.g. to make basic queries like 'select ID from server where fqdn='system.example.com').
  • Active Directory knowledge (e.g. ActiveDirectory PowerShell module).

What we need to accomplish

Given an Active Director OU with computer objects, have the script populate a static set in Centrify infrastructure service.



  • Active Directory OUs are a very popular way to organize computer objects in the directory.
  • Infrastructure Service static sets unlike dynamic sets (that provide only organization), allow for the assignment of permissions to the members of the set.
    When the static set capability is combined with automation or with the Privilege Service User entitlement, this eases a lot of the organization and administrative challenges.

Dissecting the Requirements and Constraints

  • This script is for interactive use (although a different or enhanced version can be used for automation).
  • Require identity assurance (via MFA) to run the script.
  • Provide error handling for user input error:
    • Service address (URL)
    • Organizational Unit (OU).  Some OUs are non-existent or do not contain computer objects.
    • Infrastructure Service Sets - may be non-existent or of the wrong type (e.g. Dynamic).
  • Infrastructure Service database case sensitivity.
  • Only domain-joined systems can be used to query Active Directory (without additional authentication)
    Will make this a requirement, rather than adding this logic, otherwise use this one-liner:
    (Get-WmiObject -Class Win32_ComputerSystem).PartOfDomain

General Challenges

  • Cognitive - not being a programmer, generally unfamiliar with syntax.  Most importantly, being very unfamiliar with REST APIs and JSON formatting.


Script Building Blocks

  1. Prompting for Information and Data Quality.
  2. Authenticating to Centrify Infrastructure Service and using APIs.
  3. Reading computers from Active Directory OUs.
    To keep things brief, you can learn all we need here:  https://www.powershelladmin.com/wiki/Getting_computer_names_from_AD_using_Powershell
  4. Updating servers.

Prompting for Information and Data Quality

We will be using the Read-Host commandlet to gather information from the user, however, you can quickly think about many possibilities.  Ultimately, we can settle for something like:

  • Prompt the user
  • Validate the information
  • Continue to prompt the user until the information is correct.

We will revisit data quality topics as we continue the analysis.


Authenticating to Centrify Infrastructure Service

The developer website devotes several resources to this topic here:  https://developer.centrify.com/docs/starting-the-authentication-process however, there are two things that I've struggled with:  the REST API concepts and JSON notation. Fortunately that's where my browser searches were useful.  I can't pretend that I understand everything in the developer site, but with an implementation probably I'd get better at it.


Armed with the knowledge, I started inpecting the PowerShell samples.


Import-Module C:\Downloads\Samples\module\Centrify.Samples.PowerShell.psm1

The first thing I noticed was the warning.  This is because the module is unsigned.  This means that my script needs to have the 'execution policy' relaxed before using it.


Once I exposed the module in PowerShell ISE, a commandlet immediately caught my attention:


The Centrify-InteractiveLogin-GetToken looks like a good candidate for this script. 

I noticed that if I ran it without any parameters, it would prompt me for a username, but it would try cloud.centrify.com.  The -endpoint parameter specifies the URL of the service in question. 

Here's the output when you test it correctly:

Centrify-InteractiveLogin-GetToken -endpoint https://example.my.centrify.com -username admin@tenant.suffix 
Mechanism 0 => Email... @example.com
Mechanism 1 => SMS... XXX-0734
Mechanism 2 => Security Question
Choose mechanism: 1
Mechanism 0 => Password

Name                           Value                                                                                                                                                          
----                           -----                                                                                                                                                          
BearerToken                TRUNCATEDVERYLONGSTRING
Endpoint                   https://example.my.centrify.com                    

Notice that I was prompted for MFA, and then for the password.  This is consistent with the policy settings of that service address that will prompt for MFA, then for the password:


The commandlet returns an object with 2 attributes:

A 'BearerToken' or  string that contains authorization information that can be used in subsequent requests.

The 'endpoint' or service address (URL) for the token.

Input quality #1 - need to make sure that we "ping" the service address (or endpoint) supplied by the user.


After seeing this implementation of authentication against Infrastructure Service, I re-read the "Authentication Quick Start" and understood the process much better.  The Centrify-InteractiveLogin-GetToken abstracts many of the elements of this API and make it easy to use.


I also noticed another commandlet called Centrify-InvokeREST that looked very familiar to the "Invoke-RestMethod" commandlet.  This one takes endpoint and token (at this point these are a must have), but also takes

  • method:  This is the API function to be used
  • objectContent:  This is the object that is being sent.

Looks like this will be quite useful.


Querying Information from Centrify Infrastructure Service

My next stop in the Developer's website was the 'Using Queries' section:  https://developer.centrify.com/docs/use-queries getting-started topic since I figured I need to be able to obtain information about the systems that I needed to update. 

The site pointed me to this method "/redrock/query"  that takes two parameters in JSON format:  script (the SQL query) and args (parameters like page size, etc) ;  to keep things simple, we'll only be using the script argument.  Here's the format from the example:

{"Script":"Select ID, Username from User ORDER BY Username COLLATE NOCASE"}

I learned that you can create an object in PowerShell called a hashtable to store key/value pairs (which translate very well into JSON). 


Here are the building-blocks for this method

  • Need to know the query I need - in my case I am querying systems.
  • Need to know the data structures (data dictionary) of the information I'm looking for
    The easiest way to build SQL queries is to use the Core Services > Reports. 
  • Need to find out how to create a hashtable in PowerShell
    Looks like this query will bring back the unique identifier (ID) for the systems (server table).

Two problems solved.  For the Hashtable, I found these references:

Let's now try to get the same results as the query above using the /redrock/query API.

$endpoint = 'https://example.my.centrify.com'
$user = 'user@example.com'
$token = Centrify-InteractiveLogin-GetToken -endpoint $endpoint -username $user

$api = '/redrock/query'

$obj = @{}
$obj.script = "select ID from server"

$query = Centrify-InvokeREST -endpoint $endpoint -token $token  -method $api -objectContent $obj

The contents of the query object don't reveal the result.  You have to go into the object JSON response to expose the rows with the results:

PS C:\> $query
success         : True
Result          : @{IsAggregate=False; Count=4; Columns=System.Object[]; FullCount=4; Results=System.Object[]; ReturnID=}
Message         :
MessageID       :
Exception       :
ErrorID         :
ErrorCode       :
InnerExceptions :

PS C:\> $query.Result.Results.Row.ID 257b977d-9dfd-4498-bd92-8ed8ca949a82 28b58c16-1c3d-42a2-98f7-e218b88bb58d 5d85c7c2-2cbe-4494-8b5d-568fe3a9fb2a a02937f4-de5b-4c2b-805a-a61f90b661e0

/redrock/query is a very good API to learn the data structures in Centrify Infrastructure Service.  With my new found knowledge, I started testing many of the "Resource Management" APIs:  https://developer.centrify.com/v1.2/reference


For example, here's how to add a UNIX system called dummy:

$sys =@{}
$sys.Name = "dummy"
$sys.FQDN = "dummy.example.com" 
$sys.ComputerClass = 'Unix' 
$sys.SessionType = "Ssh" 

$srvadd = Centrify-InvokeREST -endpoint $endpoint -token $token  -method '/ServerManage/AddResource' -objectContent $sys

The response is:

PS C:\> $srvadd
success         : True
Result          : 352d883d-fdb3-4ee1-ac0b-bf87006e7114

There are other (empty) attributes sent, but in this case we have an indication of success and the ID of the newly-created system.



Now we have a methodology:


  1. Determine what we need to do
  2. Examine the developer website for resource management:  https://developer.centrify.com/v1.2/reference#resource-management
  3. Examine the JSON payload and return output.
  4. Authenticate and get a token
  5. Use the Centrify-InvokeRest with the corresponding API and payload (as hashtable)
  6. Monitor the results (or apply logic)



We have determined that we need to update a resource to be added to a set.

Problem:  When reviewing the update resource (link) we realized that there is no method to update a system with set membership. 


Using the GUI as a detective tool

Where to go next?   This takes us to the Google Chrome Developer Tools.  We can use those tools in conjunctionw with the graphical interface to determine the API calls behind a GUI action.


In my case, I added a system to a set manually and discovered the following:

There is another API called /collections that contains:

  • /collections/UpdateMembersCollections:  takes the set id (id), actions (add), plus the payload it takes the set's unique ID of the member (key), system type (server), and the type of addition (row).
    I tried to look for a table or view called "Collections" in Core Services > Reports and was unable to find one.
  • /collections/GetObjectCollectionsAndFilters" that can be used to obtain the set ID.
    The first step is to get all sets:
    $obj = @{}
    $obj.ObjectType= $setType
    $obj.Name= $setName
    $obj.NoBuiltins= 'true'

    $coll = Centrify-InvokeREST -endpoint $endpoint -token $token -method "/Collection/GetObjectCollectionsAndFilters" -objectContent $obj -Verbose $true
    $collresults = $coll.Result.Results.Row.Count
    Then we need to compare until we find the matching set:
    If ($collresults -gt 1) {      
     # uses the where clause if multiple results
     $collid = $coll.Result.Results.Row.Where({$PSItem.Name -eq $obj.Name}).ID
     }  Else {
               $collid = $coll.Result.Results.Row.ID

The main directives

Most of the action will happen inside a foreach loop.  The key here is to iterate through a list of AD computer object FQDNs, check if they exist in Centrify Infrastructure Service and add them to the target set specified by the user.

Because it's possible the system was added with an IP address, the routine has expansion capabilities.


The GetServerbyFqdn function uses the /redrock/query API to search the converted to uppercase FQDNs against the Server table.

foreach ($computer in $computers)
  # cleanup values
  $sysid = $null
  $obj = $null
  $setAdd = $null

  # determine if system is in CPS
  Write-Host  'Determining if' $computer 'is in Privilege Service...'
  $sysid = (Centrify-GetServerIdByFqdn -endpoint $endpoint -fqdn $computer -token $token -ErrorAction SilentlyContinue)

  # if there are results, process
  If ($sysid -ne $null) {
    Write-Host $computer  $sysid 'found in Centrify Infrastructure Service. Adding to' $settype 'set' $setname in $endpoint
    # JSON payload (leaning carriage returns)
    $obj = ('{"id":"').replace("`n","")+''+$setid+'"'+ (',"add":[{"MemberType":"Row","Table":"Server","Key":"').replace("`n","")+''+$sysid+'' + '"}]}'
    $obj = ConvertFrom-Json $obj
    # adds to set
    $setAdd = Centrify-InvokeRest -Endpoint $endpoint -Method "/Collection/UpdateMembersCollection" -ObjectContent $obj -Token $token -Verbose:$enableVerbose

     If ($setAdd.success -ne 'True') {
        Write-Host 'Unable to add to set' $setAdd.ErrorCode 
        Else {
        Write-Host $computer  $sysid 'succesfully added to' $settype 'set' $setname 'in' $endpoint

  Else {
          Write-Host $computer 'was not found as FQDN in CPS.  Will be listed at end.'
          $unresolved += $computer

Sample Output


PS C:\> AddADOUComputerToSetInteractive.ps1
What's the target service URL (e.g. myurl.my.centrify.com)?: vault.centrify.vms
Username for https://vault.centrify.vms: user@vault.demo
Mechanism 0 => Security Question
Mechanism 0 => Password
Target OU: Computers
Target SET: Test
Determining if centos7.centrify.vms is in Privilege Service...
centos7.centrify.vms 5d85c7c2-2cbe-4494-8b5d-568fe3a9fb2a found in Centrify Infrastructure Service. Adding to Server set  in https://vault.centrify.vms
centos7.centrify.vms 5d85c7c2-2cbe-4494-8b5d-568fe3a9fb2a succesfully added to Server set  in https://vault.centrify.vms
Determining if engcen6.centrify.vms is in Privilege Service...
engcen6.centrify.vms 257b977d-9dfd-4498-bd92-8ed8ca949a82 found in Centrify Infrastructure Service. Adding to Server set  in https://vault.centrify.vms
engcen6.centrify.vms 257b977d-9dfd-4498-bd92-8ed8ca949a82 succesfully added to Server set  in https://vault.centrify.vms
centos69.centrify.vms was not found as FQDN in CPS.  Will be listed at end.
The systems not found are: centos69.centrify.vms

In this case, the program found an OU called Computers (not the default computers container) and 2 systems were added to the target set  (Test) given that they were onboarded with a matching FQDN on AD.  The unmatched system was entered using IP addresses.



Adjustments and improvements

  • More error logic and handling.
  • Run with parameters.
  • Add logic to do a second pass but using IP addresses instead of FQDN.
  • Enable to run headless (E.g. provide mappings of OUs to Sets).
  • Use OAUTH2 for headless operation (to eliminate the need of embedded passwords).


Using this project as a motivation, I have learned a lot about the power of the APIs and the excellent resource available in the Centrify Developers site.  If you are in IT ops, Security or Automation, these tools are invaluable to increase productivity.


Attachments: AddADComputerToFromOUInteractive.zip

Showing results for 
Search instead for 
Do you mean 

Community Control Panel