Passing attributes to PowerShell script

I’m trying to execute PowerShell script for enable Remote mailbox during successfully Joiner operation. Since this is my first time doing this, I want to see the attribute values ​​coming from the connector inside the rule variables.

For that, I use nativeRules inside application XML (without excludedAttributes) in IIQ 8.3p3:

<entry key="nativeRules">
        <value>
          <List>
            <String>Rule-AfterCreateAD-Powershell</String>
          </List>
        </value>
      </entry>

*The connector goes to AD/Exchange through Cloud Gateway (IQService is located on the same server).

Below is the code snippet for the “Rule-AfterCreateAD-Powershell” rule:

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE Rule PUBLIC "sailpoint.dtd" "sailpoint.dtd">
<Rule created="1694107189540" id="0a7cd3e78a51185a818a70a841244e10" language="beanshell" modified="1698100915753" name="Rule-AfterCreateAD-Powershell" type="ConnectorAfterCreate">
  <Attributes>
    <Map>
      <entry key="ObjectOrientedScript" value="true"/>
      <entry key="disabled" value="false"/>
      <entry key="extension" value=".ps1"/>
      <entry key="program" value="powershell.exe"/>
      <entry key="timeout" value="300"/>
    </Map>
  </Attributes>
  <Description>
  An IdentityIQ Server-Side rule that is executed AFTER the connector's provisioning method is called. 
  This rule is called after accounts have been created on the underlying AD domain.
  </Description>
  <Signature>
    <Inputs>
      <Argument name="log">
        <Description>
          The log object associated with the SailPointContext.
        </Description>
      </Argument>
      <Argument name="context">
        <Description>
          A sailpoint.api.SailPointContext object that can be used to query the database if necessary.
        </Description>
      </Argument>
      <Argument name="plan">
        <Description>
          The ProvisioningPlan object on its way to the Connector.
        </Description>
      </Argument>
      <Argument name="application">
        <Description>
          The application object that references this before/after script.
        </Description>
      </Argument>
      <Argument name="result">
        <Description>
The ProvisioningResult object returned by the connectors provision method. This can be null and in many cases the connector will not return a result and instead will annotate the plan's ProvisioningResult either at the plan or account level.
</Description>
      </Argument>
    </Inputs>
  </Signature>
  <Source>
$logFile = "C:\IdentityIQ\AfterCreate-Powershell.log"
$daTe = $(Get-Date -format "yyyy-MM-dd hh:mm:ss");

#Notify that we are in afterscript
"$daTe #### In After Create script" | out-file $logFile -Append
# Refer to SailPoint class library
"Loading Utils.dll..." | out-file $logFile -Append
Add-type -path "C:\IQService\Utils.dll"   
  
#Read the environment variables
$sReader = New-Object System.IO.StringReader([System.String]$env:Request);
$sResult = New-Object System.IO.StringReader([System.String]$env:Result);
  
# Form the xml reader objects
        $xmlReader = [System.xml.XmlTextReader]([sailpoint.utils.xml.XmlUtil]::getReader($sReader));
        $xmlReader_Result = [System.xml.XmlTextReader]([sailpoint.utils.xml.XmlUtil]::getReader($sResult));
        
  # Create SailPoint objects
        $requestObject = New-Object Sailpoint.Utils.objects.AccountRequest($xmlReader);
        $resultObject = New-Object Sailpoint.Utils.objects.ServiceResult($xmlReader_Result);
  
  $requestXML = $requestObject.toxml();
  "------ requestXML: $requestXML" | out-file $logFile -Append
  $resultXML = $resultObject.toxml();
  "------ resultXML: $resultXML" | out-file $logFile -Append
  
  # Write the request xml to file at the path passed as argument
  $requestObject.toxml()|out-file $args[0] $logFile -Append
  
     #Check if the request was processed successfully
        if($resultObject.Errors.count -eq 0){
       					"------ Entro al if" | out-file $logFile -Append    					 
         
                
                $atributo1 = $requestObject.getStringAttribute("sAMAccountName");
       					$atributo2 = $requestObject.getAttribute("sAMAccountName");
       					"------ Atributo sAMAccountName 1: $atributo1" | out-file $logFile -Append
                "------ Atributo sAMAccountName 2: $atributo2" | out-file $logFile -Append  
                
                $dn = $requestObject.NativeIdentity;
   						 "------ Atributo NativeIdentity: $dn" | out-file $logFile -Append
								$op= $requestObject.Operation;
               "------ Atributo Operation 3: $op" | out-file $logFile -Append
                 
                foreach ($attribute in $requestObject.AttributeRequests){
												"------ Entro al foreach" | out-file $logFile -Append
                        if($attribute.Name -eq "sAMAccountName"){
                        "########## Lee el usuario de red: $attribute.Value" | out-file $logFile -Append
                        }
                }
}

I am trying to print the attributes that I receive from the connector into variables, but they always appear empty and I have not been able to read them from the after create rule.

Is there something I’m missing to be able to pass the attribute values?
Do I need to do any additional configuration?

Thanks for your help!

Hi @Beltran ,

Welcome to Sailpoint developers community!!

Ideally native rules do not return anything it just calls powershell and performs operations based on commands. However you can still be able to print values using log statements.

You can use the following to print the data from the request:

$now = Get-Date -Format "MM.dd.yyyy HH:mm:ss"
foreach ($attribute in $requestObject.AttributeRequests) {
  Out-File $logFile -InputObject "$now : $attribute.Name = $attribute.Value" -Append
}

What I do to get a specific attribute value is, as the attributes don’t always come inthe same order:

foreach ($attribute in $requestObject.AttributeRequests) {
  if ($attribute.Name -eq "mail") {
    $mail = $attribute.Value
  }
  if ($attribute.Name -eq "sAMAccountName") {
    $username = $attribute.Value
  }
}

I hope this helps :slight_smile:

– Remold

1 Like

Adding to this, there are two types of Powershell scripts: before and after. They have somewhat different semantics.

A “before” script receives the AccountRequest before it’s run and can return modifications to it.

An “after” script receives the AccountRequest after it’s run, so cannot modify it. However, it can return messages and other data in the ServiceResult by writing it out to a temporary file (specified as the first argument to the Powershell script).

My ad hoc Powershell rule function uses a fake “after” rule to return values back to IIQ from arbitrary Powershell.

2 Likes

Thanks Remold for your reply.

I used the portion of code you shared with me to print the data from the request, but the print came out empty.

I have not been able to print the values ​​of the request, I don’t know if I need something to be able to take those values ​​in the After Script.

This is my After Script:

  <Source>
$logFile = "C:\IdentityIQ\AfterCreate-Powershell.log"
$now = $(Get-Date -format "yyyy-MM-dd hh:mm:ss");

#Notify that we are in afterscript
"$now #### In After Create script" | out-file $logFile -Append
# Refer to SailPoint class library
"Loading Utils.dll..." | out-file $logFile -Append
Add-type -path "C:\IQService\Utils.dll"   
  
#Read the environment variables
$sReader = New-Object System.IO.StringReader([System.String]$env:Request);
$sResult = New-Object System.IO.StringReader([System.String]$env:Result);
  
# Form the xml reader objects
        $xmlReader = [System.xml.XmlTextReader]([sailpoint.utils.xml.XmlUtil]::getReader($sReader));
        $xmlReader_Result = [System.xml.XmlTextReader]([sailpoint.utils.xml.XmlUtil]::getReader($sResult));
        
  # Create SailPoint objects
        $requestObject = New-Object Sailpoint.Utils.objects.AccountRequest($xmlReader);
        $resultObject = New-Object Sailpoint.Utils.objects.ServiceResult($xmlReader_Result);
    
     #Check if the request was processed successfully
        if($resultObject.Errors.count -eq 0){
       					"------ Inside IF" | out-file $logFile -Append    				
                  
                foreach ($attribute in $requestObject.AttributeRequests){
                 "------ Inside foreach" | out-file $logFile -Append
                  Out-File $logFile -InputObject "$now : $attribute.Name = $attribute.Value" -Append 
                } 
      
     } else {
      "There is an error ############" | out-file $logFile -Append 
     }
  "############ Out After Create script ############" | out-file $logFile -Append
 </Source>

in LOG the following was printed:

2023-10-24 04:18:56 #### In After Create script
Loading Utils.dll...
------ Inside IF
############ Out After Create script ############

Thanks in advance!

It already worked for me, I had the wrong path to Utils.dll, once I corrected it I was able to read the attributes and print them. thank you so much!

That had happened to me as well after an upgrade of IQService by another team ;(
And another reminder for us all to take nothing for granted, not even a correctly ‘imported’ Utils.DLL :stuck_out_tongue_winking_eye:

Good to know it is working !!

– Remold

2 Likes

This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.