Skip to content

Commit 9d2831d

Browse files
three new tests
1 parent b41127c commit 9d2831d

File tree

3 files changed

+269
-0
lines changed

3 files changed

+269
-0
lines changed
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
function Invoke-CippTestZTNA21782 {
2+
<#
3+
.SYNOPSIS
4+
Privileged accounts have phishing-resistant methods registered
5+
#>
6+
param($Tenant)
7+
8+
try {
9+
$UserRegistrationDetails = New-CIPPDbRequest -TenantFilter $Tenant -Type 'UserRegistrationDetails'
10+
$RoleAssignments = New-CIPPDbRequest -TenantFilter $Tenant -Type 'RoleAssignments'
11+
12+
if (-not $UserRegistrationDetails -or -not $RoleAssignments) {
13+
Add-CippTestResult -TenantFilter $Tenant -TestId 'ZTNA21782' -TestType 'Identity' -Status 'Skipped' -ResultMarkdown 'No data found in database. This may be due to missing required licenses or data collection not yet completed.' -Risk 'High' -Name 'Privileged accounts have phishing-resistant methods registered' -UserImpact 'Low' -ImplementationEffort 'Medium' -Category 'Privileged Access'
14+
return
15+
}
16+
17+
$PhishResistantMethods = @('passKeyDeviceBound', 'passKeyDeviceBoundAuthenticator', 'windowsHelloForBusiness')
18+
19+
# Join user registration details with role assignments
20+
$results = $UserRegistrationDetails | Where-Object {
21+
$userId = $_.id
22+
$RoleAssignments | Where-Object { $_.principalId -eq $userId }
23+
} | ForEach-Object {
24+
$user = $_
25+
$userRoles = $RoleAssignments | Where-Object { $_.principalId -eq $user.id }
26+
$hasPhishResistant = $false
27+
28+
if ($user.methodsRegistered) {
29+
foreach ($method in $PhishResistantMethods) {
30+
if ($user.methodsRegistered -contains $method) {
31+
$hasPhishResistant = $true
32+
break
33+
}
34+
}
35+
}
36+
37+
[PSCustomObject]@{
38+
id = $user.id
39+
userDisplayName = $user.userDisplayName
40+
roleDisplayName = ($userRoles.roleDefinitionName -join ', ')
41+
methodsRegistered = $user.methodsRegistered
42+
phishResistantAuthMethod = $hasPhishResistant
43+
}
44+
}
45+
46+
$totalUserCount = $results.Length
47+
$phishResistantPrivUsers = $results | Where-Object { $_.phishResistantAuthMethod }
48+
$phishablePrivUsers = $results | Where-Object { !$_.phishResistantAuthMethod }
49+
50+
$phishResistantPrivUserCount = $phishResistantPrivUsers.Length
51+
52+
$passed = $totalUserCount -eq $phishResistantPrivUserCount
53+
54+
$testResultMarkdown = if ($passed) {
55+
"Validated that all privileged users have registered phishing resistant authentication methods.`n`n%TestResult%"
56+
} else {
57+
"Found privileged users that have not yet registered phishing resistant authentication methods`n`n%TestResult%"
58+
}
59+
60+
$mdInfo = "## Privileged users`n`n"
61+
62+
if ($passed) {
63+
$mdInfo = "All privileged users have registered phishing resistant authentication methods.`n`n"
64+
} else {
65+
$mdInfo = "Found privileged users that have not registered phishing resistant authentication methods.`n`n"
66+
}
67+
68+
$mdInfo = $mdInfo + "| User | Role Name | Phishing resistant method registered |`n"
69+
$mdInfo = $mdInfo + "| :--- | :--- | :---: |`n"
70+
71+
$userLinkFormat = 'https://entra.microsoft.com/#view/Microsoft_AAD_UsersAndTenants/UserProfileMenuBlade/~/UserAuthMethods/userId/{0}/hidePreviewBanner~/true'
72+
73+
$mdLines = @($phishablePrivUsers | Sort-Object userDisplayName | ForEach-Object {
74+
$userLink = $userLinkFormat -f $_.id
75+
"|[$($_.userDisplayName)]($userLink)| $($_.roleDisplayName) | ❌ |`n"
76+
})
77+
$mdInfo = $mdInfo + ($mdLines -join '')
78+
79+
$mdLines = @($phishResistantPrivUsers | Sort-Object userDisplayName | ForEach-Object {
80+
$userLink = $userLinkFormat -f $_.id
81+
"|[$($_.userDisplayName)]($userLink)| $($_.roleDisplayName) | ✅ |`n"
82+
})
83+
$mdInfo = $mdInfo + ($mdLines -join '')
84+
85+
$testResultMarkdown = $testResultMarkdown -replace '%TestResult%', $mdInfo
86+
87+
Add-CippTestResult -TenantFilter $Tenant -TestId 'ZTNA21782' -TestType 'Identity' -Status $(if ($passed) { 'Passed' } else { 'Failed' }) -ResultMarkdown $testResultMarkdown -Risk 'High' -Name 'Privileged accounts have phishing-resistant methods registered' -UserImpact 'Low' -ImplementationEffort 'Medium' -Category 'Privileged Access'
88+
89+
} catch {
90+
$ErrorMessage = Get-CippException -Exception $_
91+
Write-LogMessage -API 'Tests' -tenant $Tenant -message "Failed to run test: $($ErrorMessage.NormalizedError)" -sev Error -LogData $ErrorMessage
92+
Add-CippTestResult -TenantFilter $Tenant -TestId 'ZTNA21782' -TestType 'Identity' -Status 'Failed' -ResultMarkdown "Test failed: $($ErrorMessage.NormalizedError)" -Risk 'High' -Name 'Privileged accounts have phishing-resistant methods registered' -UserImpact 'Low' -ImplementationEffort 'Medium' -Category 'Privileged Access'
93+
}
94+
}
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
function Invoke-CippTestZTNA21801 {
2+
<#
3+
.SYNOPSIS
4+
Users have strong authentication methods configured
5+
#>
6+
param($Tenant)
7+
8+
try {
9+
$UserRegistrationDetails = New-CIPPDbRequest -TenantFilter $Tenant -Type 'UserRegistrationDetails'
10+
$Users = New-CIPPDbRequest -TenantFilter $Tenant -Type 'Users'
11+
12+
if (-not $UserRegistrationDetails -or -not $Users) {
13+
Add-CippTestResult -TenantFilter $Tenant -TestId 'ZTNA21801' -TestType 'Identity' -Status 'Skipped' -ResultMarkdown 'No data found in database. This may be due to missing required licenses or data collection not yet completed.' -Risk 'Medium' -Name 'Users have strong authentication methods configured' -UserImpact 'Medium' -ImplementationEffort 'Medium' -Category 'Credential Management'
14+
return
15+
}
16+
17+
$PhishResistantMethods = @('passKeyDeviceBound', 'passKeyDeviceBoundAuthenticator', 'windowsHelloForBusiness')
18+
19+
$results = $UserRegistrationDetails | Where-Object {
20+
$userId = $_.id
21+
$matchingUser = $Users | Where-Object { $_.id -eq $userId -and $_.accountEnabled }
22+
$matchingUser
23+
} | ForEach-Object {
24+
$regDetail = $_
25+
$matchingUser = $Users | Where-Object { $_.id -eq $regDetail.id }
26+
$hasPhishResistant = $false
27+
28+
if ($regDetail.methodsRegistered) {
29+
foreach ($method in $PhishResistantMethods) {
30+
if ($regDetail.methodsRegistered -contains $method) {
31+
$hasPhishResistant = $true
32+
break
33+
}
34+
}
35+
}
36+
37+
[PSCustomObject]@{
38+
id = $regDetail.id
39+
displayName = $regDetail.userDisplayName
40+
phishResistantAuthMethod = $hasPhishResistant
41+
lastSuccessfulSignInDateTime = $matchingUser.signInActivity.lastSuccessfulSignInDateTime
42+
}
43+
}
44+
45+
$totalUserCount = $results.Length
46+
$phishResistantUsers = $results | Where-Object { $_.phishResistantAuthMethod }
47+
$phishableUsers = $results | Where-Object { !$_.phishResistantAuthMethod }
48+
49+
$phishResistantUserCount = $phishResistantUsers.Length
50+
51+
$passed = $totalUserCount -eq $phishResistantUserCount
52+
53+
$testResultMarkdown = if ($passed) {
54+
"Validated that all users have registered phishing resistant authentication methods.`n`n%TestResult%"
55+
} else {
56+
"Found users that have not yet registered phishing resistant authentication methods`n`n%TestResult%"
57+
}
58+
59+
$mdInfo = "## Users strong authentication methods`n`n"
60+
61+
if ($passed) {
62+
$mdInfo = "All users have registered phishing resistant authentication methods.`n`n"
63+
} else {
64+
$mdInfo = "Found users that have not registered phishing resistant authentication methods.`n`n"
65+
}
66+
67+
$mdInfo = $mdInfo + "| User | Last sign in | Phishing resistant method registered |`n"
68+
$mdInfo = $mdInfo + "| :--- | :--- | :---: |`n"
69+
70+
$userLinkFormat = 'https://entra.microsoft.com/#view/Microsoft_AAD_UsersAndTenants/UserProfileMenuBlade/~/UserAuthMethods/userId/{0}/hidePreviewBanner~/true'
71+
72+
$mdLines = @($phishableUsers | Sort-Object displayName | ForEach-Object {
73+
$userLink = $userLinkFormat -f $_.id
74+
$lastSignInDate = if ($_.lastSuccessfulSignInDateTime) { (Get-Date $_.lastSuccessfulSignInDateTime -Format 'yyyy-MM-dd') } else { 'Never' }
75+
"|[$($_.displayName)]($userLink)| $lastSignInDate | ❌ |`n"
76+
})
77+
$mdInfo = $mdInfo + ($mdLines -join '')
78+
79+
$mdLines = @($phishResistantUsers | Sort-Object displayName | ForEach-Object {
80+
$userLink = $userLinkFormat -f $_.id
81+
$lastSignInDate = if ($_.lastSuccessfulSignInDateTime) { (Get-Date $_.lastSuccessfulSignInDateTime -Format 'yyyy-MM-dd') } else { 'Never' }
82+
"|[$($_.displayName)]($userLink)| $lastSignInDate | ✅ |`n"
83+
})
84+
$mdInfo = $mdInfo + ($mdLines -join '')
85+
86+
$testResultMarkdown = $testResultMarkdown -replace '%TestResult%', $mdInfo
87+
88+
Add-CippTestResult -TenantFilter $Tenant -TestId 'ZTNA21801' -TestType 'Identity' -Status $(if ($passed) { 'Passed' } else { 'Failed' }) -ResultMarkdown $testResultMarkdown -Risk 'Medium' -Name 'Users have strong authentication methods configured' -UserImpact 'Medium' -ImplementationEffort 'Medium' -Category 'Credential Management'
89+
90+
} catch {
91+
$ErrorMessage = Get-CippException -Exception $_
92+
Write-LogMessage -API 'Tests' -tenant $Tenant -message "Failed to run test: $($ErrorMessage.NormalizedError)" -sev Error -LogData $ErrorMessage
93+
Add-CippTestResult -TenantFilter $Tenant -TestId 'ZTNA21801' -TestType 'Identity' -Status 'Failed' -ResultMarkdown "Test failed: $($ErrorMessage.NormalizedError)" -Risk 'Medium' -Name 'Users have strong authentication methods configured' -UserImpact 'Medium' -ImplementationEffort 'Medium' -Category 'Credential Management'
94+
}
95+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
function Invoke-CippTestZTNA21817 {
2+
<#
3+
.SYNOPSIS
4+
Global Administrator role activation triggers an approval workflow
5+
#>
6+
param($Tenant)
7+
8+
try {
9+
$RoleManagementPolicies = New-CIPPDbRequest -TenantFilter $Tenant -Type 'RoleManagementPolicies'
10+
11+
if (-not $RoleManagementPolicies) {
12+
Add-CippTestResult -TenantFilter $Tenant -TestId 'ZTNA21817' -TestType 'Identity' -Status 'Skipped' -ResultMarkdown 'No data found in database. This may be due to missing required licenses or data collection not yet completed.' -Risk 'High' -Name 'Global Administrator role activation triggers an approval workflow' -UserImpact 'Low' -ImplementationEffort 'Medium' -Category 'Application Management'
13+
return
14+
}
15+
16+
$globalAdminRoleId = '62e90394-69f5-4237-9190-012177145e10'
17+
18+
$globalAdminPolicy = $RoleManagementPolicies | Where-Object {
19+
$_.scopeId -eq '/' -and
20+
$_.scopeType -eq 'DirectoryRole' -and
21+
$_.roleDefinitionId -eq $globalAdminRoleId
22+
}
23+
24+
$tableRows = ''
25+
$result = $false
26+
27+
if ($globalAdminPolicy) {
28+
$approvalRule = $globalAdminPolicy.rules | Where-Object { $_.id -like '*Approval_EndUser_Assignment*' }
29+
30+
if ($approvalRule -and $approvalRule.setting.isApprovalRequired -eq $true) {
31+
$approverCount = 0
32+
foreach ($stage in $approvalRule.setting.approvalStages) {
33+
$approverCount = $approverCount + ($stage.primaryApprovers | Measure-Object).Count
34+
}
35+
36+
if ($approverCount -gt 0) {
37+
$result = $true
38+
$testResultMarkdown = "✅ **Pass**: Approval required with $approverCount primary approver(s) configured.`n`n%TestResult%"
39+
$primaryApprovers = ($approvalRule.setting.approvalStages[0].primaryApprovers.description -join ', ')
40+
$escalationApprovers = ($approvalRule.setting.approvalStages[0].escalationApprovers.description -join ', ')
41+
$tableRows = "| Yes | $primaryApprovers | $escalationApprovers |`n"
42+
} else {
43+
$testResultMarkdown = "❌ **Fail**: Approval required but no approvers configured.`n`n%TestResult%"
44+
$tableRows = "| Yes | None | None |`n"
45+
}
46+
} else {
47+
$testResultMarkdown = "❌ **Fail**: Approval not required for Global Administrator role activation.`n`n%TestResult%"
48+
$tableRows = "| No | N/A | N/A |`n"
49+
}
50+
} else {
51+
$testResultMarkdown = "❌ **Fail**: No PIM policy found for Global Administrator role.`n`n%TestResult%"
52+
$tableRows = "| N/A | N/A | N/A |`n"
53+
}
54+
55+
$passed = $result
56+
57+
$reportTitle = 'Global Administrator role activation and approval workflow'
58+
59+
$formatTemplate = @'
60+
61+
## {0}
62+
63+
64+
| Approval Required | Primary Approvers | Escalation Approvers |
65+
| :---------------- | :---------------- | :------------------- |
66+
{1}
67+
68+
'@
69+
70+
$mdInfo = $formatTemplate -f $reportTitle, $tableRows
71+
$testResultMarkdown = $testResultMarkdown -replace '%TestResult%', $mdInfo
72+
73+
Add-CippTestResult -TenantFilter $Tenant -TestId 'ZTNA21817' -TestType 'Identity' -Status $(if ($passed) { 'Passed' } else { 'Failed' }) -ResultMarkdown $testResultMarkdown -Risk 'High' -Name 'Global Administrator role activation triggers an approval workflow' -UserImpact 'Low' -ImplementationEffort 'Medium' -Category 'Application Management'
74+
75+
} catch {
76+
$ErrorMessage = Get-CippException -Exception $_
77+
Write-LogMessage -API 'Tests' -tenant $Tenant -message "Failed to run test: $($ErrorMessage.NormalizedError)" -sev Error -LogData $ErrorMessage
78+
Add-CippTestResult -TenantFilter $Tenant -TestId 'ZTNA21817' -TestType 'Identity' -Status 'Failed' -ResultMarkdown "Test failed: $($ErrorMessage.NormalizedError)" -Risk 'High' -Name 'Global Administrator role activation triggers an approval workflow' -UserImpact 'Low' -ImplementationEffort 'Medium' -Category 'Application Management'
79+
}
80+
}

0 commit comments

Comments
 (0)