I have a PowerShell script that checks whether an email address already exists in Microsoft Entra ID (Office365) and returns true or false. Can I convert this script to a Before/After Script and save the result to the identity attribute?
Short answer: you can absolutely run that email-existence check in an IQService Before/After Script—but you cannot write directly to an Identity attribute from those scripts. In Identity Security Cloud (ISC), identity attributes are computed from source account attributes. So the reliable pattern is:
-
run your check in a Before/After Script (PowerShell via IQService),
-
write the result into a writable account attribute on the target source (e.g., Entra ID/AD extension attribute), and
-
map that account attribute → identity attribute in the Identity Profile so it persists on the identity.
Below is a crisp playbook you can follow.
What works vs. what doesn’t
-
Works: Before/After Script modifies the provisioning plan and/or updates the target account (e.g., AD or Entra ID) by setting an attribute.
-
Works: Map that target account attribute to an identity attribute (in Identity Profile → Mappings) so it shows on the identity after aggregation.
-
Doesn’t: Writing an identity attribute directly from PowerShell or the script. Identities in ISC are derived from sources (authoritative + correlating) and transforms/rules—not written by IQService scripts.
Two implementation paths
Option A — “Plan-only” (Before Script modifies plan → target attribute)
Use a Before Provisioning Script on the target source (e.g., AD/Entra). Your script checks the email in Microsoft 365 (via Graph), then adds an AttributeRequest into the provisioning plan to stamp a boolean flag on the account (e.g., extensionAttribute15 = "EmailExists=True").
Later, map extensionAttribute15 → identity attribute emailExistsInM365 in Identity Profile. After the account is created/updated and aggregated, your identity shows the value.
Skeleton (Before Script)
# Assumptions:
# - Graph App Reg exists; you have clientId/tenantId/secret or cert
# - You check primary SMTP in $requestedEmail (from plan)
Add-Type -Path "C:\SailPoint\IQService\Utils.dll"
function Add-PlanAttribute([SailPoint.Utils.Objects.AccountRequest]$plan, [string]$name, $value) {
$ar = New-Object SailPoint.Utils.Objects.AttributeRequest
$ar.Name = $name
$ar.Value = $value
$ar.Operation = "Set"
$plan.AttributeRequests.Add($ar) | Out-Null
}
# -- Build AccountRequest from env:Request
$sReader = New-Object System.IO.StringReader([string]$env:Request)
$xmlReader = [System.Xml.XmlTextReader]([SailPoint.Utils.Xml.XmlUtil]::getReader($sReader))
$plan = New-Object SailPoint.Utils.Objects.AccountRequest($xmlReader)
# -- Pull the email you want to test from incoming plan
$requestedEmail = ($plan.AttributeRequests | Where-Object { $_.Name -eq "mail" -or $_.Name -eq "userPrincipalName" } | Select-Object -First 1).Value
# -- Call Graph (pseudo: use MSAL or Graph SDK/REST)
$exists = $false
try {
# Example REST (pseudo): GET https://graph.microsoft.com/v1.0/users?$count=true&$filter=proxyAddresses/any(p:p eq 'smtp:<email>') or mail eq '<email>' or userPrincipalName eq '<email>'
# ... set $exists = $true or $false
} catch {
throw "Graph email-existence check failed: $($_.Exception.Message)"
}
# -- Stamp result into a writable account attribute
# Choose an attribute you own, e.g. extensionAttribute15 in Entra/AD
Add-PlanAttribute -plan $plan -name "extensionAttribute15" -value ("EmailExists={0}" -f $exists)
# -- Return modified plan to IQService
if (-not $args -or [string]::IsNullOrWhiteSpace($args[0])) { throw "Missing output path from IQService." }
$plan.ToXml() | Out-File $args[0] -Encoding UTF8
Pros: Everything in one provisioning transaction; simple and fast.
Cons: You need a writable target attribute (agree with AD/Entra team which attribute to use).
Option B — “After update on the account” (After Script writes directly to directory)
Same check, but run it as an After Provisioning Script and directly write the result to the account using the provider’s tools/API (e.g., Set-ADUser for on-prem AD, Graph PATCH for Entra). This is handy if you prefer explicit write/confirmation after the account exists.
Pros: You can confirm the account exists first; less chance of plan/target mismatch.
Cons: Separate call; must handle retries/transients.
Hooking it into the identity
-
Pick the attribute you’ll set on the account
-
AD: e.g.,
extensionAttribute15(or any custom attribute you control) -
Entra ID: define a Directory Schema Extension (or use existing
onPremisesExtensionAttributes) and write it.
-
-
Map it in ISC
-
Go to Identity Profiles → (your profile) → Mappings.
-
Map the source account attribute (e.g.,
extensionAttribute15) → a new identity attribute (e.g.,emailExistsInM365, type: string or boolean). -
Save + Re-aggregate (or wait for next aggregation) to see it reflected on identities.
-
-
(Optional) Transform to boolean
If you wrote a string likeEmailExists=True, add a Transform to coerce to a booleantrue/falseidentity attribute.
Practical tips & safeguards
-
Do the Graph check efficiently
-
Prefer a single Graph filter that matches UPN, mail, and proxyAddresses (since aliases often live there).
-
Implement exponential backoff for 429 (throttling) and 5xx responses.
-
Cache short-lived tokens; don’t auth for every single call.
-
-
Timeouts and error propagation
-
Fail fast and throw on network/API failures so IQService marks the op as failed when the value is critical to your flow.
-
If the value is non-blocking metadata, log the error and skip writing rather than failing the whole provisioning.
-
-
Idempotency
-
Only add the plan AttributeRequest if the value is changing.
-
In an After Script, read current attribute and no-op if already correct.
-
-
Security
-
Store Graph client secret/cert securely (Windows DPAPI-protected file, or run IQService under a gMSA that can read a secured key store).
-
Scope Graph permissions to least privilege (e.g.,
User.Read.Allfor reads).
-
-
Observability
-
Log: identity ID, target source, requested email, decision, and correlation ID from Graph.
-
Avoid logging raw tokens or PII beyond what’s necessary for audit.
-
-
Where to attach the script
- Attach this script to the same source whose account you are stamping (AD/Entra), so that the attribute mapping is straightforward and aggregation brings it into the identity.
When you don’t need to persist
If you only need the “email exists?” decision at provisioning time (e.g., to branch logic), you can keep it transient: write it to the plan (e.g., additionalAttributes) and consume it in the same transaction—skip mapping. But if you want to see it on the identity later, the source-attribute-to-identity-attribute mapping is the supported route.
Cheers!!!
Thank you very much for your reply.
This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.