Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
f045a4f
Initial plan
Copilot Feb 24, 2026
a676ad0
Add IdLE.Step.PruneEntitlements with tests, capability, provider upda…
Copilot Feb 24, 2026
1bbc4a0
Fix Condition placement and step name in AD leaver template
Copilot Feb 24, 2026
cff2fd7
Add dedicated adapter PruneGroupMemberships + provider PruneEntitleme…
Copilot Feb 24, 2026
2ebe95c
Refactor: step is single delta-computation source; add NormalizeEntit…
Copilot Feb 24, 2026
7842b41
Split PruneEntitlements into two step types: PruneEntitlements (remov…
Copilot Feb 24, 2026
d3e7885
Optimize providers: remove redundant ListEntitlements reads; add idem…
Copilot Feb 25, 2026
732c333
Apply suggestions from code review
blindzero Feb 25, 2026
d7ce22a
Apply suggestions from code review
blindzero Feb 25, 2026
241aaf8
Rename NormalizeGroupId→ResolveGroup and NormalizeEntitlementId→Resol…
Copilot Feb 25, 2026
4092659
docs: fixing sidebar, adding new step types for prune
ntt-matthias-fleschuetz Feb 25, 2026
6c5c40d
docs: generating new step types reference
ntt-matthias-fleschuetz Feb 25, 2026
18401ef
Fix test failures: add @() wrapping before .Count on Where-Object pip…
Copilot Feb 25, 2026
5b45b1d
Merge branch 'main' into copilot/add-idle-step-prune-entitlements
blindzero Feb 27, 2026
04f4c02
Merge branch 'main' into copilot/add-idle-step-prune-entitlements
blindzero Feb 27, 2026
dc01dd2
Extend step reference pages: add With.* parameter tables, workflow-st…
Copilot Feb 27, 2026
36384fa
Differentiate PruneEntitlements vs PruneEntitlementsEnsureKeep docs: …
Copilot Feb 28, 2026
c3329ca
Add explicit IdLE.Entitlement.Prune capability tests for AD and Mock …
Copilot Feb 28, 2026
a452795
indent fixing
ntt-matthias-fleschuetz Feb 28, 2026
29ff07e
Filter AD primary group from ListEntitlements to prevent spurious Rev…
Copilot Feb 28, 2026
8d250b3
Fix GetPrimaryGroupDN: use primaryGroupToken filter instead of object…
Copilot Feb 28, 2026
f10f8b0
Fix GetPrimaryGroupDN: use direct SID identity lookup (domain SID + R…
Copilot Feb 28, 2026
dc81864
Simplify GetPrimaryGroupDN: read primaryGroup attribute directly — no…
Copilot Feb 28, 2026
d440ae2
Fix GetPrimaryGroupDN: use MemberOf vs Get-ADPrincipalGroupMembership…
Copilot Feb 28, 2026
863bb26
docs: remove keeppattern from PruneEntitlementsEnsureKeep
blindzero Mar 1, 2026
32a67e4
KeepPattern forbidden at plan time for EnsureKeep; Keep/KeepPattern n…
Copilot Mar 1, 2026
ec860db
Replace ForbiddenWithKeys denylist with AllowedWithKeys allowlist for…
Copilot Mar 1, 2026
0a9a51b
hashtable keyed by RequestId once to avoid O(n²) $operation invocation
ntt-matthias-fleschuetz Mar 1, 2026
f3a38ac
Remove dead BulkRevokeEntitlements from AD adapter; fix NormalizeEnti…
Copilot Mar 1, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions docs/reference/capabilities.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ Grant/assign an entitlement to an identity (e.g., add group membership, assign l
#### `IdLE.Entitlement.Revoke`
Revoke/remove an entitlement from an identity. Must be idempotent.

#### `IdLE.Entitlement.Prune`
Explicit opt-in for bulk entitlement convergence ("remove all except"). Providers that advertise this capability support the `IdLE.Step.PruneEntitlements` step, which removes all entitlements of a given kind except an explicit keep-set and/or pattern-matched entitlements. This is a separate capability from `Revoke` because the operation is bulk and destructive by design. Providers must also implement `ListEntitlements` and `RevokeEntitlement` (and optionally `GrantEntitlement`) to support this step.

### Mailbox

#### `IdLE.Mailbox.Info.Read`
Expand Down
2 changes: 2 additions & 0 deletions docs/reference/steps.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,7 @@
| [IdLE.Step.Mailbox.EnsureType](steps/step-mailbox-ensure-type.md) | ``IdLE.Steps.Mailbox`` | Ensures that a mailbox is of the desired type (User, Shared, Room, Equipment). |
| [IdLE.Step.Mailbox.GetInfo](steps/step-mailbox-get-info.md) | ``IdLE.Steps.Mailbox`` | Retrieves mailbox details and returns a structured report. |
| [IdLE.Step.MoveIdentity](steps/step-move-identity.md) | ``IdLE.Steps.Common`` | Moves an identity to a different container/OU in the target system. |
| [IdLE.Step.PruneEntitlements](steps/step-prune-entitlements.md) | ``IdLE.Steps.Common`` | Removes all non-kept entitlements of a given kind from an identity. Remove-only — does not grant anything. |
| [IdLE.Step.PruneEntitlementsEnsureKeep](steps/step-prune-entitlements-ensure-keep.md) | ``IdLE.Steps.Common`` | Removes all non-kept entitlements and GUARANTEES explicit Keep entries are present (grants if missing). |
| [IdLE.Step.RevokeIdentitySessions](steps/step-revoke-identity-sessions.md) | ``IdLE.Steps.Common`` | Revokes all active sign-in sessions for an identity in the target system. |
| [IdLE.Step.TriggerDirectorySync](steps/step-trigger-directory-sync.md) | ``IdLE.Steps.DirectorySync`` | Triggers a directory sync cycle and optionally waits for completion. |
140 changes: 134 additions & 6 deletions docs/reference/steps/step-mailbox-ensure-out-of-office.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,17 +63,145 @@ The following keys are required in the step's ``With`` configuration:

## Example

### Example 1

```powershell
# In workflow definition (enable OOF):
@{
Name = 'Enable Out of Office'
Type = 'IdLE.Step.Mailbox.EnsureOutOfOffice'
With = @{
Provider = 'ExchangeOnline'
IdentityKey = 'user@contoso.com'
Config = @{
Mode = 'Enabled'
InternalMessage = 'I am out of office.'
ExternalMessage = 'I am currently unavailable.'
ExternalAudience = 'All'
MessageFormat = 'Text'
}
}
}
```

### Example 2

```powershell
# In workflow definition (with ValueFrom for dynamic values):
@{
Name = 'IdLE.Step.Mailbox.EnsureOutOfOffice Example'
Type = 'IdLE.Step.Mailbox.EnsureOutOfOffice'
With = @{
Config = '<value>'
IdentityKey = 'user.name'
}
Name = 'Enable Out of Office for Leaver'
Type = 'IdLE.Step.Mailbox.EnsureOutOfOffice'
With = @{
Provider = 'ExchangeOnline'
IdentityKey = @{ ValueFrom = 'Request.Intent.UserPrincipalName' }
Config = @{
Mode = 'Enabled'
InternalMessage = 'This person is no longer with the organization. For assistance, please contact their manager or the main office.'
ExternalMessage = 'This person is no longer with the organization. Please contact the main office for assistance.'
ExternalAudience = 'All'
}
}
}
```

### Example 3

```powershell
# In workflow definition (scheduled OOF):
@{
Name = 'Schedule Out of Office'
Type = 'IdLE.Step.Mailbox.EnsureOutOfOffice'
With = @{
Provider = 'ExchangeOnline'
IdentityKey = 'user@contoso.com'
Config = @{
Mode = 'Scheduled'
Start = '2025-02-01T00:00:00Z'
End = '2025-02-15T00:00:00Z'
InternalMessage = 'I am on vacation until February 15.'
ExternalMessage = 'I am currently out of office.'
}
}
}
```

### Example 4

```powershell
# In workflow definition (disable OOF):
@{
Name = 'Disable Out of Office'
Type = 'IdLE.Step.Mailbox.EnsureOutOfOffice'
With = @{
Provider = 'ExchangeOnline'
IdentityKey = 'user@contoso.com'
Config = @{
Mode = 'Disabled'
}
}
}
```

### Example 5

```powershell
# In workflow definition (HTML formatted message):
@{
Name = 'Enable Out of Office with HTML'
Type = 'IdLE.Step.Mailbox.EnsureOutOfOffice'
With = @{
Provider = 'ExchangeOnline'
IdentityKey = 'user@contoso.com'
Config = @{
Mode = 'Enabled'
MessageFormat = 'Html'
InternalMessage = '<p>I am out of office.</p><p>For urgent matters, contact <a href="mailto:manager@contoso.com">my manager</a>.</p>'
ExternalMessage = '<p>I am currently unavailable.</p><p>Please contact our <strong>Service Desk</strong> at servicedesk@contoso.com.</p>'
ExternalAudience = 'All'
}
}
}
```

### Example 6

# Host-side enrichment (example):
# $user = Get-ADUser -Identity 'max.power' -Properties Manager
# $mgr = if ($user.Manager) \{
# Get-ADUser -Identity $user.Manager -Properties DisplayName, Mail
# \} else \{
# # Fallback manager/contact to avoid null template values
# [pscustomobject]@\{
# DisplayName = 'Service Desk'
# Mail = 'servicedesk@contoso.com'
# \}
# \}
# $req = New-IdleRequest -LifecycleEvent 'Leaver' -Actor $env:USERNAME -Intent @\{
# Manager = @\{ DisplayName = $mgr.DisplayName; Mail = $mgr.Mail \}
# \}

# Workflow step with template variables:
@\{
Name = 'Set OOF with Manager Contact'
Type = 'IdLE.Step.Mailbox.EnsureOutOfOffice'
With = @\{
Provider = 'ExchangeOnline'
IdentityKey = 'max.power@contoso.com'
Config = @\{
Mode = 'Enabled'
InternalMessage = 'This mailbox is no longer monitored. Please contact \{\{Request.Intent.Manager.DisplayName\}\} (\{\{Request.Intent.Manager.Mail\}\}).'
ExternalMessage = 'This mailbox is no longer monitored. Please contact \{\{Request.Intent.Manager.Mail\}\}.'
ExternalAudience = 'All'
\}
\}
\}

```powershell
# Template usage with dynamic manager attributes (Leaver scenario):
# Note: Templates are resolved during planning against the request object.
# Host must enrich request.Intent with manager data before calling New-IdlePlan.
```

## See Also

- [Capabilities Reference](../capabilities.md) - Overview of IdLE capabilities
Expand Down
54 changes: 48 additions & 6 deletions docs/reference/steps/step-mailbox-ensure-permissions.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,56 @@ The following keys are required in the step's ``With`` configuration:

## Example

### Example 1

```powershell
# In workflow definition (grant FullAccess and SendAs):
@{
Name = 'Set Shared Mailbox Permissions'
Type = 'IdLE.Step.Mailbox.EnsurePermissions'
With = @{
Provider = 'ExchangeOnline'
IdentityKey = 'shared@contoso.com'
Permissions = @(
@{ AssignedUser = 'user1@contoso.com'; Right = 'FullAccess'; Ensure = 'Present' }
@{ AssignedUser = 'user2@contoso.com'; Right = 'SendAs'; Ensure = 'Present' }
)
}
}
```

### Example 2

```powershell
# In workflow definition (revoke access):
@{
Name = 'Revoke Mailbox Access'
Type = 'IdLE.Step.Mailbox.EnsurePermissions'
With = @{
Provider = 'ExchangeOnline'
IdentityKey = 'shared@contoso.com'
Permissions = @(
@{ AssignedUser = 'leaver@contoso.com'; Right = 'FullAccess'; Ensure = 'Absent' }
@{ AssignedUser = 'leaver@contoso.com'; Right = 'SendOnBehalf'; Ensure = 'Absent' }
)
}
}
```

### Example 3

```powershell
# With dynamic identity from request:
@{
Name = 'IdLE.Step.Mailbox.EnsurePermissions Example'
Type = 'IdLE.Step.Mailbox.EnsurePermissions'
With = @{
IdentityKey = 'user.name'
Permissions = '<value>'
}
Name = 'Grant Team Mailbox Access'
Type = 'IdLE.Step.Mailbox.EnsurePermissions'
With = @{
Provider = 'ExchangeOnline'
IdentityKey = 'team@contoso.com'
Permissions = @(
@{ AssignedUser = @{ ValueFrom = 'Request.Intent.UserPrincipalName' }; Right = 'FullAccess'; Ensure = 'Present' }
)
}
}
```

Expand Down
14 changes: 8 additions & 6 deletions docs/reference/steps/step-mailbox-ensure-type.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,15 @@ The following keys are required in the step's ``With`` configuration:
## Example

```powershell
# In workflow definition (convert to shared mailbox):
@{
Name = 'IdLE.Step.Mailbox.EnsureType Example'
Type = 'IdLE.Step.Mailbox.EnsureType'
With = @{
IdentityKey = 'user.name'
MailboxType = '<value>'
}
Name = 'Convert to shared mailbox'
Type = 'IdLE.Step.Mailbox.EnsureType'
With = @{
Provider = 'ExchangeOnline'
IdentityKey = 'user@contoso.com'
MailboxType = 'Shared'
}
}
```

Expand Down
12 changes: 7 additions & 5 deletions docs/reference/steps/step-mailbox-get-info.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,14 @@ The following keys are required in the step's ``With`` configuration:
## Example

```powershell
# In workflow definition:
@{
Name = 'IdLE.Step.Mailbox.GetInfo Example'
Type = 'IdLE.Step.Mailbox.GetInfo'
With = @{
IdentityKey = 'user.name'
}
Name = 'Get mailbox info'
Type = 'IdLE.Step.Mailbox.GetInfo'
With = @{
Provider = 'ExchangeOnline'
IdentityKey = 'user@contoso.com'
}
}
```

Expand Down
Loading