AD AfterCreate Powershell Script fails: After script returned non zero exit code : 1

Hi Experts,

I am trying to invoke an AfterCreate script and at the moment I have added no logic in it, i just want to check if the script gets trigerred. But I am receiving the below error after account creation:

["sailpoint.connector.ConnectorException: Errors returned from IQService. Account creation rolledback due to partial success. Create operation is successful but post script execution failed : After script returned non zero exit code : 1 : "]

There is nothing special in the script, it is copied:

#include SailPoint library
Add-Type -Path "C:\SailPoint Files\IQService\Utils.dll";

#import AD cmdlets
Import-Module ActiveDirectory;

$logDate = Get-Date -UFormat "%Y%m%d"
$logFile = "C:\SailPoint Files\IQService\Logs\AfterCreateScript_$logDate.log"

$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")
}

The service account already has permissions to edit the log file and I have disabled non TLS port on the IQservice configuration already. Account creation works fine one I remove this rule from the “Native Rules” config on the source.

Any inputs?

  • Tamalika

Any chance that this script is created using your account and SailPoint is using some other service account for IQ Service ?

Can you validate if the powershell script is blocked to execute. Can you share the complete rule that you are uploading to tenant.

1 Like

@tamalika01 -

Why you are seeing “After script returned non-zero exit code : 1”

The message means IQService did finish creating the account in Active Directory, but when it tried to launch the PowerShell file configured in Native Rules → AfterCreateScript, that script ended with an exit code other than 0.
IQService therefore rolls the provisioning back to avoid leaving the new AD object in an indeterminate state.

Because PowerShell sets its process exit code to 1 whenever an un-handled error is written to the error stream, even a single warning inside your script is enough to trigger this rollback. Your test file is already doing several things that commonly throw such errors:

Line What might fail Typical symptom
Import-Module ActiveDirectory RSAT tools not installed, or the IQService service account does not have permission to load the module The term ‘Get-ADUser’ is not recognized …
Add-Type -Path "C:\SailPoint Files\IQService\Utils.dll" (and the second Add-Type utils.dll) Typos in the path, 32-/64-bit mismatch, or the same assembly being loaded twice Add-Type : Cannot add type. The type name already exists.
Using $env:Request REQUEST is only present when IQService actually populates it; running the script from a normal PowerShell prompt leaves it $null, so StringReader throws Exception calling “StringReader” with “1” argument(s): Value cannot be null.
Writing the log file If the IQService Windows service account cannot create or append the file Out-File : Access to the path … is denied.

Any of the above will bubble up as an unhandled error → PowerShell sets $LASTEXITCODE = 1 → IQService interprets that as failure.


A quick way to prove the script is fired

Replace the entire file with just three lines and redeploy:

Start-Transcript -Path "C:\SailPoint Files\IQService\Logs\aftercreate_debug.log"
"AfterCreate fired at $(Get-Date)" | Out-File "C:\SailPoint Files\IQService\Logs\aftercreate_marker.log" -Append
Stop-Transcript
exit 0
  1. Create or disable the user again from IdentityIQ.
  2. If the aftercreate_marker.log appears (and the task still rolls back), you know the script is launching but returning ≠ 0.
  3. If the file never appears, IQService isn’t finding or executing the script at all (wrong path, wrong NativeRule name, or execution policy blocking).

Hardening the full script

Below is a minimal skeleton that safely loads SailPoint libraries, writes a log, and always ends with an explicit exit 0 unless a trapped error occurs. It shows exactly where to add your own logic later.

<#  AfterCreateScript.ps1 – template  #>
$ErrorActionPreference = 'Stop'   # any error now becomes terminating
Set-StrictMode -Version Latest

# --- Configurable paths ----------------------------------------------------
$iqhome  = 'C:\SailPoint Files\IQService'
$logRoot = "$iqhome\Logs"
$libDir  = "$iqhome\Utils"
$logFile = Join-Path $logRoot ("AfterCreate_{0:yyyyMMdd}.log" -f (Get-Date))

# --- Helper ----------------------------------------------------------------
function Write-Log {
    param($msg) 
    $msg | Out-File $logFile -Append
}

try {
    #--- Startup banner
    Write-Log "---- AfterCreate started $(Get-Date -Format o) ----"
    
    #--- Load SailPoint utils
    Add-Type -Path (Join-Path $libDir 'Utils.dll')

    #--- Load AD cmdlets **only if needed**
    Import-Module ActiveDirectory -ErrorAction Stop
    
    #--- Parse the request XML from environment
    $reqXml = $env:REQUEST          # variable is case-insensitive
    Write-Log "Raw request length: $($reqXml.Length) characters"
    
    $reader   = New-Object System.IO.StringReader $reqXml
    $xmlRd    = [SailPoint.Utils.Xml.XmlUtil]::getReader($reader)
    $acctReq  = New-Object SailPoint.Utils.Objects.AccountRequest($xmlRd)

    #--- YOUR POST-CREATE LOGIC GOES HERE
    # … e.g. set attributes, send e-mail, etc.
    
    Write-Log "AfterCreate completed successfully"
    exit 0                              # explicit success
}
catch {
    Write-Log "ERROR: $($_.Exception.Message)"
    Write-Log $_ | Out-String
    exit 1                              # bubble failure to IQService
}
finally {
    Write-Log "----------------------------------------------------`n"
}

Key take-aways

What Why it matters
$ErrorActionPreference = 'Stop' Forces any problem to jump into the catch block where you can log details and decide the exit code intentionally.
exit 0 / exit 1 Never rely on PowerShell’s implicit exit logic; IQService checks the native process exit code.
Import-Module ActiveDirectory inside try If the module isn’t present the script fails before touching AD objects, and you get a clear error in the log.
One Add-Type Loading the same assembly twice throws a (non-terminating) warning that still yields exit-code 1 when $ErrorActionPreference is Stop.
Run the script by hand In a PowerShell console on the IQService host, simulate IQService by setting $env:REQUEST = "<dummy/>"; .\AfterCreateScript.ps1 and watch for errors.

Common root causes & remedies

Symptom in IQService log Likely root cause Fix
Cannot load ActiveDirectory RSAT tools missing on the IQService host, or the service account lacks module files in $env:PSModulePath Install “Active Directory Domain Services and LDAP Tools” (RSAT) and restart the IQService service.
Access denied writing log File ACL denies write to the service account (e.g., Local System or a dedicated AD account) Grant Modify on the folder, or move logs to a location the account can write.
Execution policy error Host still uses the default Restricted policy Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope LocalMachine (or sign the script).
Assembly already loaded Duplicate Add-Type Remove the second call or wrap it in `if (-not ([AppDomain]::CurrentDomain.GetAssemblies() where {$_.GetName().Name -eq ‘Utils’})) { … }`.

Next steps

  1. Deploy the hardened template and watch the IQService debug log (iqservice-debug.log) plus your own AfterCreate_YYYYMMDD.log.
  2. Once you consistently get exit 0, re-enable your real post-provisioning logic inside the marked section.
  3. Remember that any non-zero exit code will cause IdentityIQ to roll back the AD account (delete it) and mark the provisioning task as Failed.

Following these guidelines will let you verify exactly when the script runs, capture a full error trail, and keep IQService satisfied with a clean exit code.

Hope this helps!!!

What do you mean by script being created from my account?

You logged in to IQService using your account and created PowerShell script, service account used in to connect IQService at SailPoint side is unable to execute the same script.

@KRM7 Ah no, there is no additional script, all the logic is in the AfterCreate Rule. The Svc Account that runs IQService is the same configured on the IQService Source and has Modify permissions on the IQservice folder.
ExecutionPolicy was set as Restricted which I enabled now and removed the second Add-type -path utils.dll; and the Script is now executed. However, I was wondering are there any further best practices for native rules? I will add the hardened rule mentioned above by @officialamitguptaa , thanks!

@tamalika01 -

Glad it helps. Mark the post as solution.

Thanks!!!