Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 6 additions & 0 deletions docs/usage/workflows.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,12 @@ Prefer explicit reference fields over implicit parsing:

This makes configurations safe and statically validatable.

## Advanced Workflow Patterns

(Content for advanced patterns will be added in future updates)

This approach keeps workflows data-only while allowing rich message formatting in the host code.

## Related

- [Steps](steps.md)
Expand Down
78 changes: 78 additions & 0 deletions examples/workflows/live/complete-leaver-entraid-exo.psd1
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
@{
Name = 'Complete Leaver - EntraID + ExchangeOnline Offboarding'
LifecycleEvent = 'Leaver'
Description = 'Complete offboarding workflow: disables EntraID account, converts mailbox to shared, and enables Out of Office.'
Steps = @(
@{
Name = 'GetMailboxInfo'
Type = 'IdLE.Step.Mailbox.GetInfo'
With = @{
Provider = 'ExchangeOnline'
IdentityKey = @{ ValueFrom = 'Request.Input.UserPrincipalName' }
}
Comment thread
blindzero marked this conversation as resolved.
}
@{
Name = 'ConvertToSharedMailbox'
Type = 'IdLE.Step.Mailbox.Type.Ensure'
With = @{
Provider = 'ExchangeOnline'
IdentityKey = @{ ValueFrom = 'Request.Input.UserPrincipalName' }
MailboxType = 'Shared'
}
}
@{
Name = 'EnableOutOfOffice'
Type = 'IdLE.Step.Mailbox.OutOfOffice.Ensure'
With = @{
Provider = 'ExchangeOnline'
IdentityKey = @{ ValueFrom = 'Request.Input.UserPrincipalName' }
Config = @{
Comment thread
blindzero marked this conversation as resolved.
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'
}
}
}
@{
Name = 'RevokeAllGroupMemberships'
Type = 'IdLE.Step.EnsureEntitlement'
With = @{
Provider = 'Identity'
AuthSessionName = 'MicrosoftGraph'
AuthSessionOptions = @{ Role = 'Admin' }
IdentityKey = @{ ValueFrom = 'Request.Input.UserObjectId' }
Desired = @()
}
}
@{
Name = 'ClearManager'
Type = 'IdLE.Step.EnsureAttribute'
With = @{
Provider = 'Identity'
AuthSessionName = 'MicrosoftGraph'
AuthSessionOptions = @{ Role = 'Admin' }
IdentityKey = @{ ValueFrom = 'Request.Input.UserObjectId' }
Name = 'Manager'
Value = $null
}
}
@{
Name = 'DisableEntraIDAccount'
Type = 'IdLE.Step.DisableIdentity'
With = @{
Provider = 'Identity'
AuthSessionName = 'MicrosoftGraph'
AuthSessionOptions = @{ Role = 'Admin' }
IdentityKey = @{ ValueFrom = 'Request.Input.UserObjectId' }
}
}
@{
Name = 'EmitCompletionEvent'
Type = 'IdLE.Step.EmitEvent'
With = @{
Message = 'Complete offboarding finished: Mailbox converted to Shared, OOF enabled, EntraID account disabled.'
}
}
)
}
45 changes: 45 additions & 0 deletions examples/workflows/live/exo-leaver-mailbox-offboarding.psd1
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
@{
Name = 'ExchangeOnline Leaver - Mailbox Offboarding'
LifecycleEvent = 'Leaver'
Description = 'Converts mailbox to shared, enables Out of Office, and optionally delegates access for offboarding users.'
Steps = @(
@{
Name = 'GetMailboxInfo'
Type = 'IdLE.Step.Mailbox.GetInfo'
With = @{
Provider = 'ExchangeOnline'
IdentityKey = @{ ValueFrom = 'Request.Input.UserPrincipalName' }
}
Comment thread
blindzero marked this conversation as resolved.
}
@{
Name = 'ConvertToSharedMailbox'
Type = 'IdLE.Step.Mailbox.Type.Ensure'
With = @{
Provider = 'ExchangeOnline'
IdentityKey = @{ ValueFrom = 'Request.Input.UserPrincipalName' }
MailboxType = 'Shared'
}
}
@{
Name = 'EnableOutOfOffice'
Type = 'IdLE.Step.Mailbox.OutOfOffice.Ensure'
With = @{
Provider = 'ExchangeOnline'
IdentityKey = @{ ValueFrom = 'Request.Input.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'
}
}
}
@{
Name = 'EmitCompletionEvent'
Type = 'IdLE.Step.EmitEvent'
With = @{
Message = 'Mailbox offboarding completed.'
}
}
)
}
22 changes: 22 additions & 0 deletions src/IdLE.Provider.ExchangeOnline/IdLE.Provider.ExchangeOnline.psd1
Comment thread
blindzero marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
@{
RootModule = 'IdLE.Provider.ExchangeOnline.psm1'
ModuleVersion = '0.9.0'
GUID = 'e8f9a3b1-4c2d-4a5b-9f7e-3d2c1a9b8e7f'
Author = 'Matthias Fleschuetz'
Copyright = '(c) Matthias Fleschuetz. All rights reserved.'
Description = 'Exchange Online mailbox provider implementation for IdLE (requires ExchangeOnlineManagement module).'
PowerShellVersion = '7.0'

FunctionsToExport = @(
'New-IdleExchangeOnlineProvider'
)

PrivateData = @{
PSData = @{
Tags = @('IdentityLifecycleEngine', 'IdLE', 'Provider', 'ExchangeOnline', 'Mailbox')
LicenseUri = 'https://www.apache.org/licenses/LICENSE-2.0'
ProjectUri = 'https://github.com/blindzero/IdentityLifecycleEngine'
ContactEmail = '13959569+blindzero@users.noreply.github.com'
}
}
}
29 changes: 29 additions & 0 deletions src/IdLE.Provider.ExchangeOnline/IdLE.Provider.ExchangeOnline.psm1
Comment thread
blindzero marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#requires -Version 7.0
Set-StrictMode -Version Latest

$PrivatePath = Join-Path -Path $PSScriptRoot -ChildPath 'Private'
if (Test-Path -Path $PrivatePath) {

# Materialize first to avoid enumeration issues during import.
$privateScripts = @(Get-ChildItem -Path $PrivatePath -Filter '*.ps1' -File | Sort-Object -Property FullName)

foreach ($script in $privateScripts) {
. $script.FullName
}
}

$PublicPath = Join-Path -Path $PSScriptRoot -ChildPath 'Public'
if (Test-Path -Path $PublicPath) {

# Materialize first to avoid enumeration issues during import.
$publicScripts = @(Get-ChildItem -Path $PublicPath -Filter '*.ps1' -File | Sort-Object -Property FullName)

foreach ($script in $publicScripts) {
. $script.FullName
}
}

# Export Public functions - explicit list for deterministic behavior
Export-ModuleMember -Function @(
'New-IdleExchangeOnlineProvider'
)
Loading