Compare commits
7 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
1240f74450 | ||
|
063124eef3 | ||
|
14f3889378 | ||
|
3790ec00de | ||
|
c1171ddca5 | ||
|
fc7c8ec88f | ||
|
2fc814205d |
14
CHANGELOG.md
14
CHANGELOG.md
@@ -4,9 +4,21 @@ The format is based on and uses the types of changes according to [Keep a Change
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Added hash and compress steps to `Export-M365SecurityAuditTable` function.
|
||||||
|
|
||||||
|
## [0.1.21] - 2024-07-01
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- Fixed parameter validation for new parameters in `Invoke-M365SecurityAudit` function.
|
- Formatting for MgGraph tests.
|
||||||
|
|
||||||
|
## [0.1.20] - 2024-06-30
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Fixed parameter validation for new parameters in `Invoke-M365SecurityAudit` function
|
||||||
|
|
||||||
## [0.1.19] - 2024-06-30
|
## [0.1.19] - 2024-06-30
|
||||||
|
|
||||||
|
BIN
docs/index.html
BIN
docs/index.html
Binary file not shown.
@@ -190,10 +190,11 @@ This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable
|
|||||||
|
|
||||||
## INPUTS
|
## INPUTS
|
||||||
|
|
||||||
### [CISAuditResult[]], [string]
|
### [CISAuditResult[]] - An array of CISAuditResult objects.
|
||||||
|
### [string] - A path to a CSV file.
|
||||||
## OUTPUTS
|
## OUTPUTS
|
||||||
|
|
||||||
### [PSCustomObject]
|
### [PSCustomObject] - A custom object containing the path to the zip file and its hash.
|
||||||
## NOTES
|
## NOTES
|
||||||
|
|
||||||
## RELATED LINKS
|
## RELATED LINKS
|
||||||
|
@@ -4,7 +4,7 @@ Import-Module .\output\module\M365FoundationsCISReport\*\*.psd1
|
|||||||
|
|
||||||
|
|
||||||
<#
|
<#
|
||||||
$ver = "v0.1.18"
|
$ver = "v0.1.22"
|
||||||
git checkout main
|
git checkout main
|
||||||
git pull origin main
|
git pull origin main
|
||||||
git tag -a $ver -m "Release version $ver refactor Update"
|
git tag -a $ver -m "Release version $ver refactor Update"
|
||||||
@@ -59,6 +59,5 @@ Set-Secret -Name "GitHubToken" -Vault ModuleBuildCreds
|
|||||||
$GalleryApiToken = Get-Secret -Name "GalleryApiToken" -Vault ModuleBuildCreds -AsPlainText
|
$GalleryApiToken = Get-Secret -Name "GalleryApiToken" -Vault ModuleBuildCreds -AsPlainText
|
||||||
$GitHubToken = Get-Secret -Name "GitHubToken" -Vault ModuleBuildCreds -AsPlainText
|
$GitHubToken = Get-Secret -Name "GitHubToken" -Vault ModuleBuildCreds -AsPlainText
|
||||||
|
|
||||||
|
|
||||||
$GalleryApiToken
|
$GalleryApiToken
|
||||||
$GitHubToken
|
$GitHubToken
|
@@ -42,10 +42,12 @@ function Get-CISMgOutput {
|
|||||||
switch ($rec) {
|
switch ($rec) {
|
||||||
'1.1.1' {
|
'1.1.1' {
|
||||||
# 1.1.1
|
# 1.1.1
|
||||||
|
# Test-AdministrativeAccountCompliance
|
||||||
$AdminRoleAssignmentsAndUsers = Get-AdminRoleUserAndAssignment
|
$AdminRoleAssignmentsAndUsers = Get-AdminRoleUserAndAssignment
|
||||||
return $AdminRoleAssignmentsAndUsers
|
return $AdminRoleAssignmentsAndUsers
|
||||||
}
|
}
|
||||||
'1.1.3' {
|
'1.1.3' {
|
||||||
|
# Test-GlobalAdminsCount
|
||||||
# Step: Retrieve global admin role
|
# Step: Retrieve global admin role
|
||||||
$globalAdminRole = Get-MgDirectoryRole -Filter "RoleTemplateId eq '62e90394-69f5-4237-9190-012177145e10'"
|
$globalAdminRole = Get-MgDirectoryRole -Filter "RoleTemplateId eq '62e90394-69f5-4237-9190-012177145e10'"
|
||||||
# Step: Retrieve global admin members
|
# Step: Retrieve global admin members
|
||||||
@@ -53,6 +55,7 @@ function Get-CISMgOutput {
|
|||||||
return $globalAdmins
|
return $globalAdmins
|
||||||
}
|
}
|
||||||
'1.2.1' {
|
'1.2.1' {
|
||||||
|
# Test-ManagedApprovedPublicGroups
|
||||||
$allGroups = Get-MgGroup -All | Where-Object { $_.Visibility -eq "Public" } | Select-Object DisplayName, Visibility
|
$allGroups = Get-MgGroup -All | Where-Object { $_.Visibility -eq "Public" } | Select-Object DisplayName, Visibility
|
||||||
return $allGroups
|
return $allGroups
|
||||||
}
|
}
|
||||||
@@ -67,16 +70,19 @@ function Get-CISMgOutput {
|
|||||||
return $domains
|
return $domains
|
||||||
}
|
}
|
||||||
'5.1.2.3' {
|
'5.1.2.3' {
|
||||||
|
# Test-RestrictTenantCreation
|
||||||
# Retrieve the tenant creation policy
|
# Retrieve the tenant creation policy
|
||||||
$tenantCreationPolicy = (Get-MgPolicyAuthorizationPolicy).DefaultUserRolePermissions | Select-Object AllowedToCreateTenants
|
$tenantCreationPolicy = (Get-MgPolicyAuthorizationPolicy).DefaultUserRolePermissions | Select-Object AllowedToCreateTenants
|
||||||
return $tenantCreationPolicy
|
return $tenantCreationPolicy
|
||||||
}
|
}
|
||||||
'5.1.8.1' {
|
'5.1.8.1' {
|
||||||
|
# Test-PasswordHashSync
|
||||||
# Retrieve password hash sync status (Condition A and C)
|
# Retrieve password hash sync status (Condition A and C)
|
||||||
$passwordHashSync = Get-MgOrganization | Select-Object -ExpandProperty OnPremisesSyncEnabled
|
$passwordHashSync = Get-MgOrganization | Select-Object -ExpandProperty OnPremisesSyncEnabled
|
||||||
return $passwordHashSync
|
return $passwordHashSync
|
||||||
}
|
}
|
||||||
'6.1.2' {
|
'6.1.2' {
|
||||||
|
# Test-MailboxAuditingE3
|
||||||
$tenantSkus = Get-MgSubscribedSku -All
|
$tenantSkus = Get-MgSubscribedSku -All
|
||||||
$e3SkuPartNumber = "SPE_E3"
|
$e3SkuPartNumber = "SPE_E3"
|
||||||
$founde3Sku = $tenantSkus | Where-Object { $_.SkuPartNumber -eq $e3SkuPartNumber }
|
$founde3Sku = $tenantSkus | Where-Object { $_.SkuPartNumber -eq $e3SkuPartNumber }
|
||||||
@@ -89,6 +95,7 @@ function Get-CISMgOutput {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
'6.1.3' {
|
'6.1.3' {
|
||||||
|
# Test-MailboxAuditingE5
|
||||||
$tenantSkus = Get-MgSubscribedSku -All
|
$tenantSkus = Get-MgSubscribedSku -All
|
||||||
$e5SkuPartNumber = "SPE_E5"
|
$e5SkuPartNumber = "SPE_E5"
|
||||||
$founde5Sku = $tenantSkus | Where-Object { $_.SkuPartNumber -eq $e5SkuPartNumber }
|
$founde5Sku = $tenantSkus | Where-Object { $_.SkuPartNumber -eq $e5SkuPartNumber }
|
||||||
|
@@ -1,47 +1,52 @@
|
|||||||
<#
|
<#
|
||||||
.SYNOPSIS
|
.SYNOPSIS
|
||||||
Exports M365 security audit results to a CSV file or outputs a specific test result as an object.
|
Exports Microsoft 365 security audit results to CSV or Excel files and supports outputting specific test results as objects.
|
||||||
.DESCRIPTION
|
.DESCRIPTION
|
||||||
This function exports M365 security audit results from either an array of CISAuditResult objects or a CSV file.
|
The Export-M365SecurityAuditTable function exports Microsoft 365 security audit results from an array of CISAuditResult objects or a CSV file.
|
||||||
It can export all results to a specified path or output a specific test result as an object.
|
It can export all results to a specified path, output a specific test result as an object, and includes options for exporting results to Excel.
|
||||||
|
Additionally, it computes hashes for the exported files and includes them in the zip archive for verification purposes.
|
||||||
.PARAMETER AuditResults
|
.PARAMETER AuditResults
|
||||||
An array of CISAuditResult objects containing the audit results.
|
An array of CISAuditResult objects containing the audit results. This parameter is mandatory when exporting from audit results.
|
||||||
.PARAMETER CsvPath
|
.PARAMETER CsvPath
|
||||||
The path to a CSV file containing the audit results.
|
The path to a CSV file containing the audit results. This parameter is mandatory when exporting from a CSV file.
|
||||||
.PARAMETER OutputTestNumber
|
.PARAMETER OutputTestNumber
|
||||||
The test number to output as an object. Valid values are "1.1.1", "1.3.1", "6.1.2", "6.1.3", "7.3.4".
|
The test number to output as an object. Valid values are "1.1.1", "1.3.1", "6.1.2", "6.1.3", "7.3.4". This parameter is used to output a specific test result.
|
||||||
.PARAMETER ExportAllTests
|
.PARAMETER ExportAllTests
|
||||||
Switch to export all test results.
|
Switch to export all test results. When specified, all test results are exported to the specified path.
|
||||||
.PARAMETER ExportPath
|
.PARAMETER ExportPath
|
||||||
The path where the CSV files will be exported.
|
The path where the CSV or Excel files will be exported. This parameter is mandatory when exporting all tests.
|
||||||
.PARAMETER ExportOriginalTests
|
.PARAMETER ExportOriginalTests
|
||||||
Switch to export the original audit results to a CSV file.
|
Switch to export the original audit results to a CSV file. When specified, the original test results are exported along with the processed results.
|
||||||
.PARAMETER ExportToExcel
|
.PARAMETER ExportToExcel
|
||||||
Switch to export the results to an Excel file.
|
Switch to export the results to an Excel file. When specified, results are exported in Excel format.
|
||||||
.INPUTS
|
.INPUTS
|
||||||
[CISAuditResult[]], [string]
|
[CISAuditResult[]] - An array of CISAuditResult objects.
|
||||||
|
[string] - A path to a CSV file.
|
||||||
.OUTPUTS
|
.OUTPUTS
|
||||||
[PSCustomObject]
|
[PSCustomObject] - A custom object containing the path to the zip file and its hash.
|
||||||
.EXAMPLE
|
.EXAMPLE
|
||||||
Export-M365SecurityAuditTable -AuditResults $object -OutputTestNumber 6.1.2
|
Export-M365SecurityAuditTable -AuditResults $object -OutputTestNumber 6.1.2
|
||||||
# Output object for a single test number from audit results
|
# Outputs the result of test number 6.1.2 from the provided audit results as an object.
|
||||||
.EXAMPLE
|
.EXAMPLE
|
||||||
Export-M365SecurityAuditTable -ExportAllTests -AuditResults $object -ExportPath "C:\temp"
|
Export-M365SecurityAuditTable -ExportAllTests -AuditResults $object -ExportPath "C:\temp"
|
||||||
# Export all results from audit results to the specified path
|
# Exports all audit results to the specified path in CSV format.
|
||||||
.EXAMPLE
|
.EXAMPLE
|
||||||
Export-M365SecurityAuditTable -CsvPath "C:\temp\auditresultstoday1.csv" -OutputTestNumber 6.1.2
|
Export-M365SecurityAuditTable -CsvPath "C:\temp\auditresultstoday1.csv" -OutputTestNumber 6.1.2
|
||||||
# Output object for a single test number from CSV
|
# Outputs the result of test number 6.1.2 from the CSV file as an object.
|
||||||
.EXAMPLE
|
.EXAMPLE
|
||||||
Export-M365SecurityAuditTable -ExportAllTests -CsvPath "C:\temp\auditresultstoday1.csv" -ExportPath "C:\temp"
|
Export-M365SecurityAuditTable -ExportAllTests -CsvPath "C:\temp\auditresultstoday1.csv" -ExportPath "C:\temp"
|
||||||
# Export all results from CSV to the specified path
|
# Exports all audit results from the CSV file to the specified path in CSV format.
|
||||||
.EXAMPLE
|
.EXAMPLE
|
||||||
Export-M365SecurityAuditTable -ExportAllTests -AuditResults $object -ExportPath "C:\temp" -ExportOriginalTests
|
Export-M365SecurityAuditTable -ExportAllTests -AuditResults $object -ExportPath "C:\temp" -ExportOriginalTests
|
||||||
# Export all results from audit results to the specified path along with the original tests
|
# Exports all audit results along with the original test results to the specified path in CSV format.
|
||||||
.EXAMPLE
|
.EXAMPLE
|
||||||
Export-M365SecurityAuditTable -ExportAllTests -CsvPath "C:\temp\auditresultstoday1.csv" -ExportPath "C:\temp" -ExportOriginalTests
|
Export-M365SecurityAuditTable -ExportAllTests -CsvPath "C:\temp\auditresultstoday1.csv" -ExportPath "C:\temp" -ExportOriginalTests
|
||||||
# Export all results from CSV to the specified path along with the original tests
|
# Exports all audit results from the CSV file along with the original test results to the specified path in CSV format.
|
||||||
|
.EXAMPLE
|
||||||
|
Export-M365SecurityAuditTable -ExportAllTests -AuditResults $object -ExportPath "C:\temp" -ExportToExcel
|
||||||
|
# Exports all audit results to the specified path in Excel format.
|
||||||
.LINK
|
.LINK
|
||||||
https://criticalsolutionsnetwork.github.io/M365FoundationsCISReport/#Export-M365SecurityAuditTable
|
https://criticalsolutionsnetwork.github.io/M365FoundationsCISReport/#Export-M365SecurityAuditTable
|
||||||
#>
|
#>
|
||||||
function Export-M365SecurityAuditTable {
|
function Export-M365SecurityAuditTable {
|
||||||
[CmdletBinding()]
|
[CmdletBinding()]
|
||||||
@@ -50,179 +55,206 @@ function Export-M365SecurityAuditTable {
|
|||||||
[Parameter(Mandatory = $true, Position = 1, ParameterSetName = "ExportAllResultsFromAuditResults")]
|
[Parameter(Mandatory = $true, Position = 1, ParameterSetName = "ExportAllResultsFromAuditResults")]
|
||||||
[Parameter(Mandatory = $true, Position = 2, ParameterSetName = "OutputObjectFromAuditResultsSingle")]
|
[Parameter(Mandatory = $true, Position = 2, ParameterSetName = "OutputObjectFromAuditResultsSingle")]
|
||||||
[CISAuditResult[]]$AuditResults,
|
[CISAuditResult[]]$AuditResults,
|
||||||
|
|
||||||
[Parameter(Mandatory = $true, Position = 1, ParameterSetName = "ExportAllResultsFromCsv")]
|
[Parameter(Mandatory = $true, Position = 1, ParameterSetName = "ExportAllResultsFromCsv")]
|
||||||
[Parameter(Mandatory = $true, Position = 2, ParameterSetName = "OutputObjectFromCsvSingle")]
|
[Parameter(Mandatory = $true, Position = 2, ParameterSetName = "OutputObjectFromCsvSingle")]
|
||||||
[ValidateScript({ (Test-Path $_) -and ((Get-Item $_).PSIsContainer -eq $false) })]
|
[ValidateScript({ (Test-Path $_) -and ((Get-Item $_).PSIsContainer -eq $false) })]
|
||||||
[string]$CsvPath,
|
[string]$CsvPath,
|
||||||
|
|
||||||
[Parameter(Mandatory = $true, Position = 1, ParameterSetName = "OutputObjectFromAuditResultsSingle")]
|
[Parameter(Mandatory = $true, Position = 1, ParameterSetName = "OutputObjectFromAuditResultsSingle")]
|
||||||
[Parameter(Mandatory = $true, Position = 1, ParameterSetName = "OutputObjectFromCsvSingle")]
|
[Parameter(Mandatory = $true, Position = 1, ParameterSetName = "OutputObjectFromCsvSingle")]
|
||||||
[ValidateSet("1.1.1", "1.3.1", "6.1.2", "6.1.3", "7.3.4")]
|
[ValidateSet("1.1.1", "1.3.1", "6.1.2", "6.1.3", "7.3.4")]
|
||||||
[string]$OutputTestNumber,
|
[string]$OutputTestNumber,
|
||||||
|
|
||||||
[Parameter(Mandatory = $false, Position = 0, ParameterSetName = "ExportAllResultsFromAuditResults")]
|
[Parameter(Mandatory = $false, Position = 0, ParameterSetName = "ExportAllResultsFromAuditResults")]
|
||||||
[Parameter(Mandatory = $false, Position = 0, ParameterSetName = "ExportAllResultsFromCsv")]
|
[Parameter(Mandatory = $false, Position = 0, ParameterSetName = "ExportAllResultsFromCsv")]
|
||||||
[switch]$ExportAllTests,
|
[switch]$ExportAllTests,
|
||||||
|
|
||||||
[Parameter(Mandatory = $true, ParameterSetName = "ExportAllResultsFromAuditResults")]
|
[Parameter(Mandatory = $true, ParameterSetName = "ExportAllResultsFromAuditResults")]
|
||||||
[Parameter(Mandatory = $true, ParameterSetName = "ExportAllResultsFromCsv")]
|
[Parameter(Mandatory = $true, ParameterSetName = "ExportAllResultsFromCsv")]
|
||||||
[string]$ExportPath,
|
[string]$ExportPath,
|
||||||
|
|
||||||
[Parameter(Mandatory = $true, ParameterSetName = "ExportAllResultsFromAuditResults")]
|
[Parameter(Mandatory = $true, ParameterSetName = "ExportAllResultsFromAuditResults")]
|
||||||
[Parameter(Mandatory = $true, ParameterSetName = "ExportAllResultsFromCsv")]
|
[Parameter(Mandatory = $true, ParameterSetName = "ExportAllResultsFromCsv")]
|
||||||
[switch]$ExportOriginalTests,
|
[switch]$ExportOriginalTests,
|
||||||
|
|
||||||
[Parameter(Mandatory = $false, ParameterSetName = "ExportAllResultsFromAuditResults")]
|
[Parameter(Mandatory = $false, ParameterSetName = "ExportAllResultsFromAuditResults")]
|
||||||
[Parameter(Mandatory = $false, ParameterSetName = "ExportAllResultsFromCsv")]
|
[Parameter(Mandatory = $false, ParameterSetName = "ExportAllResultsFromCsv")]
|
||||||
[switch]$ExportToExcel
|
[switch]$ExportToExcel
|
||||||
)
|
)
|
||||||
if ($ExportToExcel) {
|
Begin {
|
||||||
Assert-ModuleAvailability -ModuleName ImportExcel -RequiredVersion "7.8.9"
|
$createdFiles = @() # Initialize an array to keep track of created files
|
||||||
}
|
if ($ExportToExcel) {
|
||||||
if ($PSCmdlet.ParameterSetName -like "ExportAllResultsFromCsv" -or $PSCmdlet.ParameterSetName -eq "OutputObjectFromCsvSingle") {
|
Assert-ModuleAvailability -ModuleName ImportExcel -RequiredVersion "7.8.9"
|
||||||
$AuditResults = Import-Csv -Path $CsvPath | ForEach-Object {
|
}
|
||||||
$params = @{
|
if ($PSCmdlet.ParameterSetName -like "ExportAllResultsFromCsv" -or $PSCmdlet.ParameterSetName -eq "OutputObjectFromCsvSingle") {
|
||||||
Rec = $_.Rec
|
$AuditResults = Import-Csv -Path $CsvPath | ForEach-Object {
|
||||||
Result = [bool]$_.Result
|
$params = @{
|
||||||
Status = $_.Status
|
Rec = $_.Rec
|
||||||
Details = $_.Details
|
Result = [bool]$_.Result
|
||||||
FailureReason = $_.FailureReason
|
Status = $_.Status
|
||||||
|
Details = $_.Details
|
||||||
|
FailureReason = $_.FailureReason
|
||||||
|
}
|
||||||
|
Initialize-CISAuditResult @params
|
||||||
}
|
}
|
||||||
Initialize-CISAuditResult @params
|
|
||||||
}
|
}
|
||||||
}
|
if ($ExportAllTests) {
|
||||||
|
$TestNumbers = "1.1.1", "1.3.1", "6.1.2", "6.1.3", "7.3.4"
|
||||||
if ($ExportAllTests) {
|
|
||||||
$TestNumbers = "1.1.1", "1.3.1", "6.1.2", "6.1.3", "7.3.4"
|
|
||||||
}
|
|
||||||
|
|
||||||
$results = @()
|
|
||||||
|
|
||||||
$testsToProcess = if ($OutputTestNumber) { @($OutputTestNumber) } else { $TestNumbers }
|
|
||||||
|
|
||||||
foreach ($test in $testsToProcess) {
|
|
||||||
$auditResult = $AuditResults | Where-Object { $_.Rec -eq $test }
|
|
||||||
if (-not $auditResult) {
|
|
||||||
Write-Information "No audit results found for the test number $test."
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
|
$results = @()
|
||||||
switch ($test) {
|
$testsToProcess = if ($OutputTestNumber) { @($OutputTestNumber) } else { $TestNumbers }
|
||||||
"6.1.2" {
|
}
|
||||||
$details = $auditResult.Details
|
Process {
|
||||||
if ($details -ne "No M365 E3 licenses found.") {
|
foreach ($test in $testsToProcess) {
|
||||||
$csv = $details | ConvertFrom-Csv -Delimiter '|'
|
$auditResult = $AuditResults | Where-Object { $_.Rec -eq $test }
|
||||||
}
|
if (-not $auditResult) {
|
||||||
else {
|
Write-Information "No audit results found for the test number $test."
|
||||||
$csv = $null
|
continue
|
||||||
}
|
}
|
||||||
|
switch ($test) {
|
||||||
if ($null -ne $csv) {
|
"6.1.2" {
|
||||||
foreach ($row in $csv) {
|
$details = $auditResult.Details
|
||||||
$row.AdminActionsMissing = (Get-Action -AbbreviatedActions $row.AdminActionsMissing.Split(',') -ReverseActionType Admin | Where-Object { $_ -notin @("MailItemsAccessed", "Send") }) -join ','
|
if ($details -ne "No M365 E3 licenses found.") {
|
||||||
$row.DelegateActionsMissing = (Get-Action -AbbreviatedActions $row.DelegateActionsMissing.Split(',') -ReverseActionType Delegate | Where-Object { $_ -notin @("MailItemsAccessed") }) -join ','
|
$csv = $details | ConvertFrom-Csv -Delimiter '|'
|
||||||
$row.OwnerActionsMissing = (Get-Action -AbbreviatedActions $row.OwnerActionsMissing.Split(',') -ReverseActionType Owner | Where-Object { $_ -notin @("MailItemsAccessed", "Send") }) -join ','
|
|
||||||
}
|
}
|
||||||
$newObjectDetails = $csv
|
else {
|
||||||
}
|
$csv = $null
|
||||||
else {
|
|
||||||
$newObjectDetails = $details
|
|
||||||
}
|
|
||||||
$results += [PSCustomObject]@{ TestNumber = $test; Details = $newObjectDetails }
|
|
||||||
}
|
|
||||||
"6.1.3" {
|
|
||||||
$details = $auditResult.Details
|
|
||||||
if ($details -ne "No M365 E5 licenses found.") {
|
|
||||||
$csv = $details | ConvertFrom-Csv -Delimiter '|'
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$csv = $null
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($null -ne $csv) {
|
|
||||||
foreach ($row in $csv) {
|
|
||||||
$row.AdminActionsMissing = (Get-Action -AbbreviatedActions $row.AdminActionsMissing.Split(',') -ReverseActionType Admin) -join ','
|
|
||||||
$row.DelegateActionsMissing = (Get-Action -AbbreviatedActions $row.DelegateActionsMissing.Split(',') -ReverseActionType Delegate) -join ','
|
|
||||||
$row.OwnerActionsMissing = (Get-Action -AbbreviatedActions $row.OwnerActionsMissing.Split(',') -ReverseActionType Owner) -join ','
|
|
||||||
}
|
}
|
||||||
$newObjectDetails = $csv
|
if ($null -ne $csv) {
|
||||||
}
|
foreach ($row in $csv) {
|
||||||
else {
|
$row.AdminActionsMissing = (Get-Action -AbbreviatedActions $row.AdminActionsMissing.Split(',') -ReverseActionType Admin | Where-Object { $_ -notin @("MailItemsAccessed", "Send") }) -join ','
|
||||||
$newObjectDetails = $details
|
$row.DelegateActionsMissing = (Get-Action -AbbreviatedActions $row.DelegateActionsMissing.Split(',') -ReverseActionType Delegate | Where-Object { $_ -notin @("MailItemsAccessed") }) -join ','
|
||||||
}
|
$row.OwnerActionsMissing = (Get-Action -AbbreviatedActions $row.OwnerActionsMissing.Split(',') -ReverseActionType Owner | Where-Object { $_ -notin @("MailItemsAccessed", "Send") }) -join ','
|
||||||
$results += [PSCustomObject]@{ TestNumber = $test; Details = $newObjectDetails }
|
|
||||||
}
|
|
||||||
Default {
|
|
||||||
$details = $auditResult.Details
|
|
||||||
$csv = $details | ConvertFrom-Csv -Delimiter '|'
|
|
||||||
$results += [PSCustomObject]@{ TestNumber = $test; Details = $csv }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($ExportPath) {
|
|
||||||
$timestamp = (Get-Date).ToString("yyyy.MM.dd_HH.mm.ss")
|
|
||||||
$exportedTests = @()
|
|
||||||
|
|
||||||
foreach ($result in $results) {
|
|
||||||
$testDef = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $result.TestNumber }
|
|
||||||
if ($testDef) {
|
|
||||||
$fileName = "$ExportPath\$($timestamp)_$($result.TestNumber).$($testDef.TestFileName -replace '\.ps1$').csv"
|
|
||||||
if ($result.Details.Count -eq 0) {
|
|
||||||
Write-Information "No results found for test number $($result.TestNumber)." -InformationAction Continue
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (($result.Details -ne "No M365 E3 licenses found.") -and ($result.Details -ne "No M365 E5 licenses found.")) {
|
|
||||||
if ($ExportToExcel) {
|
|
||||||
$xlsxPath = [System.IO.Path]::ChangeExtension($fileName, '.xlsx')
|
|
||||||
$result.Details | Export-Excel -Path $xlsxPath -WorksheetName Table -TableName Table -AutoSize -TableStyle Medium2
|
|
||||||
}
|
}
|
||||||
else {
|
$newObjectDetails = $csv
|
||||||
$result.Details | Export-Csv -Path $fileName -NoTypeInformation
|
|
||||||
}
|
|
||||||
$exportedTests += $result.TestNumber
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
$newObjectDetails = $details
|
||||||
|
}
|
||||||
|
$results += [PSCustomObject]@{ TestNumber = $test; Details = $newObjectDetails }
|
||||||
|
}
|
||||||
|
"6.1.3" {
|
||||||
|
$details = $auditResult.Details
|
||||||
|
if ($details -ne "No M365 E5 licenses found.") {
|
||||||
|
$csv = $details | ConvertFrom-Csv -Delimiter '|'
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$csv = $null
|
||||||
|
}
|
||||||
|
if ($null -ne $csv) {
|
||||||
|
foreach ($row in $csv) {
|
||||||
|
$row.AdminActionsMissing = (Get-Action -AbbreviatedActions $row.AdminActionsMissing.Split(',') -ReverseActionType Admin) -join ','
|
||||||
|
$row.DelegateActionsMissing = (Get-Action -AbbreviatedActions $row.DelegateActionsMissing.Split(',') -ReverseActionType Delegate) -join ','
|
||||||
|
$row.OwnerActionsMissing = (Get-Action -AbbreviatedActions $row.OwnerActionsMissing.Split(',') -ReverseActionType Owner) -join ','
|
||||||
|
}
|
||||||
|
$newObjectDetails = $csv
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$newObjectDetails = $details
|
||||||
|
}
|
||||||
|
$results += [PSCustomObject]@{ TestNumber = $test; Details = $newObjectDetails }
|
||||||
|
}
|
||||||
|
Default {
|
||||||
|
$details = $auditResult.Details
|
||||||
|
$csv = $details | ConvertFrom-Csv -Delimiter '|'
|
||||||
|
$results += [PSCustomObject]@{ TestNumber = $test; Details = $csv }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($exportedTests.Count -gt 0) {
|
}
|
||||||
Write-Information "The following tests were exported: $($exportedTests -join ', ')" -InformationAction Continue
|
End {
|
||||||
}
|
if ($ExportPath) {
|
||||||
else {
|
$timestamp = (Get-Date).ToString("yyyy.MM.dd_HH.mm.ss")
|
||||||
|
$exportedTests = @()
|
||||||
|
foreach ($result in $results) {
|
||||||
|
$testDef = $script:TestDefinitionsObject | Where-Object { $_.Rec -eq $result.TestNumber }
|
||||||
|
if ($testDef) {
|
||||||
|
$fileName = "$ExportPath\$($timestamp)_$($result.TestNumber).$($testDef.TestFileName -replace '\.ps1$').csv"
|
||||||
|
if ($result.Details.Count -eq 0) {
|
||||||
|
Write-Information "No results found for test number $($result.TestNumber)." -InformationAction Continue
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (($result.Details -ne "No M365 E3 licenses found.") -and ($result.Details -ne "No M365 E5 licenses found.")) {
|
||||||
|
if ($ExportToExcel) {
|
||||||
|
$xlsxPath = [System.IO.Path]::ChangeExtension($fileName, '.xlsx')
|
||||||
|
$result.Details | Export-Excel -Path $xlsxPath -WorksheetName Table -TableName Table -AutoSize -TableStyle Medium2
|
||||||
|
$createdFiles += $xlsxPath # Add the created file to the array
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$result.Details | Export-Csv -Path $fileName -NoTypeInformation
|
||||||
|
$createdFiles += $fileName # Add the created file to the array
|
||||||
|
}
|
||||||
|
$exportedTests += $result.TestNumber
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($exportedTests.Count -gt 0) {
|
||||||
|
Write-Information "The following tests were exported: $($exportedTests -join ', ')" -InformationAction Continue
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if ($ExportOriginalTests) {
|
||||||
|
Write-Information "Full audit results exported however, none of the following tests had exports: `n1.1.1, 1.3.1, 6.1.2, 6.1.3, 7.3.4" -InformationAction Continue
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Write-Information "No specified tests were included in the export." -InformationAction Continue
|
||||||
|
}
|
||||||
|
}
|
||||||
if ($ExportOriginalTests) {
|
if ($ExportOriginalTests) {
|
||||||
Write-Information "Full audit results exported however, none of the following tests had exports: `n1.1.1, 1.3.1, 6.1.2, 6.1.3, 7.3.4" -InformationAction Continue
|
# Define the test numbers to check
|
||||||
|
$TestNumbersToCheck = "1.1.1", "1.3.1", "6.1.2", "6.1.3", "7.3.4"
|
||||||
|
# Check for large details and update the AuditResults array
|
||||||
|
$updatedAuditResults = Get-ExceededLengthResultDetail -AuditResults $AuditResults -TestNumbersToCheck $TestNumbersToCheck -ExportedTests $exportedTests -DetailsLengthLimit 30000 -PreviewLineCount 25
|
||||||
|
$originalFileName = "$ExportPath\$timestamp`_M365FoundationsAudit.csv"
|
||||||
|
if ($ExportToExcel) {
|
||||||
|
$xlsxPath = [System.IO.Path]::ChangeExtension($originalFileName, '.xlsx')
|
||||||
|
$updatedAuditResults | Export-Excel -Path $xlsxPath -WorksheetName Table -TableName Table -AutoSize -TableStyle Medium2
|
||||||
|
$createdFiles += $xlsxPath # Add the created file to the array
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$updatedAuditResults | Export-Csv -Path $originalFileName -NoTypeInformation
|
||||||
|
$createdFiles += $originalFileName # Add the created file to the array
|
||||||
|
}
|
||||||
|
}
|
||||||
|
# Hash each file and add it to a dictionary
|
||||||
|
# Hash each file and save the hashes to a text file
|
||||||
|
$hashFilePath = "$ExportPath\$timestamp`_Hashes.txt"
|
||||||
|
$fileHashes = @()
|
||||||
|
foreach ($file in $createdFiles) {
|
||||||
|
$hash = Get-FileHash -Path $file -Algorithm SHA256
|
||||||
|
$fileHashes += "$($file): $($hash.Hash)"
|
||||||
|
}
|
||||||
|
$fileHashes | Set-Content -Path $hashFilePath
|
||||||
|
$createdFiles += $hashFilePath # Add the hash file to the array
|
||||||
|
|
||||||
|
# Create a zip file and add all the created files
|
||||||
|
$zipFilePath = "$ExportPath\$timestamp`_M365FoundationsAudit.zip"
|
||||||
|
Compress-Archive -Path $createdFiles -DestinationPath $zipFilePath
|
||||||
|
|
||||||
|
# Remove the original files after they have been added to the zip
|
||||||
|
foreach ($file in $createdFiles) {
|
||||||
|
Remove-Item -Path $file -Force
|
||||||
|
}
|
||||||
|
|
||||||
|
# Compute the hash for the zip file and rename it
|
||||||
|
$zipHash = Get-FileHash -Path $zipFilePath -Algorithm SHA256
|
||||||
|
$newZipFilePath = "$ExportPath\$timestamp`_M365FoundationsAudit_$($zipHash.Hash.Substring(0, 8)).zip"
|
||||||
|
Rename-Item -Path $zipFilePath -NewName $newZipFilePath
|
||||||
|
|
||||||
|
# Output the zip file path with hash
|
||||||
|
[PSCustomObject]@{
|
||||||
|
ZipFilePath = $newZipFilePath
|
||||||
|
}
|
||||||
|
} # End of ExportPath
|
||||||
|
elseif ($OutputTestNumber) {
|
||||||
|
if ($results[0].Details) {
|
||||||
|
return $results[0].Details
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Write-Information "No specified tests were included in the export." -InformationAction Continue
|
Write-Information "No results found for test number $($OutputTestNumber)." -InformationAction Continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($ExportOriginalTests) {
|
|
||||||
# Define the test numbers to check
|
|
||||||
$TestNumbersToCheck = "1.1.1", "1.3.1", "6.1.2", "6.1.3", "7.3.4"
|
|
||||||
|
|
||||||
# Check for large details and update the AuditResults array
|
|
||||||
$updatedAuditResults = Get-ExceededLengthResultDetail -AuditResults $AuditResults -TestNumbersToCheck $TestNumbersToCheck -ExportedTests $exportedTests -DetailsLengthLimit 30000 -PreviewLineCount 25
|
|
||||||
$originalFileName = "$ExportPath\$timestamp`_M365FoundationsAudit.csv"
|
|
||||||
if ($ExportToExcel) {
|
|
||||||
$xlsxPath = [System.IO.Path]::ChangeExtension($originalFileName, '.xlsx')
|
|
||||||
$updatedAuditResults | Export-Excel -Path $xlsxPath -WorksheetName Table -TableName Table -AutoSize -TableStyle Medium2
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$updatedAuditResults | Export-Csv -Path $originalFileName -NoTypeInformation
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
elseif ($OutputTestNumber) {
|
|
||||||
if ($results[0].Details) {
|
|
||||||
return $results[0].Details
|
|
||||||
}
|
|
||||||
else {
|
else {
|
||||||
Write-Information "No results found for test number $($OutputTestNumber)." -InformationAction Continue
|
Write-Error "No valid operation specified. Please provide valid parameters."
|
||||||
}
|
}
|
||||||
}
|
# Output the created files at the end
|
||||||
else {
|
#if ($createdFiles.Count -gt 0) {
|
||||||
Write-Error "No valid operation specified. Please provide valid parameters."
|
########### $createdFiles
|
||||||
|
#}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -277,7 +277,15 @@
|
|||||||
<command:inputTypes>
|
<command:inputTypes>
|
||||||
<command:inputType>
|
<command:inputType>
|
||||||
<dev:type>
|
<dev:type>
|
||||||
<maml:name>[CISAuditResult[]], [string]</maml:name>
|
<maml:name>[CISAuditResult[]] - An array of CISAuditResult objects.</maml:name>
|
||||||
|
</dev:type>
|
||||||
|
<maml:description>
|
||||||
|
<maml:para></maml:para>
|
||||||
|
</maml:description>
|
||||||
|
</command:inputType>
|
||||||
|
<command:inputType>
|
||||||
|
<dev:type>
|
||||||
|
<maml:name>[string] - A path to a CSV file.</maml:name>
|
||||||
</dev:type>
|
</dev:type>
|
||||||
<maml:description>
|
<maml:description>
|
||||||
<maml:para></maml:para>
|
<maml:para></maml:para>
|
||||||
@@ -287,7 +295,7 @@
|
|||||||
<command:returnValues>
|
<command:returnValues>
|
||||||
<command:returnValue>
|
<command:returnValue>
|
||||||
<dev:type>
|
<dev:type>
|
||||||
<maml:name>[PSCustomObject]</maml:name>
|
<maml:name>[PSCustomObject] - A custom object containing the path to the zip file and its hash.</maml:name>
|
||||||
</dev:type>
|
</dev:type>
|
||||||
<maml:description>
|
<maml:description>
|
||||||
<maml:para></maml:para>
|
<maml:para></maml:para>
|
||||||
|
@@ -1,7 +1,6 @@
|
|||||||
function Test-AdministrativeAccountCompliance {
|
function Test-AdministrativeAccountCompliance {
|
||||||
[CmdletBinding()]
|
[CmdletBinding()]
|
||||||
param ()
|
param ()
|
||||||
|
|
||||||
begin {
|
begin {
|
||||||
# The following conditions are checked:
|
# The following conditions are checked:
|
||||||
# Condition A: The administrative account is cloud-only (not synced).
|
# Condition A: The administrative account is cloud-only (not synced).
|
||||||
@@ -11,16 +10,12 @@ function Test-AdministrativeAccountCompliance {
|
|||||||
$recnum = "1.1.1"
|
$recnum = "1.1.1"
|
||||||
Write-Verbose "Starting Test-AdministrativeAccountCompliance with Rec: $recnum"
|
Write-Verbose "Starting Test-AdministrativeAccountCompliance with Rec: $recnum"
|
||||||
}
|
}
|
||||||
|
|
||||||
process {
|
process {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
# Retrieve admin roles, assignments, and user details including licenses
|
# Retrieve admin roles, assignments, and user details including licenses
|
||||||
Write-Verbose "Retrieving admin roles, assignments, and user details including licenses"
|
Write-Verbose "Retrieving admin roles, assignments, and user details including licenses"
|
||||||
$adminRoleAssignments = Get-CISMgOutput -Rec $recnum
|
$adminRoleAssignments = Get-CISMgOutput -Rec $recnum
|
||||||
|
|
||||||
$adminRoleUsers = @()
|
$adminRoleUsers = @()
|
||||||
|
|
||||||
foreach ($roleName in $adminRoleAssignments.Keys) {
|
foreach ($roleName in $adminRoleAssignments.Keys) {
|
||||||
$assignments = $adminRoleAssignments[$roleName]
|
$assignments = $adminRoleAssignments[$roleName]
|
||||||
foreach ($assignment in $assignments) {
|
foreach ($assignment in $assignments) {
|
||||||
@@ -29,21 +24,16 @@ function Test-AdministrativeAccountCompliance {
|
|||||||
$userPrincipalName = $userDetails.UserPrincipalName
|
$userPrincipalName = $userDetails.UserPrincipalName
|
||||||
$licenses = $assignment.Licenses
|
$licenses = $assignment.Licenses
|
||||||
$licenseString = if ($licenses) { ($licenses.SkuPartNumber -join '|') } else { "No Licenses Found" }
|
$licenseString = if ($licenses) { ($licenses.SkuPartNumber -join '|') } else { "No Licenses Found" }
|
||||||
|
|
||||||
# Condition A: Check if the account is cloud-only
|
# Condition A: Check if the account is cloud-only
|
||||||
$cloudOnlyStatus = if ($userDetails.OnPremisesSyncEnabled) { "Fail" } else { "Pass" }
|
$cloudOnlyStatus = if ($userDetails.OnPremisesSyncEnabled) { "Fail" } else { "Pass" }
|
||||||
|
|
||||||
# Condition B: Check if the account has valid licenses
|
# Condition B: Check if the account has valid licenses
|
||||||
$hasValidLicense = $licenses.SkuPartNumber | ForEach-Object { $validLicenses -contains $_ }
|
$hasValidLicense = $licenses.SkuPartNumber | ForEach-Object { $validLicenses -contains $_ }
|
||||||
$validLicensesStatus = if ($hasValidLicense) { "Pass" } else { "Fail" }
|
$validLicensesStatus = if ($hasValidLicense) { "Pass" } else { "Fail" }
|
||||||
|
|
||||||
# Condition C: Check if the account has no other licenses
|
# Condition C: Check if the account has no other licenses
|
||||||
$hasInvalidLicense = $licenses.SkuPartNumber | ForEach-Object { $validLicenses -notcontains $_ }
|
$hasInvalidLicense = $licenses.SkuPartNumber | ForEach-Object { $validLicenses -notcontains $_ }
|
||||||
$invalidLicenses = $licenses.SkuPartNumber | Where-Object { $validLicenses -notcontains $_ }
|
$invalidLicenses = $licenses.SkuPartNumber | Where-Object { $validLicenses -notcontains $_ }
|
||||||
$applicationAssignmentStatus = if ($hasInvalidLicense) { "Fail" } else { "Pass" }
|
$applicationAssignmentStatus = if ($hasInvalidLicense) { "Fail" } else { "Pass" }
|
||||||
|
|
||||||
Write-Verbose "User: $userPrincipalName, Cloud-Only: $cloudOnlyStatus, Valid Licenses: $validLicensesStatus, Invalid Licenses: $($invalidLicenses -join ', ')"
|
Write-Verbose "User: $userPrincipalName, Cloud-Only: $cloudOnlyStatus, Valid Licenses: $validLicensesStatus, Invalid Licenses: $($invalidLicenses -join ', ')"
|
||||||
|
|
||||||
# Collect user information
|
# Collect user information
|
||||||
$adminRoleUsers += [PSCustomObject]@{
|
$adminRoleUsers += [PSCustomObject]@{
|
||||||
UserName = $userPrincipalName
|
UserName = $userPrincipalName
|
||||||
@@ -57,17 +47,14 @@ function Test-AdministrativeAccountCompliance {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# Group admin role users by UserName and collect unique roles and licenses
|
# Group admin role users by UserName and collect unique roles and licenses
|
||||||
Write-Verbose "Grouping admin role users by UserName"
|
Write-Verbose "Grouping admin role users by UserName"
|
||||||
$uniqueAdminRoleUsers = $adminRoleUsers | Group-Object -Property UserName | ForEach-Object {
|
$uniqueAdminRoleUsers = $adminRoleUsers | Group-Object -Property UserName | ForEach-Object {
|
||||||
$first = $_.Group | Select-Object -First 1
|
$first = $_.Group | Select-Object -First 1
|
||||||
$roles = ($_.Group.RoleName -join ', ')
|
$roles = ($_.Group.RoleName -join ', ')
|
||||||
$licenses = (($_.Group | Select-Object -ExpandProperty Licenses) -join ',').Split(',') | Select-Object -Unique
|
$licenses = (($_.Group | Select-Object -ExpandProperty Licenses) -join ',').Split(',') | Select-Object -Unique
|
||||||
|
|
||||||
$first | Select-Object UserName, UserId, HybridUser, @{Name = 'Roles'; Expression = { $roles } }, @{Name = 'Licenses'; Expression = { $licenses -join '|' } }, CloudOnlyStatus, ValidLicensesStatus, ApplicationAssignmentStatus
|
$first | Select-Object UserName, UserId, HybridUser, @{Name = 'Roles'; Expression = { $roles } }, @{Name = 'Licenses'; Expression = { $licenses -join '|' } }, CloudOnlyStatus, ValidLicensesStatus, ApplicationAssignmentStatus
|
||||||
}
|
}
|
||||||
|
|
||||||
# Identify non-compliant users based on conditions A, B, and C
|
# Identify non-compliant users based on conditions A, B, and C
|
||||||
Write-Verbose "Identifying non-compliant users based on conditions"
|
Write-Verbose "Identifying non-compliant users based on conditions"
|
||||||
$nonCompliantUsers = $uniqueAdminRoleUsers | Where-Object {
|
$nonCompliantUsers = $uniqueAdminRoleUsers | Where-Object {
|
||||||
@@ -75,7 +62,6 @@ function Test-AdministrativeAccountCompliance {
|
|||||||
$_.ValidLicensesStatus -eq "Fail" -or # Fails Condition B
|
$_.ValidLicensesStatus -eq "Fail" -or # Fails Condition B
|
||||||
$_.ApplicationAssignmentStatus -eq "Fail" # Fails Condition C
|
$_.ApplicationAssignmentStatus -eq "Fail" # Fails Condition C
|
||||||
}
|
}
|
||||||
|
|
||||||
# Generate failure reasons
|
# Generate failure reasons
|
||||||
Write-Verbose "Generating failure reasons for non-compliant users"
|
Write-Verbose "Generating failure reasons for non-compliant users"
|
||||||
$failureReasons = $nonCompliantUsers | ForEach-Object {
|
$failureReasons = $nonCompliantUsers | ForEach-Object {
|
||||||
@@ -88,13 +74,10 @@ function Test-AdministrativeAccountCompliance {
|
|||||||
else {
|
else {
|
||||||
"Compliant Accounts: $($uniqueAdminRoleUsers.Count)"
|
"Compliant Accounts: $($uniqueAdminRoleUsers.Count)"
|
||||||
}
|
}
|
||||||
|
|
||||||
$result = $nonCompliantUsers.Count -eq 0
|
$result = $nonCompliantUsers.Count -eq 0
|
||||||
$status = if ($result) { 'Pass' } else { 'Fail' }
|
$status = if ($result) { 'Pass' } else { 'Fail' }
|
||||||
$details = if ($nonCompliantUsers) { "Username | Roles | Cloud-Only Status | EntraID P1/P2 License Status | Other Applications Assigned Status`n$failureReasons" } else { "N/A" }
|
$details = if ($nonCompliantUsers) { "Username | Roles | Cloud-Only Status | EntraID P1/P2 License Status | Other Applications Assigned Status`n$failureReasons" } else { "N/A" }
|
||||||
|
|
||||||
Write-Verbose "Assessment completed. Result: $status"
|
Write-Verbose "Assessment completed. Result: $status"
|
||||||
|
|
||||||
# Create the parameter splat
|
# Create the parameter splat
|
||||||
$params = @{
|
$params = @{
|
||||||
Rec = $recnum
|
Rec = $recnum
|
||||||
@@ -103,7 +86,6 @@ function Test-AdministrativeAccountCompliance {
|
|||||||
Details = $details
|
Details = $details
|
||||||
FailureReason = $failureReason
|
FailureReason = $failureReason
|
||||||
}
|
}
|
||||||
|
|
||||||
$auditResult = Initialize-CISAuditResult @params
|
$auditResult = Initialize-CISAuditResult @params
|
||||||
}
|
}
|
||||||
catch {
|
catch {
|
||||||
@@ -111,7 +93,6 @@ function Test-AdministrativeAccountCompliance {
|
|||||||
$auditResult = Get-TestError -LastError $LastError -recnum $recnum
|
$auditResult = Get-TestError -LastError $LastError -recnum $recnum
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
end {
|
end {
|
||||||
# Output the result
|
# Output the result
|
||||||
return $auditResult
|
return $auditResult
|
||||||
|
@@ -4,7 +4,6 @@ function Test-GlobalAdminsCount {
|
|||||||
param (
|
param (
|
||||||
# Define your parameters here if needed
|
# Define your parameters here if needed
|
||||||
)
|
)
|
||||||
|
|
||||||
begin {
|
begin {
|
||||||
# Dot source the class script if necessary
|
# Dot source the class script if necessary
|
||||||
#. .\source\Classes\CISAuditResult.ps1
|
#. .\source\Classes\CISAuditResult.ps1
|
||||||
@@ -23,23 +22,19 @@ function Test-GlobalAdminsCount {
|
|||||||
# - Condition A: The number of global admins is less than 2.
|
# - Condition A: The number of global admins is less than 2.
|
||||||
# - Condition B: The number of global admins is more than 4.
|
# - Condition B: The number of global admins is more than 4.
|
||||||
# - Condition C: Any discrepancies or errors in retrieving the list of global admin usernames.
|
# - Condition C: Any discrepancies or errors in retrieving the list of global admin usernames.
|
||||||
|
|
||||||
# Initialization code, if needed
|
# Initialization code, if needed
|
||||||
$recnum = "1.1.3"
|
$recnum = "1.1.3"
|
||||||
|
Write-Verbose "Starting Test-GlobalAdminsCount with Rec: $recnum"
|
||||||
}
|
}
|
||||||
|
|
||||||
process {
|
process {
|
||||||
try {
|
try {
|
||||||
$globalAdmins = Get-CISMgOutput -Rec $recnum
|
$globalAdmins = Get-CISMgOutput -Rec $recnum
|
||||||
|
|
||||||
# Step: Count the number of global admins
|
# Step: Count the number of global admins
|
||||||
$globalAdminCount = $globalAdmins.Count
|
$globalAdminCount = $globalAdmins.Count
|
||||||
|
|
||||||
# Step: Retrieve and format the usernames of global admins
|
# Step: Retrieve and format the usernames of global admins
|
||||||
$globalAdminUsernames = ($globalAdmins | ForEach-Object {
|
$globalAdminUsernames = ($globalAdmins | ForEach-Object {
|
||||||
"$($_.AdditionalProperties["displayName"]) ($($_.AdditionalProperties["userPrincipalName"]))"
|
"$($_.AdditionalProperties["displayName"]) ($($_.AdditionalProperties["userPrincipalName"]))"
|
||||||
}) -join ', '
|
}) -join ', '
|
||||||
|
|
||||||
# Step: Determine failure reasons based on global admin count
|
# Step: Determine failure reasons based on global admin count
|
||||||
$failureReasons = if ($globalAdminCount -lt 2) {
|
$failureReasons = if ($globalAdminCount -lt 2) {
|
||||||
"Less than 2 global admins: $globalAdminUsernames"
|
"Less than 2 global admins: $globalAdminUsernames"
|
||||||
@@ -50,10 +45,8 @@ function Test-GlobalAdminsCount {
|
|||||||
else {
|
else {
|
||||||
"N/A"
|
"N/A"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Step: Prepare details for the audit result
|
# Step: Prepare details for the audit result
|
||||||
$details = "Count: $globalAdminCount; Users: $globalAdminUsernames"
|
$details = "Count: $globalAdminCount; Users: $globalAdminUsernames"
|
||||||
|
|
||||||
# Step: Create and populate the CISAuditResult object
|
# Step: Create and populate the CISAuditResult object
|
||||||
$params = @{
|
$params = @{
|
||||||
Rec = $recnum
|
Rec = $recnum
|
||||||
@@ -69,7 +62,6 @@ function Test-GlobalAdminsCount {
|
|||||||
$auditResult = Get-TestError -LastError $LastError -recnum $recnum
|
$auditResult = Get-TestError -LastError $LastError -recnum $recnum
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
end {
|
end {
|
||||||
# Return the audit result
|
# Return the audit result
|
||||||
return $auditResult
|
return $auditResult
|
||||||
|
@@ -4,14 +4,12 @@ function Test-ManagedApprovedPublicGroups {
|
|||||||
param (
|
param (
|
||||||
# Parameters can be added if needed
|
# Parameters can be added if needed
|
||||||
)
|
)
|
||||||
|
|
||||||
begin {
|
begin {
|
||||||
# Dot source the class script if necessary
|
# Dot source the class script if necessary
|
||||||
#. .\source\Classes\CISAuditResult.ps1
|
#. .\source\Classes\CISAuditResult.ps1
|
||||||
|
|
||||||
# Initialization code, if needed
|
# Initialization code, if needed
|
||||||
$recnum = "1.2.1"
|
$recnum = "1.2.1"
|
||||||
|
Write-Verbose "Starting Test-ManagedApprovedPublicGroups with Rec: $recnum"
|
||||||
# Conditions for 1.2.1 (L2) Ensure that only organizationally managed/approved public groups exist (Automated)
|
# Conditions for 1.2.1 (L2) Ensure that only organizationally managed/approved public groups exist (Automated)
|
||||||
#
|
#
|
||||||
# Validate test for a pass:
|
# Validate test for a pass:
|
||||||
@@ -26,12 +24,10 @@ function Test-ManagedApprovedPublicGroups {
|
|||||||
# - Condition A: One or more groups have the status 'Public' in the privacy column on the Active teams and groups page.
|
# - Condition A: One or more groups have the status 'Public' in the privacy column on the Active teams and groups page.
|
||||||
# - Condition B: Using Microsoft Graph PowerShell, one or more groups return a status of 'Public' when checked.
|
# - Condition B: Using Microsoft Graph PowerShell, one or more groups return a status of 'Public' when checked.
|
||||||
}
|
}
|
||||||
|
|
||||||
process {
|
process {
|
||||||
try {
|
try {
|
||||||
# Step: Retrieve all groups with visibility set to 'Public'
|
# Step: Retrieve all groups with visibility set to 'Public'
|
||||||
$allGroups = Get-CISMgOutput -Rec $recnum
|
$allGroups = Get-CISMgOutput -Rec $recnum
|
||||||
|
|
||||||
# Step: Determine failure reasons based on the presence of public groups
|
# Step: Determine failure reasons based on the presence of public groups
|
||||||
$failureReasons = if ($null -ne $allGroups -and $allGroups.Count -gt 0) {
|
$failureReasons = if ($null -ne $allGroups -and $allGroups.Count -gt 0) {
|
||||||
"There are public groups present that are not organizationally managed/approved."
|
"There are public groups present that are not organizationally managed/approved."
|
||||||
@@ -39,7 +35,6 @@ function Test-ManagedApprovedPublicGroups {
|
|||||||
else {
|
else {
|
||||||
"N/A"
|
"N/A"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Step: Prepare details for the audit result
|
# Step: Prepare details for the audit result
|
||||||
$details = if ($null -eq $allGroups -or $allGroups.Count -eq 0) {
|
$details = if ($null -eq $allGroups -or $allGroups.Count -eq 0) {
|
||||||
"No public groups found."
|
"No public groups found."
|
||||||
@@ -48,7 +43,6 @@ function Test-ManagedApprovedPublicGroups {
|
|||||||
$groupDetails = $allGroups | ForEach-Object { $_.DisplayName + " (" + $_.Visibility + ")" }
|
$groupDetails = $allGroups | ForEach-Object { $_.DisplayName + " (" + $_.Visibility + ")" }
|
||||||
"Public groups found: $($groupDetails -join ', ')"
|
"Public groups found: $($groupDetails -join ', ')"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Step: Create and populate the CISAuditResult object
|
# Step: Create and populate the CISAuditResult object
|
||||||
$params = @{
|
$params = @{
|
||||||
Rec = $recnum
|
Rec = $recnum
|
||||||
@@ -64,7 +58,6 @@ function Test-ManagedApprovedPublicGroups {
|
|||||||
$auditResult = Get-TestError -LastError $LastError -recnum $recnum
|
$auditResult = Get-TestError -LastError $LastError -recnum $recnum
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
end {
|
end {
|
||||||
# Return the audit result
|
# Return the audit result
|
||||||
return $auditResult
|
return $auditResult
|
||||||
|
@@ -5,7 +5,6 @@ function Test-PasswordHashSync {
|
|||||||
# Aligned
|
# Aligned
|
||||||
# Parameters can be added if needed
|
# Parameters can be added if needed
|
||||||
)
|
)
|
||||||
|
|
||||||
begin {
|
begin {
|
||||||
# Conditions for 5.1.8.1 (L1) Ensure password hash sync is enabled for hybrid deployments
|
# Conditions for 5.1.8.1 (L1) Ensure password hash sync is enabled for hybrid deployments
|
||||||
#
|
#
|
||||||
@@ -22,21 +21,18 @@ function Test-PasswordHashSync {
|
|||||||
# - Condition A: Password hash sync is not enabled in the Azure AD Connect tool on the on-premises server.
|
# - Condition A: Password hash sync is not enabled in the Azure AD Connect tool on the on-premises server.
|
||||||
# - Condition B: Password hash sync is not verified as enabled in the Azure AD Connect Sync section in the Microsoft Entra admin center.
|
# - Condition B: Password hash sync is not verified as enabled in the Azure AD Connect Sync section in the Microsoft Entra admin center.
|
||||||
# - Condition C: Using Microsoft Graph PowerShell, the verification command returns no result indicating that password sync is not enabled for the on-premises AD.
|
# - Condition C: Using Microsoft Graph PowerShell, the verification command returns no result indicating that password sync is not enabled for the on-premises AD.
|
||||||
|
|
||||||
# Dot source the class script if necessary
|
# Dot source the class script if necessary
|
||||||
#. .\source\Classes\CISAuditResult.ps1
|
#. .\source\Classes\CISAuditResult.ps1
|
||||||
# Initialization code, if needed
|
# Initialization code, if needed
|
||||||
$recnum = "5.1.8.1"
|
$recnum = "5.1.8.1"
|
||||||
|
Write-Verbose "Starting Test-PasswordHashSync with Rec: $recnum"
|
||||||
}
|
}
|
||||||
|
|
||||||
process {
|
process {
|
||||||
try {
|
try {
|
||||||
# 5.1.8.1 (L1) Ensure password hash sync is enabled for hybrid deployments
|
# 5.1.8.1 (L1) Ensure password hash sync is enabled for hybrid deployments
|
||||||
|
|
||||||
# Retrieve password hash sync status (Condition A and C)
|
# Retrieve password hash sync status (Condition A and C)
|
||||||
$passwordHashSync = Get-CISMgOutput -Rec $recnum
|
$passwordHashSync = Get-CISMgOutput -Rec $recnum
|
||||||
$hashSyncResult = $passwordHashSync
|
$hashSyncResult = $passwordHashSync
|
||||||
|
|
||||||
# Prepare failure reasons and details based on compliance
|
# Prepare failure reasons and details based on compliance
|
||||||
$failureReasons = if (-not $hashSyncResult) {
|
$failureReasons = if (-not $hashSyncResult) {
|
||||||
"Password hash sync for hybrid deployments is not enabled"
|
"Password hash sync for hybrid deployments is not enabled"
|
||||||
@@ -44,9 +40,7 @@ function Test-PasswordHashSync {
|
|||||||
else {
|
else {
|
||||||
"N/A"
|
"N/A"
|
||||||
}
|
}
|
||||||
|
|
||||||
$details = "OnPremisesSyncEnabled: $($passwordHashSync)"
|
$details = "OnPremisesSyncEnabled: $($passwordHashSync)"
|
||||||
|
|
||||||
# Create and populate the CISAuditResult object
|
# Create and populate the CISAuditResult object
|
||||||
$params = @{
|
$params = @{
|
||||||
Rec = $recnum
|
Rec = $recnum
|
||||||
@@ -62,9 +56,8 @@ function Test-PasswordHashSync {
|
|||||||
$auditResult = Get-TestError -LastError $LastError -recnum $recnum
|
$auditResult = Get-TestError -LastError $LastError -recnum $recnum
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
end {
|
end {
|
||||||
# Return the audit result
|
# Return the audit result
|
||||||
return $auditResult
|
return $auditResult
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -5,23 +5,19 @@ function Test-RestrictTenantCreation {
|
|||||||
# Aligned
|
# Aligned
|
||||||
# Parameters can be added if needed
|
# Parameters can be added if needed
|
||||||
)
|
)
|
||||||
|
|
||||||
begin {
|
begin {
|
||||||
# Dot source the class script if necessary
|
# Dot source the class script if necessary
|
||||||
#. .\source\Classes\CISAuditResult.ps1
|
#. .\source\Classes\CISAuditResult.ps1
|
||||||
|
|
||||||
# Initialization code, if needed
|
# Initialization code, if needed
|
||||||
$recnum = "5.1.2.3"
|
$recnum = "5.1.2.3"
|
||||||
|
Write-Verbose "Starting Test-RestrictTenantCreation with Rec: $recnum"
|
||||||
<#
|
<#
|
||||||
Conditions for 5.1.2.3 (L1) Ensure 'Restrict non-admin users from creating tenants' is set to 'Yes'
|
Conditions for 5.1.2.3 (L1) Ensure 'Restrict non-admin users from creating tenants' is set to 'Yes'
|
||||||
|
|
||||||
Validate test for a pass:
|
Validate test for a pass:
|
||||||
- Confirm that the automated test results align with the manual audit steps outlined in the CIS benchmark.
|
- Confirm that the automated test results align with the manual audit steps outlined in the CIS benchmark.
|
||||||
- Specific conditions to check:
|
- Specific conditions to check:
|
||||||
- Condition A: Restrict non-admin users from creating tenants is set to 'Yes' in the Azure AD and Entra administration portal.
|
- Condition A: Restrict non-admin users from creating tenants is set to 'Yes' in the Azure AD and Entra administration portal.
|
||||||
- Condition B: Using PowerShell, the setting for restricting non-admin users from creating tenants is set to 'Yes'.
|
- Condition B: Using PowerShell, the setting for restricting non-admin users from creating tenants is set to 'Yes'.
|
||||||
|
|
||||||
Validate test for a fail:
|
Validate test for a fail:
|
||||||
- Confirm that the failure conditions in the automated test are consistent with the manual audit results.
|
- Confirm that the failure conditions in the automated test are consistent with the manual audit results.
|
||||||
- Specific conditions to check:
|
- Specific conditions to check:
|
||||||
@@ -29,15 +25,12 @@ function Test-RestrictTenantCreation {
|
|||||||
- Condition B: Using PowerShell, the setting for restricting non-admin users from creating tenants is not set to 'Yes'.
|
- Condition B: Using PowerShell, the setting for restricting non-admin users from creating tenants is not set to 'Yes'.
|
||||||
#>
|
#>
|
||||||
}
|
}
|
||||||
|
|
||||||
process {
|
process {
|
||||||
try {
|
try {
|
||||||
# 5.1.2.3 (L1) Ensure 'Restrict non-admin users from creating tenants' is set to 'Yes'
|
# 5.1.2.3 (L1) Ensure 'Restrict non-admin users from creating tenants' is set to 'Yes'
|
||||||
|
|
||||||
# Retrieve the tenant creation policy
|
# Retrieve the tenant creation policy
|
||||||
$tenantCreationPolicy = Get-CISMgOutput -Rec $recnum
|
$tenantCreationPolicy = Get-CISMgOutput -Rec $recnum
|
||||||
$tenantCreationResult = -not $tenantCreationPolicy.AllowedToCreateTenants
|
$tenantCreationResult = -not $tenantCreationPolicy.AllowedToCreateTenants
|
||||||
|
|
||||||
# Prepare failure reasons and details based on compliance
|
# Prepare failure reasons and details based on compliance
|
||||||
$failureReasons = if ($tenantCreationResult) {
|
$failureReasons = if ($tenantCreationResult) {
|
||||||
"N/A"
|
"N/A"
|
||||||
@@ -45,9 +38,7 @@ function Test-RestrictTenantCreation {
|
|||||||
else {
|
else {
|
||||||
"Non-admin users can create tenants"
|
"Non-admin users can create tenants"
|
||||||
}
|
}
|
||||||
|
|
||||||
$details = "AllowedToCreateTenants: $($tenantCreationPolicy.AllowedToCreateTenants)"
|
$details = "AllowedToCreateTenants: $($tenantCreationPolicy.AllowedToCreateTenants)"
|
||||||
|
|
||||||
# Create and populate the CISAuditResult object
|
# Create and populate the CISAuditResult object
|
||||||
$params = @{
|
$params = @{
|
||||||
Rec = $recnum
|
Rec = $recnum
|
||||||
@@ -63,9 +54,8 @@ function Test-RestrictTenantCreation {
|
|||||||
$auditResult = Get-TestError -LastError $LastError -recnum $recnum
|
$auditResult = Get-TestError -LastError $LastError -recnum $recnum
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
end {
|
end {
|
||||||
# Return the audit result
|
# Return the audit result
|
||||||
return $auditResult
|
return $auditResult
|
||||||
}
|
}
|
||||||
}
|
}
|
Reference in New Issue
Block a user