Hello everyone, my client hasn’t the password module management and they want to set up randomly the first access password and send it via email. I know that Sailpoint offers 2 standard ways (without using the password module management) that we don’t like (static password, dynamic known password) because they are not secure. So we are opting to use the PowerShell script executed inside the IQServer. I know that we need to create a “Create After Rule” to call the PowerShell Script. The Powershell script should generate randonmly the password for each newly created user and than send it trough email using STMP. But how is possible to handle possible errors like mails that are not sent for some internal problems? Or how we can handle a possible problem of the SMTP server that may goes down? Anyone experienced with generating password trough PowerShell script can help me? There are some templetes available? Thanks
try-catch block is the way to capture the SMTP related errors and retry n times to send email, if the error persist you can store those users in a log file and later execute the script to send it manually. You can also do a Test-NetConnection before you perform the actual process and provide more informative log details.
thanks, do you have an example of powershell script to perform that?
Please also note that if you create a user in AD without a password, the AD account is disabled by default (which is what you want!) and so must be (and can only be) enabled after the password is set.
Also be sure to set the password flag so that user must change password after login.
thanks for your advice :), I’m currently looking for an example from anyone that has already implemented it to have a starting point
This is a sample code snippet, you can build on top of it.
try {
Send-MailMessage -To "[email protected]" -From "[email protected]" -Subject "Password Email" -Body "This is a password email." -SmtpServer "smtp.example.com" -ErrorAction Stop
} catch {
if ($_.Exception.Message -eq "Unable to connect to the remote server"){
#Log the required user details
}
}
Thanks you guys, I was uploading the connector after rule in order to call properly the powershell script inside the IQService, but i’m not able to pass the script of the API for uploading the after connector rule. This is my rule, i don’t understand what is going wrong:
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE Rule PUBLIC "sailpoint.dtd" "sailpoint.dtd">
<Rule language="beanshell" name="SSetPassword AfterCreateRule" 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>
This is an IQService afterScript - On a successful provisioning event, this after script should be used as the starting point to
initiate a separate PowerShell script residing on the client's IQService server.
Configuration tasks include the following:
- Set a proper location for the $logFile variable.
- Set the proper script location and name for the $command variable.
- Set the $enableDebug flag to $true or $false to toggle debug mode.
</Description>
<Source>
<![CDATA[
$logDate = Get-Date -UFormat "%Y%m%d"
$logFile = "c:\SailPoint\Scripts\Logs\ConnectorAfterCreate_$logDate.log"
$command = "c:\SailPoint\Scripts\ADSource-AfterCreate.ps1"
$enableDebug = $true
#====================-------Helper functions-------====================
function LogToFile([String] $info) {
$info | Out-File $logFile -Append
}
#====================-------Get the request object-------====================
Try{
if($enableDebug) {
LogToFile("Entering SailPoint rule")
}
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: $requestAsString")
}
#Call the client script
$command = -join ($command, " -requestString '$requestAsString'")
Invoke-Expression $command
}Catch{
$ErrorMessage = $_.Exception.Message
$ErrorItem = $_.Exception.ItemName
LogToFile("Error: Item = $ErrorItem -> Message = $ErrorMessage")
}
if($enableDebug) {
LogToFile("Exiting SailPoint rule")
}
]]>
</Source>
</Rule>
Hi @s_tartaglione,
This is how your rule should look like :
{
"description": "Executes PowerShell commands on the IQService component after a source account is created.",
"type": "ConnectorAfterCreate",
"signature": {
"input": [],
"output": null
},
"sourceCode": {
"version": "1.0",
"script": "$logDate = Get-Date -UFormat \"%Y%m%d\"\r\n$logFile = \"c:\\SailPoint\\Scripts\\Logs\\ConnectorAfterCreate_$logDate.log\"\r\n$command = \"c:\\SailPoint\\Scripts\\ADSource-AfterCreate.ps1\"\r\n$enableDebug = $true\r\n\r\n#====================-------Helper functions-------====================\r\nfunction LogToFile([String] $info) {\r\n $info | Out-File $logFile -Append\r\n}\r\n\r\n#====================-------Get the request object-------====================\r\nTry{\r\n if($enableDebug) {\r\n LogToFile(\"Entering SailPoint rule\")\r\n }\r\n\r\n Add-type -path utils.dll;\r\n $sReader = New-Object System.IO.StringReader([System.String]$env:Request);\r\n $xmlReader = [System.xml.XmlTextReader]([sailpoint.utils.xml.XmlUtil]::getReader($sReader));\r\n $requestObject = New-Object Sailpoint.Utils.objects.AccountRequest($xmlReader);\r\n $requestAsString = $env:Request\r\n\r\n if($enableDebug) {\r\n LogToFile(\"Request as XML object is: $requestAsString\")\r\n }\r\n\r\n #Call the client script\r\n $command = -join ($command, \" -requestString '$requestAsString'\")\r\n Invoke-Expression $command\r\n\r\n}Catch{\r\n $ErrorMessage = $_.Exception.Message\r\n $ErrorItem = $_.Exception.ItemName\r\n LogToFile(\"Error: Item = $ErrorItem -> Message = $ErrorMessage\")\r\n}\r\n\r\nif($enableDebug) {\r\n LogToFile(\"Exiting SailPoint rule\")\r\n}"
},
"attributes": {
"ObjectOrientedScript": "true",
"extension": ".ps1",
"sourceVersion": "1.0",
"disabled": "false",
"program": "powershell.exe",
"timeout": "300"
},
"id": "2d93c02498184d83a6fc914a0af8a279",
"name": "AD_Password_After_Create_Rule"
}
The piece after CDATA[ needs to be JSON escaped (I normally use Free Online JSON Escape / Unescape Tool - FreeFormatter.com) and the escaped part needs to be placed into the “script” section of the rule.
You can easily have this rule created with the VSCode extension without having to make actual API calls :
Thanks, so I’ve created the rule for the AD and uploaded it. Than I’ve created the script inside the “Sailpoint/Scripts” folder of the IQService agent. But when I’m trying to assign the access profile to an account, it is provisioned correctly but i’m not able to access to the account in Sailpoint with the new password setted. How Can I test that all is working correctly?
Hi @s_tartaglione,
Are you able to generate the password with the script and send it out in an email.?
If you want to test the password out, you will need to login as the user in the corresponding AD domain to see if the login works as expected with the generated password.
I’m seeing that i misses to call the PATC API for the AfterCreate Rule. But I don’t know what I have to put in this sample field:
[
{
"op": "add",
"path": "/connectorAttributes/nativeRules",
"value": ["Example Rule 1", "Example Rule 2"]
}
]
You need to pass the rule name - “AD_Password_After_Create_Rule” - as per my example.
You can also add this directly from the UI through the source configuration → Additional settings → Native Rules
Thanks for your suggestions, but I inserted the name directly in the UI and I have uploaded your connector rule, but it seems it doesn’t work. I tried to acces to the AD with the username of one of identity that I have assigned an AD account, but the login fails. This is actually the powershell script that I have inserted in the Sailpoint/Scripts folder of the IQService agent that I have installed:
###############################################################################################################################
# SETUP
# Instructions (for each IQService host that could run the script):
# - Update the path to Utils.dll (can be an unqualified path like "Utils.dll" since script is copied to IQService folder for execution)
# - Make sure Utils.dll is in the specified folder on each IQService host
# - Be sure the account that runs IQService has appropriate permissions to create directories and set permissions on them
# - Be sure to set the "run as" account for the IQService in Windows Service to the above-specified account instead of just the "logged on" user
# - Set a proper location for the $logFile variable
# - Set the $enableDebug flag to $true or $false to toggle debug mode
###############################################################################################################################
param (
[Parameter(Mandatory=$true)][System.String]$requestString
)
#include SailPoint library
Add-Type -Path "c:\SailPoint\IQService\Utils.dll";
#import AD cmdlets
Import-Module activeDirectory
#log file info
$logDate = Get-Date -UFormat "%Y%m%d"
$logFile = "c:\SailPoint\Scripts\Logs\SampleSourceBeforeCreateScript_$logDate.log"
$enableDebug = $false
###############################################################################################################################
# HELPER FUNCTIONS
###############################################################################################################################
#save logging files to a separate txt file
function LogToFile([String] $info) {
$info | Out-File $logFile -Append
}
#if we have a non-null account request, get our value; otherwise return nothing
function Get-AttributeValueFromAccountRequest([sailpoint.Utils.objects.AccountRequest] $request, [String] $targetAttribute) {
$value = $null;
if ($request) {
foreach ($attrib in $request.AttributeRequests) {
if ($attrib.Name -eq $targetAttribute) {
$value = $attrib.Value;
break;
}
}
} else {
LogToFile("Account request object was null");
}
return $value;
}
###############################################################################################################################
# BODY
###############################################################################################################################
if($enableDebug) {
LogToFile("Entering beforeScript")
}
try {
##########################
# Begin SailPoint protected code -- do not modify this code block
#
$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);
#debug line for testing
if($enableDebug) {
LogToFile("Request object contents:")
LogToFile($requestObject | Out-String)
}
#
# End SailPoint protected code
##########################
##########################
# Begin Client-provided code
#get the necessary info we need from the accountRequest object
$nativeIdentity = $requestObject.nativeIdentity
# Generate a random password
$randomPassword = "RandomPassword123456!"
#Set the password in AD
Set-ADAccountPassword -Identity $nativeIdentity -NewPassword (ConvertTo-SecureString -AsPlainText $randomPassword -Force) -Reset
#
# End Client-provided code
}
catch {
$ErrorMessage = $_.Exception.Message
$ErrorItem = $_.Exception.ItemName
LogToFile("Error: Item = $ErrorItem -> Message = $ErrorMessage")
}
if($enableDebug) {
LogToFile("Exiting beforeScript")
}
Why not user this transform on a new identity attribute and just use the email template to send it out?
Random Alphanumeric | SailPoint Developer Community
Or am I missing something?
because i’m setting the password trough the powershell script and i don’t want to show it.