Running PowerShell script for ConnectorAfterModify type based on user type

Hello,

My organization has a local Active Directory source / connector, and in it, we have a reference to use an after create rule:

        "deltaAggregationEnabled": "false",
        "deltaIterationMode": "dirSync",
        "IQServicePort": "5051",
        "groupMemberAttribute": "member",
        "nativeRules": [
            "AD-AfterCreate"
        ]

The AD-AfterCreate rule simply runs a PowerShell script which is located on a Windows server running the IQService.

I am looking into doing something similar but for the ConnectorAfterModify rule type. I have not done this before and I am looking for suggestions / examples / best practices. Essentially what I am looking into doing is if a user changes from one user type to another (e.g., tempEmp → fullTimeEmp), a PowerShell script will run to create a mailbox in our local Exchange server. So I would need to somehow capture the user type being passed when there is an after modify request.

I believe the way I would accomplish this is by modifying the AD source to include the new native rule:

       "nativeRules": [
            "AD-AfterCreate", 
            "AD-AfterModify"
        ]

Then create a new rule of ConnectorAfterModify type that would call the new script. But looking through SLP documents / dev community, I didn’t see anyone making references to capture certain information such as user type.

Thank you in advance!

Sincerey,
Ricardo T.

Hi @rt111

  1. Create an afterModify rule that triggers and passes the samAccountName to another script (e.g., xyz.ps1) which will handle the heavy lifting.
  2. Add a sleep command in the xyz.ps1 script to introduce a delay.
  3. The script will search and locate the user in Active Directory (AD) using the samAccountName and retrieve all user details like user type from AD with the Get-UserProp command.
  4. Incase user type is not provisioned to AD ask client if they could create an extensionAttribute so user type can be provisioned.
  5. Finally, create an Exchange mailbox for the user using that script.

Hi @rt111

Yes, ideally you can achieve it using the attribute sync. You can set an attribute sync for identity type which will ensure that the after modify rule is triggering when ever identity type is changes for the user. ( for this please be careful that already existing users in target application and ISC do not have any differences in identity type attribute otherwise ISC will overwrite those changes and could have unexpected impacts).

Once the identity type of the user changes, then this attribute and the new value should be available for the user in provisioning plan which you can then use to write logic in powershell script. The key point is to pass the value of the provisioning plan to connector rule and then pass those arguements to the powershell script.

If you need more information, please let me know.

Regards
Vikas.

@rt111 , Adding to @gourab’s point make sure that you will add -Server/ -DomainController parameter to AD/EXCHNG commands.

You can retrieve name of the sever from RPCResponse - “CreatedOnServer” attribute ,where the modify operation has bee performed on DC.

Hello,

Thank you everyone for your suggestions! @vguleria do you have any example of what a rule would look like to achieve this? For the AD source, I believe this is what the configuration would look like (appending the AD-User-TypeChange to rules set):

        "nativeRules": [
            "AD-AfterCreate",
            "AD-User-TypeChange"
        ],

I am using the IDN plugin for VS Code, which gives me the option to create a rule of “ConnectorAfterModify” for PowerShell as such:

{
    "description": "Executes PowerShell commands on the IQService component after a source account is modified.",
    "type": "ConnectorAfterModify",
    "signature": {
        "input": [],
        "output": null
    },
    "sourceCode": {
        "version": "1.0",
        "script": "// source code"
    },
    "attributes": {
        "ObjectOrientedScript": "true",
        "extension": ".ps1",
        "sourceVersion": "1.0",
        "disabled": "false",
        "program": "powershell.exe",
        "timeout": "300"
    },
    "id": "[ID]",
    "name": "AD-UserTypeChange",
    "created": "2025-01-07T17:16:17.567Z",
    "modified": "2025-01-07T17:16:17.567Z"
}

But I am not fully sure how to A) capture the user type and B) ensure that there are no differences in identity attribute to avoid overwriting changes.

Looking at the AD-AfterCreate rule created by a 3rd party vendor who helped us with the deployment of SailPoint, I see that it specifies the AfterCreate.ps1 script to execute, amongst other options such as where to save logs, and variables to parse XML data in the “script” section under “sourceCode” (I am attaching a screenshot of the unwrap code for reference). In the script that is being used for this AD-AfterCreate rule, I see that it parses the XML response to get information such as the username in question. Is this how I would retrieve the user type information, such as the old vs new user type (I am attaching a screenshot of the AfterCreate.ps1 being called by the AD-AfterCreate rule for reference).


Thank you

Hi @rt111

Yes, that is correct. You will need to use the same function to check if the identity type attribute is present in the account Request and pass that information to your iqService powershell script where you can first check if mailbox is already provisioned to the user or not.

If it is not provisioned, then you can provision it.

I hope that works.

Regards
Vikas.

Hi,
Refer : Before and After Operations on Source Account Rule | SailPoint Developer Community

  1. Create a rule of type ConnectorAfterModify, you could either write the powershell script directly in the rule or call a powershel script.
  2. Attach the rule to the source, refer Connector Executed Rules | SailPoint Developer Community

How to trigger the rule?
There has to be a change in the AD account for the rule to be triggered, so below options:

  1. Set an identity attribute with this value User-Type and sync it to an AD attribute like Employee-Type.
  2. If Ad attribute does not exists, then use info or description AD attribute and sync this value.

How to retrieve this value in PS script, :
Refer to the AfterCreate script or the URL given above, something like below :
$UserType = Get-AttributeValueFromAccountRequest $requestObject “Employee-Type”

Hi @cinilsunny and @vguleria,

Thank you for the additional feedback. I am making good progress! So far, I have modified the AD source to use the newly created ConnectorAfterModify rule, which is pointing to a PowerShell script that follows a similar syntax as the screenshots previously shared. Then, I added a new account schema attribute for the AD source to use an extensionAttributeX within AD. Followed by creating a new attribute sync entry that would map the user type of an account over to extensionAttributeX. A few questions that I have:

1-What is the best way to retrieve the userType when being retrieved as an XML? In the UserTypeChange rule within the AD source, I see the following PowerShell code:

Add-type -path utils.dll;
$sReader = New-Object System.IO.StringReader([System.String]$env:Request);
$xmlReader = [System.xml.XmlTextReader]([sailpoint.utils.xml.XmlUtil]::getReader($sReader));
$requestObject = New-Object Sailpoint.Utils.objects.AccountRequest($xmlReader);
    $requestAsString = $env:Request

    if($enableDebug) {
        LogToFile(\"Request as XML object is: $requestAsStrin")
    }

Whereas on the PowerShell script provided by the 3rd vendor / SLP for the AfterCreate operation, I see the following (I am using this script as guidance):

$sReader = New-Object System.IO.StringReader([System.String]$requestString);
$xmlReader = [System.xml.XmlTextReader]([sailpoint.utils.xml.XmlUtil]::getReader($sReader));
$requestObject = New-Object Sailpoint.Utils.objects.AccountRequest($xmlReader);
        
 #debug line for testing
if($enableDebug) {
           LogToFile("Request object contents:")
           LogToFile($requestObject | Out-String)
           LogToFile($xmlReader | Out-String) 
 }

The first block of code set in the ConnectorAfterModify rule, it outputs the results in an XML format, which contains the user type. Whereas the second block of code, it only provides me with basic information such as DN, attributes being passed from SLP, operation type, and similar. But it does not provide the user type. The key difference that I can see is the $sReader = New-Object System.IO.StringReader([System.String]$requestString); line. Where in the first code block, it makes a reference to the environment variable Request, but on the second code block, it does not.

I tried also changing the Sailpoint.Utils.objects.AccountRequest to Sailpoint.Utils.objects.ServiceResult as I though it would give me a different response, but no luck. I am also attaching screenshot of the response I am receiving after doing an attribute sync in SailPoint or changing a user’s type from one to another.

2-Is it possible to retrieve the new and old user type on the response from SailPoint? The reason why I ask is because we are not assigning user type anywhere in AD. So I wouldn’t be able to compare to what AD has for user type versus what SailPoint is providing. I just recently added the mapping of the extensionAttributeX to the user type in the sandbox environment. I was hoping to be able to get the new and old values on the user type from SailPoint directly so that I can do a comparison and if it doesn’t match, move forward with the mailbox creation.

Thank you,
Ricardo Then

Hi @rt111

Glad to hear that you are making the progress. For the powershell script, the one i am using personnally also prints the requests in xml object so believe you can go with that.

But in this case, in my opinion you need the userType to be available always in the request object for which i do not think if there is a neater way to achieve that. What i did in one of the case, was to add this attribute into provisioning plan using the before provisioning rule (cloud based rule :slight_smile: ) using something like below.

userType = accountRequest.getAttribute(“userType”) == null? identity.getAttribute(“userType”): accountRequest.getAttribute(“userType”) ;

This is because the userType attribute will be added to the request only when there is an update to this attribute so if that is only when you need it then you can check it in the connector rule if the account request contains this attribute then handle this change.
But for example, if the first name changes for the user then provisioning plan will not contain userType and thus it will be unavailable in the request.

Other option is also to have an identity attribute created which will store last three userType values and this is how you will get the older user type value but cleanup way is to have before provisioning rule do it.

I hope this helps.

Please let me know if there are any further queries.

Regards
Vikas.

#In XML

	foreach ($attribute in $requestObject.AttributeRequests) {
        if ($attribute.Name -eq "extensionAttributeX") {
                $extensionAttributeXNewValue = $attribute.Value
        }
	}
	 $extensionAttributeXPreviousValues = $requestObject.Attributes.cloudPreviousValues.extensionAttributeX
	 
	#In PS:
	$nativeidentity = $requestObject.nativeidentity
	$extensionAttributeXNewValue = Get-AttributeValueFromAccountRequest $requestObject "extensionAttributeX"
	$extensionAttributeXPreviousValues = $requestObject.Attributes.cloudPreviousValues.extensionAttributeX