From 090ce660b4def8d25f4dfc1f1a13a8adedf4196d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 7 Feb 2026 20:37:43 +0000 Subject: [PATCH 1/4] Initial plan From 953d392b944b0ae1622dd3f17a8fb7c10d0e116c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 7 Feb 2026 20:42:04 +0000 Subject: [PATCH 2/4] Improve steps reference pages with capabilities, better inputs, and examples Co-authored-by: blindzero <13959569+blindzero@users.noreply.github.com> --- docs/reference/steps/step-create-identity.md | 33 +++- docs/reference/steps/step-delete-identity.md | 25 ++- docs/reference/steps/step-disable-identity.md | 25 ++- docs/reference/steps/step-emit-event.md | 17 +- docs/reference/steps/step-enable-identity.md | 25 ++- docs/reference/steps/step-ensure-attribute.md | 36 ++++- .../steps/step-ensure-entitlement.md | 34 +++- docs/reference/steps/step-move-identity.md | 33 +++- .../steps/step-trigger-directory-sync.md | 25 ++- tools/Generate-IdleStepReference.ps1 | 149 ++++++++++++++++-- 10 files changed, 337 insertions(+), 65 deletions(-) diff --git a/docs/reference/steps/step-create-identity.md b/docs/reference/steps/step-create-identity.md index 83cc4ab9..d692f7c8 100644 --- a/docs/reference/steps/step-create-identity.md +++ b/docs/reference/steps/step-create-identity.md @@ -9,8 +9,7 @@ - **Module**: `IdLE.Steps.Common` - **Implementation**: `Invoke-IdleStepCreateIdentity` - **Idempotent**: `Yes` -- **Contracts**: `Unknown` -- **Events**: Unknown +- **Required Capabilities**: `IdLE.Identity.Create` ## Synopsis @@ -18,7 +17,7 @@ Creates a new identity in the target system. ## Description -This is a provider-agnostic step. The host must supply a provider instance via +The host must supply a provider instance via Context.Providers[<ProviderAlias>] that implements CreateIdentity(identityKey, attributes) and returns an object with properties 'IdentityKey' and 'Changed'. @@ -38,7 +37,27 @@ Authentication: ## Inputs (With.*) -| Key | Required | -| --- | --- | -| IdentityKey | Yes | -| Attributes | Yes | +The following keys are required in the step's ``With`` configuration: + +| Key | Required | Description | +| --- | --- | --- | +| `IdentityKey` | Yes | Unique identifier for the identity | +| `Attributes` | Yes | Hashtable of attributes to set | + +## Example + +```powershell +@{ + Name = 'CreateIdentity Example' + Type = 'IdLE.Step.CreateIdentity' + With = @{ + IdentityKey = 'user.name' + Attributes = @{ GivenName = 'First'; Surname = 'Last' } + } +} +``` + +## See Also + +- [Capabilities Reference](../capabilities.md) - Details on required capabilities +- [Providers](../providers.md) - Available provider implementations diff --git a/docs/reference/steps/step-delete-identity.md b/docs/reference/steps/step-delete-identity.md index f090ffbc..fa30c345 100644 --- a/docs/reference/steps/step-delete-identity.md +++ b/docs/reference/steps/step-delete-identity.md @@ -9,8 +9,7 @@ - **Module**: `IdLE.Steps.Common` - **Implementation**: `Invoke-IdleStepDeleteIdentity` - **Idempotent**: `Yes` -- **Contracts**: `Unknown` -- **Events**: Unknown +- **Required Capabilities**: `IdLE.Identity.Delete` ## Synopsis @@ -18,7 +17,7 @@ Deletes an identity from the target system. ## Description -This is a provider-agnostic step. The host must supply a provider instance via +The host must supply a provider instance via Context.Providers[<ProviderAlias>] that implements DeleteIdentity(identityKey) and returns an object with properties 'IdentityKey' and 'Changed'. @@ -42,4 +41,22 @@ Authentication: ## Inputs (With.*) -_Unknown (not detected automatically). Document required With.* keys in the step help and/or use a supported pattern._ +This step may not require specific input keys, or they could not be detected automatically. +Please refer to the step description and examples for usage details. + +## Example + +```powershell +@{ + Name = 'DeleteIdentity Example' + Type = 'IdLE.Step.DeleteIdentity' + With = @{ + # See step description for available options + } +} +``` + +## See Also + +- [Capabilities Reference](../capabilities.md) - Details on required capabilities +- [Providers](../providers.md) - Available provider implementations diff --git a/docs/reference/steps/step-disable-identity.md b/docs/reference/steps/step-disable-identity.md index cf5ee16b..f5f8cabb 100644 --- a/docs/reference/steps/step-disable-identity.md +++ b/docs/reference/steps/step-disable-identity.md @@ -9,8 +9,7 @@ - **Module**: `IdLE.Steps.Common` - **Implementation**: `Invoke-IdleStepDisableIdentity` - **Idempotent**: `Yes` -- **Contracts**: `Unknown` -- **Events**: Unknown +- **Required Capabilities**: `IdLE.Identity.Disable` ## Synopsis @@ -18,7 +17,7 @@ Disables an identity in the target system. ## Description -This is a provider-agnostic step. The host must supply a provider instance via +The host must supply a provider instance via Context.Providers[<ProviderAlias>] that implements DisableIdentity(identityKey) and returns an object with properties 'IdentityKey' and 'Changed'. @@ -38,4 +37,22 @@ Authentication: ## Inputs (With.*) -_Unknown (not detected automatically). Document required With.* keys in the step help and/or use a supported pattern._ +This step may not require specific input keys, or they could not be detected automatically. +Please refer to the step description and examples for usage details. + +## Example + +```powershell +@{ + Name = 'DisableIdentity Example' + Type = 'IdLE.Step.DisableIdentity' + With = @{ + # See step description for available options + } +} +``` + +## See Also + +- [Capabilities Reference](../capabilities.md) - Details on required capabilities +- [Providers](../providers.md) - Available provider implementations diff --git a/docs/reference/steps/step-emit-event.md b/docs/reference/steps/step-emit-event.md index dcde656f..6d2e1617 100644 --- a/docs/reference/steps/step-emit-event.md +++ b/docs/reference/steps/step-emit-event.md @@ -9,8 +9,6 @@ - **Module**: `IdLE.Steps.Common` - **Implementation**: `Invoke-IdleStepEmitEvent` - **Idempotent**: `Unknown` -- **Contracts**: `Unknown` -- **Events**: Unknown ## Synopsis @@ -24,4 +22,17 @@ to write structured events. ## Inputs (With.*) -_Unknown (not detected automatically). Document required With.* keys in the step help and/or use a supported pattern._ +This step may not require specific input keys, or they could not be detected automatically. +Please refer to the step description and examples for usage details. + +## Example + +```powershell +@{ + Name = 'EmitEvent Example' + Type = 'IdLE.Step.EmitEvent' + With = @{ + # See step description for available options + } +} +``` diff --git a/docs/reference/steps/step-enable-identity.md b/docs/reference/steps/step-enable-identity.md index 771ddcba..5ac79ccd 100644 --- a/docs/reference/steps/step-enable-identity.md +++ b/docs/reference/steps/step-enable-identity.md @@ -9,8 +9,7 @@ - **Module**: `IdLE.Steps.Common` - **Implementation**: `Invoke-IdleStepEnableIdentity` - **Idempotent**: `Yes` -- **Contracts**: `Unknown` -- **Events**: Unknown +- **Required Capabilities**: `IdLE.Identity.Enable` ## Synopsis @@ -18,7 +17,7 @@ Enables an identity in the target system. ## Description -This is a provider-agnostic step. The host must supply a provider instance via +The host must supply a provider instance via Context.Providers[<ProviderAlias>] that implements EnableIdentity(identityKey) and returns an object with properties 'IdentityKey' and 'Changed'. @@ -38,4 +37,22 @@ Authentication: ## Inputs (With.*) -_Unknown (not detected automatically). Document required With.* keys in the step help and/or use a supported pattern._ +This step may not require specific input keys, or they could not be detected automatically. +Please refer to the step description and examples for usage details. + +## Example + +```powershell +@{ + Name = 'EnableIdentity Example' + Type = 'IdLE.Step.EnableIdentity' + With = @{ + # See step description for available options + } +} +``` + +## See Also + +- [Capabilities Reference](../capabilities.md) - Details on required capabilities +- [Providers](../providers.md) - Available provider implementations diff --git a/docs/reference/steps/step-ensure-attribute.md b/docs/reference/steps/step-ensure-attribute.md index a569a1e1..84edda1d 100644 --- a/docs/reference/steps/step-ensure-attribute.md +++ b/docs/reference/steps/step-ensure-attribute.md @@ -9,8 +9,7 @@ - **Module**: `IdLE.Steps.Common` - **Implementation**: `Invoke-IdleStepEnsureAttribute` - **Idempotent**: `Yes` -- **Contracts**: `Provider must implement method: EnsureAttribute` -- **Events**: Unknown +- **Required Capabilities**: `IdLE.Identity.Attribute.Ensure` ## Synopsis @@ -18,7 +17,7 @@ Ensures that an identity attribute matches the desired value. ## Description -This is a provider-agnostic step. The host must supply a provider instance via +The host must supply a provider instance via Context.Providers[<ProviderAlias>]. The provider must implement an EnsureAttribute method with the signature (IdentityKey, Name, Value) and return an object that contains a boolean property 'Changed'. @@ -38,8 +37,29 @@ Authentication: ## Inputs (With.*) -| Key | Required | -| --- | --- | -| IdentityKey | Yes | -| Name | Yes | -| Value | Yes | +The following keys are required in the step's ``With`` configuration: + +| Key | Required | Description | +| --- | --- | --- | +| `IdentityKey` | Yes | Unique identifier for the identity | +| `Name` | Yes | Name of the attribute or property | +| `Value` | Yes | Desired value to set | + +## Example + +```powershell +@{ + Name = 'EnsureAttribute Example' + Type = 'IdLE.Step.EnsureAttribute' + With = @{ + IdentityKey = 'user.name' + Name = 'AttributeName' + Value = 'AttributeValue' + } +} +``` + +## See Also + +- [Capabilities Reference](../capabilities.md) - Details on required capabilities +- [Providers](../providers.md) - Available provider implementations diff --git a/docs/reference/steps/step-ensure-entitlement.md b/docs/reference/steps/step-ensure-entitlement.md index 63dbbe96..ab861b98 100644 --- a/docs/reference/steps/step-ensure-entitlement.md +++ b/docs/reference/steps/step-ensure-entitlement.md @@ -9,8 +9,7 @@ - **Module**: `IdLE.Steps.Common` - **Implementation**: `Invoke-IdleStepEnsureEntitlement` - **Idempotent**: `Yes` -- **Contracts**: `Unknown` -- **Events**: Unknown +- **Required Capabilities**: `IdLE.Entitlement.List`, `IdLE.Entitlement.Grant`, `IdLE.Entitlement.Revoke` ## Synopsis @@ -44,8 +43,29 @@ Authentication: ## Inputs (With.*) -| Key | Required | -| --- | --- | -| IdentityKey | Yes | -| Entitlement | Yes | -| State | Yes | +The following keys are required in the step's ``With`` configuration: + +| Key | Required | Description | +| --- | --- | --- | +| `IdentityKey` | Yes | Unique identifier for the identity | +| `Entitlement` | Yes | Entitlement identifier or object | +| `State` | Yes | Desired state for the entitlement | + +## Example + +```powershell +@{ + Name = 'EnsureEntitlement Example' + Type = 'IdLE.Step.EnsureEntitlement' + With = @{ + IdentityKey = 'user.name' + Entitlement = @{ Type = 'Group'; Value = 'GroupId' } + State = 'Present' + } +} +``` + +## See Also + +- [Capabilities Reference](../capabilities.md) - Details on required capabilities +- [Providers](../providers.md) - Available provider implementations diff --git a/docs/reference/steps/step-move-identity.md b/docs/reference/steps/step-move-identity.md index 48134535..a69d8266 100644 --- a/docs/reference/steps/step-move-identity.md +++ b/docs/reference/steps/step-move-identity.md @@ -9,8 +9,7 @@ - **Module**: `IdLE.Steps.Common` - **Implementation**: `Invoke-IdleStepMoveIdentity` - **Idempotent**: `Yes` -- **Contracts**: `Unknown` -- **Events**: Unknown +- **Required Capabilities**: `IdLE.Identity.Move` ## Synopsis @@ -18,7 +17,7 @@ Moves an identity to a different container/OU in the target system. ## Description -This is a provider-agnostic step. The host must supply a provider instance via +The host must supply a provider instance via Context.Providers[<ProviderAlias>] that implements MoveIdentity(identityKey, targetContainer) and returns an object with properties 'IdentityKey' and 'Changed'. @@ -38,7 +37,27 @@ Authentication: ## Inputs (With.*) -| Key | Required | -| --- | --- | -| IdentityKey | Yes | -| TargetContainer | Yes | +The following keys are required in the step's ``With`` configuration: + +| Key | Required | Description | +| --- | --- | --- | +| `IdentityKey` | Yes | Unique identifier for the identity | +| `TargetContainer` | Yes | See step description for details | + +## Example + +```powershell +@{ + Name = 'MoveIdentity Example' + Type = 'IdLE.Step.MoveIdentity' + With = @{ + IdentityKey = 'user.name' + TargetContainer = '' + } +} +``` + +## See Also + +- [Capabilities Reference](../capabilities.md) - Details on required capabilities +- [Providers](../providers.md) - Available provider implementations diff --git a/docs/reference/steps/step-trigger-directory-sync.md b/docs/reference/steps/step-trigger-directory-sync.md index 8edaa1b7..a1fddd34 100644 --- a/docs/reference/steps/step-trigger-directory-sync.md +++ b/docs/reference/steps/step-trigger-directory-sync.md @@ -9,8 +9,7 @@ - **Module**: `IdLE.Steps.DirectorySync` - **Implementation**: `Invoke-IdleStepTriggerDirectorySync` - **Idempotent**: `Unknown` -- **Contracts**: `Unknown` -- **Events**: Unknown +- **Required Capabilities**: `IdLE.DirectorySync.Trigger`, `IdLE.DirectorySync.Status` ## Synopsis @@ -18,7 +17,7 @@ Triggers a directory sync cycle and optionally waits for completion. ## Description -This is a provider-agnostic step. The host must supply a provider instance via +The host must supply a provider instance via Context.Providers[<ProviderAlias>] that implements: - StartSyncCycle(PolicyType, AuthSession) @@ -38,4 +37,22 @@ Authentication: ## Inputs (With.*) -_Unknown (not detected automatically). Document required With.* keys in the step help and/or use a supported pattern._ +This step may not require specific input keys, or they could not be detected automatically. +Please refer to the step description and examples for usage details. + +## Example + +```powershell +@{ + Name = 'TriggerDirectorySync Example' + Type = 'IdLE.Step.TriggerDirectorySync' + With = @{ + # See step description for available options + } +} +``` + +## See Also + +- [Capabilities Reference](../capabilities.md) - Details on required capabilities +- [Providers](../providers.md) - Available provider implementations diff --git a/tools/Generate-IdleStepReference.ps1 b/tools/Generate-IdleStepReference.ps1 index 6a999277..01806c4e 100644 --- a/tools/Generate-IdleStepReference.ps1 +++ b/tools/Generate-IdleStepReference.ps1 @@ -332,6 +332,42 @@ function Get-IdleCommandModuleName { return 'Unknown' } +function Get-IdleStepRequiredCapabilities { + [CmdletBinding()] + param( + [Parameter(Mandatory)] + [ValidateNotNullOrEmpty()] + [string] $StepType, + + [Parameter(Mandatory)] + [ValidateNotNullOrEmpty()] + [string] $ModuleName + ) + + # Try to load metadata catalog from the step's module to get required capabilities + try { + $module = Get-Module -Name $ModuleName -ErrorAction SilentlyContinue + if ($null -ne $module) { + # Call Get-IdleStepMetadataCatalog in the context of the specific module + $catalog = & $module { Get-IdleStepMetadataCatalog -ErrorAction SilentlyContinue } + if ($null -ne $catalog) { + $fullStepTypeName = "IdLE.Step.$StepType" + if ($catalog.ContainsKey($fullStepTypeName)) { + $metadata = $catalog[$fullStepTypeName] + if ($metadata -and $metadata.ContainsKey('RequiredCapabilities')) { + return @($metadata.RequiredCapabilities) + } + } + } + } + } + catch { + # Metadata catalog not available or error loading it + } + + return @() +} + function New-IdleStepDocModel { [CmdletBinding()] param( @@ -367,6 +403,9 @@ function New-IdleStepDocModel { $synopsis = 'No synopsis available (missing comment-based help).' } + # Remove redundant "This is a provider-agnostic step." sentence + $description = $description -replace '(?i)This\s+is\s+a\s+provider-agnostic\s+step\.\s*', '' + $requiredWithKeys = @(Get-IdleRequiredWithKeysFromSource -CommandInfo $CommandInfo) $idempotent = 'Unknown' @@ -374,21 +413,21 @@ function New-IdleStepDocModel { $idempotent = 'Yes' } - $providerMethod = Get-IdleProviderMethodHintFromDescription -DescriptionText $description - $contracts = if ($providerMethod) { "Provider must implement method: $providerMethod" } else { 'Unknown' } + # Get required capabilities from metadata catalog + $requiredCapabilities = @(Get-IdleStepRequiredCapabilities -StepType $stepType -ModuleName $moduleName) $slug = ConvertTo-IdleStepSlug -StepType $stepType return [pscustomobject]@{ - StepType = $stepType - Slug = $slug - ModuleName = $moduleName - CommandName = $commandName - Synopsis = $synopsis - Description = $description - RequiredWithKeys = $requiredWithKeys - Idempotent = $idempotent - Contracts = $contracts + StepType = $stepType + Slug = $slug + ModuleName = $moduleName + CommandName = $commandName + Synopsis = $synopsis + Description = $description + RequiredWithKeys = $requiredWithKeys + Idempotent = $idempotent + RequiredCapabilities = $requiredCapabilities } } @@ -414,8 +453,12 @@ function New-IdleStepDetailPageContent { [void]$sb.AppendLine(("- **Module**: ``{0}``" -f $Model.ModuleName)) [void]$sb.AppendLine(("- **Implementation**: ``{0}``" -f $Model.CommandName)) [void]$sb.AppendLine(("- **Idempotent**: ``{0}``" -f $Model.Idempotent)) - [void]$sb.AppendLine(("- **Contracts**: ``{0}``" -f $Model.Contracts)) - [void]$sb.AppendLine(("- **Events**: Unknown")) + + # Only show Required Capabilities if we have any + if ($Model.RequiredCapabilities -and $Model.RequiredCapabilities.Count -gt 0) { + $capsFormatted = ($Model.RequiredCapabilities | ForEach-Object { "``$_``" }) -join ', ' + [void]$sb.AppendLine(("- **Required Capabilities**: {0}" -f $capsFormatted)) + } [void]$sb.AppendLine() [void]$sb.AppendLine('## Synopsis') @@ -434,15 +477,87 @@ function New-IdleStepDetailPageContent { [void]$sb.AppendLine() if ($Model.RequiredWithKeys.Count -eq 0) { - [void]$sb.AppendLine('_Unknown (not detected automatically). Document required With.* keys in the step help and/or use a supported pattern._') + [void]$sb.AppendLine('This step may not require specific input keys, or they could not be detected automatically.') + [void]$sb.AppendLine('Please refer to the step description and examples for usage details.') [void]$sb.AppendLine() } else { - [void]$sb.AppendLine('| Key | Required |') - [void]$sb.AppendLine('| --- | --- |') + [void]$sb.AppendLine('The following keys are required in the step''s ``With`` configuration:') + [void]$sb.AppendLine() + [void]$sb.AppendLine('| Key | Required | Description |') + [void]$sb.AppendLine('| --- | --- | --- |') + foreach ($k in $Model.RequiredWithKeys) { + # Add basic description based on common key patterns + $description = switch ($k) { + 'IdentityKey' { 'Unique identifier for the identity' } + 'Name' { 'Name of the attribute or property' } + 'Value' { 'Desired value to set' } + 'Attributes' { 'Hashtable of attributes to set' } + 'DestinationPath' { 'Target location or path' } + 'Message' { 'Message text to emit (optional for EmitEvent step)' } + 'EntitlementType' { 'Type of entitlement (e.g., Group, License)' } + 'EntitlementValue' { 'Specific entitlement identifier' } + 'Entitlement' { 'Entitlement identifier or object' } + 'State' { 'Desired state for the entitlement' } + 'Ensure' { 'Desired state (Present or Absent)' } + 'Provider' { 'Provider alias (optional, defaults vary by step)' } + 'AuthSessionName' { 'Name of auth session to use (optional)' } + 'PolicyType' { 'Type of policy (e.g., Delta, Initial)' } + 'Wait' { 'Whether to wait for completion' } + default { 'See step description for details' } + } + [void]$sb.AppendLine("| ``$k`` | Yes | $description |") + } + [void]$sb.AppendLine() + } + + # Add examples section + [void]$sb.AppendLine('## Example') + [void]$sb.AppendLine() + [void]$sb.AppendLine('```powershell') + [void]$sb.AppendLine('@{') + [void]$sb.AppendLine((" Name = '{0} Example'" -f $Model.StepType)) + [void]$sb.AppendLine((" Type = 'IdLE.Step.{0}'" -f $Model.StepType)) + [void]$sb.AppendLine(' With = @{') + + if ($Model.RequiredWithKeys.Count -gt 0) { foreach ($k in $Model.RequiredWithKeys) { - [void]$sb.AppendLine("| $k | Yes |") + $exampleValue = switch ($k) { + 'IdentityKey' { '''user.name''' } + 'Name' { '''AttributeName''' } + 'Value' { '''AttributeValue''' } + 'Attributes' { "@{ GivenName = 'First'; Surname = 'Last' }" } + 'DestinationPath' { '''OU=Users,DC=domain,DC=com''' } + 'Message' { '''Custom event message''' } + 'EntitlementType' { '''Group''' } + 'EntitlementValue' { '''CN=GroupName,OU=Groups,DC=domain,DC=com''' } + 'Entitlement' { "@{ Type = 'Group'; Value = 'GroupId' }" } + 'State' { '''Present''' } + 'Ensure' { '''Present''' } + 'Provider' { '''Identity''' } + 'AuthSessionName' { '''AdminSession''' } + 'PolicyType' { '''Delta''' } + 'Wait' { '$true' } + default { '''''' } + } + [void]$sb.AppendLine((" {0,-20} = {1}" -f $k, $exampleValue)) } + } + else { + [void]$sb.AppendLine(' # See step description for available options') + } + + [void]$sb.AppendLine(' }') + [void]$sb.AppendLine('}') + [void]$sb.AppendLine('```') + [void]$sb.AppendLine() + + # Add reference to capabilities if any + if ($Model.RequiredCapabilities -and $Model.RequiredCapabilities.Count -gt 0) { + [void]$sb.AppendLine('## See Also') + [void]$sb.AppendLine() + [void]$sb.AppendLine('- [Capabilities Reference](../capabilities.md) - Details on required capabilities') + [void]$sb.AppendLine('- [Providers](../providers.md) - Available provider implementations') [void]$sb.AppendLine() } From 8702c3dc7047123c8c185316f2c5642e3464d5c3 Mon Sep 17 00:00:00 2001 From: Matthias <13959569+blindzero@users.noreply.github.com> Date: Sat, 7 Feb 2026 22:46:45 +0100 Subject: [PATCH 3/4] Update tools/Generate-IdleStepReference.ps1 Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- tools/Generate-IdleStepReference.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/Generate-IdleStepReference.ps1 b/tools/Generate-IdleStepReference.ps1 index 01806c4e..75a67f7d 100644 --- a/tools/Generate-IdleStepReference.ps1 +++ b/tools/Generate-IdleStepReference.ps1 @@ -531,7 +531,7 @@ function New-IdleStepDetailPageContent { 'Message' { '''Custom event message''' } 'EntitlementType' { '''Group''' } 'EntitlementValue' { '''CN=GroupName,OU=Groups,DC=domain,DC=com''' } - 'Entitlement' { "@{ Type = 'Group'; Value = 'GroupId' }" } + 'Entitlement' { "@{ Kind = 'Group'; Id = 'GroupId'; DisplayName = 'Example Group' }" } 'State' { '''Present''' } 'Ensure' { '''Present''' } 'Provider' { '''Identity''' } From 656729f6f0cce63cf43ab86d2a87d8c16dcd46a3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 7 Feb 2026 21:51:32 +0000 Subject: [PATCH 4/4] Apply PR review feedback: improve input detection, fix module disambiguation, consistent See Also Co-authored-by: blindzero <13959569+blindzero@users.noreply.github.com> --- docs/reference/steps/step-create-identity.md | 4 +- docs/reference/steps/step-delete-identity.md | 9 ++- docs/reference/steps/step-disable-identity.md | 9 ++- docs/reference/steps/step-emit-event.md | 7 +- docs/reference/steps/step-enable-identity.md | 9 ++- .../steps/step-ensure-entitlement.md | 4 +- .../steps/step-trigger-directory-sync.md | 11 ++- tools/Generate-IdleStepReference.ps1 | 78 ++++++++++++++----- 8 files changed, 96 insertions(+), 35 deletions(-) diff --git a/docs/reference/steps/step-create-identity.md b/docs/reference/steps/step-create-identity.md index d692f7c8..0bb9f0a5 100644 --- a/docs/reference/steps/step-create-identity.md +++ b/docs/reference/steps/step-create-identity.md @@ -41,8 +41,8 @@ The following keys are required in the step's ``With`` configuration: | Key | Required | Description | | --- | --- | --- | -| `IdentityKey` | Yes | Unique identifier for the identity | | `Attributes` | Yes | Hashtable of attributes to set | +| `IdentityKey` | Yes | Unique identifier for the identity | ## Example @@ -51,8 +51,8 @@ The following keys are required in the step's ``With`` configuration: Name = 'CreateIdentity Example' Type = 'IdLE.Step.CreateIdentity' With = @{ - IdentityKey = 'user.name' Attributes = @{ GivenName = 'First'; Surname = 'Last' } + IdentityKey = 'user.name' } } ``` diff --git a/docs/reference/steps/step-delete-identity.md b/docs/reference/steps/step-delete-identity.md index fa30c345..c4b01633 100644 --- a/docs/reference/steps/step-delete-identity.md +++ b/docs/reference/steps/step-delete-identity.md @@ -41,8 +41,11 @@ Authentication: ## Inputs (With.*) -This step may not require specific input keys, or they could not be detected automatically. -Please refer to the step description and examples for usage details. +The following keys are required in the step's ``With`` configuration: + +| Key | Required | Description | +| --- | --- | --- | +| `IdentityKey` | Yes | Unique identifier for the identity | ## Example @@ -51,7 +54,7 @@ Please refer to the step description and examples for usage details. Name = 'DeleteIdentity Example' Type = 'IdLE.Step.DeleteIdentity' With = @{ - # See step description for available options + IdentityKey = 'user.name' } } ``` diff --git a/docs/reference/steps/step-disable-identity.md b/docs/reference/steps/step-disable-identity.md index f5f8cabb..35f00476 100644 --- a/docs/reference/steps/step-disable-identity.md +++ b/docs/reference/steps/step-disable-identity.md @@ -37,8 +37,11 @@ Authentication: ## Inputs (With.*) -This step may not require specific input keys, or they could not be detected automatically. -Please refer to the step description and examples for usage details. +The following keys are required in the step's ``With`` configuration: + +| Key | Required | Description | +| --- | --- | --- | +| `IdentityKey` | Yes | Unique identifier for the identity | ## Example @@ -47,7 +50,7 @@ Please refer to the step description and examples for usage details. Name = 'DisableIdentity Example' Type = 'IdLE.Step.DisableIdentity' With = @{ - # See step description for available options + IdentityKey = 'user.name' } } ``` diff --git a/docs/reference/steps/step-emit-event.md b/docs/reference/steps/step-emit-event.md index 6d2e1617..61bbaeb3 100644 --- a/docs/reference/steps/step-emit-event.md +++ b/docs/reference/steps/step-emit-event.md @@ -22,7 +22,7 @@ to write structured events. ## Inputs (With.*) -This step may not require specific input keys, or they could not be detected automatically. +The required input keys could not be detected automatically. Please refer to the step description and examples for usage details. ## Example @@ -36,3 +36,8 @@ Please refer to the step description and examples for usage details. } } ``` + +## See Also + +- [Capabilities Reference](../capabilities.md) - Overview of IdLE capabilities +- [Providers](../providers.md) - Available provider implementations diff --git a/docs/reference/steps/step-enable-identity.md b/docs/reference/steps/step-enable-identity.md index 5ac79ccd..90051687 100644 --- a/docs/reference/steps/step-enable-identity.md +++ b/docs/reference/steps/step-enable-identity.md @@ -37,8 +37,11 @@ Authentication: ## Inputs (With.*) -This step may not require specific input keys, or they could not be detected automatically. -Please refer to the step description and examples for usage details. +The following keys are required in the step's ``With`` configuration: + +| Key | Required | Description | +| --- | --- | --- | +| `IdentityKey` | Yes | Unique identifier for the identity | ## Example @@ -47,7 +50,7 @@ Please refer to the step description and examples for usage details. Name = 'EnableIdentity Example' Type = 'IdLE.Step.EnableIdentity' With = @{ - # See step description for available options + IdentityKey = 'user.name' } } ``` diff --git a/docs/reference/steps/step-ensure-entitlement.md b/docs/reference/steps/step-ensure-entitlement.md index ab861b98..80d36180 100644 --- a/docs/reference/steps/step-ensure-entitlement.md +++ b/docs/reference/steps/step-ensure-entitlement.md @@ -47,8 +47,8 @@ The following keys are required in the step's ``With`` configuration: | Key | Required | Description | | --- | --- | --- | -| `IdentityKey` | Yes | Unique identifier for the identity | | `Entitlement` | Yes | Entitlement identifier or object | +| `IdentityKey` | Yes | Unique identifier for the identity | | `State` | Yes | Desired state for the entitlement | ## Example @@ -58,8 +58,8 @@ The following keys are required in the step's ``With`` configuration: Name = 'EnsureEntitlement Example' Type = 'IdLE.Step.EnsureEntitlement' With = @{ + Entitlement = @{ Kind = 'Group'; Id = 'GroupId'; DisplayName = 'Example Group' } IdentityKey = 'user.name' - Entitlement = @{ Type = 'Group'; Value = 'GroupId' } State = 'Present' } } diff --git a/docs/reference/steps/step-trigger-directory-sync.md b/docs/reference/steps/step-trigger-directory-sync.md index a1fddd34..c80813e2 100644 --- a/docs/reference/steps/step-trigger-directory-sync.md +++ b/docs/reference/steps/step-trigger-directory-sync.md @@ -37,8 +37,12 @@ Authentication: ## Inputs (With.*) -This step may not require specific input keys, or they could not be detected automatically. -Please refer to the step description and examples for usage details. +The following keys are required in the step's ``With`` configuration: + +| Key | Required | Description | +| --- | --- | --- | +| `AuthSessionName` | Yes | Name of auth session to use (optional) | +| `PolicyType` | Yes | Type of policy (e.g., Delta, Initial) | ## Example @@ -47,7 +51,8 @@ Please refer to the step description and examples for usage details. Name = 'TriggerDirectorySync Example' Type = 'IdLE.Step.TriggerDirectorySync' With = @{ - # See step description for available options + AuthSessionName = 'AdminSession' + PolicyType = 'Delta' } } ``` diff --git a/tools/Generate-IdleStepReference.ps1 b/tools/Generate-IdleStepReference.ps1 index 75a67f7d..8bd1e362 100644 --- a/tools/Generate-IdleStepReference.ps1 +++ b/tools/Generate-IdleStepReference.ps1 @@ -206,6 +206,7 @@ function Get-IdleRequiredWithKeysFromSource { # Best-effort heuristic: detect patterns like: # foreach ($key in @('IdentityKey','Name','Value')) { ... } + # OR throw messages like: "StepName requires With.KeyName." $filePath = $null if ($CommandInfo.ScriptBlock -and $CommandInfo.ScriptBlock.File) { $filePath = $CommandInfo.ScriptBlock.File @@ -216,21 +217,48 @@ function Get-IdleRequiredWithKeysFromSource { } $content = Get-Content -Path $filePath -Raw -ErrorAction Stop + $keys = @() + # Pattern 1: foreach loop with key array $m = [regex]::Match( $content, 'foreach\s*\(\s*\$key\s+in\s+@\((?[^)]*)\)\s*\)', 'IgnoreCase' ) - if (-not $m.Success) { - return @() + if ($m.Success) { + $listText = $m.Groups['List'].Value + $foreachKeys = [regex]::Matches($listText, "'(?[^']+)'") | ForEach-Object { $_.Groups['Key'].Value } + $keys += $foreachKeys } - $listText = $m.Groups['List'].Value - $keys = [regex]::Matches($listText, "'(?[^']+)'") | ForEach-Object { $_.Groups['Key'].Value } + # Pattern 2: throw messages like "requires With.KeyName" + $throwMatches = [regex]::Matches( + $content, + 'throw\s+[^"]*"[^"]*requires\s+With\.(?[A-Za-z][A-Za-z0-9]*)', + 'IgnoreCase' + ) + foreach ($match in $throwMatches) { + $keys += $match.Groups['Key'].Value + } + + # Pattern 3: ContainsKey checks followed by throw + $containsMatches = [regex]::Matches( + $content, + '\$with\.ContainsKey\(''(?[^'']+)''\)', + 'IgnoreCase' + ) + foreach ($match in $containsMatches) { + $keyName = $match.Groups['Key'].Value + # Only include if there's a throw statement nearby (within next 100 chars) + $matchPos = $match.Index + $nextChunk = $content.Substring($matchPos, [Math]::Min(150, $content.Length - $matchPos)) + if ($nextChunk -match 'throw') { + $keys += $keyName + } + } - return @($keys | Where-Object { -not [string]::IsNullOrWhiteSpace($_) } | Select-Object -Unique) + return @($keys | Where-Object { -not [string]::IsNullOrWhiteSpace($_) } | Select-Object -Unique | Sort-Object) } function Get-IdleProviderMethodHintFromDescription { @@ -346,16 +374,27 @@ function Get-IdleStepRequiredCapabilities { # Try to load metadata catalog from the step's module to get required capabilities try { - $module = Get-Module -Name $ModuleName -ErrorAction SilentlyContinue + # Disambiguate in case multiple versions of the module are loaded + $module = Get-Module -Name $ModuleName -All -ErrorAction SilentlyContinue | Select-Object -First 1 if ($null -ne $module) { # Call Get-IdleStepMetadataCatalog in the context of the specific module $catalog = & $module { Get-IdleStepMetadataCatalog -ErrorAction SilentlyContinue } - if ($null -ne $catalog) { + if ($catalog -is [System.Collections.IDictionary]) { $fullStepTypeName = "IdLE.Step.$StepType" - if ($catalog.ContainsKey($fullStepTypeName)) { + if ($catalog.Contains($fullStepTypeName)) { $metadata = $catalog[$fullStepTypeName] - if ($metadata -and $metadata.ContainsKey('RequiredCapabilities')) { - return @($metadata.RequiredCapabilities) + if ($metadata) { + $requiredCapabilities = $null + if ($metadata -is [System.Collections.IDictionary] -and $metadata.Contains('RequiredCapabilities')) { + $requiredCapabilities = $metadata['RequiredCapabilities'] + } + elseif ($metadata.PSObject -and $metadata.PSObject.Properties['RequiredCapabilities']) { + $requiredCapabilities = $metadata.RequiredCapabilities + } + + if ($null -ne $requiredCapabilities) { + return @($requiredCapabilities) + } } } } @@ -477,7 +516,7 @@ function New-IdleStepDetailPageContent { [void]$sb.AppendLine() if ($Model.RequiredWithKeys.Count -eq 0) { - [void]$sb.AppendLine('This step may not require specific input keys, or they could not be detected automatically.') + [void]$sb.AppendLine('The required input keys could not be detected automatically.') [void]$sb.AppendLine('Please refer to the step description and examples for usage details.') [void]$sb.AppendLine() } @@ -488,7 +527,7 @@ function New-IdleStepDetailPageContent { [void]$sb.AppendLine('| --- | --- | --- |') foreach ($k in $Model.RequiredWithKeys) { # Add basic description based on common key patterns - $description = switch ($k) { + $keyDescription = switch ($k) { 'IdentityKey' { 'Unique identifier for the identity' } 'Name' { 'Name of the attribute or property' } 'Value' { 'Desired value to set' } @@ -506,7 +545,7 @@ function New-IdleStepDetailPageContent { 'Wait' { 'Whether to wait for completion' } default { 'See step description for details' } } - [void]$sb.AppendLine("| ``$k`` | Yes | $description |") + [void]$sb.AppendLine("| ``$k`` | Yes | $keyDescription |") } [void]$sb.AppendLine() } @@ -552,14 +591,17 @@ function New-IdleStepDetailPageContent { [void]$sb.AppendLine('```') [void]$sb.AppendLine() - # Add reference to capabilities if any + # Add "See Also" section for consistency across all step pages + [void]$sb.AppendLine('## See Also') + [void]$sb.AppendLine() if ($Model.RequiredCapabilities -and $Model.RequiredCapabilities.Count -gt 0) { - [void]$sb.AppendLine('## See Also') - [void]$sb.AppendLine() [void]$sb.AppendLine('- [Capabilities Reference](../capabilities.md) - Details on required capabilities') - [void]$sb.AppendLine('- [Providers](../providers.md) - Available provider implementations') - [void]$sb.AppendLine() } + else { + [void]$sb.AppendLine('- [Capabilities Reference](../capabilities.md) - Overview of IdLE capabilities') + } + [void]$sb.AppendLine('- [Providers](../providers.md) - Available provider implementations') + [void]$sb.AppendLine() # Normalize output: ensure exactly one LF at EOF. return ($sb.ToString().TrimEnd()) + "`n"