It's sometimes necessary to run a Powershell script "out of band" (i.e. from a Workflow or Run Rule task). This is not well-suited to the Before/After model used by IQService connectors. In this article, I will go through how the IQService invokes Powershell and how you can hook into this process to run your own Powershell scripts.
I've seen a lot of code floating around for calling Powershell, but nothing that explains why you're using that specific code.
The IQService is a .NET application that listens on a configured port for commands from IIQ. These commands are XML-RPC blobs that are encrypted using TLS and/or an agreed-upon private key. Ordinarily, usage of the IQService is buried within IIQ's connector code. However, since you can use any part of the IdentityIQ API in your custom workflows and rules, the IQService classes are available for you too.
These are:
RPCService: The service class that handles all of the communication from IIQ to the IQService, including serialization and encryption of requests and responses.
RpcRequest: Wraps a request to the IQService, designating which type of command is being sent and what the arguments to that command are. Different commands will require different arguments, but you'll always be using the ScriptExecutor command.
RpcResponse: Wraps the response from the IQService. What gets returned depends heavily on what the command is, as we'll see below.
To make a call to a Powershell script, you will need to:
Construct an RpcRequest using a service name of ScriptExecutor, also passing your Powershell code and other arguments.
Construct an RPCService instance, passing the connection parameters for your IQService instance.
Invoke RPCService.execute() against your RpcRequest.
Interpret the RpcResponse returned from execute().
The IQService exposes the ScriptExecutor service for running command line utilities. This can run not only Powershell but also Windows bash or other command line tools. The parameters to the command in question are passed as part of your RpcRequest.
There are two types (more or less) of script executors:
runBeforeScript: In the usual model, these are intended to run before execution, like a Before Provisioning rule. Consequently, they can modify the passed AccountRequest, but they cannot return any errors, warnings, or other messages.
runAfterScript: In the usual model, these are intended to run after execution, like an After Provisioning rule. Consequently, they cannot modify the passed AccountRequest (because it's already been executed). However, they can return errors, warnings, or other messages.
For a runBeforeScript, you must pass a preScript parameter with your Rule. For a runAfterScript, you must pass a postScript parameter with your Rule.
I tend to prefer runAfterScript for ad hoc Powershell, just because returning error messages is useful.
The following is the simplest bit of code that will invoke Powershell on the server. Note the use of postScript and runAfterScript.
import sailpoint.object.RpcRequest;
import sailpoint.object.RpcResponse;
import sailpoint.connector.RPCService;
Map data = new HashMap();
data.put("postScript", yourPowershellRuleObject);
RPCService service = new RPCService(iqServiceHost, iqServicePort, false, useTLS);
RpcRequest request = new RpcRequest("ScriptExecutor", "runAfterScript", data);
RpcResponse response = service.execute(request);
If you want to pass additional values to your script, you will need use the AccountRequest object. Specifically, create a new AccountRequest and add any parameters you'd like to pass as AttributeRequests. This must be added to your data Map as the field Request.
This Request field is not optional, even if you don't actually use it. Your RPC call will fail if you don't include it.
// Fake account request
AccountRequest accountRequest = new AccountRequest();
accountRequest.setApplication("IIQ");
accountRequest.setNativeIdentity("*FAKE*");
accountRequest.setOperation(AccountRequest.Operation.Modify);
// Fake attribute request
AttributeRequest fakeAttribute = new AttributeRequest();
fakeAttribute.setOperation(Operation.Add);
fakeAttribute.setName(paramName);
fakeAttribute.setValue(paramValue);
fakeAttributeRequests.add(fakeAttribute);
accountRequest.setAttributeRequests(fakeAttributeRequests);
// Add to the IQService params
data.put("Request", accountRequest);
If you are using client authentication, a newer security feature for the IQService available since 2019, you will need to additionally pass an Application object's Attributes with IQService configuration in your parameters.
For example:
Application ad = context.getObjectByName(Application.class, "Customer Active Directory");
data.put("Application", ad.getAttributes());
The RPCService will automatically use the configuration stored in that application, specifically the IQServiceUser and IQServicePassword attributes.
You will also need to provide it with an instance of ConnectorServices, which the RPCService will use to decrypt the passwords stored in the Application object. Failing to do this will result in a NullPointerException.
service.setConnectorServices(new sailpoint.connector.DefaultConnectorServices());
Temporary script file
The IQService will write your entire Rule's source to a temporary file, which by default is in the same directory. These files are intended to be deleted once the script completes, but the IQService is (for some reason) sometimes unable to do that. If you see a number of temp objects piling up in your IQService folder, you can safely delete them.
However, since the IQService writes each script to disk, you should not hardcode any credentials in your Powershell rules.
Receiving the input
Receiving the values passed to Powershell rules (in that fake AccountRequest) is a bit convoluted. To support various types of command line scripts, the IQService passes all parameters as environment variables. To make things more confusing, it passes them in the environment variables as XML.
Reading your AccountRequest input in Powershell thus looks like:
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);
$resultObject = New-Object Sailpoint.Utils.objects.ServiceResult;
In the first line, utils.dll is a utility provided by SailPoint that exposes several useful Powershell object types. We are using some .NET classes to read the data out of $env:Request, which is where the IQService stuffs our AccountRequest object.
Finally, we create a Sailpoint.Utils.objects.ServiceResult, which we'll use later to return the results from our script.
Interpreting the input
To interpret the Powershell input, you will need to read the data out of the AccountRequest. Fortunately, the API is identical to that in IIQ Beanshell. To make things easier, though, I like to build a Powershell hash object (i.e. a Map) with the data.
$attributes = @{}
foreach ($attribute in $requestObject.AttributeRequests){
$attributes[$attribute.Name] = $attribute.Value;
}
After this code, you can simply refer to $attributes["name"] to get at your passed data. Note that printing this value will just produce a hash.
Handling output
Once you've completed your Powershell actions, you will need to return some values back to IIQ. You will do this by dumping an object XML to the filename passed as the first parameter to your script. The IQService will read an appropriate object out of that file and pass it back to IIQ. (As with the input, this indirect method is used so that any number of scripting interfaces, not only Powershell, can be invoked by the IQService.)
I like to wrap the entire thing in a Try/Catch/Finally block so that the output is always written and errors are properly handled.
Try {
# Handle input and do stuff here
$resultObject.Messages.add("Success!");
} catch [Exception] {
# You should probably do some logging here too
$ErrorMessage = $_.Exception.ToString()
$resultObject.Errors.add($ErrorMessage);
} finally {
$resultObject.toxml() | out-file $args[0];
}
The "magic" takes place in the finally block, in which the $resultObject that we constructed earlier is exported as XML to the destination file. As with the rule source, this output object is being written to disk, so you should not store any sensitive data in your script output.
You can return Messages and Errors, which are simply Powershell lists of string.
For returning more complex objects, use the Attributes hashtable stored on the ServiceResult object. The keys must be strings, but the values can be a variety of simple object types - strings, numbers, dates, hashtables, lists, and byte arrays. Other objects that are not handled by the XML serializer will be dropped from the response, so make sure you convert your data to a handled type.
$resultObject.Attributes["someVariable"] = $someResultObject;
Using a wrapper script
It's nice to avoid boilerplate code wherever possible. To do this, I usually write a Powershell script that resides locally on the IQService host, e.g. in a D:\IQService\Scripts folder, and invoke those scripts once I've parsed my input. The rules in IIQ are responsible only for ensuring that the correct data is passed to the local scripts.
This also means that those scripts can be reused outside of IIQ, e.g. as part of a batch operation or an administrator action.
Your $resultObject will be returned to IIQ as an RpcResponse. This will contain any errors, messages, or attributes your Powershell script produced. You may want to create a standard method to check for errors and throw an exception. The following is a barebones error handler.
(Remember that, like most IIQ APIs, pretty much anything can be null at any time.)
public RpcResponse checkRpcFailure(RpcResponse response) throws Exception {
if (response == null) {
return null;
}
if (response.getErrors() != null && response.getErrors().size() > 0) {
throw new IllegalStateException(response.getErrors().toString());
}
return response;
}
You can use this waaaaay back up in the RPCService code like so:
RpcResponse response = checkRpcFailure(service.execute(request));
If you need to return structured data, passing textual values like JSON or XML as part of a Message is one option, as is returning it as part of the Attributes. See what works best for your purposes.
Hello. We are using IIQ 7.2, and this is our catch block:
Hi!
I am trying to follow this tutorial, but still getting "Object reference not set to an instance of an object" error even after adding request object to data. I am using sample AfterCreate_PowerShell rule and BS code from above. v 8.1 (p1 I think)
Would be glad to hear any suggestions up to what may case this.
@sp team, if anyone reads this. Common guys! Please output trace stacks! It is next to impossible to troubleshoot with such error messages.
OK. Got some progress. I figured that that I might debug using Visual Studio and that helped a lot.
As it was mentioned here above "Application" is also required parameter, and value MUST be real app attributes collection. I was trying to get away with putting HashMap as value, but after heavy debugging I have realized that XML deserializer simply ignores whatever it is not able to process. I would expect parsing exception... But we have what we have...
Not sure why we need jump through hurdles if this object is not even used. AbstractConnector simply access it without checking existence.
Also, taking in account that service routinely passes data through environment variables, I wonder if it would be reasonable good idea to pass authentication information this way. What is the risk? May be not that high if we pass script on each invocation making sure it is not altered in any way, such as printing information or injecting other script call. Environment should go away after completion. Can anyone share experience?
I am curious how to deal with long running scripts? I see a timeout value. But looking at disassembly I can imagine that this will suspend whole PS session. I guess it might be expensive in terms of memory. Suggestions?
I'm executing empty PS script directly via IQService to see if this approach works, I'm on 8.1p1 however I continue to get this exception something seem to be incorrect with incoming RPC request on app object, but I'm not certain what is blocking the execution. Any pointers highly appreciated
: "Exception occurred in executing the script : The input is not a valid Base-64 string as it contains a non-base 64 character, more than two padding characters, or an illegal character among the padding characters. "
"IncommingRequest:
<?xml version='1.0' encoding='UTF-8'?>
<RpcRequest method="runAfterScript" service="ScriptExecutor" version="1.0">
<Arguments>
<Map>
<entry key="Application">
<value>
<Attributes>
<Map>
<entry key="IQServiceConfiguration">
<value>
<List>
<Map>
<entry key="IQServiceHost" value="ABCIAMSQL01.abc.abco.com"/>
<entry key="IQServicePassword"/>
<entry key="IQServicePort" value="5050"/>
<entry key="IQServiceUser"/>
<entry key="useTLSForIQService">
<value>
<Boolean></Boolean>
</value>
</entry>
</Map>
</List>
</value>
</entry>
<entry key="acctAggregationEnd">
<value>
<Date>1616527693081</Date>
</value>
</entry>
<entry key="acctAggregationStart">
<value>
<Date>1616527692641</Date>
</value>
</entry>
<entry key="afterProvisioningRule" value="ABC-Rule-AfterProvisioning-ADIntranet"/>
<entry key="allowAutoPartitioning">
<value>
<Boolean></Boolean>
</value>
</entry>
<entry key="authSearchAttributes">
<value>
<List>
<String>sAMAccountName</String>
</List>
</value>
</entry>
<entry key="authorizationType" value="simple"/>
<entry key="autoPartitionCount" value="256"/>
<entry key="beforeProvisioningRule" value="ABC-Rule-BeforeProvisioning-ADIntranet"/>
<entry key="cacheRemoteObjectPort" value="40002"/>
<entry key="cacheRmiPort" value="40001"/>
<entry key="com.sun.jndi.ldap.read.timeout" value="120000"/>
<entry key="compositeDefinition"/>
<entry key="deletedObjectsContainer" value="CN=Deleted Objects,DOMAIN"/>
<entry key="deltaAggregation">
<value>
<Map>
<entry key="dc=abc,dc=abco,dc=com">
<value>
<Map>
<entry key="groups_cookie" value="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
3v16DU/fiwIAAAAA"/>
<entry key="lastDirsyncServer" value="ABCSTADDC01.abc.abco.com"/>
<entry key="users_cookie" value="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
3v16DU/fiwIAAAAA"/>
</Map>
</value>
</entry>
</Map>
</value>
</entry>
<entry key="deltaIterationMode" value="DirSync"/>
<entry key="disableComputePreloading">
<value>
<Boolean>true</Boolean>
</value>
</entry>
<entry key="domainSettings">
<value>
<List>
<Map>
<entry key="authenticationType" value="simple"/>
<entry key="authorizationType" value="simple"/>
<entry key="domainDN" value="dc=abc,dc=abco,dc=com"/>
<entry key="domainIterateSearchFilter"/>
<entry key="domainNetBiosName"/>
<entry key="forestName" value="ABC"/>
<entry key="password" value="**********"/>
<entry key="port" value="389"/>
<entry key="servers">
<value>
<List>
<String>ABCSTADDC01.abc.abco.com</String>
<String>ABCTADDC02.abc.abco.com</String>
<String>ABCTADDC03.abc.abco.com</String>
</List>
</value>
</entry>
<entry key="useSSL">
<value>
<Boolean></Boolean>
</value>
</entry>
<entry key="user" value="abc\abc_iam_admin"/>
</Map>
</List>
</value>
</entry>
<entry key="enableCache">
<value>
<Boolean></Boolean>
</value>
</entry>
<entry key="encrypted" value="domainSettings.password,forestSettings.password"/>
<entry key="exchangeversion" value="DEFAULT"/>
<entry key="excludeAttributesFromProvisioning">
<value>
<List>
<String>mailNickname</String>
</List>
</value>
</entry>
<entry key="forestSettings">
<value>
<List>
<Map>
<entry key="authenticationType" value="simple"/>
<entry key="authorizationType" value="simple"/>
<entry key="forestName" value="ABC"/>
<entry key="gcServer" value="LDAP.ABCO.COM:3269"/>
<entry key="manageAllDomains">
<value>
<Boolean></Boolean>
</value>
</entry>
<entry key="password"/>
<entry key="useGroupMembershipPreloading"/>
<entry key="useSSL">
<value>
<Boolean></Boolean>
</value>
</entry>
<entry key="user"/>
</Map>
</List>
</value>
</entry>
<entry key="group.searchDNs">
<value>
<List>
<Map>
<entry key="iterateSearchFilter" value="(objectclass=group)"/>
<entry key="searchDN" value="dc=abc,dc=abco,dc=com"/>
<entry key="searchScope" value="SUBTREE"/>
</Map>
</List>
</value>
</entry>
<entry key="groupMemberSearchDN" value="dc=abc,dc=abco,dc=com"/>
<entry key="host" value="ldap.abco.com"/>
<entry key="iterateModeOverride" value="PAGED_RESULTS"/>
<entry key="lyncAttributes" value="RegistrarPool,SipAddressType,SipAddress,SipDomain,msRTCSIP-UserEnabled"/>
<entry key="manageLync">
<value>
<Boolean></Boolean>
</value>
</entry>
<entry key="manageRecycleBin">
<value>
<Boolean>true</Boolean>
</value>
</entry>
<entry key="nativeChangeDetectionAttributeScope" value="entitlements"/>
<entry key="nativeChangeDetectionAttributes"/>
<entry key="nativeChangeDetectionEnabled">
<value>
<Boolean></Boolean>
</value>
</entry>
<entry key="nativeChangeDetectionOperations"/>
<entry key="nativeRules">
<value>
<List>
<String>ABC-Rule-ConnectorBeforeModify-ADIntranet</String>
<String>ABC-Rule-ConnectorBeforeDelete-ADIntranet</String>
<String>ABC-Rule-ConnectorAfterModify-ADIntranet</String>
</List>
</value>
</entry>
<entry key="pageSize" value="100"/>
<entry key="password" value="**********"/>
<entry key="port" value="636"/>
<entry key="referral" value="ignore"/>
<entry key="searchDN" value="dc=abc,dc=abco,dc=com"/>
<entry key="searchDNs">
<value>
<List>
<Map>
<entry key="groupMemberFilterString"/>
<entry key="groupMembershipSearchDN"/>
<entry key="iterateSearchFilter" value="(&(objectClass=user)(employeeID=*))"/>
<entry key="primaryGroupSearchDN" value="dc=abc,dc=abco,dc=com"/>
<entry key="searchDN" value="dc=abc,dc=abco,dc=com"/>
<entry key="searchScope" value="SUBTREE"/>
</Map>
</List>
</value>
</entry>
<entry key="sysDescriptions">
<value>
<Map>
<entry key="en_US"/>
</Map>
</value>
</entry>
<entry key="templateApplication" value="Active Directory Template"/>
<entry key="useHasMoreElements" value="true"/>
<entry key="user" value="abc\abc_iam_admin"/>
</Map>
</Attributes>
</value>
</entry>
<entry key="Request">
<value>
<AccountRequest application="IIQ" nativeIdentity="*FAKE*" op="Modify">
<AttributeRequest name="homeDirectory" op="Add" value="\\abc.abco.com\abc-root$\USR-DATA\J\jjshaw2\HOME"/>
<AttributeRequest name="sAMAccountName" op="Add" value="jjshaw2"/>
<AttributeRequest name="homeDrive" op="Add" value="K:"/>
<AttributeRequest name="TS_TerminalServicesProfilePath" op="Add" value="\\abc.abco.com\abc-root$\USR-DATA\J\jjshaw2\PROFILE\jjshaw2"/>
</AccountRequest>
</value>
</entry>
<entry key="postScript">
<value>
<Rule created="1621462732182" id="0a28053479371e89817986b5cd963851" language="beanshell" modified="1621553897590" name="ABC-Rule-ConnectorAfterCreate-Joiner-HomeDirectory-Email" 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="120"/>
</Map>
</Attributes>
<Description>
This is a PowerShell after script which ensures that the request was processed successfully and creates home directory at the path specified in the request
</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>
</Inputs>
</Signature>
<Source>
# Add code here
</Source>
</Rule>
</value>
</entry>
</Map>
</Arguments>
</RpcRequest>
The issue that you are running into is with the decryption and encoding of the password before making the RPCRequest. The link below should help you with your issue. I would also verify via a Rule whether it can successfully ping IIQService.
https://community.sailpoint.com/t5/IdentityIQ-Forum/RPCService/td-p/174041
Thanks
Rohit Prabhu
Hi,
We are in IIQ 8.2p1 with Credential Cycling procedure. The service account that is used to connect to IQService credentials are managed by CyberArk for password rotation for every 60 days, So, IQService password willn't be managed correctly in Application configuration for Active Directory application. So, we have to pass the IQService password as a parameter to to the rpcrequest.
I am looking for ways how to pass password so that IIQ gets connected to IQService for remote powershell execution.
I am trying to get the groups of the user via powershell as we don't have all the OU's configured in the AD application.
$ADGroupList=New-Object System.Collections.ArrayList;
$ADGroupList=(Get-ADUser $username –Properties MemberOf).MemberOf
Exception running rule: The application script threw an exception: sailpoint.tools.GeneralException: The application script threw an exception: sailpoint.tools.GeneralException: Errors returned from IQService. After script returned non zero exit code : 1 :
Getting the above error while executing the rule.
Please provide your inputs.
Thanks & Regards,
Uma
@drosenbauer How do I pass the IQService username and Password to the RPC constructor? Can we execute the PowerShell script directly from the workflow without the IQService? Is there any documentation available for RPC constructor?
Thanks,
B.B.
Hello,
I am on IIQ 8.2p1. I was able to call PS script using rule from IIQ. The problem is I could not manage get any response message / errors from the PS script back in IIQ.
Lastly, I weirdly got the exception : "The property 'Messages' cannot be found on this object. Verify that the property exists and can be set." from logging a simple :
[System.Collections.ArrayList]$messagesList = @()
$messagesList.Add("An error occured");
$resultObject.Messages = $messagesList
log ('message is : ' + $resultObject.Messages);
Do I have a version problem ? On IIQ Side, the response is always the same, without any message or errors elements :
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE String PUBLIC "sailpoint.dtd" "sailpoint.dtd">
<String><?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE RpcResponse PUBLIC "sailpoint.dtd" "sailpoint.dtd">
<RpcResponse complete="true" requestId="69c76b90-8a15-4887-9894-70f8b0147966" version="1.0">
<ResultAttributes>
<Map>
<entry key="requestProcessedOn" value="8/4/2022 3:47:13 PM"/>
<entry key="updated_request">
<value>
<AccountRequest>
<Attributes>
<Map>
<entry key="testArgumentKey" value="testArgumentValue"/>
</Map>
</Attributes>
</AccountRequest>
</value>
</entry>
</Map>
</ResultAttributes>
</RpcResponse>
</String>
Here is my PS code :
Add-type -path utils.dll
# Function for logging to a text file
function log($string) {
$logOut = "testtest.txt"
$timestamp = "$(Get-Date -format "MM-dd-yyyy HH:mm.ss"): "
$entry = $timestamp + $string
$entry | Out-File -Filepath $logOut -append
}
# Read the environment variables
$sReader = New-Object System.IO.StringReader([System.String]$env:Request);
# Read the environment variables
$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);
log ('Start');
Try {
***...block of code...***
$Resp = $Response.StatusCode
log ('response is : ' + $Resp);
[System.Collections.ArrayList]$messagesList = @()
$messagesList.Add("An error occured");
$resultObject.Messages = $messagesList
log ('message is : ' + $resultObject.Messages);
} catch [Exception] {
$ErrorMessage = $_.Exception.ToString()
log ($ErrorMessage);
$resultObject.Errors.add($ErrorMessage);
} finally {
log ($resultObject.toxml());
$resultObject.toxml() | out-file $args[0];
}
Here is IIQ code :
try {
Map dataMap = new HashMap();
// Get the application definition
Application aad = context.getObjectByName(Application.class, "Azure AD QA");
dataMap.put("Application", aad.getAttributes());
// Get the Rule definition
Rule rule = context.getObjectByName(Rule.class, "AAD Test Powershell");
dataMap.put("preScript", rule);
// Get the Account Request
AccountRequest accountRequest = new AccountRequest();
accountRequest.addArgument("testArgumentKey", "testArgumentValue");
dataMap.put("Request", accountRequest);
RpcRequest request = new RpcRequest("ScriptExecutor", "runBeforeScript" , dataMap);
RPCService service = new RPCService("...", ...);
service.setConnectorServices(new sailpoint.connector.DefaultConnectorServices());
RpcResponse response = service.execute(request);
return response.toXml();
} catch (Exception e){
return e.getMessage();
}
I found the problem, it was because I used beforeScript instead of afterScript...
Hello all ,
I am passing the attributes to the AttributeRequest object by passing arguments as attributes:
// Fake account request
AccountRequest accountRequest = new AccountRequest();
accountRequest.setApplication("Active Directory");
accountRequest.setNativeIdentity("CN="+samAccountName+ ",OU=Users,OU=Test User Provisioning,DC=testtcbna,DC=net");
accountRequest.setOperation(AccountRequest.Operation.Create);
log.error("account request is working: "+ accountRequest);
HashMap attr = new Attributes();
attr.put("Name",displayName);
attr.put("Associate id",associateID);
attr.put("Employee id",employeeID);
AttributeRequest attrRequest = new AttributeRequest();
attrRequest.setOperation(Operation.Set);
attrRequest.setArguments(attr);
attributeRequests.add(attrRequest);
How do I retrieve the values of those attributes (Name, Associate id , Employee id) in the powershell script? I looked at some examples to store the AccountRequest ojbect in an xml but that did not work.