Releases: Omnicit/Omnicit.PIM
Release list
v0.5.1
[v0.5.1]
Fixed
Enable-OPIMMyRole/Get-OPIMAzureRoleno longer skip the Azure sign-in when a stale autosaved Az context exists in a fresh session.Initialize-OPIMAuthnow validates the cached Az context with a silentGet-AzAccessTokenbefore trusting it; if no token can be acquired it reconnects viaConnect-AzAccount(restoring the expected second browser prompt for Azure RBAC).Invoke-OPIMGraphRequestnow recovers from the PIMRoleAssignmentRequestAcrsValidationFailedactivation error automatically. The claims challenge in this 400 response body is URL-encoded (&claims=%7B...%7D), a different encoding from the base64urlWWW-Authenticate: claims="..."401 form the parser previously handled.Get-ClaimsFromExceptionnow decodes both encodings (and raw JSON) and feeds the result to the existing MSALAcquireTokenInteractive().WithClaims()step-up, so activations requiring a Conditional Access authentication context succeed with a single browser prompt and no manualDisconnect-OPIM.Invoke-OPIMGraphRequestACRS retry no longer gates on the session-sticky$script:_OPIMAuthState.ClaimsSatisfiedflag. Each call performs at most one step-up retry on its own, so a second activation in the same session that requires a claims challenge is no longer silently skipped.Invoke-OPIMGraphRequestnow transparently re-authenticates and retries once when Graph rejects a bearer token as invalid/expired (HTTP 401 orInvalidAuthenticationToken/CompactToken/token is expired/Lifetime validation failed), via the newInitialize-OPIMAuth -ForceRefreshpath (MSALAcquireTokenSilent().WithForceRefresh($true)) — recovering without a destructive full disconnect.- CI build (
Build & Package Module) no longer fails with "The required module 'Configuration' is not loaded" when importingModuleBuilder.ConfigurationandMetadata(ModuleBuilder's transitive runtime dependencies) are now listed explicitly inRequiredModules.psd1because PSResourceGet 1.0.1 does not install transitiveRequiredModulesduring the bootstrap on a clean agent.
Changed
Initialize-OPIMAuthnow disables the Web Account Manager (WAM) broker at process scope (Update-AzConfig -EnableLoginByWam $false -Scope Process) immediately beforeConnect-AzAccount, so Azure RBAC sign-in uses the system browser consistently with the Graph side instead of the WAM account picker that hangs in some terminals. The user's persisted Az config is never modified. (Unlike the previously removed Graph-sideSet-MgGraphOption -DisableLoginByWAM, the Az-sideUpdate-AzConfig -EnableLoginByWamtoggle is honoured byConnect-AzAccount.)Initialize-OPIMAuthgains a-ForceRefreshswitch that bypasses the cached-token idempotency check and forces MSAL to mint a fresh access token from the refresh token.
Added
Get-OPIMCurrentTenantInfoprivate helper — resolves the current tenant GUID and display name from the active Graph session. Used byInstall-,Set-, andRemove-OPIMConfigurationto enrich the confirmation prompt.Install-OPIMConfigurationnow auto-resolves-TenantIdfrom the active Graph context when the parameter is omitted. A non-terminating error is emitted when no-TenantIdis supplied and no active Graph session is available.
Changed
Install-OPIMConfiguration,Set-OPIMConfiguration, andRemove-OPIMConfigurationnow haveConfirmImpact = 'High'. TheShouldProcessconfirmation prompt includes the tenant alias, display name, and resolved GUID, making it clear which tenant is being modified before any write occurs.-TenantIdinInstall-OPIMConfigurationis no longer[Mandatory]; it is auto-resolved fromGet-MgContextwhen omitted.- PSScriptAnalyzer suppressions added to all six argument-completer classes (
AzureEligibleRoleCompleter,AzureActivatedRoleCompleter,DirectoryEligibleRoleCompleter,DirectoryActivatedRoleCompleter,GroupEligibleCompleter,GroupActivatedCompleter).
Changed
Write-CmdletErrorrevamped: newErrorRecordparameter set (pass-through),InnerExceptionparameter for exception chaining,[CmdletBinding()]added. All public and private functions now useWrite-CmdletErroras the single error-emission entry point.- All variable names across
Convert-GraphHttpException,Get-MyId,Invoke-OPIMGraphRequest,Export-OPIMTenantMap, and completer classes updated to PascalCase per module code-style rules.
(alias Connect-PIM) — new public cmdlet to pre-authenticate against Microsoft Graph and optionally Azure. A single browser prompt covers all PIM surfaces (directory roles, Entra ID groups, Azure RBAC). All Get-/Enable-/Disable-OPIM* cmdlets call this automatically on first use.
Disconnect-OPIM(aliasDisconnect-PIM) — new public cmdlet to clear all cached session tokens and disconnect from Graph and Azure.- Centralized MSAL-based authentication layer (
Initialize-OPIMAuth,Get-OPIMMsalApplicationprivate helpers). All PIM cmdlets now share a single token-acquisition flow that caches the result and is idempotent when called multiple times in the same session. - ACRS Conditional Access claims-challenge handling moved into
Invoke-OPIMGraphRequest. A single reactive browser re-prompt is issued when Graph returns a step-up challenge, eliminating repeated browser windows when activating multiple roles in oneEnable-OPIMMyRolecall. Invoke-OPIMGraphRequestprivate wrapper replaces directInvoke-MgGraphRequestcalls throughout the module. Provides bearer-token security (removes raw error records before any processing), ACRS retry, and consistentConvert-GraphHttpExceptionerror conversion.
(ParameterSetName ByIdentity) added to all six Enable-OPIM* and Disable-OPIM* cmdlets. Activates or deactivates a role/group by schedule ID (or schedule Name for Azure) without tab completion. For Disable-* cmdlets, the ID must correspond to an active schedule instance (from Get-OPIM* -Activated). For Azure RBAC the identity is the Name property.
Get-OPIMDirectoryRole,Get-OPIMEntraIDGroup, andGet-OPIMAzureRolegain a new-AllParameterSet that returns both eligible and active schedules for the current user in a single call.-Alland-Activatedare mutually exclusive.Get-OPIMDirectoryRole— new-RoleNamepositional parameter ([Position = 0]) with tab completion viaDirectoryEligibleRoleCompleter. Extracts the schedule ID from the trailing(id)and performs a dual-search across eligible and active endpoints.Get-OPIMEntraIDGroup— new-GroupNamepositional parameter ([Position = 0]) with tab completion viaGroupEligibleCompleter. Extracts the schedule ID from the trailing(id)and performs a dual-search across eligible and active endpoints.Get-OPIMAzureRole— new-RoleNamepositional parameter ([Position = 0]) with tab completion viaAzureEligibleRoleCompleter, and new-Identityparameter for direct look-up by scheduleName. Both perform dual-search across eligible and active endpoints.- Combined schedule view: When
-All,-RoleName/-GroupName/-Identitytrigger dual-search, all threeGet-OPIM*cmdlets now returnOmnicit.PIM.*CombinedScheduletyped objects with aStatuscolumn (EligibleorActive) for consistent table output across both result types. - New format/type files for combined schedule views:
Omnicit.PIM.DirectoryCombinedSchedule,Omnicit.PIM.GroupCombinedSchedule,Omnicit.PIM.AzureCombinedSchedule— each with aStatuscolumn in the default table view.
Performance
- Module load time reduced by ~8 seconds (~55% of total import time). Consolidated 13 individual
*.Format.ps1xmlfiles into a singleOmnicit.PIM.Format.ps1xmland 13*.Types.ps1xmlfiles into a singleOmnicit.PIM.Types.ps1xml. Previously each file triggered a full format/type table rebuild (~0.49s and ~0.11s per call respectively). FormatsToProcessre-enabled in the module manifest — format data is now loaded natively by PowerShell at zero extra cost. This was previously disabled becauseUpdate-FormatData -PrependPathwas needed to override Az.Resources native types; that override (RoleAssignmentScheduleRequest) is no longer needed since all output is wrapped asOmnicit.PIM.*custom types.suffix.ps1now loads a single consolidatedOmnicit.PIM.Types.ps1xmlfile (1 call toUpdate-TypeData) instead of enumerating and loading 13 individual files (14 calls).TypesToProcessremains disabled in the manifest becauseRemove-Moduledoes not clean type data, causing "member already present" errors onImport-Module -Force.- Removed orphaned
RoleAssignmentScheduleRequest.Format.ps1xmlandRoleAssignmentScheduleRequest.Types.ps1xml— these targeted the native AzMicrosoft.Azure.PowerShell.Cmdlets.Resources.Authorization.Models.Api20201001Preview.RoleAssignmentScheduleRequesttype, but all Azure output is now wrapped withOmnicit.PIM.AzureAssignmentScheduleRequest. - Pipeline safety guards:
Enable-OPIMDirectoryRole,Enable-OPIMEntraIDGroup,Enable-OPIMAzureRolenow skip pipeline objects already tagged as active assignment instances (e.g. objects piped fromGet-OPIM* -Allthat haveStatus = Active), emitting aWrite-Verbosemessage instead of attempting an activation that would fail. - Pipeline safety guards:
Disable-OPIMDirectoryRole,Disable-OPIMEntraIDGroup,Disable-OPIMAzureRolenow skip pipeline objects tagged as eligible-only schedules (e.g. objects piped fromGet-OPIM* -Allthat haveStatus = Eligible), emitting a non-terminating error instead of attempting a deactivation that would fail.
Changed
- BREAKING —
Get-OPIMDirectoryRole -All,Get-OPIMEntraIDGroup -All, andGet-OPIMAzureRole -Allno longer removefilterByCurrentUser/asTarget()to list all principals. They now return both eligible and active schedules for the current user. Admins see...
v0.5.1-preview0001
[v0.5.1-preview0001]
Fixed
Enable-OPIMMyRole/Get-OPIMAzureRoleno longer skip the Azure sign-in when a stale autosaved Az context exists in a fresh session.Initialize-OPIMAuthnow validates the cached Az context with a silentGet-AzAccessTokenbefore trusting it; if no token can be acquired it reconnects viaConnect-AzAccount(restoring the expected second browser prompt for Azure RBAC).Invoke-OPIMGraphRequestnow recovers from the PIMRoleAssignmentRequestAcrsValidationFailedactivation error automatically. The claims challenge in this 400 response body is URL-encoded (&claims=%7B...%7D), a different encoding from the base64urlWWW-Authenticate: claims="..."401 form the parser previously handled.Get-ClaimsFromExceptionnow decodes both encodings (and raw JSON) and feeds the result to the existing MSALAcquireTokenInteractive().WithClaims()step-up, so activations requiring a Conditional Access authentication context succeed with a single browser prompt and no manualDisconnect-OPIM.Invoke-OPIMGraphRequestACRS retry no longer gates on the session-sticky$script:_OPIMAuthState.ClaimsSatisfiedflag. Each call performs at most one step-up retry on its own, so a second activation in the same session that requires a claims challenge is no longer silently skipped.Invoke-OPIMGraphRequestnow transparently re-authenticates and retries once when Graph rejects a bearer token as invalid/expired (HTTP 401 orInvalidAuthenticationToken/CompactToken/token is expired/Lifetime validation failed), via the newInitialize-OPIMAuth -ForceRefreshpath (MSALAcquireTokenSilent().WithForceRefresh($true)) — recovering without a destructive full disconnect.- CI build (
Build & Package Module) no longer fails with "The required module 'Configuration' is not loaded" when importingModuleBuilder.ConfigurationandMetadata(ModuleBuilder's transitive runtime dependencies) are now listed explicitly inRequiredModules.psd1because PSResourceGet 1.0.1 does not install transitiveRequiredModulesduring the bootstrap on a clean agent.
Changed
Initialize-OPIMAuthnow disables the Web Account Manager (WAM) broker at process scope (Update-AzConfig -EnableLoginByWam $false -Scope Process) immediately beforeConnect-AzAccount, so Azure RBAC sign-in uses the system browser consistently with the Graph side instead of the WAM account picker that hangs in some terminals. The user's persisted Az config is never modified. (Unlike the previously removed Graph-sideSet-MgGraphOption -DisableLoginByWAM, the Az-sideUpdate-AzConfig -EnableLoginByWamtoggle is honoured byConnect-AzAccount.)Initialize-OPIMAuthgains a-ForceRefreshswitch that bypasses the cached-token idempotency check and forces MSAL to mint a fresh access token from the refresh token.
Added
Get-OPIMCurrentTenantInfoprivate helper — resolves the current tenant GUID and display name from the active Graph session. Used byInstall-,Set-, andRemove-OPIMConfigurationto enrich the confirmation prompt.Install-OPIMConfigurationnow auto-resolves-TenantIdfrom the active Graph context when the parameter is omitted. A non-terminating error is emitted when no-TenantIdis supplied and no active Graph session is available.
Changed
Install-OPIMConfiguration,Set-OPIMConfiguration, andRemove-OPIMConfigurationnow haveConfirmImpact = 'High'. TheShouldProcessconfirmation prompt includes the tenant alias, display name, and resolved GUID, making it clear which tenant is being modified before any write occurs.-TenantIdinInstall-OPIMConfigurationis no longer[Mandatory]; it is auto-resolved fromGet-MgContextwhen omitted.- PSScriptAnalyzer suppressions added to all six argument-completer classes (
AzureEligibleRoleCompleter,AzureActivatedRoleCompleter,DirectoryEligibleRoleCompleter,DirectoryActivatedRoleCompleter,GroupEligibleCompleter,GroupActivatedCompleter).
Changed
Write-CmdletErrorrevamped: newErrorRecordparameter set (pass-through),InnerExceptionparameter for exception chaining,[CmdletBinding()]added. All public and private functions now useWrite-CmdletErroras the single error-emission entry point.- All variable names across
Convert-GraphHttpException,Get-MyId,Invoke-OPIMGraphRequest,Export-OPIMTenantMap, and completer classes updated to PascalCase per module code-style rules.
(alias Connect-PIM) — new public cmdlet to pre-authenticate against Microsoft Graph and optionally Azure. A single browser prompt covers all PIM surfaces (directory roles, Entra ID groups, Azure RBAC). All Get-/Enable-/Disable-OPIM* cmdlets call this automatically on first use.
Disconnect-OPIM(aliasDisconnect-PIM) — new public cmdlet to clear all cached session tokens and disconnect from Graph and Azure.- Centralized MSAL-based authentication layer (
Initialize-OPIMAuth,Get-OPIMMsalApplicationprivate helpers). All PIM cmdlets now share a single token-acquisition flow that caches the result and is idempotent when called multiple times in the same session. - ACRS Conditional Access claims-challenge handling moved into
Invoke-OPIMGraphRequest. A single reactive browser re-prompt is issued when Graph returns a step-up challenge, eliminating repeated browser windows when activating multiple roles in oneEnable-OPIMMyRolecall. Invoke-OPIMGraphRequestprivate wrapper replaces directInvoke-MgGraphRequestcalls throughout the module. Provides bearer-token security (removes raw error records before any processing), ACRS retry, and consistentConvert-GraphHttpExceptionerror conversion.
(ParameterSetName ByIdentity) added to all six Enable-OPIM* and Disable-OPIM* cmdlets. Activates or deactivates a role/group by schedule ID (or schedule Name for Azure) without tab completion. For Disable-* cmdlets, the ID must correspond to an active schedule instance (from Get-OPIM* -Activated). For Azure RBAC the identity is the Name property.
Get-OPIMDirectoryRole,Get-OPIMEntraIDGroup, andGet-OPIMAzureRolegain a new-AllParameterSet that returns both eligible and active schedules for the current user in a single call.-Alland-Activatedare mutually exclusive.Get-OPIMDirectoryRole— new-RoleNamepositional parameter ([Position = 0]) with tab completion viaDirectoryEligibleRoleCompleter. Extracts the schedule ID from the trailing(id)and performs a dual-search across eligible and active endpoints.Get-OPIMEntraIDGroup— new-GroupNamepositional parameter ([Position = 0]) with tab completion viaGroupEligibleCompleter. Extracts the schedule ID from the trailing(id)and performs a dual-search across eligible and active endpoints.Get-OPIMAzureRole— new-RoleNamepositional parameter ([Position = 0]) with tab completion viaAzureEligibleRoleCompleter, and new-Identityparameter for direct look-up by scheduleName. Both perform dual-search across eligible and active endpoints.- Combined schedule view: When
-All,-RoleName/-GroupName/-Identitytrigger dual-search, all threeGet-OPIM*cmdlets now returnOmnicit.PIM.*CombinedScheduletyped objects with aStatuscolumn (EligibleorActive) for consistent table output across both result types. - New format/type files for combined schedule views:
Omnicit.PIM.DirectoryCombinedSchedule,Omnicit.PIM.GroupCombinedSchedule,Omnicit.PIM.AzureCombinedSchedule— each with aStatuscolumn in the default table view.
Performance
- Module load time reduced by ~8 seconds (~55% of total import time). Consolidated 13 individual
*.Format.ps1xmlfiles into a singleOmnicit.PIM.Format.ps1xmland 13*.Types.ps1xmlfiles into a singleOmnicit.PIM.Types.ps1xml. Previously each file triggered a full format/type table rebuild (~0.49s and ~0.11s per call respectively). FormatsToProcessre-enabled in the module manifest — format data is now loaded natively by PowerShell at zero extra cost. This was previously disabled becauseUpdate-FormatData -PrependPathwas needed to override Az.Resources native types; that override (RoleAssignmentScheduleRequest) is no longer needed since all output is wrapped asOmnicit.PIM.*custom types.suffix.ps1now loads a single consolidatedOmnicit.PIM.Types.ps1xmlfile (1 call toUpdate-TypeData) instead of enumerating and loading 13 individual files (14 calls).TypesToProcessremains disabled in the manifest becauseRemove-Moduledoes not clean type data, causing "member already present" errors onImport-Module -Force.- Removed orphaned
RoleAssignmentScheduleRequest.Format.ps1xmlandRoleAssignmentScheduleRequest.Types.ps1xml— these targeted the native AzMicrosoft.Azure.PowerShell.Cmdlets.Resources.Authorization.Models.Api20201001Preview.RoleAssignmentScheduleRequesttype, but all Azure output is now wrapped withOmnicit.PIM.AzureAssignmentScheduleRequest. - Pipeline safety guards:
Enable-OPIMDirectoryRole,Enable-OPIMEntraIDGroup,Enable-OPIMAzureRolenow skip pipeline objects already tagged as active assignment instances (e.g. objects piped fromGet-OPIM* -Allthat haveStatus = Active), emitting aWrite-Verbosemessage instead of attempting an activation that would fail. - Pipeline safety guards:
Disable-OPIMDirectoryRole,Disable-OPIMEntraIDGroup,Disable-OPIMAzureRolenow skip pipeline objects tagged as eligible-only schedules (e.g. objects piped fromGet-OPIM* -Allthat haveStatus = Eligible), emitting a non-terminating error instead of attempting a deactivation that would fail.
Changed
- BREAKING —
Get-OPIMDirectoryRole -All,Get-OPIMEntraIDGroup -All, andGet-OPIMAzureRole -Allno longer removefilterByCurrentUser/asTarget()to list all principals. They now return both eligible and active schedules for the current user...
v0.5.0
[v0.5.0]
Fixed
Invoke-OPIMGraphRequestnow recovers from the PIMRoleAssignmentRequestAcrsValidationFailedactivation error automatically. The claims challenge in this 400 response body is URL-encoded (&claims=%7B...%7D), a different encoding from the base64urlWWW-Authenticate: claims="..."401 form the parser previously handled.Get-ClaimsFromExceptionnow decodes both encodings (and raw JSON) and feeds the result to the existing MSALAcquireTokenInteractive().WithClaims()step-up, so activations requiring a Conditional Access authentication context succeed with a single browser prompt and no manualDisconnect-OPIM.Invoke-OPIMGraphRequestACRS retry no longer gates on the session-sticky$script:_OPIMAuthState.ClaimsSatisfiedflag. Each call performs at most one step-up retry on its own, so a second activation in the same session that requires a claims challenge is no longer silently skipped.Invoke-OPIMGraphRequestnow transparently re-authenticates and retries once when Graph rejects a bearer token as invalid/expired (HTTP 401 orInvalidAuthenticationToken/CompactToken/token is expired/Lifetime validation failed), via the newInitialize-OPIMAuth -ForceRefreshpath (MSALAcquireTokenSilent().WithForceRefresh($true)) — recovering without a destructive full disconnect.- CI build (
Build & Package Module) no longer fails with "The required module 'Configuration' is not loaded" when importingModuleBuilder.ConfigurationandMetadata(ModuleBuilder's transitive runtime dependencies) are now listed explicitly inRequiredModules.psd1because PSResourceGet 1.0.1 does not install transitiveRequiredModulesduring the bootstrap on a clean agent.
Changed
Initialize-OPIMAuthnow disables the Web Account Manager (WAM) broker at process scope (Update-AzConfig -EnableLoginByWam $false -Scope Process) immediately beforeConnect-AzAccount, so Azure RBAC sign-in uses the system browser consistently with the Graph side instead of the WAM account picker that hangs in some terminals. The user's persisted Az config is never modified. (Unlike the previously removed Graph-sideSet-MgGraphOption -DisableLoginByWAM, the Az-sideUpdate-AzConfig -EnableLoginByWamtoggle is honoured byConnect-AzAccount.)Initialize-OPIMAuthgains a-ForceRefreshswitch that bypasses the cached-token idempotency check and forces MSAL to mint a fresh access token from the refresh token.
Added
Get-OPIMCurrentTenantInfoprivate helper — resolves the current tenant GUID and display name from the active Graph session. Used byInstall-,Set-, andRemove-OPIMConfigurationto enrich the confirmation prompt.Install-OPIMConfigurationnow auto-resolves-TenantIdfrom the active Graph context when the parameter is omitted. A non-terminating error is emitted when no-TenantIdis supplied and no active Graph session is available.
Changed
Install-OPIMConfiguration,Set-OPIMConfiguration, andRemove-OPIMConfigurationnow haveConfirmImpact = 'High'. TheShouldProcessconfirmation prompt includes the tenant alias, display name, and resolved GUID, making it clear which tenant is being modified before any write occurs.-TenantIdinInstall-OPIMConfigurationis no longer[Mandatory]; it is auto-resolved fromGet-MgContextwhen omitted.- PSScriptAnalyzer suppressions added to all six argument-completer classes (
AzureEligibleRoleCompleter,AzureActivatedRoleCompleter,DirectoryEligibleRoleCompleter,DirectoryActivatedRoleCompleter,GroupEligibleCompleter,GroupActivatedCompleter).
Changed
Write-CmdletErrorrevamped: newErrorRecordparameter set (pass-through),InnerExceptionparameter for exception chaining,[CmdletBinding()]added. All public and private functions now useWrite-CmdletErroras the single error-emission entry point.- All variable names across
Convert-GraphHttpException,Get-MyId,Invoke-OPIMGraphRequest,Export-OPIMTenantMap, and completer classes updated to PascalCase per module code-style rules.
(alias Connect-PIM) — new public cmdlet to pre-authenticate against Microsoft Graph and optionally Azure. A single browser prompt covers all PIM surfaces (directory roles, Entra ID groups, Azure RBAC). All Get-/Enable-/Disable-OPIM* cmdlets call this automatically on first use.
Disconnect-OPIM(aliasDisconnect-PIM) — new public cmdlet to clear all cached session tokens and disconnect from Graph and Azure.- Centralized MSAL-based authentication layer (
Initialize-OPIMAuth,Get-OPIMMsalApplicationprivate helpers). All PIM cmdlets now share a single token-acquisition flow that caches the result and is idempotent when called multiple times in the same session. - ACRS Conditional Access claims-challenge handling moved into
Invoke-OPIMGraphRequest. A single reactive browser re-prompt is issued when Graph returns a step-up challenge, eliminating repeated browser windows when activating multiple roles in oneEnable-OPIMMyRolecall. Invoke-OPIMGraphRequestprivate wrapper replaces directInvoke-MgGraphRequestcalls throughout the module. Provides bearer-token security (removes raw error records before any processing), ACRS retry, and consistentConvert-GraphHttpExceptionerror conversion.
(ParameterSetName ByIdentity) added to all six Enable-OPIM* and Disable-OPIM* cmdlets. Activates or deactivates a role/group by schedule ID (or schedule Name for Azure) without tab completion. For Disable-* cmdlets, the ID must correspond to an active schedule instance (from Get-OPIM* -Activated). For Azure RBAC the identity is the Name property.
Get-OPIMDirectoryRole,Get-OPIMEntraIDGroup, andGet-OPIMAzureRolegain a new-AllParameterSet that returns both eligible and active schedules for the current user in a single call.-Alland-Activatedare mutually exclusive.Get-OPIMDirectoryRole— new-RoleNamepositional parameter ([Position = 0]) with tab completion viaDirectoryEligibleRoleCompleter. Extracts the schedule ID from the trailing(id)and performs a dual-search across eligible and active endpoints.Get-OPIMEntraIDGroup— new-GroupNamepositional parameter ([Position = 0]) with tab completion viaGroupEligibleCompleter. Extracts the schedule ID from the trailing(id)and performs a dual-search across eligible and active endpoints.Get-OPIMAzureRole— new-RoleNamepositional parameter ([Position = 0]) with tab completion viaAzureEligibleRoleCompleter, and new-Identityparameter for direct look-up by scheduleName. Both perform dual-search across eligible and active endpoints.- Combined schedule view: When
-All,-RoleName/-GroupName/-Identitytrigger dual-search, all threeGet-OPIM*cmdlets now returnOmnicit.PIM.*CombinedScheduletyped objects with aStatuscolumn (EligibleorActive) for consistent table output across both result types. - New format/type files for combined schedule views:
Omnicit.PIM.DirectoryCombinedSchedule,Omnicit.PIM.GroupCombinedSchedule,Omnicit.PIM.AzureCombinedSchedule— each with aStatuscolumn in the default table view.
Performance
- Module load time reduced by ~8 seconds (~55% of total import time). Consolidated 13 individual
*.Format.ps1xmlfiles into a singleOmnicit.PIM.Format.ps1xmland 13*.Types.ps1xmlfiles into a singleOmnicit.PIM.Types.ps1xml. Previously each file triggered a full format/type table rebuild (~0.49s and ~0.11s per call respectively). FormatsToProcessre-enabled in the module manifest — format data is now loaded natively by PowerShell at zero extra cost. This was previously disabled becauseUpdate-FormatData -PrependPathwas needed to override Az.Resources native types; that override (RoleAssignmentScheduleRequest) is no longer needed since all output is wrapped asOmnicit.PIM.*custom types.suffix.ps1now loads a single consolidatedOmnicit.PIM.Types.ps1xmlfile (1 call toUpdate-TypeData) instead of enumerating and loading 13 individual files (14 calls).TypesToProcessremains disabled in the manifest becauseRemove-Moduledoes not clean type data, causing "member already present" errors onImport-Module -Force.- Removed orphaned
RoleAssignmentScheduleRequest.Format.ps1xmlandRoleAssignmentScheduleRequest.Types.ps1xml— these targeted the native AzMicrosoft.Azure.PowerShell.Cmdlets.Resources.Authorization.Models.Api20201001Preview.RoleAssignmentScheduleRequesttype, but all Azure output is now wrapped withOmnicit.PIM.AzureAssignmentScheduleRequest. - Pipeline safety guards:
Enable-OPIMDirectoryRole,Enable-OPIMEntraIDGroup,Enable-OPIMAzureRolenow skip pipeline objects already tagged as active assignment instances (e.g. objects piped fromGet-OPIM* -Allthat haveStatus = Active), emitting aWrite-Verbosemessage instead of attempting an activation that would fail. - Pipeline safety guards:
Disable-OPIMDirectoryRole,Disable-OPIMEntraIDGroup,Disable-OPIMAzureRolenow skip pipeline objects tagged as eligible-only schedules (e.g. objects piped fromGet-OPIM* -Allthat haveStatus = Eligible), emitting a non-terminating error instead of attempting a deactivation that would fail.
Changed
- BREAKING —
Get-OPIMDirectoryRole -All,Get-OPIMEntraIDGroup -All, andGet-OPIMAzureRole -Allno longer removefilterByCurrentUser/asTarget()to list all principals. They now return both eligible and active schedules for the current user. Admins seeking all-principals data should query the Graph API directly with elevated permissions. - BREAKING —
-Alland-Activatedare now mutually exclusive on all threeGet-OPIM*cmdlets. Combining them raises a parameter binding error. Enable-OPIMDirectoryRole,Enable-OPIMEntraIDGroup,Enable-OPIMAzureRole—-Justificationis now positional[Position = 1]and ...
v0.5.0-preview0002
[v0.5.0-preview0002]
Fixed
Invoke-OPIMGraphRequestnow recovers from the PIMRoleAssignmentRequestAcrsValidationFailedactivation error automatically. The claims challenge in this 400 response body is URL-encoded (&claims=%7B...%7D), a different encoding from the base64urlWWW-Authenticate: claims="..."401 form the parser previously handled.Get-ClaimsFromExceptionnow decodes both encodings (and raw JSON) and feeds the result to the existing MSALAcquireTokenInteractive().WithClaims()step-up, so activations requiring a Conditional Access authentication context succeed with a single browser prompt and no manualDisconnect-OPIM.Invoke-OPIMGraphRequestACRS retry no longer gates on the session-sticky$script:_OPIMAuthState.ClaimsSatisfiedflag. Each call performs at most one step-up retry on its own, so a second activation in the same session that requires a claims challenge is no longer silently skipped.Invoke-OPIMGraphRequestnow transparently re-authenticates and retries once when Graph rejects a bearer token as invalid/expired (HTTP 401 orInvalidAuthenticationToken/CompactToken/token is expired/Lifetime validation failed), via the newInitialize-OPIMAuth -ForceRefreshpath (MSALAcquireTokenSilent().WithForceRefresh($true)) — recovering without a destructive full disconnect.- CI build (
Build & Package Module) no longer fails with "The required module 'Configuration' is not loaded" when importingModuleBuilder.ConfigurationandMetadata(ModuleBuilder's transitive runtime dependencies) are now listed explicitly inRequiredModules.psd1because PSResourceGet 1.0.1 does not install transitiveRequiredModulesduring the bootstrap on a clean agent.
Changed
Initialize-OPIMAuthnow disables the Web Account Manager (WAM) broker at process scope (Update-AzConfig -EnableLoginByWam $false -Scope Process) immediately beforeConnect-AzAccount, so Azure RBAC sign-in uses the system browser consistently with the Graph side instead of the WAM account picker that hangs in some terminals. The user's persisted Az config is never modified. (Unlike the previously removed Graph-sideSet-MgGraphOption -DisableLoginByWAM, the Az-sideUpdate-AzConfig -EnableLoginByWamtoggle is honoured byConnect-AzAccount.)Initialize-OPIMAuthgains a-ForceRefreshswitch that bypasses the cached-token idempotency check and forces MSAL to mint a fresh access token from the refresh token.
Added
Get-OPIMCurrentTenantInfoprivate helper — resolves the current tenant GUID and display name from the active Graph session. Used byInstall-,Set-, andRemove-OPIMConfigurationto enrich the confirmation prompt.Install-OPIMConfigurationnow auto-resolves-TenantIdfrom the active Graph context when the parameter is omitted. A non-terminating error is emitted when no-TenantIdis supplied and no active Graph session is available.
Changed
Install-OPIMConfiguration,Set-OPIMConfiguration, andRemove-OPIMConfigurationnow haveConfirmImpact = 'High'. TheShouldProcessconfirmation prompt includes the tenant alias, display name, and resolved GUID, making it clear which tenant is being modified before any write occurs.-TenantIdinInstall-OPIMConfigurationis no longer[Mandatory]; it is auto-resolved fromGet-MgContextwhen omitted.- PSScriptAnalyzer suppressions added to all six argument-completer classes (
AzureEligibleRoleCompleter,AzureActivatedRoleCompleter,DirectoryEligibleRoleCompleter,DirectoryActivatedRoleCompleter,GroupEligibleCompleter,GroupActivatedCompleter).
Changed
Write-CmdletErrorrevamped: newErrorRecordparameter set (pass-through),InnerExceptionparameter for exception chaining,[CmdletBinding()]added. All public and private functions now useWrite-CmdletErroras the single error-emission entry point.- All variable names across
Convert-GraphHttpException,Get-MyId,Invoke-OPIMGraphRequest,Export-OPIMTenantMap, and completer classes updated to PascalCase per module code-style rules.
(alias Connect-PIM) — new public cmdlet to pre-authenticate against Microsoft Graph and optionally Azure. A single browser prompt covers all PIM surfaces (directory roles, Entra ID groups, Azure RBAC). All Get-/Enable-/Disable-OPIM* cmdlets call this automatically on first use.
Disconnect-OPIM(aliasDisconnect-PIM) — new public cmdlet to clear all cached session tokens and disconnect from Graph and Azure.- Centralized MSAL-based authentication layer (
Initialize-OPIMAuth,Get-OPIMMsalApplicationprivate helpers). All PIM cmdlets now share a single token-acquisition flow that caches the result and is idempotent when called multiple times in the same session. - ACRS Conditional Access claims-challenge handling moved into
Invoke-OPIMGraphRequest. A single reactive browser re-prompt is issued when Graph returns a step-up challenge, eliminating repeated browser windows when activating multiple roles in oneEnable-OPIMMyRolecall. Invoke-OPIMGraphRequestprivate wrapper replaces directInvoke-MgGraphRequestcalls throughout the module. Provides bearer-token security (removes raw error records before any processing), ACRS retry, and consistentConvert-GraphHttpExceptionerror conversion.
(ParameterSetName ByIdentity) added to all six Enable-OPIM* and Disable-OPIM* cmdlets. Activates or deactivates a role/group by schedule ID (or schedule Name for Azure) without tab completion. For Disable-* cmdlets, the ID must correspond to an active schedule instance (from Get-OPIM* -Activated). For Azure RBAC the identity is the Name property.
Get-OPIMDirectoryRole,Get-OPIMEntraIDGroup, andGet-OPIMAzureRolegain a new-AllParameterSet that returns both eligible and active schedules for the current user in a single call.-Alland-Activatedare mutually exclusive.Get-OPIMDirectoryRole— new-RoleNamepositional parameter ([Position = 0]) with tab completion viaDirectoryEligibleRoleCompleter. Extracts the schedule ID from the trailing(id)and performs a dual-search across eligible and active endpoints.Get-OPIMEntraIDGroup— new-GroupNamepositional parameter ([Position = 0]) with tab completion viaGroupEligibleCompleter. Extracts the schedule ID from the trailing(id)and performs a dual-search across eligible and active endpoints.Get-OPIMAzureRole— new-RoleNamepositional parameter ([Position = 0]) with tab completion viaAzureEligibleRoleCompleter, and new-Identityparameter for direct look-up by scheduleName. Both perform dual-search across eligible and active endpoints.- Combined schedule view: When
-All,-RoleName/-GroupName/-Identitytrigger dual-search, all threeGet-OPIM*cmdlets now returnOmnicit.PIM.*CombinedScheduletyped objects with aStatuscolumn (EligibleorActive) for consistent table output across both result types. - New format/type files for combined schedule views:
Omnicit.PIM.DirectoryCombinedSchedule,Omnicit.PIM.GroupCombinedSchedule,Omnicit.PIM.AzureCombinedSchedule— each with aStatuscolumn in the default table view.
Performance
- Module load time reduced by ~8 seconds (~55% of total import time). Consolidated 13 individual
*.Format.ps1xmlfiles into a singleOmnicit.PIM.Format.ps1xmland 13*.Types.ps1xmlfiles into a singleOmnicit.PIM.Types.ps1xml. Previously each file triggered a full format/type table rebuild (~0.49s and ~0.11s per call respectively). FormatsToProcessre-enabled in the module manifest — format data is now loaded natively by PowerShell at zero extra cost. This was previously disabled becauseUpdate-FormatData -PrependPathwas needed to override Az.Resources native types; that override (RoleAssignmentScheduleRequest) is no longer needed since all output is wrapped asOmnicit.PIM.*custom types.suffix.ps1now loads a single consolidatedOmnicit.PIM.Types.ps1xmlfile (1 call toUpdate-TypeData) instead of enumerating and loading 13 individual files (14 calls).TypesToProcessremains disabled in the manifest becauseRemove-Moduledoes not clean type data, causing "member already present" errors onImport-Module -Force.- Removed orphaned
RoleAssignmentScheduleRequest.Format.ps1xmlandRoleAssignmentScheduleRequest.Types.ps1xml— these targeted the native AzMicrosoft.Azure.PowerShell.Cmdlets.Resources.Authorization.Models.Api20201001Preview.RoleAssignmentScheduleRequesttype, but all Azure output is now wrapped withOmnicit.PIM.AzureAssignmentScheduleRequest. - Pipeline safety guards:
Enable-OPIMDirectoryRole,Enable-OPIMEntraIDGroup,Enable-OPIMAzureRolenow skip pipeline objects already tagged as active assignment instances (e.g. objects piped fromGet-OPIM* -Allthat haveStatus = Active), emitting aWrite-Verbosemessage instead of attempting an activation that would fail. - Pipeline safety guards:
Disable-OPIMDirectoryRole,Disable-OPIMEntraIDGroup,Disable-OPIMAzureRolenow skip pipeline objects tagged as eligible-only schedules (e.g. objects piped fromGet-OPIM* -Allthat haveStatus = Eligible), emitting a non-terminating error instead of attempting a deactivation that would fail.
Changed
- BREAKING —
Get-OPIMDirectoryRole -All,Get-OPIMEntraIDGroup -All, andGet-OPIMAzureRole -Allno longer removefilterByCurrentUser/asTarget()to list all principals. They now return both eligible and active schedules for the current user. Admins seeking all-principals data should query the Graph API directly with elevated permissions. - BREAKING —
-Alland-Activatedare now mutually exclusive on all threeGet-OPIM*cmdlets. Combining them raises a parameter binding error. Enable-OPIMDirectoryRole,Enable-OPIMEntraIDGroup,Enable-OPIMAzureRole—-Justificationis now positional `[Positio...
v0.5.0-preview0001
[v0.5.0-preview0001]
Fixed
- CI build (
Build & Package Module) no longer fails with "The required module 'Configuration' is not loaded" when importingModuleBuilder.ConfigurationandMetadata(ModuleBuilder's transitive runtime dependencies) are now listed explicitly inRequiredModules.psd1because PSResourceGet 1.0.1 does not install transitiveRequiredModulesduring the bootstrap on a clean agent.
Added
Get-OPIMCurrentTenantInfoprivate helper — resolves the current tenant GUID and display name from the active Graph session. Used byInstall-,Set-, andRemove-OPIMConfigurationto enrich the confirmation prompt.Install-OPIMConfigurationnow auto-resolves-TenantIdfrom the active Graph context when the parameter is omitted. A non-terminating error is emitted when no-TenantIdis supplied and no active Graph session is available.
Changed
Install-OPIMConfiguration,Set-OPIMConfiguration, andRemove-OPIMConfigurationnow haveConfirmImpact = 'High'. TheShouldProcessconfirmation prompt includes the tenant alias, display name, and resolved GUID, making it clear which tenant is being modified before any write occurs.-TenantIdinInstall-OPIMConfigurationis no longer[Mandatory]; it is auto-resolved fromGet-MgContextwhen omitted.- PSScriptAnalyzer suppressions added to all six argument-completer classes (
AzureEligibleRoleCompleter,AzureActivatedRoleCompleter,DirectoryEligibleRoleCompleter,DirectoryActivatedRoleCompleter,GroupEligibleCompleter,GroupActivatedCompleter).
Changed
Write-CmdletErrorrevamped: newErrorRecordparameter set (pass-through),InnerExceptionparameter for exception chaining,[CmdletBinding()]added. All public and private functions now useWrite-CmdletErroras the single error-emission entry point.- All variable names across
Convert-GraphHttpException,Get-MyId,Invoke-OPIMGraphRequest,Export-OPIMTenantMap, and completer classes updated to PascalCase per module code-style rules.
(alias Connect-PIM) — new public cmdlet to pre-authenticate against Microsoft Graph and optionally Azure. A single browser prompt covers all PIM surfaces (directory roles, Entra ID groups, Azure RBAC). All Get-/Enable-/Disable-OPIM* cmdlets call this automatically on first use.
Disconnect-OPIM(aliasDisconnect-PIM) — new public cmdlet to clear all cached session tokens and disconnect from Graph and Azure.- Centralized MSAL-based authentication layer (
Initialize-OPIMAuth,Get-OPIMMsalApplicationprivate helpers). All PIM cmdlets now share a single token-acquisition flow that caches the result and is idempotent when called multiple times in the same session. - ACRS Conditional Access claims-challenge handling moved into
Invoke-OPIMGraphRequest. A single reactive browser re-prompt is issued when Graph returns a step-up challenge, eliminating repeated browser windows when activating multiple roles in oneEnable-OPIMMyRolecall. Invoke-OPIMGraphRequestprivate wrapper replaces directInvoke-MgGraphRequestcalls throughout the module. Provides bearer-token security (removes raw error records before any processing), ACRS retry, and consistentConvert-GraphHttpExceptionerror conversion.
(ParameterSetName ByIdentity) added to all six Enable-OPIM* and Disable-OPIM* cmdlets. Activates or deactivates a role/group by schedule ID (or schedule Name for Azure) without tab completion. For Disable-* cmdlets, the ID must correspond to an active schedule instance (from Get-OPIM* -Activated). For Azure RBAC the identity is the Name property.
Get-OPIMDirectoryRole,Get-OPIMEntraIDGroup, andGet-OPIMAzureRolegain a new-AllParameterSet that returns both eligible and active schedules for the current user in a single call.-Alland-Activatedare mutually exclusive.Get-OPIMDirectoryRole— new-RoleNamepositional parameter ([Position = 0]) with tab completion viaDirectoryEligibleRoleCompleter. Extracts the schedule ID from the trailing(id)and performs a dual-search across eligible and active endpoints.Get-OPIMEntraIDGroup— new-GroupNamepositional parameter ([Position = 0]) with tab completion viaGroupEligibleCompleter. Extracts the schedule ID from the trailing(id)and performs a dual-search across eligible and active endpoints.Get-OPIMAzureRole— new-RoleNamepositional parameter ([Position = 0]) with tab completion viaAzureEligibleRoleCompleter, and new-Identityparameter for direct look-up by scheduleName. Both perform dual-search across eligible and active endpoints.- Combined schedule view: When
-All,-RoleName/-GroupName/-Identitytrigger dual-search, all threeGet-OPIM*cmdlets now returnOmnicit.PIM.*CombinedScheduletyped objects with aStatuscolumn (EligibleorActive) for consistent table output across both result types. - New format/type files for combined schedule views:
Omnicit.PIM.DirectoryCombinedSchedule,Omnicit.PIM.GroupCombinedSchedule,Omnicit.PIM.AzureCombinedSchedule— each with aStatuscolumn in the default table view.
Performance
- Module load time reduced by ~8 seconds (~55% of total import time). Consolidated 13 individual
*.Format.ps1xmlfiles into a singleOmnicit.PIM.Format.ps1xmland 13*.Types.ps1xmlfiles into a singleOmnicit.PIM.Types.ps1xml. Previously each file triggered a full format/type table rebuild (~0.49s and ~0.11s per call respectively). FormatsToProcessre-enabled in the module manifest — format data is now loaded natively by PowerShell at zero extra cost. This was previously disabled becauseUpdate-FormatData -PrependPathwas needed to override Az.Resources native types; that override (RoleAssignmentScheduleRequest) is no longer needed since all output is wrapped asOmnicit.PIM.*custom types.suffix.ps1now loads a single consolidatedOmnicit.PIM.Types.ps1xmlfile (1 call toUpdate-TypeData) instead of enumerating and loading 13 individual files (14 calls).TypesToProcessremains disabled in the manifest becauseRemove-Moduledoes not clean type data, causing "member already present" errors onImport-Module -Force.- Removed orphaned
RoleAssignmentScheduleRequest.Format.ps1xmlandRoleAssignmentScheduleRequest.Types.ps1xml— these targeted the native AzMicrosoft.Azure.PowerShell.Cmdlets.Resources.Authorization.Models.Api20201001Preview.RoleAssignmentScheduleRequesttype, but all Azure output is now wrapped withOmnicit.PIM.AzureAssignmentScheduleRequest. - Pipeline safety guards:
Enable-OPIMDirectoryRole,Enable-OPIMEntraIDGroup,Enable-OPIMAzureRolenow skip pipeline objects already tagged as active assignment instances (e.g. objects piped fromGet-OPIM* -Allthat haveStatus = Active), emitting aWrite-Verbosemessage instead of attempting an activation that would fail. - Pipeline safety guards:
Disable-OPIMDirectoryRole,Disable-OPIMEntraIDGroup,Disable-OPIMAzureRolenow skip pipeline objects tagged as eligible-only schedules (e.g. objects piped fromGet-OPIM* -Allthat haveStatus = Eligible), emitting a non-terminating error instead of attempting a deactivation that would fail.
Changed
- BREAKING —
Get-OPIMDirectoryRole -All,Get-OPIMEntraIDGroup -All, andGet-OPIMAzureRole -Allno longer removefilterByCurrentUser/asTarget()to list all principals. They now return both eligible and active schedules for the current user. Admins seeking all-principals data should query the Graph API directly with elevated permissions. - BREAKING —
-Alland-Activatedare now mutually exclusive on all threeGet-OPIM*cmdlets. Combining them raises a parameter binding error. Enable-OPIMDirectoryRole,Enable-OPIMEntraIDGroup,Enable-OPIMAzureRole—-Justificationis now positional[Position = 1]and-Hoursis positional[Position = 2], enabling:Enable-OPIMDirectoryRole 'Role (id)' 'Justification' 4.
Fixed
Get-OPIMDirectoryRole -Activatedno longer applies a post-filter ofassignmentType -eq 'Activated'. All items returned byroleAssignmentScheduleInstancesare inherently active assignments; the filter suppressed results when the real Graph API response omitted or differed in that field.Get-OPIMEntraIDGroup -Allno longer throwsMissingParameters: The required parameters GroupId or PrincipalId is missing. The PIM Groups API requiresfilterByCurrentUser(on='principal')even when listing all types; this is now preserved.Get-OPIMAzureRole -Allno longer throwsInsufficientPermissions. TheasTarget()filter is now preserved with-All, restricting results to the current user at scope/.Get-OPIMAzureRole -Activated -Scope '<specific-scope>'now returns only instances at that exact scope. Previously,Get-AzRoleAssignmentScheduleInstancereturned inherited parent-scope instances; these are now filtered out client-side when scope is not/.Get-OPIMDirectoryRole,Get-OPIMEntraIDGroup— improved.PARAMETER Filterdocumentation with OData examples. Added.EXAMPLEblocks for-Filterand-Identityusage.Get-OPIMEntraIDGroup—-AccessTypefilter now applies correctly when-Allis combined with-AccessType memberor-AccessType owner. Previously the filter was silently ignored in-Allmode.Get-OPIMAzureRole— removed[Alias('Id')]from the-Scopeparameter. PowerShell's prefix-matching treatedIdas an abbreviation of-Identity, causing "Parameter set cannot be resolved" errors when-Identitywas specified alongside the default$Scope = '/'binding.Get-OPIMAzureRole—Add-Member -NotePropertyName Statusnow uses-Forceto prevent "Cannot add a member with the name 'Status' because a member already exists" errors when the same object is processed more than once (e.g. across multiple pipeline invocations).Get-OPIMAzureRole...
v0.4.0
[v0.4.0]
Added
Get-OPIMCurrentTenantInfoprivate helper — resolves the current tenant GUID and display name from the active Graph session. Used byInstall-,Set-, andRemove-OPIMConfigurationto enrich the confirmation prompt.Install-OPIMConfigurationnow auto-resolves-TenantIdfrom the active Graph context when the parameter is omitted. A non-terminating error is emitted when no-TenantIdis supplied and no active Graph session is available.
Changed
Install-OPIMConfiguration,Set-OPIMConfiguration, andRemove-OPIMConfigurationnow haveConfirmImpact = 'High'. TheShouldProcessconfirmation prompt includes the tenant alias, display name, and resolved GUID, making it clear which tenant is being modified before any write occurs.-TenantIdinInstall-OPIMConfigurationis no longer[Mandatory]; it is auto-resolved fromGet-MgContextwhen omitted.- PSScriptAnalyzer suppressions added to all six argument-completer classes (
AzureEligibleRoleCompleter,AzureActivatedRoleCompleter,DirectoryEligibleRoleCompleter,DirectoryActivatedRoleCompleter,GroupEligibleCompleter,GroupActivatedCompleter).
Changed
Write-CmdletErrorrevamped: newErrorRecordparameter set (pass-through),InnerExceptionparameter for exception chaining,[CmdletBinding()]added. All public and private functions now useWrite-CmdletErroras the single error-emission entry point.- All variable names across
Convert-GraphHttpException,Get-MyId,Invoke-OPIMGraphRequest,Export-OPIMTenantMap, and completer classes updated to PascalCase per module code-style rules.
(alias Connect-PIM) — new public cmdlet to pre-authenticate against Microsoft Graph and optionally Azure. A single browser prompt covers all PIM surfaces (directory roles, Entra ID groups, Azure RBAC). All Get-/Enable-/Disable-OPIM* cmdlets call this automatically on first use.
Disconnect-OPIM(aliasDisconnect-PIM) — new public cmdlet to clear all cached session tokens and disconnect from Graph and Azure.- Centralized MSAL-based authentication layer (
Initialize-OPIMAuth,Get-OPIMMsalApplicationprivate helpers). All PIM cmdlets now share a single token-acquisition flow that caches the result and is idempotent when called multiple times in the same session. - ACRS Conditional Access claims-challenge handling moved into
Invoke-OPIMGraphRequest. A single reactive browser re-prompt is issued when Graph returns a step-up challenge, eliminating repeated browser windows when activating multiple roles in oneEnable-OPIMMyRolecall. Invoke-OPIMGraphRequestprivate wrapper replaces directInvoke-MgGraphRequestcalls throughout the module. Provides bearer-token security (removes raw error records before any processing), ACRS retry, and consistentConvert-GraphHttpExceptionerror conversion.
(ParameterSetName ByIdentity) added to all six Enable-OPIM* and Disable-OPIM* cmdlets. Activates or deactivates a role/group by schedule ID (or schedule Name for Azure) without tab completion. For Disable-* cmdlets, the ID must correspond to an active schedule instance (from Get-OPIM* -Activated). For Azure RBAC the identity is the Name property.
Get-OPIMDirectoryRole,Get-OPIMEntraIDGroup, andGet-OPIMAzureRolegain a new-AllParameterSet that returns both eligible and active schedules for the current user in a single call.-Alland-Activatedare mutually exclusive.Get-OPIMDirectoryRole— new-RoleNamepositional parameter ([Position = 0]) with tab completion viaDirectoryEligibleRoleCompleter. Extracts the schedule ID from the trailing(id)and performs a dual-search across eligible and active endpoints.Get-OPIMEntraIDGroup— new-GroupNamepositional parameter ([Position = 0]) with tab completion viaGroupEligibleCompleter. Extracts the schedule ID from the trailing(id)and performs a dual-search across eligible and active endpoints.Get-OPIMAzureRole— new-RoleNamepositional parameter ([Position = 0]) with tab completion viaAzureEligibleRoleCompleter, and new-Identityparameter for direct look-up by scheduleName. Both perform dual-search across eligible and active endpoints.- Combined schedule view: When
-All,-RoleName/-GroupName/-Identitytrigger dual-search, all threeGet-OPIM*cmdlets now returnOmnicit.PIM.*CombinedScheduletyped objects with aStatuscolumn (EligibleorActive) for consistent table output across both result types. - New format/type files for combined schedule views:
Omnicit.PIM.DirectoryCombinedSchedule,Omnicit.PIM.GroupCombinedSchedule,Omnicit.PIM.AzureCombinedSchedule— each with aStatuscolumn in the default table view.
Performance
- Module load time reduced by ~8 seconds (~55% of total import time). Consolidated 13 individual
*.Format.ps1xmlfiles into a singleOmnicit.PIM.Format.ps1xmland 13*.Types.ps1xmlfiles into a singleOmnicit.PIM.Types.ps1xml. Previously each file triggered a full format/type table rebuild (~0.49s and ~0.11s per call respectively). FormatsToProcessre-enabled in the module manifest — format data is now loaded natively by PowerShell at zero extra cost. This was previously disabled becauseUpdate-FormatData -PrependPathwas needed to override Az.Resources native types; that override (RoleAssignmentScheduleRequest) is no longer needed since all output is wrapped asOmnicit.PIM.*custom types.suffix.ps1now loads a single consolidatedOmnicit.PIM.Types.ps1xmlfile (1 call toUpdate-TypeData) instead of enumerating and loading 13 individual files (14 calls).TypesToProcessremains disabled in the manifest becauseRemove-Moduledoes not clean type data, causing "member already present" errors onImport-Module -Force.- Removed orphaned
RoleAssignmentScheduleRequest.Format.ps1xmlandRoleAssignmentScheduleRequest.Types.ps1xml— these targeted the native AzMicrosoft.Azure.PowerShell.Cmdlets.Resources.Authorization.Models.Api20201001Preview.RoleAssignmentScheduleRequesttype, but all Azure output is now wrapped withOmnicit.PIM.AzureAssignmentScheduleRequest. - Pipeline safety guards:
Enable-OPIMDirectoryRole,Enable-OPIMEntraIDGroup,Enable-OPIMAzureRolenow skip pipeline objects already tagged as active assignment instances (e.g. objects piped fromGet-OPIM* -Allthat haveStatus = Active), emitting aWrite-Verbosemessage instead of attempting an activation that would fail. - Pipeline safety guards:
Disable-OPIMDirectoryRole,Disable-OPIMEntraIDGroup,Disable-OPIMAzureRolenow skip pipeline objects tagged as eligible-only schedules (e.g. objects piped fromGet-OPIM* -Allthat haveStatus = Eligible), emitting a non-terminating error instead of attempting a deactivation that would fail.
Changed
- BREAKING —
Get-OPIMDirectoryRole -All,Get-OPIMEntraIDGroup -All, andGet-OPIMAzureRole -Allno longer removefilterByCurrentUser/asTarget()to list all principals. They now return both eligible and active schedules for the current user. Admins seeking all-principals data should query the Graph API directly with elevated permissions. - BREAKING —
-Alland-Activatedare now mutually exclusive on all threeGet-OPIM*cmdlets. Combining them raises a parameter binding error. Enable-OPIMDirectoryRole,Enable-OPIMEntraIDGroup,Enable-OPIMAzureRole—-Justificationis now positional[Position = 1]and-Hoursis positional[Position = 2], enabling:Enable-OPIMDirectoryRole 'Role (id)' 'Justification' 4.
Fixed
Get-OPIMDirectoryRole -Activatedno longer applies a post-filter ofassignmentType -eq 'Activated'. All items returned byroleAssignmentScheduleInstancesare inherently active assignments; the filter suppressed results when the real Graph API response omitted or differed in that field.Get-OPIMEntraIDGroup -Allno longer throwsMissingParameters: The required parameters GroupId or PrincipalId is missing. The PIM Groups API requiresfilterByCurrentUser(on='principal')even when listing all types; this is now preserved.Get-OPIMAzureRole -Allno longer throwsInsufficientPermissions. TheasTarget()filter is now preserved with-All, restricting results to the current user at scope/.Get-OPIMAzureRole -Activated -Scope '<specific-scope>'now returns only instances at that exact scope. Previously,Get-AzRoleAssignmentScheduleInstancereturned inherited parent-scope instances; these are now filtered out client-side when scope is not/.Get-OPIMDirectoryRole,Get-OPIMEntraIDGroup— improved.PARAMETER Filterdocumentation with OData examples. Added.EXAMPLEblocks for-Filterand-Identityusage.Get-OPIMEntraIDGroup—-AccessTypefilter now applies correctly when-Allis combined with-AccessType memberor-AccessType owner. Previously the filter was silently ignored in-Allmode.Get-OPIMAzureRole— removed[Alias('Id')]from the-Scopeparameter. PowerShell's prefix-matching treatedIdas an abbreviation of-Identity, causing "Parameter set cannot be resolved" errors when-Identitywas specified alongside the default$Scope = '/'binding.Get-OPIMAzureRole—Add-Member -NotePropertyName Statusnow uses-Forceto prevent "Cannot add a member with the name 'Status' because a member already exists" errors when the same object is processed more than once (e.g. across multiple pipeline invocations).Get-OPIMAzureRoledual-search now correctly separates the-Name(Get parameter set) and-Filter(List parameter set) calls toGet-AzRoleEligibilityScheduleandGet-AzRoleAssignmentScheduleInstance. These are mutually exclusive parameter sets in Az.Resources; previously passing both parameters caused a parameter binding error.
— wraps Invoke-MgGraphRequest for PIM activation POST requests with automatic ACRS claims-c...
v0.4.0-preview0003
[v0.4.0-preview0003]
Added
Get-OPIMCurrentTenantInfoprivate helper — resolves the current tenant GUID and display name from the active Graph session. Used byInstall-,Set-, andRemove-OPIMConfigurationto enrich the confirmation prompt.Install-OPIMConfigurationnow auto-resolves-TenantIdfrom the active Graph context when the parameter is omitted. A non-terminating error is emitted when no-TenantIdis supplied and no active Graph session is available.
Changed
Install-OPIMConfiguration,Set-OPIMConfiguration, andRemove-OPIMConfigurationnow haveConfirmImpact = 'High'. TheShouldProcessconfirmation prompt includes the tenant alias, display name, and resolved GUID, making it clear which tenant is being modified before any write occurs.-TenantIdinInstall-OPIMConfigurationis no longer[Mandatory]; it is auto-resolved fromGet-MgContextwhen omitted.- PSScriptAnalyzer suppressions added to all six argument-completer classes (
AzureEligibleRoleCompleter,AzureActivatedRoleCompleter,DirectoryEligibleRoleCompleter,DirectoryActivatedRoleCompleter,GroupEligibleCompleter,GroupActivatedCompleter).
Changed
Write-CmdletErrorrevamped: newErrorRecordparameter set (pass-through),InnerExceptionparameter for exception chaining,[CmdletBinding()]added. All public and private functions now useWrite-CmdletErroras the single error-emission entry point.- All variable names across
Convert-GraphHttpException,Get-MyId,Invoke-OPIMGraphRequest,Export-OPIMTenantMap, and completer classes updated to PascalCase per module code-style rules.
(alias Connect-PIM) — new public cmdlet to pre-authenticate against Microsoft Graph and optionally Azure. A single browser prompt covers all PIM surfaces (directory roles, Entra ID groups, Azure RBAC). All Get-/Enable-/Disable-OPIM* cmdlets call this automatically on first use.
Disconnect-OPIM(aliasDisconnect-PIM) — new public cmdlet to clear all cached session tokens and disconnect from Graph and Azure.- Centralized MSAL-based authentication layer (
Initialize-OPIMAuth,Get-OPIMMsalApplicationprivate helpers). All PIM cmdlets now share a single token-acquisition flow that caches the result and is idempotent when called multiple times in the same session. - ACRS Conditional Access claims-challenge handling moved into
Invoke-OPIMGraphRequest. A single reactive browser re-prompt is issued when Graph returns a step-up challenge, eliminating repeated browser windows when activating multiple roles in oneEnable-OPIMMyRolecall. Invoke-OPIMGraphRequestprivate wrapper replaces directInvoke-MgGraphRequestcalls throughout the module. Provides bearer-token security (removes raw error records before any processing), ACRS retry, and consistentConvert-GraphHttpExceptionerror conversion.
(ParameterSetName ByIdentity) added to all six Enable-OPIM* and Disable-OPIM* cmdlets. Activates or deactivates a role/group by schedule ID (or schedule Name for Azure) without tab completion. For Disable-* cmdlets, the ID must correspond to an active schedule instance (from Get-OPIM* -Activated). For Azure RBAC the identity is the Name property.
Get-OPIMDirectoryRole,Get-OPIMEntraIDGroup, andGet-OPIMAzureRolegain a new-AllParameterSet that returns both eligible and active schedules for the current user in a single call.-Alland-Activatedare mutually exclusive.Get-OPIMDirectoryRole— new-RoleNamepositional parameter ([Position = 0]) with tab completion viaDirectoryEligibleRoleCompleter. Extracts the schedule ID from the trailing(id)and performs a dual-search across eligible and active endpoints.Get-OPIMEntraIDGroup— new-GroupNamepositional parameter ([Position = 0]) with tab completion viaGroupEligibleCompleter. Extracts the schedule ID from the trailing(id)and performs a dual-search across eligible and active endpoints.Get-OPIMAzureRole— new-RoleNamepositional parameter ([Position = 0]) with tab completion viaAzureEligibleRoleCompleter, and new-Identityparameter for direct look-up by scheduleName. Both perform dual-search across eligible and active endpoints.- Combined schedule view: When
-All,-RoleName/-GroupName/-Identitytrigger dual-search, all threeGet-OPIM*cmdlets now returnOmnicit.PIM.*CombinedScheduletyped objects with aStatuscolumn (EligibleorActive) for consistent table output across both result types. - New format/type files for combined schedule views:
Omnicit.PIM.DirectoryCombinedSchedule,Omnicit.PIM.GroupCombinedSchedule,Omnicit.PIM.AzureCombinedSchedule— each with aStatuscolumn in the default table view.
Performance
- Module load time reduced by ~8 seconds (~55% of total import time). Consolidated 13 individual
*.Format.ps1xmlfiles into a singleOmnicit.PIM.Format.ps1xmland 13*.Types.ps1xmlfiles into a singleOmnicit.PIM.Types.ps1xml. Previously each file triggered a full format/type table rebuild (~0.49s and ~0.11s per call respectively). FormatsToProcessre-enabled in the module manifest — format data is now loaded natively by PowerShell at zero extra cost. This was previously disabled becauseUpdate-FormatData -PrependPathwas needed to override Az.Resources native types; that override (RoleAssignmentScheduleRequest) is no longer needed since all output is wrapped asOmnicit.PIM.*custom types.suffix.ps1now loads a single consolidatedOmnicit.PIM.Types.ps1xmlfile (1 call toUpdate-TypeData) instead of enumerating and loading 13 individual files (14 calls).TypesToProcessremains disabled in the manifest becauseRemove-Moduledoes not clean type data, causing "member already present" errors onImport-Module -Force.- Removed orphaned
RoleAssignmentScheduleRequest.Format.ps1xmlandRoleAssignmentScheduleRequest.Types.ps1xml— these targeted the native AzMicrosoft.Azure.PowerShell.Cmdlets.Resources.Authorization.Models.Api20201001Preview.RoleAssignmentScheduleRequesttype, but all Azure output is now wrapped withOmnicit.PIM.AzureAssignmentScheduleRequest. - Pipeline safety guards:
Enable-OPIMDirectoryRole,Enable-OPIMEntraIDGroup,Enable-OPIMAzureRolenow skip pipeline objects already tagged as active assignment instances (e.g. objects piped fromGet-OPIM* -Allthat haveStatus = Active), emitting aWrite-Verbosemessage instead of attempting an activation that would fail. - Pipeline safety guards:
Disable-OPIMDirectoryRole,Disable-OPIMEntraIDGroup,Disable-OPIMAzureRolenow skip pipeline objects tagged as eligible-only schedules (e.g. objects piped fromGet-OPIM* -Allthat haveStatus = Eligible), emitting a non-terminating error instead of attempting a deactivation that would fail.
Changed
- BREAKING —
Get-OPIMDirectoryRole -All,Get-OPIMEntraIDGroup -All, andGet-OPIMAzureRole -Allno longer removefilterByCurrentUser/asTarget()to list all principals. They now return both eligible and active schedules for the current user. Admins seeking all-principals data should query the Graph API directly with elevated permissions. - BREAKING —
-Alland-Activatedare now mutually exclusive on all threeGet-OPIM*cmdlets. Combining them raises a parameter binding error. Enable-OPIMDirectoryRole,Enable-OPIMEntraIDGroup,Enable-OPIMAzureRole—-Justificationis now positional[Position = 1]and-Hoursis positional[Position = 2], enabling:Enable-OPIMDirectoryRole 'Role (id)' 'Justification' 4.
Fixed
Get-OPIMDirectoryRole -Activatedno longer applies a post-filter ofassignmentType -eq 'Activated'. All items returned byroleAssignmentScheduleInstancesare inherently active assignments; the filter suppressed results when the real Graph API response omitted or differed in that field.Get-OPIMEntraIDGroup -Allno longer throwsMissingParameters: The required parameters GroupId or PrincipalId is missing. The PIM Groups API requiresfilterByCurrentUser(on='principal')even when listing all types; this is now preserved.Get-OPIMAzureRole -Allno longer throwsInsufficientPermissions. TheasTarget()filter is now preserved with-All, restricting results to the current user at scope/.Get-OPIMAzureRole -Activated -Scope '<specific-scope>'now returns only instances at that exact scope. Previously,Get-AzRoleAssignmentScheduleInstancereturned inherited parent-scope instances; these are now filtered out client-side when scope is not/.Get-OPIMDirectoryRole,Get-OPIMEntraIDGroup— improved.PARAMETER Filterdocumentation with OData examples. Added.EXAMPLEblocks for-Filterand-Identityusage.Get-OPIMEntraIDGroup—-AccessTypefilter now applies correctly when-Allis combined with-AccessType memberor-AccessType owner. Previously the filter was silently ignored in-Allmode.Get-OPIMAzureRole— removed[Alias('Id')]from the-Scopeparameter. PowerShell's prefix-matching treatedIdas an abbreviation of-Identity, causing "Parameter set cannot be resolved" errors when-Identitywas specified alongside the default$Scope = '/'binding.Get-OPIMAzureRole—Add-Member -NotePropertyName Statusnow uses-Forceto prevent "Cannot add a member with the name 'Status' because a member already exists" errors when the same object is processed more than once (e.g. across multiple pipeline invocations).Get-OPIMAzureRoledual-search now correctly separates the-Name(Get parameter set) and-Filter(List parameter set) calls toGet-AzRoleEligibilityScheduleandGet-AzRoleAssignmentScheduleInstance. These are mutually exclusive parameter sets in Az.Resources; previously passing both parameters caused a parameter binding error.
— wraps Invoke-MgGraphRequest for PIM activation POST requests with automatic A...
v0.4.0-preview0002
[v0.4.0-preview0002]
Added
ConvertTo-ActiveDurationTooShortErrorandConvertTo-PolicyValidationErrorprivate helpers centralise the cooldown and PIM-policy error-handling patterns previously duplicated across all sixEnable-/Disable-OPIM*cmdlets.- PSScriptAnalyzer suppressions added to all six argument-completer classes (
AzureEligibleRoleCompleter,AzureActivatedRoleCompleter,DirectoryEligibleRoleCompleter,DirectoryActivatedRoleCompleter,GroupEligibleCompleter,GroupActivatedCompleter).
Changed
Write-CmdletErrorrevamped: newErrorRecordparameter set (pass-through),InnerExceptionparameter for exception chaining,[CmdletBinding()]added. All public and private functions now useWrite-CmdletErroras the single error-emission entry point.- All variable names across
Convert-GraphHttpException,Get-MyId,Invoke-OPIMGraphRequest,Export-OPIMTenantMap, and completer classes updated to PascalCase per module code-style rules.
(alias Connect-PIM) — new public cmdlet to pre-authenticate against Microsoft Graph and optionally Azure. A single browser prompt covers all PIM surfaces (directory roles, Entra ID groups, Azure RBAC). All Get-/Enable-/Disable-OPIM* cmdlets call this automatically on first use.
Disconnect-OPIM(aliasDisconnect-PIM) — new public cmdlet to clear all cached session tokens and disconnect from Graph and Azure.- Centralized MSAL-based authentication layer (
Initialize-OPIMAuth,Get-OPIMMsalApplicationprivate helpers). All PIM cmdlets now share a single token-acquisition flow that caches the result and is idempotent when called multiple times in the same session. - ACRS Conditional Access claims-challenge handling moved into
Invoke-OPIMGraphRequest. A single reactive browser re-prompt is issued when Graph returns a step-up challenge, eliminating repeated browser windows when activating multiple roles in oneEnable-OPIMMyRolecall. Invoke-OPIMGraphRequestprivate wrapper replaces directInvoke-MgGraphRequestcalls throughout the module. Provides bearer-token security (removes raw error records before any processing), ACRS retry, and consistentConvert-GraphHttpExceptionerror conversion.
(ParameterSetName ByIdentity) added to all six Enable-OPIM* and Disable-OPIM* cmdlets. Activates or deactivates a role/group by schedule ID (or schedule Name for Azure) without tab completion. For Disable-* cmdlets, the ID must correspond to an active schedule instance (from Get-OPIM* -Activated). For Azure RBAC the identity is the Name property.
Get-OPIMDirectoryRole,Get-OPIMEntraIDGroup, andGet-OPIMAzureRolegain a new-AllParameterSet that returns both eligible and active schedules for the current user in a single call.-Alland-Activatedare mutually exclusive.Get-OPIMDirectoryRole— new-RoleNamepositional parameter ([Position = 0]) with tab completion viaDirectoryEligibleRoleCompleter. Extracts the schedule ID from the trailing(id)and performs a dual-search across eligible and active endpoints.Get-OPIMEntraIDGroup— new-GroupNamepositional parameter ([Position = 0]) with tab completion viaGroupEligibleCompleter. Extracts the schedule ID from the trailing(id)and performs a dual-search across eligible and active endpoints.Get-OPIMAzureRole— new-RoleNamepositional parameter ([Position = 0]) with tab completion viaAzureEligibleRoleCompleter, and new-Identityparameter for direct look-up by scheduleName. Both perform dual-search across eligible and active endpoints.- Combined schedule view: When
-All,-RoleName/-GroupName/-Identitytrigger dual-search, all threeGet-OPIM*cmdlets now returnOmnicit.PIM.*CombinedScheduletyped objects with aStatuscolumn (EligibleorActive) for consistent table output across both result types. - New format/type files for combined schedule views:
Omnicit.PIM.DirectoryCombinedSchedule,Omnicit.PIM.GroupCombinedSchedule,Omnicit.PIM.AzureCombinedSchedule— each with aStatuscolumn in the default table view.
Performance
- Module load time reduced by ~8 seconds (~55% of total import time). Consolidated 13 individual
*.Format.ps1xmlfiles into a singleOmnicit.PIM.Format.ps1xmland 13*.Types.ps1xmlfiles into a singleOmnicit.PIM.Types.ps1xml. Previously each file triggered a full format/type table rebuild (~0.49s and ~0.11s per call respectively). FormatsToProcessre-enabled in the module manifest — format data is now loaded natively by PowerShell at zero extra cost. This was previously disabled becauseUpdate-FormatData -PrependPathwas needed to override Az.Resources native types; that override (RoleAssignmentScheduleRequest) is no longer needed since all output is wrapped asOmnicit.PIM.*custom types.suffix.ps1now loads a single consolidatedOmnicit.PIM.Types.ps1xmlfile (1 call toUpdate-TypeData) instead of enumerating and loading 13 individual files (14 calls).TypesToProcessremains disabled in the manifest becauseRemove-Moduledoes not clean type data, causing "member already present" errors onImport-Module -Force.- Removed orphaned
RoleAssignmentScheduleRequest.Format.ps1xmlandRoleAssignmentScheduleRequest.Types.ps1xml— these targeted the native AzMicrosoft.Azure.PowerShell.Cmdlets.Resources.Authorization.Models.Api20201001Preview.RoleAssignmentScheduleRequesttype, but all Azure output is now wrapped withOmnicit.PIM.AzureAssignmentScheduleRequest. - Pipeline safety guards:
Enable-OPIMDirectoryRole,Enable-OPIMEntraIDGroup,Enable-OPIMAzureRolenow skip pipeline objects already tagged as active assignment instances (e.g. objects piped fromGet-OPIM* -Allthat haveStatus = Active), emitting aWrite-Verbosemessage instead of attempting an activation that would fail. - Pipeline safety guards:
Disable-OPIMDirectoryRole,Disable-OPIMEntraIDGroup,Disable-OPIMAzureRolenow skip pipeline objects tagged as eligible-only schedules (e.g. objects piped fromGet-OPIM* -Allthat haveStatus = Eligible), emitting a non-terminating error instead of attempting a deactivation that would fail.
Changed
- BREAKING —
Get-OPIMDirectoryRole -All,Get-OPIMEntraIDGroup -All, andGet-OPIMAzureRole -Allno longer removefilterByCurrentUser/asTarget()to list all principals. They now return both eligible and active schedules for the current user. Admins seeking all-principals data should query the Graph API directly with elevated permissions. - BREAKING —
-Alland-Activatedare now mutually exclusive on all threeGet-OPIM*cmdlets. Combining them raises a parameter binding error. Enable-OPIMDirectoryRole,Enable-OPIMEntraIDGroup,Enable-OPIMAzureRole—-Justificationis now positional[Position = 1]and-Hoursis positional[Position = 2], enabling:Enable-OPIMDirectoryRole 'Role (id)' 'Justification' 4.
Fixed
Get-OPIMDirectoryRole -Activatedno longer applies a post-filter ofassignmentType -eq 'Activated'. All items returned byroleAssignmentScheduleInstancesare inherently active assignments; the filter suppressed results when the real Graph API response omitted or differed in that field.Get-OPIMEntraIDGroup -Allno longer throwsMissingParameters: The required parameters GroupId or PrincipalId is missing. The PIM Groups API requiresfilterByCurrentUser(on='principal')even when listing all types; this is now preserved.Get-OPIMAzureRole -Allno longer throwsInsufficientPermissions. TheasTarget()filter is now preserved with-All, restricting results to the current user at scope/.Get-OPIMAzureRole -Activated -Scope '<specific-scope>'now returns only instances at that exact scope. Previously,Get-AzRoleAssignmentScheduleInstancereturned inherited parent-scope instances; these are now filtered out client-side when scope is not/.Get-OPIMDirectoryRole,Get-OPIMEntraIDGroup— improved.PARAMETER Filterdocumentation with OData examples. Added.EXAMPLEblocks for-Filterand-Identityusage.Get-OPIMEntraIDGroup—-AccessTypefilter now applies correctly when-Allis combined with-AccessType memberor-AccessType owner. Previously the filter was silently ignored in-Allmode.Get-OPIMAzureRole— removed[Alias('Id')]from the-Scopeparameter. PowerShell's prefix-matching treatedIdas an abbreviation of-Identity, causing "Parameter set cannot be resolved" errors when-Identitywas specified alongside the default$Scope = '/'binding.Get-OPIMAzureRole—Add-Member -NotePropertyName Statusnow uses-Forceto prevent "Cannot add a member with the name 'Status' because a member already exists" errors when the same object is processed more than once (e.g. across multiple pipeline invocations).Get-OPIMAzureRoledual-search now correctly separates the-Name(Get parameter set) and-Filter(List parameter set) calls toGet-AzRoleEligibilityScheduleandGet-AzRoleAssignmentScheduleInstance. These are mutually exclusive parameter sets in Az.Resources; previously passing both parameters caused a parameter binding error.
— wraps Invoke-MgGraphRequest for PIM activation POST requests with automatic ACRS claims-challenge retry via MSAL interactive authentication. Used by Enable-OPIMDirectoryRole and Enable-OPIMEntraIDGroup.
Enable-OPIMMyRolegains four new switch parameters:-AllEligible,-AllEligibleDirectoryRoles,-AllEligibleEntraIDGroups,-AllEligibleAzureRoles. These bypass the TenantMap filter and activate all eligible roles in the selected categories, each requiring interactive ShouldProcess confirmation (supports-WhatIf/-Confirm).Omnicit.PIM.AzureAssignmentScheduleRequesttype with matchingFormat.ps1xmlandTypes.ps1xml— enables consistent table output forEnable-OPIMAzureRoleandDisable-OPIMAzureRoler...
v0.4.0-preview0001
[v0.4.0-preview0001]
Added
Connect-OPIM(aliasConnect-PIM) — new public cmdlet to pre-authenticate against Microsoft Graph and optionally Azure. A single browser prompt covers all PIM surfaces (directory roles, Entra ID groups, Azure RBAC). AllGet-/Enable-/Disable-OPIM*cmdlets call this automatically on first use.Disconnect-OPIM(aliasDisconnect-PIM) — new public cmdlet to clear all cached session tokens and disconnect from Graph and Azure.- Centralized MSAL-based authentication layer (
Initialize-OPIMAuth,Get-OPIMMsalApplicationprivate helpers). All PIM cmdlets now share a single token-acquisition flow that caches the result and is idempotent when called multiple times in the same session. - ACRS Conditional Access claims-challenge handling moved into
Invoke-OPIMGraphRequest. A single reactive browser re-prompt is issued when Graph returns a step-up challenge, eliminating repeated browser windows when activating multiple roles in oneEnable-OPIMMyRolecall. Invoke-OPIMGraphRequestprivate wrapper replaces directInvoke-MgGraphRequestcalls throughout the module. Provides bearer-token security (removes raw error records before any processing), ACRS retry, and consistentConvert-GraphHttpExceptionerror conversion.
(ParameterSetName ByIdentity) added to all six Enable-OPIM* and Disable-OPIM* cmdlets. Activates or deactivates a role/group by schedule ID (or schedule Name for Azure) without tab completion. For Disable-* cmdlets, the ID must correspond to an active schedule instance (from Get-OPIM* -Activated). For Azure RBAC the identity is the Name property.
Get-OPIMDirectoryRole,Get-OPIMEntraIDGroup, andGet-OPIMAzureRolegain a new-AllParameterSet that returns both eligible and active schedules for the current user in a single call.-Alland-Activatedare mutually exclusive.Get-OPIMDirectoryRole— new-RoleNamepositional parameter ([Position = 0]) with tab completion viaDirectoryEligibleRoleCompleter. Extracts the schedule ID from the trailing(id)and performs a dual-search across eligible and active endpoints.Get-OPIMEntraIDGroup— new-GroupNamepositional parameter ([Position = 0]) with tab completion viaGroupEligibleCompleter. Extracts the schedule ID from the trailing(id)and performs a dual-search across eligible and active endpoints.Get-OPIMAzureRole— new-RoleNamepositional parameter ([Position = 0]) with tab completion viaAzureEligibleRoleCompleter, and new-Identityparameter for direct look-up by scheduleName. Both perform dual-search across eligible and active endpoints.- Combined schedule view: When
-All,-RoleName/-GroupName/-Identitytrigger dual-search, all threeGet-OPIM*cmdlets now returnOmnicit.PIM.*CombinedScheduletyped objects with aStatuscolumn (EligibleorActive) for consistent table output across both result types. - New format/type files for combined schedule views:
Omnicit.PIM.DirectoryCombinedSchedule,Omnicit.PIM.GroupCombinedSchedule,Omnicit.PIM.AzureCombinedSchedule— each with aStatuscolumn in the default table view. - Pipeline safety guards:
Enable-OPIMDirectoryRole,Enable-OPIMEntraIDGroup,Enable-OPIMAzureRolenow skip pipeline objects already tagged as active assignment instances (e.g. objects piped fromGet-OPIM* -Allthat haveStatus = Active), emitting aWrite-Verbosemessage instead of attempting an activation that would fail. - Pipeline safety guards:
Disable-OPIMDirectoryRole,Disable-OPIMEntraIDGroup,Disable-OPIMAzureRolenow skip pipeline objects tagged as eligible-only schedules (e.g. objects piped fromGet-OPIM* -Allthat haveStatus = Eligible), emitting a non-terminating error instead of attempting a deactivation that would fail.
Changed
- BREAKING —
Get-OPIMDirectoryRole -All,Get-OPIMEntraIDGroup -All, andGet-OPIMAzureRole -Allno longer removefilterByCurrentUser/asTarget()to list all principals. They now return both eligible and active schedules for the current user. Admins seeking all-principals data should query the Graph API directly with elevated permissions. - BREAKING —
-Alland-Activatedare now mutually exclusive on all threeGet-OPIM*cmdlets. Combining them raises a parameter binding error. Enable-OPIMDirectoryRole,Enable-OPIMEntraIDGroup,Enable-OPIMAzureRole—-Justificationis now positional[Position = 1]and-Hoursis positional[Position = 2], enabling:Enable-OPIMDirectoryRole 'Role (id)' 'Justification' 4.
Fixed
Get-OPIMDirectoryRole -Activatedno longer applies a post-filter ofassignmentType -eq 'Activated'. All items returned byroleAssignmentScheduleInstancesare inherently active assignments; the filter suppressed results when the real Graph API response omitted or differed in that field.Get-OPIMEntraIDGroup -Allno longer throwsMissingParameters: The required parameters GroupId or PrincipalId is missing. The PIM Groups API requiresfilterByCurrentUser(on='principal')even when listing all types; this is now preserved.Get-OPIMAzureRole -Allno longer throwsInsufficientPermissions. TheasTarget()filter is now preserved with-All, restricting results to the current user at scope/.Get-OPIMAzureRole -Activated -Scope '<specific-scope>'now returns only instances at that exact scope. Previously,Get-AzRoleAssignmentScheduleInstancereturned inherited parent-scope instances; these are now filtered out client-side when scope is not/.Get-OPIMDirectoryRole,Get-OPIMEntraIDGroup— improved.PARAMETER Filterdocumentation with OData examples. Added.EXAMPLEblocks for-Filterand-Identityusage.Get-OPIMEntraIDGroup—-AccessTypefilter now applies correctly when-Allis combined with-AccessType memberor-AccessType owner. Previously the filter was silently ignored in-Allmode.Get-OPIMAzureRole— removed[Alias('Id')]from the-Scopeparameter. PowerShell's prefix-matching treatedIdas an abbreviation of-Identity, causing "Parameter set cannot be resolved" errors when-Identitywas specified alongside the default$Scope = '/'binding.Get-OPIMAzureRole—Add-Member -NotePropertyName Statusnow uses-Forceto prevent "Cannot add a member with the name 'Status' because a member already exists" errors when the same object is processed more than once (e.g. across multiple pipeline invocations).Get-OPIMAzureRoledual-search now correctly separates the-Name(Get parameter set) and-Filter(List parameter set) calls toGet-AzRoleEligibilityScheduleandGet-AzRoleAssignmentScheduleInstance. These are mutually exclusive parameter sets in Az.Resources; previously passing both parameters caused a parameter binding error.
— wraps Invoke-MgGraphRequest for PIM activation POST requests with automatic ACRS claims-challenge retry via MSAL interactive authentication. Used by Enable-OPIMDirectoryRole and Enable-OPIMEntraIDGroup.
Enable-OPIMMyRolegains four new switch parameters:-AllEligible,-AllEligibleDirectoryRoles,-AllEligibleEntraIDGroups,-AllEligibleAzureRoles. These bypass the TenantMap filter and activate all eligible roles in the selected categories, each requiring interactive ShouldProcess confirmation (supports-WhatIf/-Confirm).Omnicit.PIM.AzureAssignmentScheduleRequesttype with matchingFormat.ps1xmlandTypes.ps1xml— enables consistent table output forEnable-OPIMAzureRoleandDisable-OPIMAzureRoleresults.Get-OPIMConfiguration— reads the TenantMap.psd1 file and returns typedOmnicit.PIM.TenantConfigurationobjects (one per alias). Supports-TenantAliasfilter and-TenantMapPathoverride. Alias:Get-PIMConfig.Set-OPIMConfiguration— updates an existing tenant alias entry. Accepts-TenantIdto change the GUID and pipeline input fromGet-OPIMDirectoryRole,Get-OPIMEntraIDGroup, orGet-OPIMAzureRoleto replace stored role/group lists. Categories not supplied via pipeline are preserved. Supports-WhatIf/-Confirm. Alias:Set-PIMConfig.Remove-OPIMConfiguration— removes a single tenant alias from the TenantMap.psd1 file while preserving all other entries. Supports-WhatIf/-Confirm. Alias:Remove-PIMConfig.Export-OPIMTenantMap(private) — shared PSD1 serializer extracted fromInstall-OPIMConfigurationand reused bySet-OPIMConfigurationandRemove-OPIMConfiguration.Omnicit.PIM.TenantConfigurationtype with script propertiesDirectoryRoleCount,EntraIDGroupCount, andAzureRoleCountfor concise table display.
Changed
- BREAKING —
Enable-OPIMMyRolenow requires explicit activation intent. Calling it without-TenantAliasor an-AllEligible*switch emits a non-terminating error (NoActivationTargetSpecified) and exits immediately. Previously it silently activated all eligible roles using the current Graph context. Enable-OPIMMyRole— when-TenantAliasis used with a hashtable Config that omits a category key (DirectoryRoles,EntraIDGroups,AzureRoles), aWrite-Warningis now emitted and that category is skipped instead of activating all eligible roles in it.Enable-OPIMMyRole— replaced barethrowcalls (for TenantMap-not-found and alias-not-found errors) with$PSCmdlet.WriteError()+return, making the function honour-ErrorAction SilentlyContinue.Enable-OPIMAzureRoleandDisable-OPIMAzureRole— output is now tagged with theOmnicit.PIM.AzureAssignmentScheduleRequesttype name so the new format file applies.- BREAKING —
Install-OPIMConfigurationis now a create-only operation. It emits a non-terminating error if the alias already exists and instructs the user to callSet-OPIMConfigurationinstead. - BREAKING — the
-Forceparameter has been removed fromInstall-OPIMConfiguration. Update semantics (including catego...
v0.3.1
[v0.3.1]
Added
-Identityparameter (ParameterSetNameByIdentity) added to all sixEnable-OPIM*andDisable-OPIM*cmdlets. Activates or deactivates a role/group by schedule ID (or scheduleNamefor Azure) without tab completion. ForDisable-*cmdlets, the ID must correspond to an active schedule instance (fromGet-OPIM* -Activated). For Azure RBAC the identity is theNameproperty.Get-OPIMDirectoryRole,Get-OPIMEntraIDGroup, andGet-OPIMAzureRolegain a new-AllParameterSet that returns both eligible and active schedules for the current user in a single call.-Alland-Activatedare mutually exclusive.Get-OPIMDirectoryRole— new-RoleNamepositional parameter ([Position = 0]) with tab completion viaDirectoryEligibleRoleCompleter. Extracts the schedule ID from the trailing(id)and performs a dual-search across eligible and active endpoints.Get-OPIMEntraIDGroup— new-GroupNamepositional parameter ([Position = 0]) with tab completion viaGroupEligibleCompleter. Extracts the schedule ID from the trailing(id)and performs a dual-search across eligible and active endpoints.Get-OPIMAzureRole— new-RoleNamepositional parameter ([Position = 0]) with tab completion viaAzureEligibleRoleCompleter, and new-Identityparameter for direct look-up by scheduleName. Both perform dual-search across eligible and active endpoints.- Combined schedule view: When
-All,-RoleName/-GroupName/-Identitytrigger dual-search, all threeGet-OPIM*cmdlets now returnOmnicit.PIM.*CombinedScheduletyped objects with aStatuscolumn (EligibleorActive) for consistent table output across both result types. - New format/type files for combined schedule views:
Omnicit.PIM.DirectoryCombinedSchedule,Omnicit.PIM.GroupCombinedSchedule,Omnicit.PIM.AzureCombinedSchedule— each with aStatuscolumn in the default table view. - Pipeline safety guards:
Enable-OPIMDirectoryRole,Enable-OPIMEntraIDGroup,Enable-OPIMAzureRolenow skip pipeline objects already tagged as active assignment instances (e.g. objects piped fromGet-OPIM* -Allthat haveStatus = Active), emitting aWrite-Verbosemessage instead of attempting an activation that would fail. - Pipeline safety guards:
Disable-OPIMDirectoryRole,Disable-OPIMEntraIDGroup,Disable-OPIMAzureRolenow skip pipeline objects tagged as eligible-only schedules (e.g. objects piped fromGet-OPIM* -Allthat haveStatus = Eligible), emitting a non-terminating error instead of attempting a deactivation that would fail.
Changed
- BREAKING —
Get-OPIMDirectoryRole -All,Get-OPIMEntraIDGroup -All, andGet-OPIMAzureRole -Allno longer removefilterByCurrentUser/asTarget()to list all principals. They now return both eligible and active schedules for the current user. Admins seeking all-principals data should query the Graph API directly with elevated permissions. - BREAKING —
-Alland-Activatedare now mutually exclusive on all threeGet-OPIM*cmdlets. Combining them raises a parameter binding error. Enable-OPIMDirectoryRole,Enable-OPIMEntraIDGroup,Enable-OPIMAzureRole—-Justificationis now positional[Position = 1]and-Hoursis positional[Position = 2], enabling:Enable-OPIMDirectoryRole 'Role (id)' 'Justification' 4.
Fixed
Get-OPIMDirectoryRole -Activatedno longer applies a post-filter ofassignmentType -eq 'Activated'. All items returned byroleAssignmentScheduleInstancesare inherently active assignments; the filter suppressed results when the real Graph API response omitted or differed in that field.Get-OPIMEntraIDGroup -Allno longer throwsMissingParameters: The required parameters GroupId or PrincipalId is missing. The PIM Groups API requiresfilterByCurrentUser(on='principal')even when listing all types; this is now preserved.Get-OPIMAzureRole -Allno longer throwsInsufficientPermissions. TheasTarget()filter is now preserved with-All, restricting results to the current user at scope/.Get-OPIMAzureRole -Activated -Scope '<specific-scope>'now returns only instances at that exact scope. Previously,Get-AzRoleAssignmentScheduleInstancereturned inherited parent-scope instances; these are now filtered out client-side when scope is not/.Get-OPIMDirectoryRole,Get-OPIMEntraIDGroup— improved.PARAMETER Filterdocumentation with OData examples. Added.EXAMPLEblocks for-Filterand-Identityusage.Get-OPIMEntraIDGroup—-AccessTypefilter now applies correctly when-Allis combined with-AccessType memberor-AccessType owner. Previously the filter was silently ignored in-Allmode.Get-OPIMAzureRole— removed[Alias('Id')]from the-Scopeparameter. PowerShell's prefix-matching treatedIdas an abbreviation of-Identity, causing "Parameter set cannot be resolved" errors when-Identitywas specified alongside the default$Scope = '/'binding.Get-OPIMAzureRole—Add-Member -NotePropertyName Statusnow uses-Forceto prevent "Cannot add a member with the name 'Status' because a member already exists" errors when the same object is processed more than once (e.g. across multiple pipeline invocations).Get-OPIMAzureRoledual-search now correctly separates the-Name(Get parameter set) and-Filter(List parameter set) calls toGet-AzRoleEligibilityScheduleandGet-AzRoleAssignmentScheduleInstance. These are mutually exclusive parameter sets in Az.Resources; previously passing both parameters caused a parameter binding error.
— wraps Invoke-MgGraphRequest for PIM activation POST requests with automatic ACRS claims-challenge retry via MSAL interactive authentication. Used by Enable-OPIMDirectoryRole and Enable-OPIMEntraIDGroup.
Enable-OPIMMyRolegains four new switch parameters:-AllEligible,-AllEligibleDirectoryRoles,-AllEligibleEntraIDGroups,-AllEligibleAzureRoles. These bypass the TenantMap filter and activate all eligible roles in the selected categories, each requiring interactive ShouldProcess confirmation (supports-WhatIf/-Confirm).Omnicit.PIM.AzureAssignmentScheduleRequesttype with matchingFormat.ps1xmlandTypes.ps1xml— enables consistent table output forEnable-OPIMAzureRoleandDisable-OPIMAzureRoleresults.Get-OPIMConfiguration— reads the TenantMap.psd1 file and returns typedOmnicit.PIM.TenantConfigurationobjects (one per alias). Supports-TenantAliasfilter and-TenantMapPathoverride. Alias:Get-PIMConfig.Set-OPIMConfiguration— updates an existing tenant alias entry. Accepts-TenantIdto change the GUID and pipeline input fromGet-OPIMDirectoryRole,Get-OPIMEntraIDGroup, orGet-OPIMAzureRoleto replace stored role/group lists. Categories not supplied via pipeline are preserved. Supports-WhatIf/-Confirm. Alias:Set-PIMConfig.Remove-OPIMConfiguration— removes a single tenant alias from the TenantMap.psd1 file while preserving all other entries. Supports-WhatIf/-Confirm. Alias:Remove-PIMConfig.Export-OPIMTenantMap(private) — shared PSD1 serializer extracted fromInstall-OPIMConfigurationand reused bySet-OPIMConfigurationandRemove-OPIMConfiguration.Omnicit.PIM.TenantConfigurationtype with script propertiesDirectoryRoleCount,EntraIDGroupCount, andAzureRoleCountfor concise table display.
Changed
- BREAKING —
Enable-OPIMMyRolenow requires explicit activation intent. Calling it without-TenantAliasor an-AllEligible*switch emits a non-terminating error (NoActivationTargetSpecified) and exits immediately. Previously it silently activated all eligible roles using the current Graph context. Enable-OPIMMyRole— when-TenantAliasis used with a hashtable Config that omits a category key (DirectoryRoles,EntraIDGroups,AzureRoles), aWrite-Warningis now emitted and that category is skipped instead of activating all eligible roles in it.Enable-OPIMMyRole— replaced barethrowcalls (for TenantMap-not-found and alias-not-found errors) with$PSCmdlet.WriteError()+return, making the function honour-ErrorAction SilentlyContinue.Enable-OPIMAzureRoleandDisable-OPIMAzureRole— output is now tagged with theOmnicit.PIM.AzureAssignmentScheduleRequesttype name so the new format file applies.- BREAKING —
Install-OPIMConfigurationis now a create-only operation. It emits a non-terminating error if the alias already exists and instructs the user to callSet-OPIMConfigurationinstead. - BREAKING — the
-Forceparameter has been removed fromInstall-OPIMConfiguration. Update semantics (including category preservation) are now handled bySet-OPIMConfiguration. Install-OPIMConfigurationnow delegates PSD1 serialization to the new private helperExport-OPIMTenantMap.
Removed
- The
-Forceswitch onInstall-OPIMConfigurationhas been removed (see Changed above).
Fixed
- Security: All Graph API
catchblocks now call$null = $Error.Remove($PSItem)as the first statement, removing the rawHttpRequestMessage(which contains theAuthorization: Bearer <token>) from$Errorbefore any further processing. Previously the bearer token could be inspected via$Errorafter a failed Graph call. Enable-OPIMEntraIDGroupandEnable-OPIMDirectoryRolenow surfaceRoleAssignmentRequestAcrsValidationFailed(CAE/ACRS claims challenge) as a direct, non-terminatingAuthenticationErrorwith an actionable message directing the user to runConnect-MgGraphin a new PowerShell session. The previous WAM-disable/disconnect/retry logic has been removed becauseSet-MgGraphOption -DisableLoginByWAM $trueis silently ignored when using the default Graph ClientId, making the retry ineffective and causing unnecessary session disconnection.- All
IArgumentCompleterclass methods now invoke `Get-OPIM*...