Provider Reference - IdLE.Provider.AD (Active Directory)
Summary
- Module:
IdLE.Provider.AD - Provider kind:
Identity+Entitlement (Groups) - Targets: On-premises Windows Active Directory domains
- Status: Built-in
- Runs on: Windows only (requires RSAT /
ActiveDirectoryPowerShell module) - Default safety: destructive operations are opt-in (e.g. delete)
When to use this provider
Use this provider when your workflow needs to manage on-premises AD user accounts, such as:
- Joiner: create/update AD users and set baseline attributes
- Mover: update org attributes and adjust managed group memberships
- Leaver: disable accounts and apply offboarding changes
Non-goals:
- Configuring connectivity/authentication itself (handled via your runtime context and the AuthSessionBroker)
- Managing non-user object types (computers, GPOs, etc.)
Getting started
Requirements
- Windows host with RSAT /
ActiveDirectorymodule available - Permissions sufficient for the operations you plan to run (create/modify users, move OUs, manage group membership)
Install (PowerShell Gallery)
Install-Module IdLE.Provider.AD -Scope CurrentUser
Import
Import-Module IdLE.Provider.AD
Quickstart
Minimal provider creation (safe defaults):
$provider = New-IdleADIdentityProvider
Typical workflow usage:
- Set the provider alias in your workflow (
With.Provider = 'Directory'is a common convention) - Reference your auth session via
With.AuthSessionNamein steps (recommended for multi-role scenarios)
Authentication
- By default, the AD provider uses the run-as identity (integrated authentication).
- For explicit runtime credential selection, use the AuthSessionBroker and pass an
AuthSessionvia step configuration:With.AuthSessionNameWith.AuthSessionOptions(optional)
Keep credentials/secrets out of workflow files. Use the broker/host to resolve them at runtime.
Supported Step Types
The AD provider supports the common identity lifecycle and entitlement operations used by these step types:
| Step type | Typical use | Notes |
|---|---|---|
IdLE.Step.CreateIdentity | Create user (if missing) | Identity can be addressed by GUID, UPN, or sAMAccountName |
IdLE.Step.EnsureAttributes | Set/update AD user attributes | Use placeholders from your request input |
IdLE.Step.DisableIdentity | Disable user account | Typical leaver action |
IdLE.Step.EnableIdentity | Enable user account | Rare (rehire) |
IdLE.Step.MoveIdentity | Move user to another OU | Useful for leaver or org changes |
IdLE.Step.EnsureEntitlement | Ensure group memberships | AD entitlements are groups |
IdLE.Step.RemoveEntitlement | Remove managed groups | Prefer explicit allow-lists / managed lists |
IdLE.Step.DeleteIdentity | Delete user | Opt-in via -AllowDelete (see Configuration) |
Context Resolvers
This provider supports Context Resolvers for the allowlisted, read-only capabilities below.
Capability: IdLE.Identity.Read
Writes to scoped path: Request.Context.Providers.<ProviderAlias>.<AuthSessionKey>.Identity.Profile
Engine-defined View: Request.Context.Views.Identity.Profile
Type: PSCustomObject (PSTypeName = 'IdLE.Identity')
Top-level properties:
| Property | Type | Notes |
|---|---|---|
PSTypeName | string | Always IdLE.Identity. |
IdentityKey | string | The identity key used by the workflow (GUID/UPN/sAMAccountName). |
Enabled | bool | Derived from AD user Enabled. |
Attributes | hashtable | Key/value bag; keys are strings; values are typically string. |
Attributes keys populated by this provider (when present on the AD user object):
| Attribute key | Type |
|---|---|
GivenName | string |
Surname | string |
DisplayName | string |
Description | string |
Department | string |
Title | string |
EmailAddress | string |
UserPrincipalName | string |
sAMAccountName | string |
DistinguishedName | string |
Attribute access: Profile attributes are nested under the
Attributeskey. UseRequest.Context.Views.Identity.Profile.Attributes.DisplayNamein Conditions (or the scopedRequest.Context.Providers.<ProviderAlias>.<AuthSessionKey>.Identity.Profile.Attributes.DisplayName), notRequest.Context.Views.Identity.Profile.DisplayName.
Capability: IdLE.Entitlement.List
Writes to scoped path: Request.Context.Providers.<ProviderAlias>.<AuthSessionKey>.Identity.Entitlements
Engine-defined View: Request.Context.Views.Identity.Entitlements
Type: object[] (array of PSCustomObject, PSTypeName = 'IdLE.Entitlement')
Each element represents one AD group membership:
| Property | Type | Notes |
|---|---|---|
PSTypeName | string | Always IdLE.Entitlement. |
Kind | string | Always Group. |
Id | string | AD group DistinguishedName. |
Notes:
- The output paths are fixed by the engine and cannot be changed.
- Each entry is automatically annotated with
SourceProviderandSourceAuthSessionNamemetadata. - Use the global View (
Request.Context.Views.Identity.Entitlements) in Conditions when you don't need to filter by provider. Use the scoped path when you need results from a specific provider only. - See Context Resolvers for the full path reference.
Configuration
Provider factory
# Safe defaults
$provider = New-IdleADIdentityProvider
# Opt-in: allow identity deletion (advertises IdLE.Identity.Delete)
$provider = New-IdleADIdentityProvider -AllowDelete
Options reference
| Option | Type | Default | Meaning |
|---|---|---|---|
AllowDelete | bool | false | Enables identity deletion capability (opt-in for safety) |
PasswordGenerationFallbackMinLength | int | 24 | Fallback minimum length if domain policy cannot be read |
PasswordGenerationRequireUpper | bool | true | Require uppercase in generated passwords (fallback) |
PasswordGenerationRequireLower | bool | true | Require lowercase in generated passwords (fallback) |
PasswordGenerationRequireDigit | bool | true | Require digit in generated passwords (fallback) |
PasswordGenerationRequireSpecial | bool | true | Require special char in generated passwords (fallback) |
Operational behavior
- Identity addressing: GUID (ObjectGuid), UPN, or sAMAccountName (fallback)
- Safety defaults: deletion is disabled unless you pass
-AllowDelete - Entitlements: groups only (
Kind='Group')
Attribute handling
CreateIdentity attributes
IdLE.Step.CreateIdentity maps attributes to New-ADUser named parameters. Attributes not listed in the named parameter set can be passed via the OtherAttributes container using their LDAP attribute names as keys.
@{
Name = 'Create AD user'
Type = 'IdLE.Step.CreateIdentity'
With = @{
IdentityKey = '{{Request.IdentityKeys.sAMAccountName}}'
Provider = 'AD'
Attributes = @{
GivenName = '{{Request.GivenName}}'
Surname = '{{Request.Surname}}'
OtherAttributes = @{
extensionAttribute1 = '{{Request.Department}}'
}
}
}
}
Note: Keys in
OtherAttributesmust be valid LDAP attribute names (e.g.extensionAttribute1,employeeType), not PowerShell parameter names.
EnsureAttributes attributes
IdLE.Step.EnsureAttributes maps attributes to Set-ADUser named parameters. Setting an attribute to $null clears the value from the directory. Attributes not listed in the named parameter set can be set or cleared via the OtherAttributes container using their LDAP attribute names as keys.
Custom LDAP attributes (via OtherAttributes container):
@{
Name = 'Clear phone numbers'
Type = 'IdLE.Step.EnsureAttributes'
With = @{
IdentityKey = '{{Request.IdentityKeys.sAMAccountName}}'
Provider = 'AD'
Attributes = @{
MobilePhone = $null # Clears the mobile attribute
OfficePhone = $null # Clears the telephoneNumber attribute
OtherAttributes = @{
extensionAttribute1 = 'NewValue' # Sets custom LDAP attribute
employeeType = $null # Clears custom LDAP attribute
}
}
}
}
Note: Keys in
OtherAttributesmust be valid LDAP attribute names (e.g.mobile,telephoneNumber,extensionAttribute1), not PowerShell parameter names. Setting a key to$nullclears that LDAP attribute.
Examples
These are the canonical, doc-embed friendly templates for AD. Mover scenarios are intentionally folded into Joiner/Leaver (as optional patterns) to keep the template set small.
@{
Name = 'Complete Joiner - EntraID + ExchangeOnline Offboarding'
LifecycleEvent = 'Joiner'
Description = 'AD joiner workflow template (safe defaults).'
Steps = @(
# --- Identity creation / baseline ---
@{
Type = 'IdLE.Step.CreateIdentity'
Name = 'Create identity (if missing)'
With = @{
# Required by the provider: which auth session to use
AuthSessionName = 'Directory'
# Provider-specific: identify the target identity
# The exact key names depend on provider contracts; keep it consistent with your provider docs.
IdentityKey = '{{Request.Intent.SamAccountName}}'
# Optional: initial attributes that are commonly required
Attributes = @{
GivenName = '{{Request.Intent.GivenName}}'
Surname = '{{Request.Intent.Surname}}'
DisplayName = '{{Request.Intent.DisplayName}}'
}
}
}
@{
Type = 'IdLE.Step.EnsureAttributes'
Name = 'Ensure core attributes'
With = @{
AuthSessionName = 'Directory'
IdentityKey = '{{Request.Intent.SamAccountName}}'
Attributes = @{
Mail = '{{Request.Intent.Mail}}'
Department = '{{Request.Intent.Department}}'
Title = '{{Request.Intent.Title}}'
Company = '{{Request.Intent.Company}}'
Office = '{{Request.Intent.Office}}'
Manager = '{{Request.Intent.ManagerSamAccountName}}'
TelephoneNumber = '{{Request.Intent.Phone}}'
}
}
}
@{
Type = 'IdLE.Step.EnsureEntitlement'
Name = 'Ensure baseline group membership (1)'
With = @{
AuthSessionName = 'Directory'
IdentityKey = '{{Request.Intent.SamAccountName}}'
Entitlement = @{
Kind = 'Group';
Id = '{{Request.Intent.BaselineGroups.0}}';
DisplayName = '{{Request.Intent.BaselineGroups.0}}'
}
State = 'Present'
}
},
@{
Type = 'IdLE.Step.EnsureEntitlement'
Name = 'Ensure baseline group membership (2)'
With = @{
AuthSessionName = 'Directory'
IdentityKey = '{{Request.Intent.SamAccountName}}'
Entitlement = @{
Kind = 'Group';
Id = '{{Request.Intent.BaselineGroups.1}}';
DisplayName = '{{Request.Intent.BaselineGroups.1}}'
}
State = 'Present'
}
}
# --- Optional: Mover patterns (disabled by default) ---
# Use one of these approaches:
# A) Guard execution via a flag (preferred)
# B) Keep steps commented out and enable when needed
@{
Type = 'IdLE.Step.EnsureAttributes'
Name = 'Mover: update org attributes (optional)'
With = @{
# Guard by convention: only run when request indicates mover
Condition = '{{Request.Intent.IsMover}}'
AuthSessionName = 'Directory'
IdentityKey = '{{Request.Intent.SamAccountName}}'
Attributes = @{
Department = '{{Request.Intent.NewDepartment}}'
Title = '{{Request.Intent.NewTitle}}'
Office = '{{Request.Intent.NewOffice}}'
Manager = '{{Request.Intent.NewManagerSamAccountName}}'
Description = 'Moved on {{Request.Execution.Timestamp}}'
}
}
}
@{
Type = 'IdLE.Step.EnsureEntitlement'
Name = 'Mover: adjust group memberships (optional, baseline 1)'
With = @{
Condition = '{{Request.Intent.IsMover}}'
AuthSessionName = 'Directory'
IdentityKey = '{{Request.Intent.SamAccountName}}'
# Optional: baseline + department-specific groups.
Entitlement = @{ Kind = 'Group'; Id = '{{Request.Intent.BaselineGroups.0}}' }
State = 'Present'
}
}
@{
Type = 'IdLE.Step.EnsureEntitlement'
Name = 'Mover: adjust group memberships (optional, baseline 2)'
With = @{
Condition = '{{Request.Intent.IsMover}}'
AuthSessionName = 'Directory'
IdentityKey = '{{Request.Intent.SamAccountName}}'
# Optional: baseline + department-specific groups.
Entitlement = @{ Kind = 'Group'; Id = '{{Request.Intent.BaselineGroups.1}}' }
State = 'Present'
}
}
@{
Type = 'IdLE.Step.EnsureEntitlement'
Name = 'Mover: adjust group memberships (optional, department 1)'
With = @{
Condition = '{{Request.Intent.IsMover}}'
AuthSessionName = 'Directory'
IdentityKey = '{{Request.Intent.SamAccountName}}'
# Optional: baseline + department-specific groups.
Entitlement = @{ Kind = 'Group'; Id = '{{Request.Intent.DepartmentGroups.0}}' }
State = 'Present'
}
}
@{
Type = 'IdLE.Step.EnsureEntitlement'
Name = 'Mover: adjust group memberships (optional, department 2)'
With = @{
Condition = '{{Request.Intent.IsMover}}'
AuthSessionName = 'Directory'
IdentityKey = '{{Request.Intent.SamAccountName}}'
# Optional: baseline + department-specific groups.
Entitlement = @{ Kind = 'Group'; Id = '{{Request.Intent.DepartmentGroups.1}}' }
State = 'Present'
}
}
)
}
@{
Name = 'AD - Leaver (offboarding)'
LifecycleEvent = 'Leaver'
Description = 'Disables an AD identity and applies offboarding changes. Includes notes for mover-to-leaver transitions.'
Steps = @(
@{
Type = 'IdLE.Step.DisableIdentity'
Name = 'Disable identity'
With = @{
AuthSessionName = 'Directory'
IdentityKey = '{{Request.Intent.SamAccountName}}'
Reason = '{{Request.Intent.LeaverReason}}'
}
}
@{
Type = 'IdLE.Step.EnsureAttributes'
Name = 'Stamp offboarding attributes'
With = @{
AuthSessionName = 'Directory'
IdentityKey = '{{Request.Intent.SamAccountName}}'
Attributes = @{
Description = 'Leaver (CorrelationId: {{Request.CorrelationId}}) - {{Request.Intent.LeaverReason}}'
}
}
}
# Optional, use with caution:
# Removing groups can break business processes unexpectedly.
# PruneEntitlementsEnsureKeep removes all groups except the keep set AND ensures
# explicit Keep items are present. Use PruneEntitlements if you only need removal.
@{
Type = 'IdLE.Step.PruneEntitlementsEnsureKeep'
Name = 'Prune group memberships (leaver)'
Condition = @{ Equals = @{ Path = 'Request.Intent.PruneGroups'; Value = $true } }
With = @{
AuthSessionName = 'Directory'
IdentityKey = '{{Request.Intent.SamAccountName}}'
Kind = 'Group'
# Explicitly retain this group and ensure it is present after pruning.
Keep = @(
@{ Kind = 'Group'; Id = '{{Request.Intent.LeaverRetainGroupDn}}' }
)
# Pattern-based retention is not supported by PruneEntitlementsEnsureKeep. Use a
# separate IdLE.Step.PruneEntitlements step earlier in the workflow if you need to
# preserve wildcard-matched memberships without granting them.
}
}
# Alternatively, remove individual managed group memberships one by one:
# Prefer PruneEntitlements above for bulk removal scenarios.
@{
Type = 'IdLE.Step.EnsureEntitlement'
Name = 'Remove managed group memberships (optional, item 1)'
With = @{
Condition = @{ Equals = @{ Path = 'Request.Intent.RemoveGroups'; Value = $true } }
AuthSessionName = 'Directory'
IdentityKey = '{{Request.Intent.SamAccountName}}'
# Only remove what you explicitly manage via IdLE.
Entitlement = @{
Kind = 'Group';
Id = '{{Request.Intent.ManagedGroupsToRemove.0}}'
}
State = 'Absent'
}
}
@{
Type = 'IdLE.Step.EnsureEntitlement'
Name = 'Remove managed group memberships (optional, item 2)'
With = @{
Condition = @{ Equals = @{ Path = 'Request.Intent.RemoveGroups'; Value = $true } }
AuthSessionName = 'Directory'
IdentityKey = '{{Request.Intent.SamAccountName}}'
# Only remove what you explicitly manage via IdLE.
Entitlement = @{
Kind = 'Group';
Id = '{{Request.Intent.ManagedGroupsToRemove.1}}'
}
State = 'Absent'
}
}
# --- Mover-to-leaver transition notes (operational) ---
# Common approach:
# - Day 0: Disable + stamp description (safe, minimal risk)
# - Day N: Remove managed groups + move to Disabled OU (explicit opt-in)
@{
Type = 'IdLE.Step.MoveIdentity'
Name = 'Move to Disabled OU (optional)'
With = @{
Condition = @{ Equals = @{ Path = 'Request.Intent.MoveToDisabledOu'; Value = $true } }
AuthSessionName = 'Directory'
IdentityKey = '{{Request.Intent.SamAccountName}}'
TargetContainer = '{{Request.Intent.DisabledOuPath}}'
}
}
)
}
Troubleshooting
-
Import fails / ActiveDirectory module missing
Install RSAT / theActiveDirectorymodule on the machine where you run IdLE. -
Access denied / insufficient rights
Ensure the account used (run-as or broker-provided credential) has the required rights for the operation (create user, set attributes, group membership, move OU). -
Delete step doesn’t work
Deletion is opt-in. Create the provider with-AllowDeleteand ensure your workflow uses that provider instance. -
Group membership changes are risky
Prefer removing only explicit “managed groups” (allow-list) to avoid breaking access unexpectedly.