diff --git a/docs/reference/providers/provider-ad.md b/docs/reference/providers/provider-ad.md index 32dba30b..5c4c2cf0 100644 --- a/docs/reference/providers/provider-ad.md +++ b/docs/reference/providers/provider-ad.md @@ -141,3 +141,10 @@ Mover scenarios are intentionally folded into Joiner/Leaver (as optional pattern - **Group membership changes are risky** Prefer removing only explicit “managed groups” (allow-list) to avoid breaking access unexpectedly. + +## Scenarios (link-only) + +Cross-provider orchestration examples are valuable, but should not be embedded in a single provider reference page. +Keep them as **link-only** and collect them on a central Examples/Scenarios page: + +- `examples/workflows/templates/ad-joiner-entraconnect-entraid.psd1` - Joiner workflow that creates an AD account, triggers Entra Connect sync, and assigns Entra ID groups diff --git a/docs/reference/providers/provider-directorysync-entraconnect.md b/docs/reference/providers/provider-directorysync-entraconnect.md index b6deeae4..3206f4db 100644 --- a/docs/reference/providers/provider-directorysync-entraconnect.md +++ b/docs/reference/providers/provider-directorysync-entraconnect.md @@ -110,3 +110,10 @@ This provider has no admin-facing option bag. Configuration is done through: - **“AuthSession must implement InvokeCommand”**: your host must provide an AuthSession object with an `InvokeCommand()` method. - **Get-ADSyncScheduler not found**: ensure ADSync cmdlets are available in the remote session (module installed/accessible). - **Timeout waiting for completion**: increase `TimeoutSeconds` or check the scheduler state on the server. + +## Scenarios (link-only) + +Cross-provider orchestration examples are valuable, but should not be embedded in a single provider reference page. +Keep them as **link-only** and collect them on a central Examples/Scenarios page: + +- `examples/workflows/templates/ad-joiner-entraconnect-entraid.psd1` - Joiner workflow that creates an AD account, triggers Entra Connect sync, and assigns Entra ID groups diff --git a/docs/reference/providers/provider-entraID.md b/docs/reference/providers/provider-entraID.md index a4c3e244..23c4ce03 100644 --- a/docs/reference/providers/provider-entraID.md +++ b/docs/reference/providers/provider-entraID.md @@ -126,3 +126,11 @@ Mover scenarios are integrated as **optional patterns** in the Joiner template. - **Auth session not found**: check `AuthSessionName` matches your runtime/broker configuration. - **Delete doesn’t work**: deletion is opt-in. Create the provider with `-AllowDelete` and only use delete with a privileged auth role. - **Group cleanup is disruptive**: only enable revoke/remove operations when you fully understand the impact (prefer managed allow-lists). + +## Scenarios (link-only) + +Cross-provider orchestration examples are valuable, but should not be embedded in a single provider reference page. +Keep them as **link-only** and collect them on a central Examples/Scenarios page: + +- `examples/workflows/templates/ad-joiner-entraconnect-entraid.psd1` - Joiner workflow that creates an AD account, triggers Entra Connect sync, and assigns Entra ID groups +- `examples/workflows/templates/entraid-exo-leaver.psd1` - Leaver workflow that disables Entra ID account, converts mailbox to shared, and enables Out of Office diff --git a/examples/workflows/mock/mock-identity-and-entitlements.psd1 b/examples/workflows/mock/mock-identity-and-entitlements.psd1 index 83bc4a00..5785eb2e 100644 --- a/examples/workflows/mock/mock-identity-and-entitlements.psd1 +++ b/examples/workflows/mock/mock-identity-and-entitlements.psd1 @@ -28,13 +28,12 @@ # In the mock provider, entitlements are just stored in-memory. # Use this to validate your workflow logic and template placeholders. - Desired = @( - @{ - Kind = 'Group' - Id = '{{Request.Input.GroupId}}' - DisplayName = '{{Request.Input.GroupName}}' - } - ) + Entitlement = @{ + Kind = 'Group' + Id = '{{Request.Input.GroupId}}' + DisplayName = '{{Request.Input.GroupName}}' + } + State = 'Present' } } @@ -47,42 +46,3 @@ } ) } - -``` - -### File: examples/workflows/mock/mock-onfailure.psd1 - -```powershell -@{ - Name = 'Mock Provider - OnFailure handling (Demo)' - LifecycleEvent = 'Joiner' - Description = 'Demonstrates OnFailureSteps for cleanup/notification when primary steps fail (using Mock provider).' - - Steps = @( - @{ - Name = 'Emit start' - Type = 'IdLE.Step.EmitEvent' - With = @{ - Message = 'Starting workflow with OnFailure handling.' - } - } - - @{ - Name = 'Primary action (will fail intentionally)' - Type = 'IdLE.Step.Fail' - With = @{ - Message = 'Intentional failure to demonstrate OnFailureSteps.' - } - - OnFailureSteps = @( - @{ - Name = 'Emit failure notification' - Type = 'IdLE.Step.EmitEvent' - With = @{ - Message = 'Primary action failed for {{Request.Input.IdentityKey}}.' - } - } - ) - } - ) -} diff --git a/examples/workflows/templates/exo-joiner.psd1 b/examples/workflows/templates/exo-joiner.psd1 index f42092e5..8075dbbf 100644 --- a/examples/workflows/templates/exo-joiner.psd1 +++ b/examples/workflows/templates/exo-joiner.psd1 @@ -30,94 +30,3 @@ } ) } - -``` - -### 2) Keep `entraid-exo-leaver.psd1` but update it to the standard placeholder style - -This file is a **cross-provider scenario** (Entra ID + EXO). It should remain **link-only** (not embedded in a single provider page), but it should be consistent: - -- Replace all `IdentityKey = @{ ValueFrom = 'Request.Input.X' }` with `IdentityKey = '{{Request.Input.X}}'` - -Updated full content: - -```powershell -@{ - 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 = '{{Request.Input.UserPrincipalName}}' - } - } - @{ - Name = 'ConvertToSharedMailbox' - Type = 'IdLE.Step.Mailbox.EnsureType' - With = @{ - Provider = 'ExchangeOnline' - IdentityKey = '{{Request.Input.UserPrincipalName}}' - MailboxType = 'Shared' - } - } - @{ - Name = 'EnableOutOfOffice' - Type = 'IdLE.Step.Mailbox.EnsureOutOfOffice' - With = @{ - Provider = 'ExchangeOnline' - IdentityKey = '{{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 = 'RevokeAllGroupMemberships' - Type = 'IdLE.Step.EnsureEntitlement' - With = @{ - Provider = 'Identity' - AuthSessionName = 'MicrosoftGraph' - AuthSessionOptions = @{ Role = 'Admin' } - IdentityKey = '{{Request.Input.UserObjectId}}' - Desired = @() - } - } - @{ - Name = 'ClearManager' - Type = 'IdLE.Step.EnsureAttributes' - With = @{ - Provider = 'Identity' - AuthSessionName = 'MicrosoftGraph' - AuthSessionOptions = @{ Role = 'Admin' } - IdentityKey = '{{Request.Input.UserObjectId}}' - Attributes = @{ - Manager = $null - } - } - } - @{ - Name = 'DisableEntraIDAccount' - Type = 'IdLE.Step.DisableIdentity' - With = @{ - Provider = 'Identity' - AuthSessionName = 'MicrosoftGraph' - AuthSessionOptions = @{ Role = 'Admin' } - IdentityKey = '{{Request.Input.UserObjectId}}' - } - } - @{ - Name = 'EmitCompletionEvent' - Type = 'IdLE.Step.EmitEvent' - With = @{ - Message = 'Complete offboarding finished: Mailbox converted to Shared, OOF enabled, EntraID account disabled.' - } - } - ) -} diff --git a/tests/Core/CapabilityDeprecation.Tests.ps1 b/tests/Core/CapabilityDeprecation.Tests.ps1 index cdbbe6a3..f3c520f2 100644 --- a/tests/Core/CapabilityDeprecation.Tests.ps1 +++ b/tests/Core/CapabilityDeprecation.Tests.ps1 @@ -27,16 +27,21 @@ Describe 'Capability Deprecation and Migration' { } # Use a real workflow file that uses mailbox steps - $wfPath = Join-Path $PSScriptRoot '..' '..' 'examples' 'workflows' 'templates' 'exo-leaver-mailbox-offboarding.psd1' + $wfPath = Join-Path $PSScriptRoot '..' '..' 'examples' 'workflows' 'templates' 'exo-leaver.psd1' # Verify the workflow file exists $wfPath | Should -Exist $req = New-IdleTestRequest -LifecycleEvent 'Leaver' -DesiredState @{ + UserPrincipalName = 'testuser@contoso.com' Manager = @{ DisplayName = 'IT Support' Mail = 'support@contoso.com' } + ServiceDesk = @{ + DisplayName = 'Service Desk' + Mail = 'servicedesk@contoso.com' + } } $providers = @{ MockProvider = $mockProvider } @@ -70,13 +75,18 @@ Describe 'Capability Deprecation and Migration' { } # Use a real workflow file - $wfPath = Join-Path $PSScriptRoot '..' '..' 'examples' 'workflows' 'templates' 'exo-leaver-mailbox-offboarding.psd1' + $wfPath = Join-Path $PSScriptRoot '..' '..' 'examples' 'workflows' 'templates' 'exo-leaver.psd1' $req = New-IdleTestRequest -LifecycleEvent 'Leaver' -DesiredState @{ + UserPrincipalName = 'testuser@contoso.com' Manager = @{ DisplayName = 'IT Support' Mail = 'support@contoso.com' } + ServiceDesk = @{ + DisplayName = 'Service Desk' + Mail = 'servicedesk@contoso.com' + } } $providers = @{ MockProvider = $mockProvider } diff --git a/tests/Examples/WorkflowSamples.Tests.ps1 b/tests/Examples/WorkflowSamples.Tests.ps1 index c4973a9c..56fbb178 100644 --- a/tests/Examples/WorkflowSamples.Tests.ps1 +++ b/tests/Examples/WorkflowSamples.Tests.ps1 @@ -31,7 +31,19 @@ Describe 'Example workflows' { foreach ($file in $mockWorkflows) { $workflow = Import-PowerShellDataFile -Path $file.FullName $lifecycleEvent = if ($workflow.ContainsKey('LifecycleEvent')) { $workflow.LifecycleEvent } else { 'Joiner' } - $request = New-IdleTestRequest -LifecycleEvent $lifecycleEvent -Actor 'test-user' + + # Provide sample data for workflows that use templates + $desiredState = @{ + IdentityKey = 'test-user' + GivenName = 'Test' + Surname = 'User' + Department = 'IT' + Title = 'Engineer' + GroupId = 'test-group-id' + GroupName = 'Test Group' + } + + $request = New-IdleTestRequest -LifecycleEvent $lifecycleEvent -Actor 'test-user' -DesiredState $desiredState { New-IdlePlan -WorkflowPath $file.FullName -Request $request -Providers $providers } | Should -Not -Throw } @@ -43,7 +55,19 @@ Describe 'Example workflows' { foreach ($file in $mockWorkflows) { $workflow = Import-PowerShellDataFile -Path $file.FullName $lifecycleEvent = if ($workflow.ContainsKey('LifecycleEvent')) { $workflow.LifecycleEvent } else { 'Joiner' } - $request = New-IdleTestRequest -LifecycleEvent $lifecycleEvent -Actor 'test-user' + + # Provide sample data for workflows that use templates + $desiredState = @{ + IdentityKey = 'test-user' + GivenName = 'Test' + Surname = 'User' + Department = 'IT' + Title = 'Engineer' + GroupId = 'test-group-id' + GroupName = 'Test Group' + } + + $request = New-IdleTestRequest -LifecycleEvent $lifecycleEvent -Actor 'test-user' -DesiredState $desiredState $plan = New-IdlePlan -WorkflowPath $file.FullName -Request $request -Providers $providers $result = Invoke-IdlePlan -Plan $plan -Providers $providers @@ -66,6 +90,16 @@ Describe 'Example workflows' { It 'validates template workflows (if any exist)' { if ($templateWorkflows) { foreach ($file in $templateWorkflows) { + # Load the file to check its structure + $content = Import-PowerShellDataFile -Path $file.FullName + + # Skip template library files (with Metadata + Workflow structure) + # These are documentation/reference templates, not executable workflows + if ($content.ContainsKey('Metadata') -and $content.ContainsKey('Workflow')) { + Write-Verbose "Skipping template library file: $($file.Name)" + continue + } + { Test-IdleWorkflow -WorkflowPath $file.FullName } | Should -Not -Throw } } else { diff --git a/tools/import-idle.ps1 b/tools/import-idle.ps1 index b478d4ec..a68c009a 100644 --- a/tools/import-idle.ps1 +++ b/tools/import-idle.ps1 @@ -42,6 +42,16 @@ if (-not $workflowPaths) { } foreach ($wf in $workflowPaths) { + # Load the file to check its structure + $content = Import-PowerShellDataFile -Path $wf + + # Skip template library files (with Metadata + Workflow structure) + # These are documentation/reference templates, not executable workflows + if ($content.ContainsKey('Metadata') -and $content.ContainsKey('Workflow')) { + Write-Host "Skipping template library file: $wf" -ForegroundColor Yellow + continue + } + Test-IdleWorkflow -WorkflowPath $wf }