Merge pull request #111 from CriticalSolutionsNetwork/6.1.2/6.1.3-refactor

6.1.2/6.1.3 refactor
Added
Added Get-MFAStatus function to help with auditing mfa for conditional access controls.
Fixed
Fixed 6.1.2/6.1.3 tests to minimize calls to the Graph API.
Fixed 2.1.1,2.1.4,2.1.5 to suppress error messages and create a standard object when no e5"
This commit is contained in:
Doug Rios
2024-06-14 11:06:00 -05:00
committed by GitHub
14 changed files with 663 additions and 214 deletions

View File

@@ -6,6 +6,17 @@ The format is based on and uses the types of changes according to [Keep a Change
### Added ### Added
- Added Get-MFAStatus function to help with auditing mfa for conditional access controls.
### Fixed
- Fixed 6.1.2/6.1.3 tests to minimize calls to the Graph API.
- Fixed 2.1.1,2.1.4,2.1.5 to suppress error messages and create a standard object when no e5"
## [0.1.10] - 2024-06-12
### Added
- Added condition comments to each test. - Added condition comments to each test.
### Fixed ### Fixed

BIN
README.md

Binary file not shown.

Binary file not shown.

View File

@@ -4,7 +4,7 @@ Import-Module .\output\module\M365FoundationsCISReport\*\*.psd1
<# <#
$ver = "v0.1.9" $ver = "v0.1.10"
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"

View File

@@ -18,7 +18,7 @@ function Connect-M365Suite {
Write-Host "Successfully connected to Azure Active Directory." -ForegroundColor Green Write-Host "Successfully connected to Azure Active Directory." -ForegroundColor Green
} }
if ($RequiredConnections -contains "Microsoft Graph" -or $RequiredConnections -contains "AzureAD | EXO | Microsoft Graph") { if ($RequiredConnections -contains "Microsoft Graph" -or $RequiredConnections -contains "EXO | Microsoft Graph") {
Write-Host "Connecting to Microsoft Graph with scopes: Directory.Read.All, Domain.Read.All, Policy.Read.All, Organization.Read.All" -ForegroundColor Cyan Write-Host "Connecting to Microsoft Graph with scopes: Directory.Read.All, Domain.Read.All, Policy.Read.All, Organization.Read.All" -ForegroundColor Cyan
try { try {
Connect-MgGraph -Scopes "Directory.Read.All", "Domain.Read.All", "Policy.Read.All", "Organization.Read.All" -NoWelcome | Out-Null Connect-MgGraph -Scopes "Directory.Read.All", "Domain.Read.All", "Policy.Read.All", "Organization.Read.All" -NoWelcome | Out-Null
@@ -31,7 +31,7 @@ function Connect-M365Suite {
} }
} }
if ($RequiredConnections -contains "EXO" -or $RequiredConnections -contains "AzureAD | EXO" -or $RequiredConnections -contains "Microsoft Teams | EXO" -or $RequiredConnections -contains "AzureAD | EXO | Microsoft Graph") { if ($RequiredConnections -contains "EXO" -or $RequiredConnections -contains "AzureAD | EXO" -or $RequiredConnections -contains "Microsoft Teams | EXO" -or $RequiredConnections -contains "EXO | Microsoft Graph") {
Write-Host "Connecting to Exchange Online..." -ForegroundColor Cyan Write-Host "Connecting to Exchange Online..." -ForegroundColor Cyan
Connect-ExchangeOnline | Out-Null Connect-ExchangeOnline | Out-Null
Write-Host "Successfully connected to Exchange Online." -ForegroundColor Green Write-Host "Successfully connected to Exchange Online." -ForegroundColor Green

View File

@@ -0,0 +1,103 @@
<#
.SYNOPSIS
Retrieves the MFA (Multi-Factor Authentication) status for Azure Active Directory users.
.DESCRIPTION
The Get-MFAStatus function connects to Microsoft Online Service and retrieves the MFA status for all Azure Active Directory users, excluding guest accounts. Optionally, you can specify a single user by their User Principal Name (UPN) to get their MFA status.
.PARAMETER UserId
The User Principal Name (UPN) of a specific user to retrieve MFA status for. If not provided, the function retrieves MFA status for all users.
.EXAMPLE
Get-MFAStatus
Retrieves the MFA status for all Azure Active Directory users.
.EXAMPLE
Get-MFAStatus -UserId "example@domain.com"
Retrieves the MFA status for the specified user with the UPN "example@domain.com".
.OUTPUTS
System.Object
Returns a sorted list of custom objects containing the following properties:
- UserPrincipalName
- DisplayName
- MFAState
- MFADefaultMethod
- MFAPhoneNumber
- PrimarySMTP
- Aliases
.NOTES
The function requires the MSOL module to be installed and connected to your tenant.
Ensure that you have the necessary permissions to read user and MFA status information.
.LINK
https://criticalsolutionsnetwork.github.io/M365FoundationsCISReport/#Get-MFAStatus
#>
function Get-MFAStatus {
[OutputType([System.Object])]
[CmdletBinding()]
param (
[Parameter(Mandatory = $false)]
[ValidateNotNullOrEmpty()]
[string]$UserId
)
begin {
# Connect to Microsoft Online service
Import-Module MSOnline -ErrorAction SilentlyContinue
}
process {
if (Get-Module MSOnline){
Connect-MsolService
Write-Host -Object "Finding Azure Active Directory Accounts..."
# Get all users, excluding guests
$Users = if ($PSBoundParameters.ContainsKey('UserId')) {
Get-MsolUser -UserPrincipalName $UserId
} else {
Get-MsolUser -All | Where-Object { $_.UserType -ne "Guest" }
}
$Report = [System.Collections.Generic.List[Object]]::new() # Create output list
Write-Host -Object "Processing" $Users.Count "accounts..."
ForEach ($User in $Users) {
$MFADefaultMethod = ($User.StrongAuthenticationMethods | Where-Object { $_.IsDefault -eq "True" }).MethodType
$MFAPhoneNumber = $User.StrongAuthenticationUserDetails.PhoneNumber
$PrimarySMTP = $User.ProxyAddresses | Where-Object { $_ -clike "SMTP*" } | ForEach-Object { $_ -replace "SMTP:", "" }
$Aliases = $User.ProxyAddresses | Where-Object { $_ -clike "smtp*" } | ForEach-Object { $_ -replace "smtp:", "" }
If ($User.StrongAuthenticationRequirements) {
$MFAState = $User.StrongAuthenticationRequirements.State
}
Else {
$MFAState = 'Disabled'
}
If ($MFADefaultMethod) {
Switch ($MFADefaultMethod) {
"OneWaySMS" { $MFADefaultMethod = "Text code authentication phone" }
"TwoWayVoiceMobile" { $MFADefaultMethod = "Call authentication phone" }
"TwoWayVoiceOffice" { $MFADefaultMethod = "Call office phone" }
"PhoneAppOTP" { $MFADefaultMethod = "Authenticator app or hardware token" }
"PhoneAppNotification" { $MFADefaultMethod = "Microsoft authenticator app" }
}
}
Else {
$MFADefaultMethod = "Not enabled"
}
$ReportLine = [PSCustomObject] @{
UserPrincipalName = $User.UserPrincipalName
DisplayName = $User.DisplayName
MFAState = $MFAState
MFADefaultMethod = $MFADefaultMethod
MFAPhoneNumber = $MFAPhoneNumber
PrimarySMTP = ($PrimarySMTP -join ',')
Aliases = ($Aliases -join ',')
}
$Report.Add($ReportLine)
}
Write-Host -Object "Processing complete."
return $Report | Select-Object UserPrincipalName, DisplayName, MFAState, MFADefaultMethod, MFAPhoneNumber, PrimarySMTP, Aliases | Sort-Object UserPrincipalName
}
else {
Write-Host -Object "You must first install MSOL using:`nInstall-Module MSOnline -Scope CurrentUser -Force"
}
}
}

View File

@@ -18,8 +18,8 @@
17,Test-RestrictTenantCreation.ps1,5.1.2.3,Ensure 'Restrict non-admin users from creating tenants' is set to 'Yes',E3,L1,0,Explicitly Not Mapped,FALSE,FALSE,FALSE,TRUE,Microsoft Graph 17,Test-RestrictTenantCreation.ps1,5.1.2.3,Ensure 'Restrict non-admin users from creating tenants' is set to 'Yes',E3,L1,0,Explicitly Not Mapped,FALSE,FALSE,FALSE,TRUE,Microsoft Graph
18,Test-PasswordHashSync.ps1,5.1.8.1,Ensure password hash sync is enabled for hybrid deployments,E3,L1,6.7,Centralize Access Control,FALSE,TRUE,TRUE,TRUE,Microsoft Graph 18,Test-PasswordHashSync.ps1,5.1.8.1,Ensure password hash sync is enabled for hybrid deployments,E3,L1,6.7,Centralize Access Control,FALSE,TRUE,TRUE,TRUE,Microsoft Graph
19,Test-AuditDisabledFalse.ps1,6.1.1,Ensure 'AuditDisabled' organizationally is set to 'False',E3,L1,8.2,Collect Audit Logs,TRUE,TRUE,TRUE,TRUE,Microsoft Graph 19,Test-AuditDisabledFalse.ps1,6.1.1,Ensure 'AuditDisabled' organizationally is set to 'False',E3,L1,8.2,Collect Audit Logs,TRUE,TRUE,TRUE,TRUE,Microsoft Graph
20,Test-MailboxAuditingE3.ps1,6.1.2,Ensure mailbox auditing for Office E3 users is Enabled,E3,L1,8.2,Collect audit logs.,TRUE,TRUE,TRUE,TRUE,AzureAD | EXO | Microsoft Graph 20,Test-MailboxAuditingE3.ps1,6.1.2,Ensure mailbox auditing for Office E3 users is Enabled,E3,L1,8.2,Collect audit logs.,TRUE,TRUE,TRUE,TRUE,EXO | Microsoft Graph
21,Test-MailboxAuditingE5.ps1,6.1.3,Ensure mailbox auditing for Office E5 users is Enabled,E5,L1,8.2,Collect audit logs.,TRUE,TRUE,TRUE,TRUE,AzureAD | EXO | Microsoft Graph 21,Test-MailboxAuditingE5.ps1,6.1.3,Ensure mailbox auditing for Office E5 users is Enabled,E5,L1,8.2,Collect audit logs.,TRUE,TRUE,TRUE,TRUE,EXO | Microsoft Graph
22,Test-BlockMailForwarding.ps1,6.2.1,Ensure all forms of mail forwarding are blocked and/or disabled,E3,L1,0,Explicitly Not Mapped,FALSE,FALSE,FALSE,TRUE,EXO 22,Test-BlockMailForwarding.ps1,6.2.1,Ensure all forms of mail forwarding are blocked and/or disabled,E3,L1,0,Explicitly Not Mapped,FALSE,FALSE,FALSE,TRUE,EXO
23,Test-NoWhitelistDomains.ps1,6.2.2,Ensure mail transport rules do not whitelist specific domains,E3,L1,0,Explicitly Not Mapped,FALSE,FALSE,FALSE,TRUE,EXO 23,Test-NoWhitelistDomains.ps1,6.2.2,Ensure mail transport rules do not whitelist specific domains,E3,L1,0,Explicitly Not Mapped,FALSE,FALSE,FALSE,TRUE,EXO
24,Test-IdentifyExternalEmail.ps1,6.2.3,Ensure email from external senders is identified,E3,L1,0,Explicitly Not Mapped,FALSE,FALSE,FALSE,TRUE,EXO 24,Test-IdentifyExternalEmail.ps1,6.2.3,Ensure email from external senders is identified,E3,L1,0,Explicitly Not Mapped,FALSE,FALSE,FALSE,TRUE,EXO
1 Index TestFileName Rec RecDescription ELevel ProfileLevel CISControl CISDescription IG1 IG2 IG3 Automated Connection
18 17 Test-RestrictTenantCreation.ps1 5.1.2.3 Ensure 'Restrict non-admin users from creating tenants' is set to 'Yes' E3 L1 0 Explicitly Not Mapped FALSE FALSE FALSE TRUE Microsoft Graph
19 18 Test-PasswordHashSync.ps1 5.1.8.1 Ensure password hash sync is enabled for hybrid deployments E3 L1 6.7 Centralize Access Control FALSE TRUE TRUE TRUE Microsoft Graph
20 19 Test-AuditDisabledFalse.ps1 6.1.1 Ensure 'AuditDisabled' organizationally is set to 'False' E3 L1 8.2 Collect Audit Logs TRUE TRUE TRUE TRUE Microsoft Graph
21 20 Test-MailboxAuditingE3.ps1 6.1.2 Ensure mailbox auditing for Office E3 users is Enabled E3 L1 8.2 Collect audit logs. TRUE TRUE TRUE TRUE AzureAD | EXO | Microsoft Graph EXO | Microsoft Graph
22 21 Test-MailboxAuditingE5.ps1 6.1.3 Ensure mailbox auditing for Office E5 users is Enabled E5 L1 8.2 Collect audit logs. TRUE TRUE TRUE TRUE AzureAD | EXO | Microsoft Graph EXO | Microsoft Graph
23 22 Test-BlockMailForwarding.ps1 6.2.1 Ensure all forms of mail forwarding are blocked and/or disabled E3 L1 0 Explicitly Not Mapped FALSE FALSE FALSE TRUE EXO
24 23 Test-NoWhitelistDomains.ps1 6.2.2 Ensure mail transport rules do not whitelist specific domains E3 L1 0 Explicitly Not Mapped FALSE FALSE FALSE TRUE EXO
25 24 Test-IdentifyExternalEmail.ps1 6.2.3 Ensure email from external senders is identified E3 L1 0 Explicitly Not Mapped FALSE FALSE FALSE TRUE EXO

View File

@@ -29,18 +29,23 @@ function Test-MailboxAuditingE3 {
# Dot source the class script if necessary # Dot source the class script if necessary
#. .\source\Classes\CISAuditResult.ps1 #. .\source\Classes\CISAuditResult.ps1
$e3SkuPartNumbers = @("ENTERPRISEPACK", "OFFICESUBSCRIPTION") $e3SkuPartNumber = "SPE_E3"
$AdminActions = @("ApplyRecord", "Copy", "Create", "FolderBind", "HardDelete", "Move", "MoveToDeletedItems", "SendAs", "SendOnBehalf", "SoftDelete", "Update", "UpdateCalendarDelegation", "UpdateFolderPermissions", "UpdateInboxRules") $AdminActions = @("ApplyRecord", "Copy", "Create", "FolderBind", "HardDelete", "Move", "MoveToDeletedItems", "SendAs", "SendOnBehalf", "SoftDelete", "Update", "UpdateCalendarDelegation", "UpdateFolderPermissions", "UpdateInboxRules")
$DelegateActions = @("ApplyRecord", "Create", "FolderBind", "HardDelete", "Move", "MoveToDeletedItems", "SendAs", "SendOnBehalf", "SoftDelete", "Update", "UpdateFolderPermissions", "UpdateInboxRules") $DelegateActions = @("ApplyRecord", "Create", "FolderBind", "HardDelete", "Move", "MoveToDeletedItems", "SendAs", "SendOnBehalf", "SoftDelete", "Update", "UpdateFolderPermissions", "UpdateInboxRules")
$OwnerActions = @("ApplyRecord", "Create", "HardDelete", "MailboxLogin", "Move", "MoveToDeletedItems", "SoftDelete", "Update", "UpdateCalendarDelegation", "UpdateFolderPermissions", "UpdateInboxRules") $OwnerActions = @("ApplyRecord", "Create", "HardDelete", "MailboxLogin", "Move", "MoveToDeletedItems", "SoftDelete", "Update", "UpdateCalendarDelegation", "UpdateFolderPermissions", "UpdateInboxRules")
$allFailures = @() $allFailures = @()
$allUsers = Get-AzureADUser -All $true #$allUsers = Get-AzureADUser -All $true
$founde3Sku = Get-MgSubscribedSku -All | Where-Object {$_.SkuPartNumber -eq $e3SkuPartNumber}
$processedUsers = @{} # Dictionary to track processed users $processedUsers = @{} # Dictionary to track processed users
$recnum = "6.1.2" $recnum = "6.1.2"
} }
process { process {
if (($founde3Sku.count)-ne 0) {
$allUsers = Get-MgUser -Filter "assignedLicenses/any(x:x/skuId eq $($founde3Sku.SkuId) )" -All
$mailboxes = Get-EXOMailbox -PropertySets Audit
try { try {
foreach ($user in $allUsers) { foreach ($user in $allUsers) {
if ($processedUsers.ContainsKey($user.UserPrincipalName)) { if ($processedUsers.ContainsKey($user.UserPrincipalName)) {
@@ -48,13 +53,12 @@ function Test-MailboxAuditingE3 {
continue continue
} }
$licenseDetails = Get-MgUserLicenseDetail -UserId $user.UserPrincipalName #$licenseDetails = Get-MgUserLicenseDetail -UserId $user.UserPrincipalName
$hasOfficeE3 = ($licenseDetails | Where-Object { $_.SkuPartNumber -in $e3SkuPartNumbers }).Count -gt 0 #$hasOfficeE3 = ($licenseDetails | Where-Object { $_.SkuPartNumber -in $e3SkuPartNumbers }).Count -gt 0
Write-Verbose "Evaluating user $($user.UserPrincipalName) for Office E3 license." #Write-Verbose "Evaluating user $($user.UserPrincipalName) for Office E3 license."
if ($hasOfficeE3) {
$userUPN = $user.UserPrincipalName $userUPN = $user.UserPrincipalName
$mailbox = Get-EXOMailbox -Identity $userUPN -PropertySets Audit $mailbox = $mailboxes | Where-Object { $_.UserPrincipalName -eq $user.UserPrincipalName }
$missingActions = @() $missingActions = @()
if ($mailbox.AuditEnabled) { if ($mailbox.AuditEnabled) {
@@ -84,7 +88,6 @@ function Test-MailboxAuditingE3 {
# Mark the user as processed # Mark the user as processed
$processedUsers[$user.UserPrincipalName] = $true $processedUsers[$user.UserPrincipalName] = $true
} }
}
# Prepare failure reasons and details based on compliance # Prepare failure reasons and details based on compliance
$failureReasons = if ($allFailures.Count -eq 0) { "N/A" } else { "Audit issues detected." } $failureReasons = if ($allFailures.Count -eq 0) { "N/A" } else { "Audit issues detected." }
@@ -118,6 +121,17 @@ function Test-MailboxAuditingE3 {
$auditResult = Initialize-CISAuditResult -Rec $recnum -Failure $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure
} }
} }
else {
$params = @{
Rec = $recnum
Result = $false
Status = "Fail"
Details = "No M365 E3 licenses found."
FailureReason = "The audit is for M365 E3 licenses, but no such licenses were found."
}
$auditResult = Initialize-CISAuditResult @params
}
}
end { end {
#$verbosePreference = 'Continue' #$verbosePreference = 'Continue'

View File

@@ -27,18 +27,22 @@ function Test-MailboxAuditingE5 {
# - Condition C: AuditDelegate actions do not include all of the following: ApplyRecord, Create, HardDelete, MailItemsAccessed, MoveToDeletedItems, SendAs, SendOnBehalf, SoftDelete, Update, UpdateFolderPermissions, UpdateInboxRules. # - Condition C: AuditDelegate actions do not include all of the following: ApplyRecord, Create, HardDelete, MailItemsAccessed, MoveToDeletedItems, SendAs, SendOnBehalf, SoftDelete, Update, UpdateFolderPermissions, UpdateInboxRules.
# - Condition D: AuditOwner actions do not include all of the following: ApplyRecord, HardDelete, MailItemsAccessed, MoveToDeletedItems, Send, SoftDelete, Update, UpdateCalendarDelegation, UpdateFolderPermissions, UpdateInboxRules. # - Condition D: AuditOwner actions do not include all of the following: ApplyRecord, HardDelete, MailItemsAccessed, MoveToDeletedItems, Send, SoftDelete, Update, UpdateCalendarDelegation, UpdateFolderPermissions, UpdateInboxRules.
$e5SkuPartNumbers = @("SPE_E5", "ENTERPRISEPREMIUM", "OFFICEE5") $e5SkuPartNumber = "SPE_E5"
$AdminActions = @("ApplyRecord", "Copy", "Create", "FolderBind", "HardDelete", "MailItemsAccessed", "Move", "MoveToDeletedItems", "SendAs", "SendOnBehalf", "Send", "SoftDelete", "Update", "UpdateCalendarDelegation", "UpdateFolderPermissions", "UpdateInboxRules") $AdminActions = @("ApplyRecord", "Copy", "Create", "FolderBind", "HardDelete", "MailItemsAccessed", "Move", "MoveToDeletedItems", "SendAs", "SendOnBehalf", "Send", "SoftDelete", "Update", "UpdateCalendarDelegation", "UpdateFolderPermissions", "UpdateInboxRules")
$DelegateActions = @("ApplyRecord", "Create", "FolderBind", "HardDelete", "MailItemsAccessed", "Move", "MoveToDeletedItems", "SendAs", "SendOnBehalf", "SoftDelete", "Update", "UpdateFolderPermissions", "UpdateInboxRules") $DelegateActions = @("ApplyRecord", "Create", "FolderBind", "HardDelete", "MailItemsAccessed", "Move", "MoveToDeletedItems", "SendAs", "SendOnBehalf", "SoftDelete", "Update", "UpdateFolderPermissions", "UpdateInboxRules")
$OwnerActions = @("ApplyRecord", "Create", "HardDelete", "MailboxLogin", "Move", "MailItemsAccessed", "MoveToDeletedItems", "Send", "SoftDelete", "Update", "UpdateCalendarDelegation", "UpdateFolderPermissions", "UpdateInboxRules") $OwnerActions = @("ApplyRecord", "Create", "HardDelete", "MailboxLogin", "Move", "MailItemsAccessed", "MoveToDeletedItems", "Send", "SoftDelete", "Update", "UpdateCalendarDelegation", "UpdateFolderPermissions", "UpdateInboxRules")
$allFailures = @() $allFailures = @()
$allUsers = Get-AzureADUser -All $true #$allUsers = Get-AzureADUser -All $true
$founde5Sku = Get-MgSubscribedSku -All | Where-Object { $_.SkuPartNumber -eq $e5SkuPartNumber }
$processedUsers = @{} # Dictionary to track processed users $processedUsers = @{} # Dictionary to track processed users
$recnum = "6.1.3" $recnum = "6.1.3"
} }
process { process {
if (($founde5Sku.count) -ne 0) {
$allUsers = Get-MgUser -Filter "assignedLicenses/any(x:x/skuId eq $($founde5Sku.SkuId) )" -All
$mailboxes = Get-EXOMailbox -PropertySets Audit
try { try {
foreach ($user in $allUsers) { foreach ($user in $allUsers) {
if ($processedUsers.ContainsKey($user.UserPrincipalName)) { if ($processedUsers.ContainsKey($user.UserPrincipalName)) {
@@ -46,13 +50,12 @@ function Test-MailboxAuditingE5 {
continue continue
} }
$licenseDetails = Get-MgUserLicenseDetail -UserId $user.UserPrincipalName #$licenseDetails = Get-MgUserLicenseDetail -UserId $user.UserPrincipalName
$hasOfficeE5 = ($licenseDetails | Where-Object { $_.SkuPartNumber -in $e5SkuPartNumbers }).Count -gt 0 #$hasOfficeE5 = ($licenseDetails | Where-Object { $_.SkuPartNumber -in $e5SkuPartNumbers }).Count -gt 0
Write-Verbose "Evaluating user $($user.UserPrincipalName) for Office E5 license." #Write-Verbose "Evaluating user $($user.UserPrincipalName) for Office E5 license."
$mailbox = $mailboxes | Where-Object { $_.UserPrincipalName -eq $user.UserPrincipalName }
if ($hasOfficeE5) {
$userUPN = $user.UserPrincipalName $userUPN = $user.UserPrincipalName
$mailbox = Get-EXOMailbox -Identity $userUPN -PropertySets Audit #$mailbox = Get-EXOMailbox -Identity $userUPN -PropertySets Audit
$missingActions = @() $missingActions = @()
if ($mailbox.AuditEnabled) { if ($mailbox.AuditEnabled) {
@@ -81,7 +84,6 @@ function Test-MailboxAuditingE5 {
# Mark the user as processed # Mark the user as processed
$processedUsers[$user.UserPrincipalName] = $true $processedUsers[$user.UserPrincipalName] = $true
} }
}
# Prepare failure reasons and details based on compliance # Prepare failure reasons and details based on compliance
$failureReasons = if ($allFailures.Count -eq 0) { "N/A" } else { "Audit issues detected." } $failureReasons = if ($allFailures.Count -eq 0) { "N/A" } else { "Audit issues detected." }
@@ -115,6 +117,17 @@ function Test-MailboxAuditingE5 {
$auditResult = Initialize-CISAuditResult -Rec $recnum -Failure $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure
} }
} }
else {
$params = @{
Rec = $recnum
Result = $false
Status = "Fail"
Details = "No M365 E5 licenses found."
FailureReason = "The audit is for M365 E5 licenses, but no such licenses were found."
}
$auditResult = Initialize-CISAuditResult @params
}
}
end { end {
#$verbosePreference = 'Continue' #$verbosePreference = 'Continue'

View File

@@ -1,10 +1,7 @@
function Test-SafeAttachmentsPolicy { function Test-SafeAttachmentsPolicy {
[CmdletBinding()] [CmdletBinding()]
[OutputType([CISAuditResult])] [OutputType([CISAuditResult])]
param ( param ()
# Aligned
# Parameters can be added if needed
)
begin { begin {
# Dot source the class script if necessary # Dot source the class script if necessary
@@ -35,39 +32,56 @@ function Test-SafeAttachmentsPolicy {
} }
process { process {
if (Get-Command Get-SafeAttachmentPolicy -ErrorAction SilentlyContinue) {
try { try {
# 2.1.4 (L2) Ensure Safe Attachments policy is enabled
# Retrieve all Safe Attachment policies where Enable is set to True # Retrieve all Safe Attachment policies where Enable is set to True
$safeAttachmentPolicies = Get-SafeAttachmentPolicy | Where-Object { $_.Enable -eq $true } $safeAttachmentPolicies = Get-SafeAttachmentPolicy -ErrorAction SilentlyContinue | Where-Object { $_.Enable -eq $true }
# Check if any Safe Attachments policy is enabled (Condition A)
# Condition A: Check if any Safe Attachments policy is enabled
$result = $null -ne $safeAttachmentPolicies -and $safeAttachmentPolicies.Count -gt 0 $result = $null -ne $safeAttachmentPolicies -and $safeAttachmentPolicies.Count -gt 0
# Condition B, C, D: Additional checks can be added here if more detailed policy attributes are required # Initialize details and failure reasons
$details = @()
$failureReasons = @()
# Determine details and failure reasons based on the presence of enabled policies foreach ($policy in $safeAttachmentPolicies) {
$details = if ($result) { # Initialize policy detail and failed status
"Enabled Safe Attachments Policies: $($safeAttachmentPolicies.Name -join ', ')" $failed = $false
}
else { # Check if the policy action is set to "Dynamic Delivery" or "Quarantine" (Condition C)
"No Safe Attachments Policies are enabled." if ($policy.Action -notin @("DynamicDelivery", "Quarantine")) {
$failureReasons += "Policy '$($policy.Name)' action is not set to 'Dynamic Delivery' or 'Quarantine'."
$failed = $true
} }
$failureReasons = if ($result) { # Check if the policy is not disabled (Condition D)
"N/A" if (-not $policy.Enable) {
$failureReasons += "Policy '$($policy.Name)' is disabled."
$failed = $true
} }
else {
"Safe Attachments policy is not enabled." # Add policy details to the details array
$details += [PSCustomObject]@{
Policy = $policy.Name
Enabled = $policy.Enable
Action = $policy.Action
Failed = $failed
} }
}
# The result is a pass if there are no failure reasons
$result = $failureReasons.Count -eq 0
# Format details for output
$detailsString = $details | Format-Table -AutoSize | Out-String
$failureReasonsString = ($failureReasons | ForEach-Object { $_ }) -join ' '
# Create and populate the CISAuditResult object # Create and populate the CISAuditResult object
$params = @{ $params = @{
Rec = $recnum Rec = $recnum
Result = $result Result = $result
Status = if ($result) { "Pass" } else { "Fail" } Status = if ($result) { "Pass" } else { "Fail" }
Details = $details Details = $detailsString
FailureReason = $failureReasons FailureReason = if ($result) { "N/A" } else { $failureReasonsString }
} }
$auditResult = Initialize-CISAuditResult @params $auditResult = Initialize-CISAuditResult @params
} }
@@ -84,10 +98,20 @@ function Test-SafeAttachmentsPolicy {
$auditResult = Initialize-CISAuditResult -Rec $recnum -Failure $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure
} }
} }
else {
$params = @{
Rec = $recnum
Result = $false
Status = "Fail"
Details = "No M365 E5 licenses found."
FailureReason = "The audit is for M365 E5 licenses and the required EXO commands will not be available otherwise."
}
$auditResult = Initialize-CISAuditResult @params
}
}
end { end {
# Return the audit result # Return the audit result
return $auditResult return $auditResult
} }
} }

View File

@@ -31,12 +31,11 @@ function Test-SafeAttachmentsTeams {
} }
process { process {
if (Get-Command Get-AtpPolicyForO365 -ErrorAction SilentlyContinue) {
try { try {
# 2.1.5 (L2) Ensure Safe Attachments for SharePoint, OneDrive, and Microsoft Teams is Enabled # 2.1.5 (L2) Ensure Safe Attachments for SharePoint, OneDrive, and Microsoft Teams is Enabled
# Retrieve the ATP policies for Office 365 and check Safe Attachments settings # Retrieve the ATP policies for Office 365 and check Safe Attachments settings
$atpPolicies = Get-AtpPolicyForO365 $atpPolicies = Get-AtpPolicyForO365
# Check if the required ATP policies are enabled # Check if the required ATP policies are enabled
$atpPolicyResult = $atpPolicies | Where-Object { $atpPolicyResult = $atpPolicies | Where-Object {
$_.EnableATPForSPOTeamsODB -eq $true -and $_.EnableATPForSPOTeamsODB -eq $true -and
@@ -87,6 +86,17 @@ function Test-SafeAttachmentsTeams {
$auditResult = Initialize-CISAuditResult -Rec $recnum -Failure $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure
} }
} }
else {
$params = @{
Rec = $recnum
Result = $false
Status = "Fail"
Details = "No M365 E5 licenses found."
FailureReason = "The audit is for M365 E5 licenses and the required EXO commands will not be available otherwise."
}
$auditResult = Initialize-CISAuditResult @params
}
}
end { end {
# Return the audit result # Return the audit result

View File

@@ -40,12 +40,11 @@ function Test-SafeLinksOfficeApps {
} }
process { process {
if (Get-Command Get-SafeLinksPolicy -ErrorAction SilentlyContinue) {
try { try {
# 2.1.1 (L2) Ensure Safe Links for Office Applications is Enabled # 2.1.1 (L2) Ensure Safe Links for Office Applications is Enabled
# Retrieve all Safe Links policies # Retrieve all Safe Links policies
$policies = Get-SafeLinksPolicy $policies = Get-SafeLinksPolicy
# Initialize the details collection # Initialize the details collection
$misconfiguredDetails = @() $misconfiguredDetails = @()
@@ -97,6 +96,17 @@ function Test-SafeLinksOfficeApps {
$auditResult = Initialize-CISAuditResult -Rec $recnum -Failure $auditResult = Initialize-CISAuditResult -Rec $recnum -Failure
} }
} }
else {
$params = @{
Rec = $recnum
Result = $false
Status = "Fail"
Details = "No M365 E5 licenses found."
FailureReason = "The audit is for M365 E5 licenses and the required EXO commands will not be available otherwise."
}
$auditResult = Initialize-CISAuditResult @params
}
}
end { end {
# Return the audit result # Return the audit result

View File

@@ -210,3 +210,196 @@ if ($warnings.Count -gt 0) {
Get-GitHubRepository -OwnerName 'CriticalSolutionsNetwork' -RepositoryName 'M365FoundationsCISReport' Get-GitHubRepository -OwnerName 'CriticalSolutionsNetwork' -RepositoryName 'M365FoundationsCISReport'
#########################################################################################
connect-MgGraph -Scopes "Directory.Read.All", "Domain.Read.All", "Policy.Read.All", "Organization.Read.All" -NoWelcome
# Retrieve the subscribed SKUs
$sub = Get-MgSubscribedSku -All
# Define the product array
$ProductArray = @(
"Microsoft_Cloud_App_Security_App_Governance_Add_On",
"Defender_Threat_Intelligence",
"THREAT_INTELLIGENCE",
"WIN_DEF_ATP",
"Microsoft_Defender_for_Endpoint_F2",
"DEFENDER_ENDPOINT_P1",
"DEFENDER_ENDPOINT_P1_EDU",
"MDATP_XPLAT",
"MDATP_Server",
"ATP_ENTERPRISE_FACULTY",
"ATA",
"ATP_ENTERPRISE_GOV",
"ATP_ENTERPRISE_USGOV_GCCHIGH",
"THREAT_INTELLIGENCE_GOV",
"TVM_Premium_Standalone",
"TVM_Premium_Add_on",
"ATP_ENTERPRISE",
"Azure_Information_Protection_Premium_P1",
"Azure_Information_Protection_Premium_P2",
"Microsoft_Application_Protection_and_Governance",
"Exchange_Online_Protection",
"Microsoft_365_Defender",
"Cloud_App_Security_Discovery"
)
# Define the hashtable
$ProductHashTable = @{
"App governance add-on to Microsoft Defender for Cloud Apps" = "Microsoft_Cloud_App_Security_App_Governance_Add_On"
"Defender Threat Intelligence" = "Defender_Threat_Intelligence"
"Microsoft Defender for Office 365 (Plan 2)" = "THREAT_INTELLIGENCE"
"Microsoft Defender for Endpoint" = "WIN_DEF_ATP"
"Microsoft Defender for Endpoint F2" = "Microsoft_Defender_for_Endpoint_F2"
"Microsoft Defender for Endpoint P1" = "DEFENDER_ENDPOINT_P1"
"Microsoft Defender for Endpoint P1 for EDU" = "DEFENDER_ENDPOINT_P1_EDU"
"Microsoft Defender for Endpoint P2_XPLAT" = "MDATP_XPLAT"
"Microsoft Defender for Endpoint Server" = "MDATP_Server"
"Microsoft Defender for Office 365 (Plan 1) Faculty" = "ATP_ENTERPRISE_FACULTY"
"Microsoft Defender for Identity" = "ATA"
"Microsoft Defender for Office 365 (Plan 1) GCC" = "ATP_ENTERPRISE_GOV"
"Microsoft Defender for Office 365 (Plan 1)_USGOV_GCCHIGH" = "ATP_ENTERPRISE_USGOV_GCCHIGH"
"Microsoft Defender for Office 365 (Plan 2) GCC" = "THREAT_INTELLIGENCE_GOV"
"Microsoft Defender Vulnerability Management" = "TVM_Premium_Standalone"
"Microsoft Defender Vulnerability Management Add-on" = "TVM_Premium_Add_on"
"Microsoft Defender for Office 365 (Plan 1)" = "ATP_ENTERPRISE"
"Azure Information Protection Premium P1" = "Azure_Information_Protection_Premium_P1"
"Azure Information Protection Premium P2" = "Azure_Information_Protection_Premium_P2"
"Microsoft Application Protection and Governance" = "Microsoft_Application_Protection_and_Governance"
"Exchange Online Protection" = "Exchange_Online_Protection"
"Microsoft 365 Defender" = "Microsoft_365_Defender"
"Cloud App Security Discovery" = "Cloud_App_Security_Discovery"
}
# Reverse the hashtable
$ReverseProductHashTable = @{}
foreach ($key in $ProductHashTable.Keys) {
$ReverseProductHashTable[$ProductHashTable[$key]] = $key
}
# Loop through each SKU and get the enabled security features
$securityFeatures = foreach ($sku in $sub) {
if ($sku.SkuPartNumber -eq "MDATP_XPLAT_EDU") {
Write-Host "the SKU is: `n$($sku | gm)"
[PSCustomObject]@{
Skupartnumber = $sku.skupartnumber
AppliesTo = $sku.AppliesTo
ProvisioningStatus = $sku.ProvisioningStatus
ServicePlanId = $sku.ServicePlanId
ServicePlanName = $sku.ServicePlanName
FriendlyName = "Defender P2 for EDU"
}
}
else {
$sku.serviceplans | Where-Object { $_.serviceplanname -in $ProductArray } | ForEach-Object {
$friendlyName = $ReverseProductHashTable[$_.ServicePlanName]
[PSCustomObject]@{
Skupartnumber = $sku.skupartnumber
AppliesTo = $_.AppliesTo
ProvisioningStatus = $_.ProvisioningStatus
ServicePlanId = $_.ServicePlanId
ServicePlanName = $_.ServicePlanName
FriendlyName = $friendlyName
}
}
}
}
# Output the security features
$securityFeatures | Format-Table -AutoSize
##########
# Ensure the ImportExcel module is available
# Ensure the ImportExcel module is available
if (-not (Get-Module -ListAvailable -Name ImportExcel)) {
Install-Module -Name ImportExcel -Force -Scope CurrentUser
}
# Function to wait until the file is available
function Wait-ForFile {
param (
[string]$FilePath
)
while (Test-Path -Path $FilePath -PathType Leaf -and -not (Get-Content $FilePath -ErrorAction SilentlyContinue)) {
Start-Sleep -Seconds 1
}
}
# Path to the Excel file
$excelFilePath = "C:\Users\dougrios\OneDrive - CRITICALSOLUTIONS NET LLC\Documents\_Tools\Benchies\SKUs.xlsx"
# Wait for the file to be available
# Import the Excel file
$excelData = Import-Excel -Path $excelFilePath
# Retrieve the subscribed SKUs
$subscribedSkus = Get-MgSubscribedSku -All
# Define the hashtable with security-related product names
$ProductHashTable = @{
"App governance add-on to Microsoft Defender for Cloud Apps" = "Microsoft_Cloud_App_Security_App_Governance_Add_On"
"Defender Threat Intelligence" = "Defender_Threat_Intelligence"
"Microsoft Defender for Office 365 (Plan 2)" = "THREAT_INTELLIGENCE"
"Microsoft Defender for Endpoint" = "WIN_DEF_ATP"
"Microsoft Defender for Endpoint F2" = "Microsoft_Defender_for_Endpoint_F2"
"Microsoft Defender for Endpoint P1" = "DEFENDER_ENDPOINT_P1"
"Microsoft Defender for Endpoint P1 for EDU" = "DEFENDER_ENDPOINT_P1_EDU"
"Microsoft Defender for Endpoint P2_XPLAT" = "MDATP_XPLAT"
"Microsoft Defender for Endpoint Server" = "MDATP_Server"
"Microsoft Defender for Office 365 (Plan 1) Faculty" = "ATP_ENTERPRISE_FACULTY"
"Microsoft Defender for Identity" = "ATA"
"Microsoft Defender for Office 365 (Plan 1) GCC" = "ATP_ENTERPRISE_GOV"
"Microsoft Defender for Office 365 (Plan 1)_USGOV_GCCHIGH" = "ATP_ENTERPRISE_USGOV_GCCHIGH"
"Microsoft Defender for Office 365 (Plan 2) GCC" = "THREAT_INTELLIGENCE_GOV"
"Microsoft Defender Vulnerability Management" = "TVM_Premium_Standalone"
"Microsoft Defender Vulnerability Management Add-on" = "TVM_Premium_Add_on"
"Microsoft Defender for Office 365 (Plan 1)" = "ATP_ENTERPRISE"
"Azure Information Protection Premium P1" = "Azure_Information_Protection_Premium_P1"
"Azure Information Protection Premium P2" = "Azure_Information_Protection_Premium_P2"
"Microsoft Application Protection and Governance" = "Microsoft_Application_Protection_and_Governance"
"Exchange Online Protection" = "Exchange_Online_Protection"
"Microsoft 365 Defender" = "Microsoft_365_Defender"
"Cloud App Security Discovery" = "Cloud_App_Security_Discovery"
}
# Create a hashtable to store the SKU part numbers and their associated security features
$skuSecurityFeatures = @{}
# Populate the hashtable with data from the Excel file
foreach ($row in $excelData) {
if ($null -ne $row.'String ID' -and $null -ne $row.'Service plans included (friendly names)') {
$skuSecurityFeatures[$row.'String ID'] = $row.'Service plans included (friendly names)'
}
}
# Display the SKU part numbers and their associated security features
foreach ($sku in $subscribedSkus) {
$skuPartNumber = $sku.SkuPartNumber
if ($skuSecurityFeatures.ContainsKey($skuPartNumber)) {
$securityFeatures = $skuSecurityFeatures[$skuPartNumber]
# Check if the security feature is in the hashtable
$isSecurityFeature = $ProductHashTable.ContainsKey($securityFeatures)
if ($isSecurityFeature) {
Write-Output "SKU Part Number: $skuPartNumber"
Write-Output "Security Features: $securityFeatures (Security-related)"
} else {
Write-Output "SKU Part Number: $skuPartNumber"
Write-Output "Security Features: $securityFeatures"
}
Write-Output "----------------------------"
} else {
Write-Output "SKU Part Number: $skuPartNumber"
Write-Output "Security Features: Not Found in Excel"
Write-Output "----------------------------"
}
}

View File

@@ -0,0 +1,71 @@
BeforeAll {
$script:moduleName = '<% $PLASTER_PARAM_ModuleName %>'
# If the module is not found, run the build task 'noop'.
if (-not (Get-Module -Name $script:moduleName -ListAvailable))
{
# Redirect all streams to $null, except the error stream (stream 2)
& "$PSScriptRoot/../../build.ps1" -Tasks 'noop' 2>&1 4>&1 5>&1 6>&1 > $null
}
# Re-import the module using force to get any code changes between runs.
Import-Module -Name $script:moduleName -Force -ErrorAction 'Stop'
$PSDefaultParameterValues['InModuleScope:ModuleName'] = $script:moduleName
$PSDefaultParameterValues['Mock:ModuleName'] = $script:moduleName
$PSDefaultParameterValues['Should:ModuleName'] = $script:moduleName
}
AfterAll {
$PSDefaultParameterValues.Remove('Mock:ModuleName')
$PSDefaultParameterValues.Remove('InModuleScope:ModuleName')
$PSDefaultParameterValues.Remove('Should:ModuleName')
Remove-Module -Name $script:moduleName
}
Describe Get-Something {
Context 'Return values' {
BeforeEach {
$return = Get-Something -Data 'value'
}
It 'Returns a single object' {
($return | Measure-Object).Count | Should -Be 1
}
}
Context 'Pipeline' {
It 'Accepts values from the pipeline by value' {
$return = 'value1', 'value2' | Get-Something
$return[0] | Should -Be 'value1'
$return[1] | Should -Be 'value2'
}
It 'Accepts value from the pipeline by property name' {
$return = 'value1', 'value2' | ForEach-Object {
[PSCustomObject]@{
Data = $_
OtherProperty = 'other'
}
} | Get-Something
$return[0] | Should -Be 'value1'
$return[1] | Should -Be 'value2'
}
}
Context 'ShouldProcess' {
It 'Supports WhatIf' {
(Get-Command Get-Something).Parameters.ContainsKey('WhatIf') | Should -Be $true
{ Get-Something -Data 'value' -WhatIf } | Should -Not -Throw
}
}
}