tests/Get-MsecEntraPimPolicy.Tests.ps1
|
#Requires -Module Pester # # Tests for Get-MsecEntraPimPolicy. # # The traps here are all about reading a setting the way the question is asked: # # isExpirationRequired IS INVERTED. PermanentActiveAllowed is NOT isExpirationRequired, and # getting it backwards reports a tenant that forbids standing privilege as one that permits # it, or worse the other way round. # # AN ABSENT RULE IS NOT A DISABLED ONE. A policy that does not carry an enablement rule has # not been measured, so the flag is $null - $false would claim PIM was asked and said no. # # A POLICY ON A ROLE NOBODY IS ELIGIBLE FOR GOVERNS NOTHING, but it is still returned: it may # be deliberately pre-configured. HasEligibleHolder is how the two are told apart, and it is # null - never false - when eligibility could not be read. BeforeAll { Import-Module (Join-Path $PSScriptRoot '..' 'Msec.psm1') -Force -ErrorAction Stop } AfterAll { Remove-Module msec -Force -ErrorAction SilentlyContinue } Describe 'Get-MsecEntraPimPolicy' { BeforeEach { InModuleScope msec { $script:MsecSession = @{ TenantId = 't'; ClientId = 'c'; Tokens = @{} } } } It 'reads activation requirements out of enabledRules' { $rows = InModuleScope msec { Mock Invoke-MsecGraphRequest -MockWith { if ($Path -like '*roleDefinitions*') { @([pscustomobject]@{ id = 'def-1'; displayName = 'Global Administrator' templateId = '62e90394-69f5-4237-9190-012177145e10' }) } elseif ($Path -like '*roleEligibilityScheduleInstances*') { @([pscustomobject]@{ roleDefinitionId = 'def-1' }) } elseif ($Path -like '*roleManagementPolicyAssignments*') { @([pscustomobject]@{ roleDefinitionId = 'def-1'; policy = [pscustomobject]@{ rules = @( [pscustomobject]@{ id = 'Enablement_EndUser_Assignment' enabledRules = @('MultiFactorAuthentication', 'Justification') } ) } }) } else { @() } } Get-MsecEntraPimPolicy } $get = { param($s) ($rows | Where-Object Setting -eq $s).Value } (& $get 'ActivationRequiresMfa') | Should -Be 'True' (& $get 'ActivationRequiresJustification') | Should -Be 'True' # Ticketing is absent from enabledRules, which is a measured "not demanded". (& $get 'ActivationRequiresTicket') | Should -Be 'False' $rows[0].IsHighlyPrivileged | Should -BeTrue $rows[0].HasEligibleHolder | Should -BeTrue } It 'inverts isExpirationRequired into PermanentActiveAllowed' { $rows = InModuleScope msec { Mock Invoke-MsecGraphRequest -MockWith { if ($Path -like '*roleDefinitions*') { @([pscustomobject]@{ id = 'def-1'; displayName = 'Role'; templateId = 'tpl-1' }) } elseif ($Path -like '*roleEligibilityScheduleInstances*') { @() } elseif ($Path -like '*roleManagementPolicyAssignments*') { @([pscustomobject]@{ roleDefinitionId = 'def-1'; policy = [pscustomobject]@{ rules = @( # Expiration NOT required => a permanent assignment IS allowed. [pscustomobject]@{ id = 'Expiration_Admin_Assignment'; isExpirationRequired = $false; maximumDuration = 'P180D' } # Expiration required => permanent eligibility is NOT allowed. [pscustomobject]@{ id = 'Expiration_Admin_Eligibility'; isExpirationRequired = $true; maximumDuration = 'P365D' } ) } }) } else { @() } } Get-MsecEntraPimPolicy } $get = { param($s) ($rows | Where-Object Setting -eq $s).Value } (& $get 'PermanentActiveAllowed') | Should -Be 'True' (& $get 'MaxActiveDuration') | Should -Be 'P180D' (& $get 'PermanentEligibleAllowed') | Should -Be 'False' } It 'reports an absent enablement rule as null rather than as not required' { $rows = InModuleScope msec { Mock Invoke-MsecGraphRequest -MockWith { if ($Path -like '*roleDefinitions*') { @([pscustomobject]@{ id = 'def-1'; displayName = 'Role'; templateId = 'tpl-1' }) } elseif ($Path -like '*roleEligibilityScheduleInstances*') { @() } elseif ($Path -like '*roleManagementPolicyAssignments*') { @([pscustomobject]@{ roleDefinitionId = 'def-1'; policy = [pscustomobject]@{ rules = @() } }) } else { @() } } Get-MsecEntraPimPolicy } ($rows | Where-Object Setting -eq 'ActivationRequiresMfa').Value | Should -BeNullOrEmpty ($rows | Where-Object Setting -eq 'PermanentActiveAllowed').Value | Should -BeNullOrEmpty } It 'still returns a role nobody is eligible for, flagged as such' { $rows = InModuleScope msec { Mock Invoke-MsecGraphRequest -MockWith { if ($Path -like '*roleDefinitions*') { @([pscustomobject]@{ id = 'def-1'; displayName = 'Unused Role'; templateId = 'tpl-1' }) } elseif ($Path -like '*roleEligibilityScheduleInstances*') { @() } elseif ($Path -like '*roleManagementPolicyAssignments*') { @([pscustomobject]@{ roleDefinitionId = 'def-1'; policy = [pscustomobject]@{ rules = @( [pscustomobject]@{ id = 'Enablement_EndUser_Assignment'; enabledRules = @() }) } }) } else { @() } } Get-MsecEntraPimPolicy } # Dropping it would hide a policy someone pre-configured ahead of an assignment. $rows | Should -Not -BeNullOrEmpty $rows[0].HasEligibleHolder | Should -BeFalse } It 'leaves HasEligibleHolder null when eligibility could not be read' { $rows = InModuleScope msec { Mock Invoke-MsecGraphRequest -MockWith { if ($Path -like '*roleDefinitions*') { @([pscustomobject]@{ id = 'def-1'; displayName = 'Role'; templateId = 'tpl-1' }) } elseif ($Path -like '*roleEligibilityScheduleInstances*') { throw 'Insufficient privileges' } elseif ($Path -like '*roleManagementPolicyAssignments*') { @([pscustomobject]@{ roleDefinitionId = 'def-1'; policy = [pscustomobject]@{ rules = @() } }) } else { @() } } Get-MsecEntraPimPolicy -WarningAction SilentlyContinue } # $false would claim nobody is eligible, which nothing established. $rows[0].HasEligibleHolder | Should -BeNullOrEmpty } It 'filters to the shared privileged role list with -HighlyPrivilegedOnly' { $rows = InModuleScope msec { Mock Invoke-MsecGraphRequest -MockWith { if ($Path -like '*roleDefinitions*') { @( [pscustomobject]@{ id = 'def-1'; displayName = 'Global Administrator' templateId = '62e90394-69f5-4237-9190-012177145e10' } [pscustomobject]@{ id = 'def-2'; displayName = 'Message Center Reader'; templateId = 'tpl-mcr' } ) } elseif ($Path -like '*roleEligibilityScheduleInstances*') { @() } elseif ($Path -like '*roleManagementPolicyAssignments*') { @( [pscustomobject]@{ roleDefinitionId = 'def-1'; policy = [pscustomobject]@{ rules = @() } } [pscustomobject]@{ roleDefinitionId = 'def-2'; policy = [pscustomobject]@{ rules = @() } } ) } else { @() } } Get-MsecEntraPimPolicy -HighlyPrivilegedOnly } @($rows | Select-Object -ExpandProperty RoleName -Unique) | Should -Be 'Global Administrator' } It 'accepts -Role by display name or by template id' { $byName = InModuleScope msec { Mock Invoke-MsecGraphRequest -MockWith { if ($Path -like '*roleDefinitions*') { @( [pscustomobject]@{ id = 'def-1'; displayName = 'Intune Administrator'; templateId = 'tpl-intune' } [pscustomobject]@{ id = 'def-2'; displayName = 'User Administrator'; templateId = 'tpl-user' } ) } elseif ($Path -like '*roleEligibilityScheduleInstances*') { @() } elseif ($Path -like '*roleManagementPolicyAssignments*') { @( [pscustomobject]@{ roleDefinitionId = 'def-1'; policy = [pscustomobject]@{ rules = @() } } [pscustomobject]@{ roleDefinitionId = 'def-2'; policy = [pscustomobject]@{ rules = @() } } ) } else { @() } } @( (Get-MsecEntraPimPolicy -Role 'Intune Administrator' | Select-Object -ExpandProperty RoleName -Unique) (Get-MsecEntraPimPolicy -Role 'tpl-user' | Select-Object -ExpandProperty RoleName -Unique) ) } $byName[0] | Should -Be 'Intune Administrator' $byName[1] | Should -Be 'User Administrator' } } |