Skip to content

Commit 020776a

Browse files
more tests
1 parent 489f507 commit 020776a

File tree

7 files changed

+366
-5
lines changed

7 files changed

+366
-5
lines changed

Modules/CIPPCore/Public/Tests/Invoke-CippTestZTNA21858.ps1

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ function Invoke-CippTestZTNA21858 {
2020
$InactiveGuests = @()
2121
foreach ($Guest in $EnabledGuests) {
2222
$DaysSinceLastActivity = $null
23-
23+
2424
if ($Guest.signInActivity.lastSuccessfulSignInDateTime) {
2525
$LastSignIn = [DateTime]$Guest.signInActivity.lastSuccessfulSignInDateTime
2626
$DaysSinceLastActivity = ($Today - $LastSignIn).Days
@@ -36,7 +36,45 @@ function Invoke-CippTestZTNA21858 {
3636

3737
if ($InactiveGuests.Count -gt 0) {
3838
$Status = 'Failed'
39-
$Result = "Found $($InactiveGuests.Count) inactive guest user(s) with no sign-in activity in the last $InactivityThresholdDays days"
39+
40+
$ResultLines = @(
41+
"Found $($InactiveGuests.Count) inactive guest user(s) with no sign-in activity in the last $InactivityThresholdDays days."
42+
''
43+
"**Total enabled guests:** $($EnabledGuests.Count)"
44+
"**Inactive guests:** $($InactiveGuests.Count)"
45+
"**Inactivity threshold:** $InactivityThresholdDays days"
46+
''
47+
'**Top 10 inactive guest users:**'
48+
)
49+
50+
$Top10Guests = $InactiveGuests | Sort-Object {
51+
if ($_.signInActivity.lastSuccessfulSignInDateTime) {
52+
[DateTime]$_.signInActivity.lastSuccessfulSignInDateTime
53+
} else {
54+
[DateTime]$_.createdDateTime
55+
}
56+
} | Select-Object -First 10
57+
58+
foreach ($Guest in $Top10Guests) {
59+
if ($Guest.signInActivity.lastSuccessfulSignInDateTime) {
60+
$LastActivity = [DateTime]$Guest.signInActivity.lastSuccessfulSignInDateTime
61+
$DaysInactive = [Math]::Round(($Today - $LastActivity).TotalDays, 0)
62+
$ResultLines += "- $($Guest.displayName) ($($Guest.userPrincipalName)) - Last sign-in: $DaysInactive days ago"
63+
} else {
64+
$Created = [DateTime]$Guest.createdDateTime
65+
$DaysSinceCreated = [Math]::Round(($Today - $Created).TotalDays, 0)
66+
$ResultLines += "- $($Guest.displayName) ($($Guest.userPrincipalName)) - Never signed in (Created $DaysSinceCreated days ago)"
67+
}
68+
}
69+
70+
if ($InactiveGuests.Count -gt 10) {
71+
$ResultLines += "- ... and $($InactiveGuests.Count - 10) more inactive guest(s)"
72+
}
73+
74+
$ResultLines += ''
75+
$ResultLines += '**Recommendation:** Review and remove or disable inactive guest accounts to reduce security risks.'
76+
77+
$Result = $ResultLines -join "`n"
4078
} else {
4179
$Status = 'Passed'
4280
$Result = "All enabled guest users have been active within the last $InactivityThresholdDays days"

Modules/CIPPCore/Public/Tests/Invoke-CippTestZTNA21869.ps1

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,28 @@ function Invoke-CippTestZTNA21869 {
2121
}
2222

2323
$Status = 'Investigate'
24-
$Result = "Found $($AppsWithoutAssignment.Count) enterprise application(s) without assignment requirements. Full provisioning scope validation requires Graph API calls not available in cache."
24+
25+
$ResultLines = @(
26+
"Found $($AppsWithoutAssignment.Count) enterprise application(s) without assignment requirements."
27+
''
28+
'**Applications without user assignment requirements:**'
29+
)
30+
31+
$Top10Apps = $AppsWithoutAssignment | Select-Object -First 10
32+
foreach ($App in $Top10Apps) {
33+
$ResultLines += "- $($App.displayName) (SSO: $($App.preferredSingleSignOnMode))"
34+
}
35+
36+
if ($AppsWithoutAssignment.Count -gt 10) {
37+
$ResultLines += "- ... and $($AppsWithoutAssignment.Count - 10) more application(s)"
38+
}
39+
40+
$ResultLines += ''
41+
$ResultLines += '**Note:** Full provisioning scope validation requires Graph API synchronization endpoint not available in cache.'
42+
$ResultLines += ''
43+
$ResultLines += '**Recommendation:** Enable user assignment requirements or configure scoped provisioning to limit application access.'
44+
45+
$Result = $ResultLines -join "`n"
2546

2647
Add-CippTestResult -TenantFilter $Tenant -TestId 'ZTNA21869' -TestType 'Identity' -Status $Status -ResultMarkdown $Result -Risk 'Medium' -Name 'Enterprise applications must require explicit assignment or scoped provisioning' -UserImpact 'Medium' -ImplementationEffort 'Medium' -Category 'Application management'
2748
}

Modules/CIPPCore/Public/Tests/Invoke-CippTestZTNA21877.ps1

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,30 @@ function Invoke-CippTestZTNA21877 {
2020
$Result = 'All guest accounts in the tenant have an assigned sponsor'
2121
} else {
2222
$Status = 'Failed'
23-
$Result = "Found $($GuestsWithoutSponsors.Count) guest user(s) without sponsors out of $($Guests.Count) total guests"
23+
24+
$ResultLines = @(
25+
"Found $($GuestsWithoutSponsors.Count) guest user(s) without sponsors out of $($Guests.Count) total guests."
26+
''
27+
"**Total guests:** $($Guests.Count)"
28+
"**Guests without sponsors:** $($GuestsWithoutSponsors.Count)"
29+
"**Guests with sponsors:** $($Guests.Count - $GuestsWithoutSponsors.Count)"
30+
''
31+
'**Top 10 guests without sponsors:**'
32+
)
33+
34+
$Top10Guests = $GuestsWithoutSponsors | Select-Object -First 10
35+
foreach ($Guest in $Top10Guests) {
36+
$ResultLines += "- $($Guest.displayName) ($($Guest.userPrincipalName))"
37+
}
38+
39+
if ($GuestsWithoutSponsors.Count -gt 10) {
40+
$ResultLines += "- ... and $($GuestsWithoutSponsors.Count - 10) more guest(s)"
41+
}
42+
43+
$ResultLines += ''
44+
$ResultLines += '**Recommendation:** Assign sponsors to all guest accounts for better accountability and lifecycle management.'
45+
46+
$Result = $ResultLines -join "`n"
2447
}
2548

2649
Add-CippTestResult -TenantFilter $Tenant -TestId 'ZTNA21877' -TestType 'Identity' -Status $Status -ResultMarkdown $Result -Risk 'Medium' -Name 'All guests have a sponsor' -UserImpact 'Medium' -ImplementationEffort 'Medium' -Category 'Application management'

Modules/CIPPCore/Public/Tests/Invoke-CippTestZTNA21886.ps1

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,32 @@ function Invoke-CippTestZTNA21886 {
2020
}
2121

2222
$Status = 'Investigate'
23-
$Result = "Found $($AppsWithSSO.Count) application(s) configured for SSO. Provisioning template and job validation requires Graph API synchronization endpoint not available in cache."
23+
24+
$ResultLines = @(
25+
"Found $($AppsWithSSO.Count) application(s) configured for SSO."
26+
''
27+
'**Applications with SSO enabled:**'
28+
)
29+
30+
$SSOByType = $AppsWithSSO | Group-Object -Property preferredSingleSignOnMode
31+
foreach ($Group in $SSOByType) {
32+
$ResultLines += ""
33+
$ResultLines += "**$($Group.Name.ToUpper()) SSO** ($($Group.Count) app(s)):"
34+
$Top5 = $Group.Group | Select-Object -First 5
35+
foreach ($App in $Top5) {
36+
$ResultLines += "- $($App.displayName)"
37+
}
38+
if ($Group.Count -gt 5) {
39+
$ResultLines += "- ... and $($Group.Count - 5) more"
40+
}
41+
}
42+
43+
$ResultLines += ''
44+
$ResultLines += '**Note:** Provisioning template and job validation requires Graph API synchronization endpoint not available in cache.'
45+
$ResultLines += ''
46+
$ResultLines += '**Recommendation:** Configure automatic user provisioning for applications that support it to ensure consistent access management.'
47+
48+
$Result = $ResultLines -join "`n"
2449

2550
Add-CippTestResult -TenantFilter $Tenant -TestId 'ZTNA21886' -TestType 'Identity' -Status $Status -ResultMarkdown $Result -Risk 'Medium' -Name 'Applications are configured for automatic user provisioning' -UserImpact 'Low' -ImplementationEffort 'Medium' -Category 'Applications management'
2651
} catch {
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
function Invoke-CippTestZTNA21896 {
2+
param($Tenant)
3+
4+
try {
5+
$ServicePrincipals = New-CIPPDbRequest -TenantFilter $Tenant -Type 'ServicePrincipals'
6+
if (-not $ServicePrincipals) {
7+
Add-CippTestResult -TenantFilter $Tenant -TestId 'ZTNA21896' -TestType 'Identity' -Status 'Investigate' -ResultMarkdown 'Service principal data not found in database' -Risk 'Medium' -Name 'Service principals do not have certificates or credentials associated with them' -UserImpact 'Low' -ImplementationEffort 'Medium' -Category 'Application management'
8+
return
9+
}
10+
11+
$MicrosoftOwnerId = 'f8cdef31-a31e-4b4a-93e4-5f571e91255a'
12+
$SPsWithPassCreds = $ServicePrincipals | Where-Object {
13+
$_.passwordCredentials -and $_.passwordCredentials.Count -gt 0 -and $_.appOwnerOrganizationId -ne $MicrosoftOwnerId
14+
}
15+
$SPsWithKeyCreds = $ServicePrincipals | Where-Object {
16+
$_.keyCredentials -and $_.keyCredentials.Count -gt 0 -and $_.appOwnerOrganizationId -ne $MicrosoftOwnerId
17+
}
18+
19+
if (-not $SPsWithPassCreds -and -not $SPsWithKeyCreds) {
20+
Add-CippTestResult -TenantFilter $Tenant -TestId 'ZTNA21896' -TestType 'Identity' -Status 'Passed' -ResultMarkdown 'Service principals do not have credentials associated with them' -Risk 'Medium' -Name 'Service principals do not have certificates or credentials associated with them' -UserImpact 'Low' -ImplementationEffort 'Medium' -Category 'Application management'
21+
return
22+
}
23+
24+
$TotalWithCreds = $SPsWithPassCreds.Count + $SPsWithKeyCreds.Count
25+
$Status = 'Investigate'
26+
27+
$ResultLines = @(
28+
"Found $TotalWithCreds service principal(s) with credentials configured in the tenant, which represents a security risk."
29+
''
30+
)
31+
32+
if ($SPsWithPassCreds.Count -gt 0) {
33+
$ResultLines += "**Service principals with password credentials:** $($SPsWithPassCreds.Count)"
34+
$ResultLines += ''
35+
}
36+
37+
if ($SPsWithKeyCreds.Count -gt 0) {
38+
$ResultLines += "**Service principals with key credentials (certificates):** $($SPsWithKeyCreds.Count)"
39+
$ResultLines += ''
40+
}
41+
42+
$ResultLines += '**Security implications:**'
43+
$ResultLines += '- Service principals with credentials can be compromised if not properly secured'
44+
$ResultLines += '- Password credentials are less secure than managed identities or certificate-based authentication'
45+
$ResultLines += '- Consider using managed identities where possible to eliminate credential management'
46+
47+
$Result = $ResultLines -join "`n"
48+
49+
Add-CippTestResult -TenantFilter $Tenant -TestId 'ZTNA21896' -TestType 'Identity' -Status $Status -ResultMarkdown $Result -Risk 'Medium' -Name 'Service principals do not have certificates or credentials associated with them' -UserImpact 'Low' -ImplementationEffort 'Medium' -Category 'Application management'
50+
}
51+
catch {
52+
$ErrorMessage = Get-CippException -Exception $_
53+
Write-LogMessage -API 'Tests' -tenant $Tenant -message "Failed to run test: $($ErrorMessage.NormalizedError)" -sev Error -LogData $ErrorMessage
54+
Add-CippTestResult -TenantFilter $Tenant -TestId 'ZTNA21896' -TestType 'Identity' -Status 'Failed' -ResultMarkdown "Test failed: $($ErrorMessage.NormalizedError)" -Risk 'Medium' -Name 'Service principals do not have certificates or credentials associated with them' -UserImpact 'Low' -ImplementationEffort 'Medium' -Category 'Application management'
55+
}
56+
}
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
function Invoke-CippTestZTNA21992 {
2+
param($Tenant)
3+
4+
try {
5+
$Apps = New-CIPPDbRequest -TenantFilter $Tenant -Type 'Apps'
6+
$ServicePrincipals = New-CIPPDbRequest -TenantFilter $Tenant -Type 'ServicePrincipals'
7+
8+
if (-not $Apps -and -not $ServicePrincipals) {
9+
Add-CippTestResult -TenantFilter $Tenant -TestId 'ZTNA21992' -TestType 'Identity' -Status 'Investigate' -ResultMarkdown 'Application and service principal data not found in database' -Risk 'High' -Name 'Application certificates must be rotated on a regular basis' -UserImpact 'Low' -ImplementationEffort 'High' -Category 'Application management'
10+
return
11+
}
12+
13+
$RotationThresholdDays = 180
14+
$ThresholdDate = (Get-Date).AddDays(-$RotationThresholdDays)
15+
16+
$OldAppCerts = @()
17+
if ($Apps) {
18+
$OldAppCerts = $Apps | Where-Object {
19+
$_.keyCredentials -and $_.keyCredentials.Count -gt 0
20+
} | ForEach-Object {
21+
$App = $_
22+
$OldestCert = $App.keyCredentials | Where-Object { $_.startDateTime } | ForEach-Object {
23+
[DateTime]$_.startDateTime
24+
} | Sort-Object | Select-Object -First 1
25+
26+
if ($OldestCert -and $OldestCert -lt $ThresholdDate) {
27+
[PSCustomObject]@{
28+
Type = 'Application'
29+
DisplayName = $App.displayName
30+
AppId = $App.appId
31+
Id = $App.id
32+
OldestCertDate = $OldestCert
33+
}
34+
}
35+
}
36+
}
37+
38+
$OldSPCerts = @()
39+
if ($ServicePrincipals) {
40+
$OldSPCerts = $ServicePrincipals | Where-Object {
41+
$_.keyCredentials -and $_.keyCredentials.Count -gt 0
42+
} | ForEach-Object {
43+
$SP = $_
44+
$OldestCert = $SP.keyCredentials | Where-Object { $_.startDateTime } | ForEach-Object {
45+
[DateTime]$_.startDateTime
46+
} | Sort-Object | Select-Object -First 1
47+
48+
if ($OldestCert -and $OldestCert -lt $ThresholdDate) {
49+
[PSCustomObject]@{
50+
Type = 'ServicePrincipal'
51+
DisplayName = $SP.displayName
52+
AppId = $SP.appId
53+
Id = $SP.id
54+
OldestCertDate = $OldestCert
55+
}
56+
}
57+
}
58+
}
59+
60+
if ($OldAppCerts.Count -eq 0 -and $OldSPCerts.Count -eq 0) {
61+
Add-CippTestResult -TenantFilter $Tenant -TestId 'ZTNA21992' -TestType 'Identity' -Status 'Passed' -ResultMarkdown "Certificates for applications in your tenant have been issued within $RotationThresholdDays days" -Risk 'High' -Name 'Application certificates must be rotated on a regular basis' -UserImpact 'Low' -ImplementationEffort 'High' -Category 'Application management'
62+
return
63+
}
64+
65+
$Status = 'Failed'
66+
67+
$ResultLines = @(
68+
"Found $($OldAppCerts.Count) application(s) and $($OldSPCerts.Count) service principal(s) with certificates not rotated within $RotationThresholdDays days."
69+
''
70+
"**Certificate rotation threshold:** $RotationThresholdDays days"
71+
''
72+
)
73+
74+
if ($OldAppCerts.Count -gt 0) {
75+
$ResultLines += '**Applications with old certificates:**'
76+
$Top10Apps = $OldAppCerts | Select-Object -First 10
77+
foreach ($App in $Top10Apps) {
78+
$DaysOld = [Math]::Round(((Get-Date) - $App.OldestCertDate).TotalDays, 0)
79+
$ResultLines += "- $($App.DisplayName) (Certificate age: $DaysOld days)"
80+
}
81+
if ($OldAppCerts.Count -gt 10) {
82+
$ResultLines += "- ... and $($OldAppCerts.Count - 10) more application(s)"
83+
}
84+
$ResultLines += ''
85+
}
86+
87+
if ($OldSPCerts.Count -gt 0) {
88+
$ResultLines += '**Service principals with old certificates:**'
89+
$Top10SPs = $OldSPCerts | Select-Object -First 10
90+
foreach ($SP in $Top10SPs) {
91+
$DaysOld = [Math]::Round(((Get-Date) - $SP.OldestCertDate).TotalDays, 0)
92+
$ResultLines += "- $($SP.DisplayName) (Certificate age: $DaysOld days)"
93+
}
94+
if ($OldSPCerts.Count -gt 10) {
95+
$ResultLines += "- ... and $($OldSPCerts.Count - 10) more service principal(s)"
96+
}
97+
$ResultLines += ''
98+
}
99+
100+
$ResultLines += '**Recommendation:** Rotate certificates regularly to reduce the risk of credential compromise.'
101+
102+
$Result = $ResultLines -join "`n"
103+
104+
Add-CippTestResult -TenantFilter $Tenant -TestId 'ZTNA21992' -TestType 'Identity' -Status $Status -ResultMarkdown $Result -Risk 'High' -Name 'Application certificates must be rotated on a regular basis' -UserImpact 'Low' -ImplementationEffort 'High' -Category 'Application management'
105+
} catch {
106+
$ErrorMessage = Get-CippException -Exception $_
107+
Write-LogMessage -API 'Tests' -tenant $Tenant -message "Failed to run test: $($ErrorMessage.NormalizedError)" -sev Error -LogData $ErrorMessage
108+
Add-CippTestResult -TenantFilter $Tenant -TestId 'ZTNA21992' -TestType 'Identity' -Status 'Failed' -ResultMarkdown "Test failed: $($ErrorMessage.NormalizedError)" -Risk 'High' -Name 'Application certificates must be rotated on a regular basis' -UserImpact 'Low' -ImplementationEffort 'High' -Category 'Application management'
109+
}
110+
}

0 commit comments

Comments
 (0)