Skip to main content

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 / ActiveDirectory PowerShell 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 / ActiveDirectory module available
  • Permissions sufficient for the operations you plan to run (create/modify users, move OUs, manage group membership)
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.AuthSessionName in 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 AuthSession via step configuration:
    • With.AuthSessionName
    • With.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 typeTypical useNotes
IdLE.Step.CreateIdentityCreate user (if missing)Identity can be addressed by GUID, UPN, or sAMAccountName
IdLE.Step.EnsureAttributesSet/update AD user attributesUse placeholders from your request input
IdLE.Step.DisableIdentityDisable user accountTypical leaver action
IdLE.Step.EnableIdentityEnable user accountRare (rehire)
IdLE.Step.MoveIdentityMove user to another OUUseful for leaver or org changes
IdLE.Step.EnsureEntitlementEnsure group membershipsAD entitlements are groups
IdLE.Step.RemoveEntitlementRemove managed groupsPrefer explicit allow-lists / managed lists
IdLE.Step.DeleteIdentityDelete userOpt-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:

PropertyTypeNotes
PSTypeNamestringAlways IdLE.Identity.
IdentityKeystringThe identity key used by the workflow (GUID/UPN/sAMAccountName).
EnabledboolDerived from AD user Enabled.
AttributeshashtableKey/value bag; keys are strings; values are typically string.

Attributes keys populated by this provider (when present on the AD user object):

Attribute keyType
GivenNamestring
Surnamestring
DisplayNamestring
Descriptionstring
Departmentstring
Titlestring
EmailAddressstring
UserPrincipalNamestring
sAMAccountNamestring
DistinguishedNamestring

Attribute access: Profile attributes are nested under the Attributes key. Use Request.Context.Views.Identity.Profile.Attributes.DisplayName in Conditions (or the scoped Request.Context.Providers.<ProviderAlias>.<AuthSessionKey>.Identity.Profile.Attributes.DisplayName), not Request.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:

PropertyTypeNotes
PSTypeNamestringAlways IdLE.Entitlement.
KindstringAlways Group.
IdstringAD group DistinguishedName.

Notes:

  • The output paths are fixed by the engine and cannot be changed.
  • Each entry is automatically annotated with SourceProvider and SourceAuthSessionName metadata.
  • 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

OptionTypeDefaultMeaning
AllowDeleteboolfalseEnables identity deletion capability (opt-in for safety)
PasswordGenerationFallbackMinLengthint24Fallback minimum length if domain policy cannot be read
PasswordGenerationRequireUpperbooltrueRequire uppercase in generated passwords (fallback)
PasswordGenerationRequireLowerbooltrueRequire lowercase in generated passwords (fallback)
PasswordGenerationRequireDigitbooltrueRequire digit in generated passwords (fallback)
PasswordGenerationRequireSpecialbooltrueRequire 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 OtherAttributes must 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 OtherAttributes must be valid LDAP attribute names (e.g. mobile, telephoneNumber, extensionAttribute1), not PowerShell parameter names. Setting a key to $null clears 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.

examples/workflows/templates/ad-joiner.psd1
@{
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'
}
}
)
}
examples/workflows/templates/ad-leaver.psd1
@{
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 / the ActiveDirectory module 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 -AllowDelete and 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.