Omnicit.EntraRBAC.psd1

@{
    RootModule           = 'Omnicit.EntraRBAC.psm1'
    ModuleVersion        = '1.1.3'
    CompatiblePSEditions = @('Core')
    GUID                 = '7b9e4a1c-2d6f-4f3a-9c8b-1e5d0a7c3f42'
    Author               = 'Omnicit AB / Philip Haglund'
    CompanyName          = 'Omnicit'
    Copyright            = '(c) 2026 Omnicit AB'
    Description          = 'Manage Entra ID and Azure RBAC building blocks across tenants: Entra ID groups, PIM, Administrative Units, Entitlement Management, Access Reviews, Azure resources and RBAC, plus a JSON inventory and declarative apply engine.'
    PowerShellVersion    = '7.2'

    RequiredModules = @(
        @{ ModuleName = 'AzAuth'; ModuleVersion = '2.9.0' }
        @{ ModuleName = 'Microsoft.Graph.Authentication'; ModuleVersion = '2.36.0' }
    )

    # Loaded via Update-TypeData in suffix.ps1 (Remove-Module does not clean type data).
    TypesToProcess   = @()
    FormatsToProcess = @('Formats/Omnicit.EntraRBAC.Format.ps1xml')

    FunctionsToExport = @('Add-OERAccessPackageResourceRole','Add-OERAdministrativeUnitMember','Add-OERAdministrativeUnitScopedRole','Add-OERCatalogResource','Add-OERGroupEligibility','Add-OERGroupMember','Connect-OER','Disable-OEREligibleRoleAssignment','Disconnect-OER','Enable-OEREligibleRoleAssignment','Export-OERInventory','Get-OERAccessPackage','Get-OERAccessPackageAssignment','Get-OERAccessPackageAssignmentPolicy','Get-OERAccessPackageResourceRole','Get-OERAccessReviewDefinition','Get-OERAccessReviewInstance','Get-OERAccessReviewInstanceDecision','Get-OERActiveDirectoryRoleAssignment','Get-OERActiveRoleAssignment','Get-OERAdministrativeUnit','Get-OERAdministrativeUnitScopedRole','Get-OERAuthenticationContext','Get-OERCatalog','Get-OERCatalogResource','Get-OERConfiguration','Get-OERDirectoryRoleManagementPolicy','Get-OEREligibleDirectoryRoleAssignment','Get-OEREligibleRoleAssignment','Get-OERGroup','Get-OERGroupEligibility','Get-OERGroupMember','Get-OERGroupPimPolicy','Get-OERInventory','Get-OERManagementGroup','Get-OERRequiredScope','Get-OERResource','Get-OERResourceGroup','Get-OERRoleAssignment','Get-OERRoleDefinition','Get-OERRoleManagementPolicy','Get-OERSubscription','Invoke-OERAccessReviewInstanceDecision','Invoke-OERStructure','New-OERAccessPackage','New-OERAccessPackageApprovalStage','New-OERAccessPackageAssignment','New-OERAccessPackageAssignmentPolicy','New-OERAccessPackageRequestorScope','New-OERAccessPackageRequestorSettings','New-OERAccessReviewDefinition','New-OERAccessReviewStage','New-OERActiveDirectoryRoleAssignment','New-OERActiveRoleAssignment','New-OERAdministrativeUnit','New-OERCatalog','New-OERConfiguration','New-OEREligibleDirectoryRoleAssignment','New-OEREligibleRoleAssignment','New-OERGroup','New-OERPolicyNotificationRule','New-OERResourceGroup','New-OERRoleAssignment','Remove-OERAccessPackage','Remove-OERAccessPackageAssignment','Remove-OERAccessPackageAssignmentPolicy','Remove-OERAccessPackageResourceRole','Remove-OERAccessReviewDefinition','Remove-OERActiveDirectoryRoleAssignment','Remove-OERActiveRoleAssignment','Remove-OERAdministrativeUnit','Remove-OERAdministrativeUnitMember','Remove-OERAdministrativeUnitScopedRole','Remove-OERCatalog','Remove-OERCatalogResource','Remove-OERConfiguration','Remove-OEREligibleDirectoryRoleAssignment','Remove-OEREligibleRoleAssignment','Remove-OERGroup','Remove-OERGroupEligibility','Remove-OERGroupMember','Remove-OERResourceGroup','Remove-OERRoleAssignment','Send-OERAccessReviewReminder','Set-OERAccessPackage','Set-OERAccessPackageAssignmentPolicy','Set-OERAccessReviewDefinition','Set-OERAdministrativeUnit','Set-OERCatalog','Set-OERConfiguration','Set-OERDirectoryRoleManagementPolicy','Set-OERGroup','Set-OERGroupPimPolicy','Set-OERResourceGroup','Set-OERRoleAssignment','Set-OERRoleManagementPolicy','Stop-OERAccessReviewInstance','Test-OERStructure')
    CmdletsToExport   = @()
    VariablesToExport = @()
    AliasesToExport   = @()

    PrivateData = @{
        PSData = @{
            Tags                     = @('EntraID', 'Azure', 'RBAC', 'PIM', 'Identity', 'Governance',
                                          'PSEdition_Core', 'Windows', 'Linux', 'MacOS')
            ProjectUri               = 'https://github.com/Omnicit/Omnicit.EntraRBAC'
            LicenseUri               = 'https://github.com/Omnicit/Omnicit.EntraRBAC/blob/main/LICENSE'
            RequireLicenseAcceptance = $false
            ReleaseNotes             = '## [1.1.3-preview0008] - 2026-10-07

`Invoke-OERStructure` without `-TenantId`, and the builders that look up a name
(`New-OERAccessPackageApprovalStage`, `New-OERAccessPackageRequestorScope`,
`New-OERAccessReviewStage`), refuse with `SignInSuperseded` and send nothing when another command in
their pipeline signs in to another tenant or identity after they began; in a script block they begin
only when it runs, so name `-TenantId` there. `Get-OERInventory` and `Export-OERInventory` now name
their tenant (`tenantId`), and `Invoke-OERStructure` refuses a document naming another tenant than
`-TenantId` or the session with the new `DocumentTenantMismatch`, reading and writing nothing;
change or remove the key to apply it elsewhere. Cmdlets a refused command calls are refused at their
sign-in (`SignInRefused`), before any token request or prompt. A tenant named by domain is looked up
before any token request and checked against each token: one from another tenant is refused with
`TenantMismatch`, a domain naming no tenant, or `common`, with the new `TenantResolutionFailed`; the
warning after such a sign-in is gone. After a failed or refused sign-in, a command naming no tenant
sends nothing (`SignInRefused`) until a sign-in naming its tenant, `Connect-OER` or `Disconnect-OER`
succeeds. An empty `-TenantId` is refused, by `Connect-OER` with the new `InvalidTenantId`, and an
Azure token no longer outlives a renewal from another tenant.

Sixteen cmdlets now warn before the confirmation prompt, so `-WhatIf` and `-Confirm` show the
warning; with `-WhatIf -WarningAction Stop` they stop there, before the What if line, changing
nothing. `Invoke-OERStructure -WhatIf` writes the warning of the cmdlet it would call for an
administrative unit''s membership type change, a removed ABAC condition, a group PIM policy opened
for permanent eligibility and a reconciled MFA / authentication context pair; a real run now also
gives the last for a group''s policy.

Group member and owner reads include service principals, which Graph v1.0 lists omit
(`Get-OERGroup`, `Get-OERGroupMember`, the export, `Invoke-OERStructure`); a failed read leaves the
collection unread, not half-read. A document not listing them reports them `Extra`, and `-Prune`
keeps them. `-Prune` no longer removes, in the run that creates a group, the unit membership its
`administrativeUnit` gave it (`Skipped`, `prune withheld`); every later apply with `-Prune` removes
it unless the unit''s `members` name the group, which `Test-OERStructure` now also checks for a
template-named group and a unit named by id.

`Set-OERGroupPimPolicy` puts back the accepted half of the MFA / authentication context pair when
Graph rejects the other, and neither it nor `Set-OERDirectoryRoleManagementPolicy` warns between its
first rule update and its last, so `-WarningAction Stop` no longer stops half-way. These two and
`Set-OERRoleManagementPolicy` refuse `-RequireApproval $false` beside an approver parameter
(`MutuallyExclusiveParameter`), and the last refuses an empty approver list (`ApproverRequired`); in
`Invoke-OERStructure` an empty Azure approver side matches an empty live one. Eleven cmdlets
sending a PIM schedule request treat a request accepted with a status starting `Failed` as an error,
after the request object (`EligibilityRequestFailed`, or the new `AssignmentRequestFailed`), so
`Invoke-OERStructure` reports the row Failed. `New-OERActiveRoleAssignment` opens a role policy for
a permanent assignment only once confirmed; it and `New-OEREligibleRoleAssignment` roll it back if
the assignment fails.

`Set-OERAccessPackageAssignmentPolicy` refuses a connected-organization scope naming none
(`InvalidPolicyInput`). `Remove-OERActiveDirectoryRoleAssignment` and
`Remove-OEREligibleDirectoryRoleAssignment`, refusing a piped `Get-OERGroupMember` row
(`NotDirectAssignment`), now say how to remove that principal''s own assignment.

'

            Prerelease               = 'preview0008'
        }
    }
}