Sailpoint to powershell $env:Request and $env and other variable showing empty

Which IIQ version are you inquiring about?

8.3p3

Please share any images or screenshots, if relevant.

All variable which we send from running powershell rule like AccountRequest are showing empty in powershell rule. Even though powershell getting called. We are using 8.3p3 and we are windows 2022 , it is working on windows 2012

Please share any other relevant files that may be required (for example, logs).

refer logic Running Powershell directly via the IQService - Compass
Everything is same.

Share all details about your problem, including any error messages you may have received.

We are using windows 2022 and calling powershell from rpcservice , no error showing in iiq logs but when it call powershell rule, none of the vairbale like $env or account request or below attribute having any value. it seems all the content are removed.
Note : Same thing working on windows 2012

$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;

@Manishsharm -

This is almost always about how IQService is launching PowerShell on that Windows 2022 box (path/bitness), version mismatches, or policy/PowerShell-mode changes that prevent the expected environment variables from being injected.

Below is a focused “find & fix” runbook you can execute end-to-end. I’ve put the highest-probability fixes first.


1) Confirm you’re really launching Windows PowerShell 5.1 (64-bit)

IdentityIQ’s RPCService/IQService populates the request into process environment variables (e.g., $env:Request) and, for non-OO scripts, creates SP_* variables. This is explicitly how IQService is designed to pass the AccountRequest/XML to your PowerShell script. (Running Powershell directly via the IQService, Writing a Script)

On Windows Server 2022, some hosts have PowerShell 7 installed and in PATH earlier than Windows PowerShell 5.1. If your rule calls a generic powershell.exe (or even pwsh) incorrectly, you can end up in the wrong host, or the 32-bit subsystem.

What to do (on the IQService host):

  • In your PowerShell Rule (or connector rule), call the absolute 64-bit path:

    C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
    
    

    (Do not rely on PATH.) SailPoint’s own troubleshooting notes recommend using the absolute path to PowerShell to avoid PATH/host confusion. (Troubleshooting)

  • Avoid SysWOW64 (that’s 32-bit). If IQService or your script somehow hits C:\Windows\SysWOW64\WindowsPowerShell\v1.0\powershell.exe, the environment injection may not line up with your script expectations.

Quick verification snippet (drop at the top of your PS rule/script):

"$PSVersionTable"
[Environment]::Is64BitProcess
$PSHOME
(Get-Process -Id $PID).MainModule.FileName

You want PSVersion 5.1.x, Is64BitProcess = True, and the path under System32.


2) Make sure IQService version matches your IdentityIQ version/patch

IQService must match the IdentityIQ server version (including patches). An out-of-date IQService on a newer OS (Server 2022) can behave oddly, including failing to inject the process environment block expected by your script. Re-installing the current IQService build that matches your IIQ patch often resolves “vars not there” symptoms. (Install and Register the IQService for Use with Windows)

Also note SailPoint continues to update IQService (even recently), so grabbing the latest for your major/minor and re-registering can help—especially on newer OS builds like Windows Server 2022. (Introduction to IQService)


3) Prove the env injection path works (no IIQ involved)

Run this on the IQService host in an elevated Windows PowerShell 5.1 console:

# Simulate what IQService does
$env:Request = "<AccountRequest><nativeIdentity>dummy</nativeIdentity></AccountRequest>"

# Your parsing code (unchanged)
$sReader      = New-Object System.IO.StringReader([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

$requestObject | Format-List *   # Should NOT be empty
$env:Request.Length              # Should show a non-zero value

  • If $env:Request shows a value here, your parsing code is fine. Your problem is therefore how IQService is launching PowerShell (step 1) or the IQService build (step 2).

  • If it fails with .Utils types not found, ensure your script is executed in the same way IQService runs it (object-oriented example from the wiki assumes the SailPoint client types are available to the process launched by IQService). The wiki and docs outline how that request is provided and parsed in OO vs non-OO styles.


4) Check for Constrained Language Mode (CLM) / WDAC

On hardened Server 2022 builds with Windows Defender Application Control / Device Guard, PowerShell can be forced into ConstrainedLanguage. That can block New-Object with custom types and assembly usage (your Sailpoint.Utils.objects.* calls). Even if $env:Request exists, object creation silently fails and your downstream objects end up $null, which looks like “the content is removed”.

Test:

$ExecutionContext.SessionState.LanguageMode

If you see ConstrainedLanguage, ask security to allow this script path/signing policy or run the script in FullLanguage context for IQService. (This is a Windows policy issue, not SailPoint.) Microsoft’s CLM restricts .NET type usage.


5) Verify the rule is not spawning a child process that loses the env

IQService populates the environment of the process it launches. If your rule/script immediately calls Start-Process, Invoke-Command, or remotes to another session, that child context won’t have the injected $env:Request unless you explicitly pass it.

If you must spawn, pass the data explicitly, e.g.:

$req = $env:Request
Start-Process -FilePath "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" `
  -ArgumentList "-NoProfile -Command `"param([string]`$r) ...`"", $req"

Or avoid spawning—do the work in the original process that IQService started.


6) Try the non-OO variable names as a sanity check

IQService also creates environment variables in the form SP_<OPERATION>_<NAME> and SP_APP_<NAME> for non-OO scripts. Quick smoke test at the script start:

Get-ChildItem Env: | Where-Object Name -like 'SP_*' | Sort-Object Name
$env:SP_NativeIdentity

If none of these exist either, it strongly points to PowerShell host mismatch or IQService not injecting (steps 1 & 2).


7) Turn on IQService troubleshooting basics

  • Confirm IQService logs and that your rule actually triggers on 2022.

  • Double-check PowerShell path configured in your rule; SailPoint docs explicitly suggest trying the absolute powershell.exe path during troubleshooting.

  • Ensure network/TLS changes in newer IQService builds aren’t blocking the script call (recent IQService versions enforce TLS defaults). (Installing and Registering IQService)


8) Known-good sample (minimal dump)

Add this at the top of the script to capture state the moment IQService launches it:

"=== IQService PS Host Info ==="
$PSVersionTable
"64-bit? " + [Environment]::Is64BitProcess
"PSHOME : $PSHOME"
"Proc  : " + (Get-Process -Id $PID).MainModule.FileName

"=== Language Mode ==="
$ExecutionContext.SessionState.LanguageMode

"=== Env smoke ==="
"REQUEST length : " + (($env:Request).ToString()).Length
Get-ChildItem Env: | Where Name -like 'SP_*' | Sort Name

If REQUEST length is 0 and there are no SP_* variables, you’re not in the intended process (wrong PowerShell path/bitness) or IQService didn’t inject due to version/policy issues.


Why this worked on Windows 2012 but not on 2022

  • Newer servers often have PowerShell 7 alongside 5.1; PATH differences and service redirection (32-bit vs 64-bit) pop up during migrations.

  • Security baselines on 2022 frequently enable Application ControlConstrainedLanguage. That breaks your New-Object usage and makes it look like nothing comes through.

  • Older IQService builds may not play nicely on newer OSes; SailPoint requires matching IQService/IIQ versions and recommends the absolute PowerShell path for script launching. (Install and Register the IQService for Use with Windows)


TL;DR — the quickest fix path

  1. Change your rule to call:
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe

(not powershell.exe or pwsh.exe).

  1. Upgrade/reinstall IQService to match your IIQ patch on that 2022 host.

  2. Check LanguageMode; if ConstrainedLanguage, get an allow policy for the script/assemblies or run in FullLanguage.

  3. Run the env dump snippet above and confirm $env:Request length > 0 and/or SP_* variables appear. If they do, your original parsing code will work as on 2012

Thanks

hi Amit,

I have validate all the thing , Language mode is fulllanguage, and other parameter also same.
Even i can see $env.Request is showing once i have added complete powershell.exe path which is mentioned.
I am still seeing the problem when we use below line as it always show null,nothing printing it seems New-Object not working properly. So let us know what else we can check. We have 8.3p3 so everything is compatible as well. So let us know what else we can check
$sReader = New-Object System.IO.StringReader([string]$env:Request)$xmlReader = [System.Xml.XmlTextReader]([sailpoint.Utils.xml.XmlUtil]::getReader($sReader))$requestObject= New-Object Sailpoint.Utils.objects.AccountRequest($xmlReader)

Hi @Manishsharm -

If $env:Request is now definitely populated (after forcing the full 64-bit powershell.exe path) but $requestObject stays $null, the usual culprit is that the SailPoint Utils assembly isn’t actually loaded in that PowerShell process on your Windows 2022 host. On older hosts it’s easy to “get lucky” because of working-directory/probing behavior; on 2022/.NET 4.8 you often have to explicitly load Utils.dll before you can New-Object Sailpoint.Utils.objects.AccountRequest(...). SailPoint’s own samples show doing exactly that with Add-Type -Path ...\Utils.dll. (Writing a Script)

Below is a tight, copy-paste block that (1) resolves the actual IQService install directory, (2) unblocks and loads Utils.dll, (3) sanity-checks the types are visible, and (4) constructs the objects without using the XmlUtil helper (to avoid one more dependency while we debug):

# Fail fast and log real errors (IQService can swallow non-terminating errors otherwise)
$ErrorActionPreference = 'Stop'

# 1) Find IQService home and Utils.dll robustly from the service definition
$svc = Get-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Services\IQService' -Name ImagePath
$svcPath = ($svc.ImagePath -replace '^"|"$','')                     # strip quotes
$iqHome  = Split-Path $svcPath                                      # e.g. C:\SailPoint\IQService
$utils   = Join-Path $iqHome 'Utils.dll'

# 2) Unblock and load Utils.dll (unsigned/“downloaded” DLLs can be blocked on 2022)
if (Get-Item $utils -Stream Zone.Identifier -ErrorAction SilentlyContinue) { Unblock-File $utils }
Add-Type -Path $utils

# 3) Prove the SailPoint types are now visible
if (-not [Type]::GetType('Sailpoint.Utils.objects.AccountRequest', $false)) {
  throw "Sailpoint.Utils.objects.AccountRequest type not visible. Loaded from: $utils"
}

# 4) Build readers without XmlUtil to reduce moving parts while debugging
$sReader   = New-Object System.IO.StringReader([string]$env:Request)
$xmlReader = New-Object System.Xml.XmlTextReader($sReader)

# 5) Construct the request/result objects
$requestObject = New-Object 'Sailpoint.Utils.objects.AccountRequest' ($xmlReader)

# Optional: dump a quick proof
"Request XML length: $([string]$env:Request).Length"
"RequestObject type : " + ($requestObject.GetType().FullName)

Why this usually fixes it

  • Utils.dll must be loaded for those Sailpoint.Utils.* types to exist. Without it, New-Object has nothing to construct and—depending on error handling—can look like “it returns null”. SailPoint’s samples and docs explicitly Add-Type -Path ...\Utils.dll before using AccountRequest/ServiceResult.

  • On Server 2022/.NET 4.8, default probing is less forgiving. If the PS working directory isn’t the IQService bin (very common when you hard-pin the powershell.exe path), the assembly won’t auto-resolve, so explicit path loading is required. (SailPoint docs and community threads show Add-Type -Path "C:\SailPoint\IQService\Utils.dll" patterns.) (Powershell script : Accessing attributes within accountRequest)

  • Also check for Windows “blocked” file state on Utils.dll (Zone.Identifier). That’s bitten a lot of people post-upgrade on hardened 2022 images; unblocking resolves the silent load failure. (We are seeing an exception while provisioning an identity to AD after the recent IQ service upgrade)

If you still hit issues after Add-Type

Run these quick probes to pinpoint the exact failure:

# 1) Is the SailPoint assembly actually loaded?
[AppDomain]::CurrentDomain.GetAssemblies() | Where-Object FullName -match 'Utils' |
  Select-Object FullName, Location

# 2) Do we see the types?
[AppDomain]::CurrentDomain.GetAssemblies() |
  ForEach-Object { $_.GetTypes() } |
  Where-Object FullName -like 'Sailpoint.*' |
  Sort-Object FullName

# 3) Does the XML parse natively? (rule out truncation/bad XML)
try { [xml]$reqXml = $env:Request; $reqXml.DocumentElement.Name } catch { $_ | fl * -Force; throw }

# 4) How big is Request? (environment vars over ~32K can get you into trouble)
([string]$env:Request).Length

  • If (1)/(2) show no SailPoint types, the assembly is not loading (wrong path, blocked DLL, or policy).

  • If (3) fails, your request XML is malformed/truncated (less likely now that $env:Request prints, but worth checking).

  • If (4) shows a very large value (tens of thousands of chars), you may be bumping environment-block limits; consider a non-OO fallback (use the SP_* request variables, which IQService emits for non-OO scripts) to avoid parsing the full XML. (Before After Script)

Bonus: keep XmlUtil if you prefer it

Once Utils.dll is loading cleanly, you can go back to your original style:

$sReader   = New-Object System.IO.StringReader([string]$env:Request)
$xmlReader = [sailpoint.Utils.xml.XmlUtil]::getReader($sReader)
$requestObject = New-Object Sailpoint.Utils.objects.AccountRequest($xmlReader)
$resultObject  = New-Object Sailpoint.Utils.objects.ServiceResult

(But verify the type exists first; the reflection snippet above will tell you.)


TL;DR

On Windows 2022, explicitly load Utils.dll before New-Object Sailpoint.Utils.objects.AccountRequest(...), ensure the DLL isn’t blocked, and confirm the types are visible—then your existing code will work the same as it did on 2012. SailPoint’s docs and examples show this Add-Type -Path ...\Utils.dll step as required.

If you paste the output of the 4 probe snippets (assemblies/types/XML/length), I’ll tell you exactly which link in the chain is breaking.

Thanks

these below three line fix our issue

4) Build readers without XmlUtil to reduce moving parts while debugging $sReader = New-Object System.IO.StringReader([string]$env:Request) $xmlReader = New-Object System.Xml.XmlTextReader($sReader) # 5) Construct the request/result objects $requestObject = New-Object ‘Sailpoint.Utils.objects.AccountRequest’ ($xmlReader)