Hey Sailors,
Hope you are healthy and safe during these uncertain and unprecedented times.
Running Powershell directly via the IQService. This is a Native Rule to invoke PowerShell which creates RemoteUserMailbox for clients that are in Hybrid Environment after the Active Directory account is created.
We need to send Exchange Attributes [i.e. username, password in text] to Provisioning Plan as attributes map in Account Request that is used while establishing a Remote PSS connection to exchange server.
public static Attributes<String, String> getExchangeAttributes(SailPointContext context, String flow)
throws GeneralException {
Custom custom = context.getObjectByName(Custom.class, "Customobject where Exchange credentials are saved");
Attributes<String, String> attributes = new Attributes<String, String>();
attributes.put("flow", flow);
attributes.put("username", custom.get("SVC_UserName"));
attributes.put("pwdText", context.decrypt((String) custom.get("SVC_Password")));
return attributes;
}
acctReq.setArguments(CORPUtil.getExchangeAttributes(context,"Joiner"));
Here some example code for the ConnectorAfterCreate PowerShell script that can be invoked after AD account creation.
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE Rule PUBLIC "sailpoint.dtd" "sailpoint.dtd">
<Rule language="beanshell" name="RemoteMailbox-Create-PSScript" 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="150"/>
</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>
</Inputs>
</Signature>
<Source><![CDATA[
$logFile = "C:\ExchangeLogs\AfterCreateLogs\$(Get-Date -format "yyyy-MM-dd").ConnectorAfterCreate.log"
Function writeToLog() {
param([string]$message)
Add-Content ($(Get-Date -format "yyyy-MM-dd HH:mm:ss") + "::$message") -Path $logFile
}
Function sendEmail{
$emailMessage = New-Object System.Net.Mail.MailMessage
$emailMessage.From = "John Smith <john@CORP.com>"
$emailMessage.To.Add("akhilreddy@CORP.com" )
$emailMessage.Subject = "User mailbox creation failed for User -$sAMAccountName"
$emailMessage.IsBodyHtml = $true
$emailMessage.Body = @"
<p>Hello Team,</p>
<p>The usermailbox creation for user -$sAMAccountName has falied due to following erros.</p>
<p> $dn on server: $exchangeServer . Error:: $_.FullyQualifiedErrorId $_.Exception.Message </p>
<p>Please take neccessary actions to create an mailbox for the individual immediately .</p>
<p>Best Regards,</p>
<p>-Akhil Reddy</p>
"@
$SMTPClient = New-Object System.Net.Mail.SmtpClient( "yourSMTPServer -FQDN/IP" , "port" )
$SMTPClient.Credentials = New-Object System.Net.NetworkCredential( $username , $pwdText );
$SMTPClient.Send( $emailMessage)
}
#Notify that we are in afterscript
writeToLog("Running AfterCreate Script: 'CORP-Rule-AfterCreateScript'`r`n");
#Refer to SailPoint class library
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 object###
$xmlReader = [System.xml.XmlTextReader]([sailpoint.Utils.xml.XmlUtil]::getReader($sReader));
$xmlReader_Result = [System.xml.XmlTextReader]([sailpoint.utils.xml.XmlUtil]::getReader($sResult));
###Create SailPoint Request object
$requestObject = New-Object Sailpoint.Utils.objects.AccountRequest($xmlReader);
$resultObject = New-Object Sailpoint.Utils.objects.ServiceResult($xmlReader_Result);
##Done for inclusion in Log File
$requestXML = $requestObject.toxml();
$resultXML = $resultObject.toxml();
writeToLog("Request Object :: $requestXML");
writeToLog("Result Object :: $resultXML");
$objectType = ""
if($resultObject.Errors.count -eq 0){
foreach ($attribute in $requestObject.AttributeRequests){
if($attribute.Name -eq "ObjectType"){
$objectType = $attribute.value
}
if($attribute.Name -eq "op"){
$op = $attribute.value
}
if($attribute.Name -eq "sAMAccountName"){
$samAccountName = $attribute.value
}
if($attribute.Name -eq "userPrincipalName"){
$upn = $attribute.value
}
}
if($objectType -eq "User"){
foreach ($resultEntry in $resultObject.Attributes.GetEnumerator()){
if($resultEntry.Name -eq "createdOnServer"){
$createdOnServer = $resultEntry.Value
}
}
foreach ($requestEntry in $requestObject.Attributes.GetEnumerator()){
if($requestEntry.Name -eq "username"){
$username = $requestEntry.Value
}
if($requestEntry.Name -eq "pwdText"){
$pwdText = $requestEntry.Value
}
if($requestEntry.Name -eq "flow"){
$flow = $requestEntry.Value
}
}
$dn = $requestObject.NativeIdentity;
$op= $requestObject.Operation
writeToLog("//********************* Main Entry Point *******************************//");
writeToLog("Request attributes ---- dn: $dn, ObjectType: $objectType, op : $op, createdOnServer: $createdOnServer, sAMAccountName: $sAMAccountName, upn: $upn, flow:$flow ");
if( $flow -eq "Joiner" -And $op -eq"Create"){
$sApplication = New-Object System.IO.StringReader([System.String]$env:Application);
$xmlReader_Application = [System.xml.XmlTextReader]([sailpoint.utils.xml.XmlUtil]::getReader($sApplication));
[System.Xml.XmlDocument]$document = new-object System.Xml.XmlDocument
$document.load($xmlReader_Application)
$exchangeServers = $document.SelectNodes("//Map/entry[@key='ExchHost']/value/List/String")
$exchangeServersString = $exchangeServers.InnerText
writeToLog("Exchange servers is :::::::::::::::::::::::::$exchangeServersString")
foreach ($exchServerAddress in $exchangeServers) {
Try {
$exchServerAddressString = $exchServerAddress.InnerText
writeToLog("Trying exchange server: $exchServerAddressString")
$hostInfo = [System.Net.Dns]::GetHostByName($exchServerAddressString)
$exchangeServer = $hostInfo.HostName
$IsOnline = Test-Connection -ComputerName $hostInfo.HostName -BufferSize 16 -Count 1 -Quiet
writeToLog("is server online::::::::::::::::::::: $IsOnline ")
if ($IsOnline -eq $true){
Function Login {
$secpasswd = ConvertTo-SecureString $pwdText -AsPlainText -Force
$credObject = New-Object System.Management.Automation.PSCredential($username, $secpasswd)
$uri = "http://"+ $exchangeServersString + ":80/PowerShell/"
$session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri $uri -Credential $credObject -Authentication Kerberos #-ErrorAction Stop
Import-PSSession $session -AllowClobber -DisableNameChecking
$session
}
$session = Login
writeToLog("Session value: $session")
writeToLog("Invoking Enable-RemoteMailbox command for account: $samAccountName")
set-adserversettings -viewentireforest $true
$email = $samAccountName +"@CORP365.mail.onmicrosoft.com"
writeToLog("email:::::::::::::::::::::::$email")
writeToLog("Executing second cmd for account: $samAccountName")
Enable-RemoteMailbox $samAccountName -RemoteRoutingAddress $email
$logger = Get-RemoteMailbox -Identity $samAccountName
writeToLog("checking mailbox print the display name of the user :: $logger")
writeToLog("cmdlets execution completed")
$id =$session.ID
Remove-PSSession -ID $session.ID
writeToLog("After session remove: $Session")
$scriptExecuted=$true
}
else{
writeToLog("Cannot connect to server : $exchServerAddressString")
}
if($scriptExecuted){
writeToLog("Mailbox script execution completed for ::: $samAccountName on server ::: $exchServerAddressString")
}
} catch {
writeToLog("Cannot create mailbox features for user: $dn on server: $exchangeServer . Error: $_.FullyQualifiedErrorId $_.Exception.Message")
sendEmail
}
finally {
if($session){
writeToLog(":::::Finally:::")
Remove-PSSession -ID $session.ID
##Disconnect-PSSession -ID $session.ID
}
}
}
}
else{
writeToLog("::::--!! skipping the after create scripts execution as the plan would be from the identityRefreshExecutor !!--:::::")
}
} else {
writeToLog("Skipping mailbox creation. After Create script triggered for ObjectType: $objectType")
}
} else {
foreach ($errorMsg in $resultObject.Errors){
writeToLog("Errors from Service Result :::`n`r $errorMsg ");
}
}
writeToLog("Executing After Create Script completed for User: $samAccountName");
writeToLog("//*********************End of Script *******************************//");
]]></Source>
</Rule>
Set-RemoteMailbox $sAMAccountName -HiddenFromAddressListsEnabled $true