Omnicit.PIM
0.5.0-preview0002
Entra ID Privileged Identity Management (PIM) Self Activation Commands for Directory Roles, Azure Resources, and Entra ID Groups
Minimum PowerShell version
7.2
See the version list below for details.
Installation Options
Owners
Copyright
(c) Omnicit. All rights reserved.
Package Details
Author(s)
- Omnicit (originally by Justin Grote @justinwgrote)
Tags
PIM Azure EntraID Identity Privileged Windows MacOS Linux
Functions
Connect-OPIM Disable-OPIMAzureRole Disable-OPIMDirectoryRole Disable-OPIMEntraIDGroup Disable-OPIMMyRole Disconnect-OPIM Enable-OPIMAzureRole Enable-OPIMDirectoryRole Enable-OPIMEntraIDGroup Enable-OPIMMyRole Get-OPIMAzureRole Get-OPIMConfiguration Get-OPIMDirectoryRole Get-OPIMEntraIDGroup Install-OPIMConfiguration Remove-OPIMConfiguration Set-OPIMConfiguration Wait-OPIMDirectoryRole
PSEditions
Dependencies
-
- Az.Resources (>= 9.0.3)
- Microsoft.Graph.Authentication (>= 2.36.0)
Release Notes
## [0.5.0-preview0002] - 2026-05-27
### Fixed
- `Invoke-OPIMGraphRequest` now recovers from the PIM `RoleAssignmentRequestAcrsValidationFailed` activation error automatically. The claims challenge in this 400 response body is URL-encoded (`&claims=%7B...%7D`), a different encoding from the base64url `WWW-Authenticate: claims="..."` 401 form the parser previously handled. `Get-ClaimsFromException` now decodes both encodings (and raw JSON) and feeds the result to the existing MSAL `AcquireTokenInteractive().WithClaims()` step-up, so activations requiring a Conditional Access authentication context succeed with a single browser prompt and **no** manual `Disconnect-OPIM`.
- `Invoke-OPIMGraphRequest` ACRS retry no longer gates on the session-sticky `$script:_OPIMAuthState.ClaimsSatisfied` flag. 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-OPIMGraphRequest` now transparently re-authenticates and retries once when Graph rejects a bearer token as invalid/expired (HTTP 401 or `InvalidAuthenticationToken`/`CompactToken`/`token is expired`/`Lifetime validation failed`), via the new `Initialize-OPIMAuth -ForceRefresh` path (MSAL `AcquireTokenSilent().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 importing `ModuleBuilder`. `Configuration` and `Metadata` (ModuleBuilder's transitive runtime dependencies) are now listed explicitly in `RequiredModules.psd1` because PSResourceGet 1.0.1 does not install transitive `RequiredModules` during the bootstrap on a clean agent.
### Changed
- `Initialize-OPIMAuth` now disables the Web Account Manager (WAM) broker at **process scope** (`Update-AzConfig -EnableLoginByWam $false -Scope Process`) immediately before `Connect-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-side `Set-MgGraphOption -DisableLoginByWAM`, the Az-side `Update-AzConfig -EnableLoginByWam` toggle is honoured by `Connect-AzAccount`.)
- `Initialize-OPIMAuth` gains a `-ForceRefresh` switch that bypasses the cached-token idempotency check and forces MSAL to mint a fresh access token from the refresh token.
### Added
- `Get-OPIMCurrentTenantInfo` private helper — resolves the current tenant GUID and display name from the active Graph session. Used by `Install-`, `Set-`, and `Remove-OPIMConfiguration` to enrich the confirmation prompt.
- `Install-OPIMConfiguration` now auto-resolves `-TenantId` from the active Graph context when the parameter is omitted. A non-terminating error is emitted when no `-TenantId` is supplied and no active Graph session is available.
### Changed
- `Install-OPIMConfiguration`, `Set-OPIMConfiguration`, and `Remove-OPIMConfiguration` now have `ConfirmImpact = 'High'`. The `ShouldProcess` confirmation prompt includes the tenant alias, display name, and resolved GUID, making it clear which tenant is being modified before any write occurs.
- `-TenantId` in `Install-OPIMConfiguration` is no longer `[Mandatory]`; it is auto-resolved from `Get-MgContext` when omitted.
- PSScriptAnalyzer suppressions added to all six argument-completer classes (`AzureEligibleRoleCompleter`, `AzureActivatedRoleCompleter`, `DirectoryEligibleRoleCompleter`, `DirectoryActivatedRoleCompleter`, `GroupEligibleCompleter`, `GroupActivatedCompleter`).
### Changed
- `Write-CmdletError` revamped: new `ErrorRecord` parameter set (pass-through), `InnerException` parameter for exception chaining, `[CmdletBinding()]` added. All public and private functions now use `Write-CmdletError` as 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` (alias `Disconnect-PIM`) — new public cmdlet to clear all cached session tokens and disconnect from Graph and Azure.
- Centralized MSAL-based authentication layer (`Initialize-OPIMAuth`, `Get-OPIMMsalApplication` private 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 one `Enable-OPIMMyRole` call.
- `Invoke-OPIMGraphRequest` private wrapper replaces direct `Invoke-MgGraphRequest` calls throughout the module. Provides bearer-token security (removes raw error records before any processing), ACRS retry, and consistent `Convert-GraphHttpException` error 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`, and `Get-OPIMAzureRole` gain a new `-All` ParameterSet that returns **both** eligible and active schedules for the current user in a single call. `-All` and `-Activated` are mutually exclusive.
- `Get-OPIMDirectoryRole` — new `-RoleName` positional parameter (`[Position = 0]`) with tab completion via `DirectoryEligibleRoleCompleter`. Extracts the schedule ID from the trailing `(id)` and performs a dual-search across eligible and active endpoints.
- `Get-OPIMEntraIDGroup` — new `-GroupName` positional parameter (`[Position = 0]`) with tab completion via `GroupEligibleCompleter`. Extracts the schedule ID from the trailing `(id)` and performs a dual-search across eligible and active endpoints.
- `Get-OPIMAzureRole` — new `-RoleName` positional parameter (`[Position = 0]`) with tab completion via `AzureEligibleRoleCompleter`, and new `-Identity` parameter for direct look-up by schedule `Name`. Both perform dual-search across eligible and active endpoints.
- Combined schedule view: When `-All`, `-RoleName`/`-GroupName`/`-Identity` trigger dual-search, all three `Get-OPIM*` cmdlets now return `Omnicit.PIM.*CombinedSchedule` typed objects with a `Status` column (`Eligible` or `Active`) 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 a `Status` column in the default table view.
### Performance
- **Module load time reduced by ~8 seconds** (~55% of total import time). Consolidated 13 individual `*.Format.ps1xml` files into a single `Omnicit.PIM.Format.ps1xml` and 13 `*.Types.ps1xml` files into a single `Omnicit.PIM.Types.ps1xml`. Previously each file triggered a full format/type table rebuild (~0.49s and ~0.11s per call respectively).
- `FormatsToProcess` re-enabled in the module manifest — format data is now loaded natively by PowerShell at zero extra cost. This was previously disabled because `Update-FormatData -PrependPath` was needed to override Az.Resources native types; that override (`RoleAssignmentScheduleRequest`) is no longer needed since all output is wrapped as `Omnicit.PIM.*` custom types.
- `suffix.ps1` now loads a single consolidated `Omnicit.PIM.Types.ps1xml` file (1 call to `Update-TypeData`) instead of enumerating and loading 13 individual files (14 calls). `TypesToProcess` remains disabled in the manifest because `Remove-Module` does not clean type data, causing "member already present" errors on `Import-Module -Force`.
- Removed orphaned `RoleAssignmentScheduleRequest.Format.ps1xml` and `RoleAssignmentScheduleRequest.Types.ps1xml` — these targeted the native Az `Microsoft.Azure.PowerShell.Cmdlets.Resources.Authorization.Models.Api20201001Preview.RoleAssignmentScheduleRequest` type, but all Azure output is now wrapped with `Omnicit.PIM.AzureAssignmentScheduleRequest`.
- Pipeline safety guards: `Enable-OPIMDirectoryRole`, `Enable-OPIMEntraIDGroup`, `Enable-OPIMAzureRole` now skip pipeline objects already tagged as active assignment instances (e.g. objects piped from `Get-OPIM* -All` that have `Status = Active`), emitting a `Write-Verbose` message instead of attempting an activation that would fail.
- Pipeline safety guards: `Disable-OPIMDirectoryRole`, `Disable-OPIMEntraIDGroup`, `Disable-OPIMAzureRole` now skip pipeline objects tagged as eligible-only schedules (e.g. objects piped from `Get-OPIM* -All` that have `Status = Eligible`), emitting a non-terminating error instead of attempting a deactivation that would fail.
### Changed
- **BREAKING** — `Get-OPIMDirectoryRole -All`, `Get-OPIMEntraIDGroup -All`, and `Get-OPIMAzureRole -All` no longer remove `filterByCurrentUser` / `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** — `-All` and `-Activated` are now mutually exclusive on all three `Get-OPIM*` cmdlets. Combining them raises a parameter binding error.
- `Enable-OPIMDirectoryRole`, `Enable-OPIMEntraIDGroup`, `Enable-OPIMAzureRole` — `-Justification` is now positional
FileList
- Omnicit.PIM.nuspec
- Formats\Omnicit.PIM.Format.ps1xml
- Omnicit.PIM.psd1
- Formats\Omnicit.PIM.Types.ps1xml
- Omnicit.PIM.psm1
- Formats\README.md
- en-US\about_Omnicit.PIM.help.txt
Version History
| Version | Downloads | Last updated |
|---|---|---|
| 0.5.1 | 5 | 5/29/2026 |
| 0.5.1-previe... | 2 | 5/29/2026 |
| 0.5.0 | 5 | 5/27/2026 |
| 0.5.0-previe... (current version) | 2 | 5/27/2026 |
| 0.5.0-previe... | 3 | 5/27/2026 |
| 0.4.0 | 15 | 4/21/2026 |
| 0.4.0-previe... | 2 | 4/21/2026 |
| 0.4.0-previe... | 3 | 4/20/2026 |
| 0.4.0-previe... | 4 | 4/19/2026 |
| 0.3.1 | 6 | 4/16/2026 |
| 0.3.1-previe... | 2 | 4/16/2026 |
| 0.3.1-previe... | 2 | 4/16/2026 |
| 0.3.1-previe... | 2 | 4/16/2026 |
| 0.3.0 | 3 | 4/16/2026 |
| 0.3.0-previe... | 4 | 4/15/2026 |
| 0.3.0-previe... | 4 | 4/14/2026 |
| 0.3.0-previe... | 2 | 4/14/2026 |
| 0.3.0-previe... | 2 | 4/13/2026 |
| 0.3.0-previe... | 4 | 4/2/2026 |
| 0.3.0-previe... | 2 | 4/2/2026 |