Compare commits
77 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
5c60f39dad | ||
|
399288b10a | ||
|
87d0aaaea6 | ||
|
8301b8cdbe | ||
|
3f4166e98a | ||
|
7582511dd5 | ||
|
20afb8d83e | ||
|
c378f5d119 | ||
|
3a37d465e8 | ||
|
531cedc0f6 | ||
|
54f9e086a9 | ||
|
d1555e1d25 | ||
|
ac8014ae77 | ||
|
fc9923b980 | ||
|
290540b25a | ||
|
b064f9f271 | ||
|
cafcaf2671 | ||
|
129bb33a99 | ||
|
8505439516 | ||
|
686272d4e0 | ||
|
f445893aed | ||
|
050ea83acd | ||
|
deec4c4f5e | ||
|
6930673209 | ||
|
87db439d66 | ||
|
3d84a86793 | ||
|
dbc577bc67 | ||
|
d1a5cb8d73 | ||
|
c1e94ff3bc | ||
|
532cb942e8 | ||
|
2d93422027 | ||
|
75faf04ea6 | ||
|
c7cdaa4bf6 | ||
|
d511ea7b27 | ||
|
5b3c68a8f9 | ||
|
3883e33a4a | ||
|
398ce397f5 | ||
|
776b0bf2ec | ||
|
8d03d1825b | ||
|
26fa3a8922 | ||
|
c918f0203e | ||
|
c752b7e4fd | ||
|
3cf76bb6b3 | ||
|
36cb3f1944 | ||
|
c122174cb7 | ||
|
d5c64910ab | ||
|
77c74432fe | ||
|
b4c0993240 | ||
|
e96a5a9d48 | ||
|
2148a37b35 | ||
|
0196607f69 | ||
|
f5a3f0e460 | ||
|
5ed1e1de35 | ||
|
0d049c6dcb | ||
|
4b28258b3e | ||
|
b8690ddb44 | ||
|
dc88df6eef | ||
|
d0c3d907b9 | ||
|
20ee994ebc | ||
|
0d764e6152 | ||
|
0ae69e5b56 | ||
|
ccb02d84d2 | ||
|
5f4217d264 | ||
|
5e9fbfd690 | ||
|
fbe22abe9c | ||
|
283b278524 | ||
|
2f8d7b358a | ||
|
b93df00334 | ||
|
d5faf071b9 | ||
|
a1a2ecbd49 | ||
|
f4ae24b99f | ||
|
652e5ead75 | ||
|
71736bfb43 | ||
|
4bc75db1dc | ||
|
37fbf2b32a | ||
|
05dbf4661c | ||
|
5f5b220fd4 |
49
.github/workflows/powershell.yml
vendored
Normal file
49
.github/workflows/powershell.yml
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
# This workflow uses actions that are not certified by GitHub.
|
||||
# They are provided by a third-party and are governed by
|
||||
# separate terms of service, privacy policy, and support
|
||||
# documentation.
|
||||
#
|
||||
# https://github.com/microsoft/action-psscriptanalyzer
|
||||
# For more information on PSScriptAnalyzer in general, see
|
||||
# https://github.com/PowerShell/PSScriptAnalyzer
|
||||
|
||||
name: PSScriptAnalyzer
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "main" ]
|
||||
pull_request:
|
||||
branches: [ "main" ]
|
||||
schedule:
|
||||
- cron: '33 20 * * 4'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build:
|
||||
permissions:
|
||||
contents: read # for actions/checkout to fetch code
|
||||
security-events: write # for github/codeql-action/upload-sarif to upload SARIF results
|
||||
actions: read # only required for a private repository by github/codeql-action/upload-sarif to get the Action run status
|
||||
name: PSScriptAnalyzer
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Run PSScriptAnalyzer
|
||||
uses: microsoft/psscriptanalyzer-action@6b2948b1944407914a58661c49941824d149734f
|
||||
with:
|
||||
# Check https://github.com/microsoft/action-psscriptanalyzer for more info about the options.
|
||||
# The below set up runs PSScriptAnalyzer to your entire repository and runs some basic security rules.
|
||||
path: .\
|
||||
recurse: true
|
||||
# Include your own basic security rules. Removing this option will run all the rules
|
||||
includeRule: '"PSAvoidGlobalAliases", "PSAvoidUsingConvertToSecureStringWithPlainText"'
|
||||
output: results.sarif
|
||||
|
||||
# Upload the SARIF file generated in the previous step
|
||||
- name: Upload SARIF results file
|
||||
uses: github/codeql-action/upload-sarif@v2
|
||||
with:
|
||||
sarif_file: results.sarif
|
1
.gitignore
vendored
1
.gitignore
vendored
@@ -15,3 +15,4 @@ output/
|
||||
markdownissues.txt
|
||||
node_modules
|
||||
package-lock.json
|
||||
Aligned.xlsx
|
39
CHANGELOG.md
39
CHANGELOG.md
@@ -6,6 +6,44 @@ The format is based on and uses the types of changes according to [Keep a Change
|
||||
|
||||
### Added
|
||||
|
||||
- Test definitions filter function.
|
||||
- Logging function for future use.
|
||||
- Test grade written to console.
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated sync function to include connection info.
|
||||
- Refactored connect/disconnect functions to evaluate needed connections.
|
||||
|
||||
## [0.1.3] - 2024-05-28
|
||||
|
||||
### Added
|
||||
|
||||
- Array list to store the results of the audit.
|
||||
- Arraylist tests and helper template.
|
||||
- New testing function.
|
||||
- Missing properties to CSV.
|
||||
|
||||
### Changed
|
||||
|
||||
- Refactored object initialization to source `RecDescription`, `CISControl`, and `CISDescription` properties from the CSV.
|
||||
- Added `Automated` and `Connection` properties to the output object.
|
||||
- All test functions aligned with the test-template.
|
||||
- Initialize-CISAuditResult refactored to use global test definitions.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Corrected test-template.
|
||||
- Details added to pass.
|
||||
|
||||
### Docs
|
||||
|
||||
- Updated comments and documentation for new functions.
|
||||
|
||||
## [0.1.2] - 2024-04-29
|
||||
|
||||
### Added
|
||||
|
||||
- Automated and organized CSV testing and added test 1.1.1.
|
||||
- Functions to merge tests into an Excel benchmark.
|
||||
- Public function for merging tests.
|
||||
@@ -24,6 +62,7 @@ The format is based on and uses the types of changes according to [Keep a Change
|
||||
|
||||
- Updated comments for new functions.
|
||||
- Updated help documentation.
|
||||
- Updated online link in public function.
|
||||
|
||||
## [0.1.1] - 2024-04-02
|
||||
|
||||
|
BIN
docs/index.html
BIN
docs/index.html
Binary file not shown.
@@ -4,10 +4,10 @@ Import-Module .\output\module\M365FoundationsCISReport\*\*.psd1
|
||||
|
||||
|
||||
<#
|
||||
$ver = "v0.1.1"
|
||||
$ver = "v0.1.3"
|
||||
git checkout main
|
||||
git pull origin main
|
||||
git tag -a $ver -m "Release version $ver Bugfix Update"
|
||||
git tag -a $ver -m "Release version $ver refactor Update"
|
||||
git push origin $ver
|
||||
"Fix: PR #37"
|
||||
git push origin $ver
|
||||
|
97
helpers/CIS 365 v3.0.0 Controls/Test-Template.ps1
Normal file
97
helpers/CIS 365 v3.0.0 Controls/Test-Template.ps1
Normal file
@@ -0,0 +1,97 @@
|
||||
function Test-Template {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
# Parameters can be added if needed
|
||||
)
|
||||
|
||||
begin {
|
||||
# Initialization code, if needed
|
||||
# Load necessary scripts, define variables, etc.
|
||||
}
|
||||
|
||||
process {
|
||||
# Fetch relevant data
|
||||
# Example: $data = Get-SomeData
|
||||
|
||||
# Process the data to evaluate compliance
|
||||
# Example: $compliantItems = $data | Where-Object { $_.Property -eq 'ExpectedValue' }
|
||||
# Example: $nonCompliantItems = $data | Where-Object { $_.Property -ne 'ExpectedValue' }
|
||||
|
||||
# Prepare failure reasons for non-compliant items
|
||||
$failureReasons = $nonCompliantItems | ForEach-Object {
|
||||
# Example: "Item: $($_.Name) - Reason: Missing expected value"
|
||||
}
|
||||
$failureReasons = $failureReasons -join "`n"
|
||||
|
||||
# Prepare details for non-compliant items
|
||||
$nonCompliantDetails = $nonCompliantItems | ForEach-Object {
|
||||
# Example: "$($_.Name) - Value: $($_.Property)"
|
||||
}
|
||||
$nonCompliantDetails = $nonCompliantDetails -join "`n"
|
||||
|
||||
# Prepare details based on compliance
|
||||
$details = if ($nonCompliantItems) {
|
||||
"Non-Compliant Items: $($nonCompliantItems.Count)`nDetails:`n$nonCompliantDetails"
|
||||
} else {
|
||||
"Compliant Items: $($compliantItems.Count)"
|
||||
}
|
||||
|
||||
# Create and populate the CISAuditResult object
|
||||
$auditResult = [CISAuditResult]::new()
|
||||
$auditResult.Status = if ($nonCompliantItems) { 'Fail' } else { 'Pass' }
|
||||
$auditResult.ELevel = 'E3' # Modify as needed
|
||||
$auditResult.ProfileLevel = 'L1' # Modify as needed
|
||||
$auditResult.Rec = '1.1.1' # Modify as needed
|
||||
$auditResult.RecDescription = "Description of the recommendation" # Modify as needed
|
||||
$auditResult.CISControlVer = 'v8' # Modify as needed
|
||||
$auditResult.CISControl = "5.4" # Modify as needed
|
||||
$auditResult.CISDescription = "Description of the CIS control" # Modify as needed
|
||||
$auditResult.IG1 = $true # Modify as needed
|
||||
$auditResult.IG2 = $true # Modify as needed
|
||||
$auditResult.IG3 = $true # Modify as needed
|
||||
$auditResult.Result = $nonCompliantItems.Count -eq 0
|
||||
$auditResult.Details = $details
|
||||
$auditResult.FailureReason = if ($nonCompliantItems) {
|
||||
"Non-compliant items:`n$failureReasons"
|
||||
} else {
|
||||
"N/A"
|
||||
}
|
||||
|
||||
# Example output object for a pass result
|
||||
# Status : Pass
|
||||
# ELevel : E3
|
||||
# ProfileLevel : L2
|
||||
# Rec : 8.1.1
|
||||
# RecDescription : Ensure external file sharing in Teams is enabled for only approved cloud storage services
|
||||
# CISControlVer : v8
|
||||
# CISControl : 3.3
|
||||
# CISDescription : Configure Data Access Control Lists
|
||||
# IG1 : True
|
||||
# IG2 : True
|
||||
# IG3 : True
|
||||
# Result : True
|
||||
# Details : Compliant Items: 5
|
||||
# FailureReason : N/A
|
||||
|
||||
# Example output object for a fail result
|
||||
# Status : Fail
|
||||
# ELevel : E3
|
||||
# ProfileLevel : L2
|
||||
# Rec : 8.1.1
|
||||
# RecDescription : Ensure external file sharing in Teams is enabled for only approved cloud storage services
|
||||
# CISControlVer : v8
|
||||
# CISControl : 3.3
|
||||
# CISDescription : Configure Data Access Control Lists
|
||||
# IG1 : True
|
||||
# IG2 : True
|
||||
# IG3 : True
|
||||
# Result : False
|
||||
# Details : Non-Compliant Items: 2
|
||||
# FailureReason : Non-compliant items:`nUsername | Roles | HybridStatus | Missing Licence
|
||||
}
|
||||
|
||||
end {
|
||||
# Return the audit result
|
||||
return $auditResult
|
||||
}
|
||||
}
|
@@ -2,6 +2,8 @@ class CISAuditResult {
|
||||
[string]$Status
|
||||
[string]$ELevel
|
||||
[string]$ProfileLevel
|
||||
[bool]$Automated
|
||||
[string]$Connection
|
||||
[string]$Rec
|
||||
[string]$RecDescription
|
||||
[string]$CISControlVer = 'v8'
|
||||
|
@@ -1,56 +1,58 @@
|
||||
function Connect-M365Suite {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
# Parameter to specify the SharePoint Online Tenant Admin URL
|
||||
[Parameter(Mandatory)]
|
||||
[string]$TenantAdminUrl
|
||||
[string]$TenantAdminUrl,
|
||||
|
||||
[Parameter(Mandatory)]
|
||||
[string[]]$RequiredConnections
|
||||
)
|
||||
$VerbosePreference = "SilentlyContinue"
|
||||
|
||||
$VerbosePreference = "SilentlyContinue"
|
||||
|
||||
try {
|
||||
if ($RequiredConnections -contains "AzureAD" -or $RequiredConnections -contains "AzureAD | EXO") {
|
||||
Write-Host "Connecting to Azure Active Directory..." -ForegroundColor Cyan
|
||||
Connect-AzureAD | Out-Null
|
||||
Write-Host "Successfully connected to Azure Active Directory." -ForegroundColor Green
|
||||
}
|
||||
|
||||
# Attempt to connect to Azure Active Directory
|
||||
Write-Host "Connecting to Azure Active Directory..." -ForegroundColor Cyan
|
||||
Connect-AzureAD | Out-Null
|
||||
Write-Host "Successfully connected to Azure Active Directory." -ForegroundColor Green
|
||||
|
||||
# Attempt to connect to Exchange Online
|
||||
Write-Host "Connecting to Exchange Online..." -ForegroundColor Cyan
|
||||
Connect-ExchangeOnline | Out-Null
|
||||
Write-Host "Successfully connected to Exchange Online." -ForegroundColor Green
|
||||
try {
|
||||
# Attempt to connect to Microsoft Graph with specified scopes
|
||||
if ($RequiredConnections -contains "Microsoft Graph") {
|
||||
Write-Host "Connecting to Microsoft Graph with scopes: Directory.Read.All, Domain.Read.All, Policy.Read.All, Organization.Read.All" -ForegroundColor Cyan
|
||||
Connect-MgGraph -Scopes "Directory.Read.All", "Domain.Read.All", "Policy.Read.All", "Organization.Read.All" -NoWelcome | Out-Null
|
||||
Write-Host "Successfully connected to Microsoft Graph with specified scopes." -ForegroundColor Green
|
||||
}
|
||||
catch {
|
||||
Write-Host "Failed to connect o MgGraph, attempting device auth." -ForegroundColor Yellow
|
||||
# Attempt to connect to Microsoft Graph with specified scopes
|
||||
Write-Host "Connecting to Microsoft Graph using device auth with scopes: Directory.Read.All, Domain.Read.All, Policy.Read.All, Organization.Read.All" -ForegroundColor Cyan
|
||||
Connect-MgGraph -Scopes "Directory.Read.All", "Domain.Read.All", "Policy.Read.All", "Organization.Read.All" -UseDeviceCode -NoWelcome | Out-Null
|
||||
Write-Host "Successfully connected to Microsoft Graph with specified scopes." -ForegroundColor Green
|
||||
try {
|
||||
Connect-MgGraph -Scopes "Directory.Read.All", "Domain.Read.All", "Policy.Read.All", "Organization.Read.All" -NoWelcome | Out-Null
|
||||
Write-Host "Successfully connected to Microsoft Graph with specified scopes." -ForegroundColor Green
|
||||
}
|
||||
catch {
|
||||
Write-Host "Failed to connect to MgGraph, attempting device auth." -ForegroundColor Yellow
|
||||
Connect-MgGraph -Scopes "Directory.Read.All", "Domain.Read.All", "Policy.Read.All", "Organization.Read.All" -UseDeviceCode -NoWelcome | Out-Null
|
||||
Write-Host "Successfully connected to Microsoft Graph with specified scopes." -ForegroundColor Green
|
||||
}
|
||||
}
|
||||
|
||||
# Validate SharePoint Online Tenant Admin URL
|
||||
if (-not $TenantAdminUrl) {
|
||||
throw "SharePoint Online Tenant Admin URL is required."
|
||||
if ($RequiredConnections -contains "EXO" -or $RequiredConnections -contains "AzureAD | EXO" -or $RequiredConnections -contains "Microsoft Teams | EXO") {
|
||||
Write-Host "Connecting to Exchange Online..." -ForegroundColor Cyan
|
||||
Connect-ExchangeOnline | Out-Null
|
||||
Write-Host "Successfully connected to Exchange Online." -ForegroundColor Green
|
||||
}
|
||||
|
||||
# Attempt to connect to SharePoint Online
|
||||
Write-Host "Connecting to SharePoint Online..." -ForegroundColor Cyan
|
||||
Connect-SPOService -Url $TenantAdminUrl | Out-Null
|
||||
Write-Host "Successfully connected to SharePoint Online." -ForegroundColor Green
|
||||
if ($RequiredConnections -contains "SPO") {
|
||||
Write-Host "Connecting to SharePoint Online..." -ForegroundColor Cyan
|
||||
Connect-SPOService -Url $TenantAdminUrl | Out-Null
|
||||
Write-Host "Successfully connected to SharePoint Online." -ForegroundColor Green
|
||||
}
|
||||
|
||||
# Attempt to connect to Microsoft Teams
|
||||
Write-Host "Connecting to Microsoft Teams..." -ForegroundColor Cyan
|
||||
Connect-MicrosoftTeams | Out-Null
|
||||
Write-Host "Successfully connected to Microsoft Teams." -ForegroundColor Green
|
||||
if ($RequiredConnections -contains "Microsoft Teams" -or $RequiredConnections -contains "Microsoft Teams | EXO") {
|
||||
Write-Host "Connecting to Microsoft Teams..." -ForegroundColor Cyan
|
||||
Connect-MicrosoftTeams | Out-Null
|
||||
Write-Host "Successfully connected to Microsoft Teams." -ForegroundColor Green
|
||||
}
|
||||
}
|
||||
catch {
|
||||
$VerbosePreference = "Continue"
|
||||
Write-Host "There was an error establishing one or more connections: $_" -ForegroundColor Red
|
||||
throw $_
|
||||
}
|
||||
|
||||
$VerbosePreference = "Continue"
|
||||
}
|
||||
|
||||
|
@@ -1,39 +1,59 @@
|
||||
function Disconnect-M365Suite {
|
||||
param (
|
||||
[Parameter(Mandatory)]
|
||||
[string[]]$RequiredConnections
|
||||
)
|
||||
|
||||
# Clean up sessions
|
||||
try {
|
||||
Write-Host "Disconnecting from Exchange Online..." -ForegroundColor Green
|
||||
Disconnect-ExchangeOnline -Confirm:$false | Out-Null
|
||||
if ($RequiredConnections -contains "EXO" -or $RequiredConnections -contains "AzureAD | EXO" -or $RequiredConnections -contains "Microsoft Teams | EXO") {
|
||||
Write-Host "Disconnecting from Exchange Online..." -ForegroundColor Green
|
||||
Disconnect-ExchangeOnline -Confirm:$false | Out-Null
|
||||
}
|
||||
}
|
||||
catch {
|
||||
Write-Warning "Failed to disconnect from Exchange Online: $_"
|
||||
}
|
||||
|
||||
try {
|
||||
Write-Host "Disconnecting from Azure AD..." -ForegroundColor Green
|
||||
Disconnect-AzureAD | Out-Null
|
||||
if ($RequiredConnections -contains "AzureAD" -or $RequiredConnections -contains "AzureAD | EXO") {
|
||||
Write-Host "Disconnecting from Azure AD..." -ForegroundColor Green
|
||||
Disconnect-AzureAD | Out-Null
|
||||
}
|
||||
}
|
||||
catch {
|
||||
Write-Warning "Failed to disconnect from Azure AD: $_"
|
||||
}
|
||||
|
||||
try {
|
||||
Write-Host "Disconnecting from Microsoft Graph..." -ForegroundColor Green
|
||||
Disconnect-MgGraph | Out-Null
|
||||
if ($RequiredConnections -contains "Microsoft Graph") {
|
||||
Write-Host "Disconnecting from Microsoft Graph..." -ForegroundColor Green
|
||||
Disconnect-MgGraph | Out-Null
|
||||
}
|
||||
}
|
||||
catch {
|
||||
Write-Warning "Failed to disconnect from Microsoft Graph: $_"
|
||||
}
|
||||
|
||||
try {
|
||||
Write-Host "Disconnecting from SharePoint Online..." -ForegroundColor Green
|
||||
Disconnect-SPOService | Out-Null
|
||||
if ($RequiredConnections -contains "SPO") {
|
||||
Write-Host "Disconnecting from SharePoint Online..." -ForegroundColor Green
|
||||
Disconnect-SPOService | Out-Null
|
||||
}
|
||||
}
|
||||
catch {
|
||||
Write-Warning "Failed to disconnect from SharePoint Online: $_"
|
||||
}
|
||||
|
||||
try {
|
||||
Write-Host "Disconnecting from Microsoft Teams..." -ForegroundColor Green
|
||||
Disconnect-MicrosoftTeams | Out-Null
|
||||
if ($RequiredConnections -contains "Microsoft Teams" -or $RequiredConnections -contains "Microsoft Teams | EXO") {
|
||||
Write-Host "Disconnecting from Microsoft Teams..." -ForegroundColor Green
|
||||
Disconnect-MicrosoftTeams | Out-Null
|
||||
}
|
||||
}
|
||||
catch {
|
||||
Write-Warning "Failed to disconnect from Microsoft Teams: $_"
|
||||
}
|
||||
Write-Host "All sessions have been disconnected." -ForegroundColor Green
|
||||
|
||||
Write-Host "All necessary sessions have been disconnected." -ForegroundColor Green
|
||||
}
|
63
source/Private/Get-TestDefinitionsObject.ps1
Normal file
63
source/Private/Get-TestDefinitionsObject.ps1
Normal file
@@ -0,0 +1,63 @@
|
||||
function Get-TestDefinitionsObject {
|
||||
param (
|
||||
[Parameter(Mandatory = $true)]
|
||||
[object[]]$TestDefinitions,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$ParameterSetName,
|
||||
|
||||
[string]$ELevel,
|
||||
[string]$ProfileLevel,
|
||||
[string[]]$IncludeRecommendation,
|
||||
[string[]]$SkipRecommendation
|
||||
)
|
||||
|
||||
Write-Verbose "Initial test definitions count: $($TestDefinitions.Count)"
|
||||
|
||||
switch ($ParameterSetName) {
|
||||
'ELevelFilter' {
|
||||
Write-Verbose "Applying ELevelFilter"
|
||||
if ($null -ne $ELevel -and $null -ne $ProfileLevel) {
|
||||
Write-Verbose "Filtering on ELevel = $ELevel and ProfileLevel = $ProfileLevel"
|
||||
$TestDefinitions = $TestDefinitions | Where-Object {
|
||||
$_.ELevel -eq $ELevel -and $_.ProfileLevel -eq $ProfileLevel
|
||||
}
|
||||
}
|
||||
elseif ($null -ne $ELevel) {
|
||||
Write-Verbose "Filtering on ELevel = $ELevel"
|
||||
$TestDefinitions = $TestDefinitions | Where-Object {
|
||||
$_.ELevel -eq $ELevel
|
||||
}
|
||||
}
|
||||
elseif ($null -ne $ProfileLevel) {
|
||||
Write-Verbose "Filtering on ProfileLevel = $ProfileLevel"
|
||||
$TestDefinitions = $TestDefinitions | Where-Object {
|
||||
$_.ProfileLevel -eq $ProfileLevel
|
||||
}
|
||||
}
|
||||
}
|
||||
'IG1Filter' {
|
||||
Write-Verbose "Applying IG1Filter"
|
||||
$TestDefinitions = $TestDefinitions | Where-Object { $_.IG1 -eq 'TRUE' }
|
||||
}
|
||||
'IG2Filter' {
|
||||
Write-Verbose "Applying IG2Filter"
|
||||
$TestDefinitions = $TestDefinitions | Where-Object { $_.IG2 -eq 'TRUE' }
|
||||
}
|
||||
'IG3Filter' {
|
||||
Write-Verbose "Applying IG3Filter"
|
||||
$TestDefinitions = $TestDefinitions | Where-Object { $_.IG3 -eq 'TRUE' }
|
||||
}
|
||||
'RecFilter' {
|
||||
Write-Verbose "Applying RecFilter"
|
||||
$TestDefinitions = $TestDefinitions | Where-Object { $IncludeRecommendation -contains $_.Rec }
|
||||
}
|
||||
'SkipRecFilter' {
|
||||
Write-Verbose "Applying SkipRecFilter"
|
||||
$TestDefinitions = $TestDefinitions | Where-Object { $SkipRecommendation -notcontains $_.Rec }
|
||||
}
|
||||
}
|
||||
|
||||
Write-Verbose "Filtered test definitions count: $($TestDefinitions.Count)"
|
||||
return $TestDefinitions
|
||||
}
|
45
source/Private/Initialize-CISAuditResult.ps1
Normal file
45
source/Private/Initialize-CISAuditResult.ps1
Normal file
@@ -0,0 +1,45 @@
|
||||
function Initialize-CISAuditResult {
|
||||
param (
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$Rec,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[bool]$Result,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$Status,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$Details,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$FailureReason
|
||||
)
|
||||
|
||||
# Import the test definitions CSV file
|
||||
$testDefinitions = $script:TestDefinitionsObject
|
||||
|
||||
# Find the row that matches the provided recommendation (Rec)
|
||||
$testDefinition = $testDefinitions | Where-Object { $_.Rec -eq $Rec }
|
||||
|
||||
# Create an instance of CISAuditResult and populate it
|
||||
$auditResult = [CISAuditResult]::new()
|
||||
$auditResult.Rec = $Rec
|
||||
$auditResult.ELevel = $testDefinition.ELevel
|
||||
$auditResult.ProfileLevel = $testDefinition.ProfileLevel
|
||||
$auditResult.IG1 = [bool]::Parse($testDefinition.IG1)
|
||||
$auditResult.IG2 = [bool]::Parse($testDefinition.IG2)
|
||||
$auditResult.IG3 = [bool]::Parse($testDefinition.IG3)
|
||||
$auditResult.RecDescription = $testDefinition.RecDescription
|
||||
$auditResult.CISControl = $testDefinition.CISControl
|
||||
$auditResult.CISDescription = $testDefinition.CISDescription
|
||||
$auditResult.Automated = [bool]::Parse($testDefinition.Automated)
|
||||
$auditResult.Connection = $testDefinition.Connection
|
||||
$auditResult.CISControlVer = 'v8'
|
||||
$auditResult.Result = $Result
|
||||
$auditResult.Status = $Status
|
||||
$auditResult.Details = $Details
|
||||
$auditResult.FailureReason = $FailureReason
|
||||
|
||||
return $auditResult
|
||||
}
|
@@ -23,11 +23,10 @@ function Merge-CISExcelAndCsvData {
|
||||
foreach ($property in $excelItem.PSObject.Properties) {
|
||||
$newObject | Add-Member -MemberType NoteProperty -Name $property.Name -Value $property.Value
|
||||
}
|
||||
|
||||
$newObject | Add-Member -MemberType NoteProperty -Name 'CSV_Connection' -Value $csvRow.Connection
|
||||
$newObject | Add-Member -MemberType NoteProperty -Name 'CSV_Status' -Value $csvRow.Status
|
||||
$newObject | Add-Member -MemberType NoteProperty -Name 'CSV_Details' -Value $csvRow.Details
|
||||
$newObject | Add-Member -MemberType NoteProperty -Name 'CSV_FailureReason' -Value $csvRow.FailureReason
|
||||
|
||||
return $newObject
|
||||
}
|
||||
|
||||
@@ -37,7 +36,7 @@ function Merge-CISExcelAndCsvData {
|
||||
if ($csvRow) {
|
||||
CreateMergedObject -excelItem $item -csvRow $csvRow
|
||||
} else {
|
||||
CreateMergedObject -excelItem $item -csvRow ([PSCustomObject]@{Status=$null; Details=$null; FailureReason=$null})
|
||||
CreateMergedObject -excelItem $item -csvRow ([PSCustomObject]@{Connection=$null;Status=$null; Details=$null; FailureReason=$null })
|
||||
}
|
||||
}
|
||||
|
||||
|
22
source/Private/Test-IsAdmin.ps1
Normal file
22
source/Private/Test-IsAdmin.ps1
Normal file
@@ -0,0 +1,22 @@
|
||||
function Test-IsAdmin {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Checks if the current user is an administrator on the machine.
|
||||
.DESCRIPTION
|
||||
This private function returns a Boolean value indicating whether
|
||||
the current user has administrator privileges on the machine.
|
||||
It does this by creating a new WindowsPrincipal object, passing
|
||||
in a WindowsIdentity object representing the current user, and
|
||||
then checking if that principal is in the Administrator role.
|
||||
.INPUTS
|
||||
None.
|
||||
.OUTPUTS
|
||||
Boolean. Returns True if the current user is an administrator, and False otherwise.
|
||||
.EXAMPLE
|
||||
PS C:\> Test-IsAdmin
|
||||
True
|
||||
#>
|
||||
|
||||
# Create a new WindowsPrincipal object for the current user and check if it is in the Administrator role
|
||||
(New-Object Security.Principal.WindowsPrincipal ([Security.Principal.WindowsIdentity]::GetCurrent())).IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator)
|
||||
}
|
212
source/Private/Write-AuditLog.ps1
Normal file
212
source/Private/Write-AuditLog.ps1
Normal file
@@ -0,0 +1,212 @@
|
||||
function Write-AuditLog {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Writes log messages to the console and updates the script-wide log variable.
|
||||
.DESCRIPTION
|
||||
The Write-AuditLog function writes log messages to the console based on the severity (Verbose, Warning, or Error) and updates
|
||||
the script-wide log variable ($script:LogString) with the log entry. You can use the Start, End, and EndFunction switches to
|
||||
manage the lifecycle of the logging.
|
||||
.INPUTS
|
||||
System.String
|
||||
You can pipe a string to the Write-AuditLog function as the Message parameter.
|
||||
You can also pipe an object with a Severity property as the Severity parameter.
|
||||
.OUTPUTS
|
||||
None
|
||||
The Write-AuditLog function doesn't output any objects to the pipeline. It writes messages to the console and updates the
|
||||
script-wide log variable ($script:LogString).
|
||||
.PARAMETER BeginFunction
|
||||
Sets the message to "Begin [FunctionName] function log.", where FunctionName is the name of the calling function, and adds it to the log variable.
|
||||
.PARAMETER Message
|
||||
The message string to log.
|
||||
.PARAMETER Severity
|
||||
The severity of the log message. Accepted values are 'Information', 'Warning', and 'Error'. Defaults to 'Information'.
|
||||
.PARAMETER Start
|
||||
Initializes the script-wide log variable and sets the message to "Begin [FunctionName] Log.", where FunctionName is the name of the calling function.
|
||||
.PARAMETER End
|
||||
Sets the message to "End Log" and exports the log to a CSV file if the OutputPath parameter is provided.
|
||||
.PARAMETER EndFunction
|
||||
Sets the message to "End [FunctionName] log.", where FunctionName is the name of the calling function, and adds it to the log variable.
|
||||
.PARAMETER OutputPath
|
||||
The file path for exporting the log to a CSV file when using the End switch.
|
||||
.EXAMPLE
|
||||
Write-AuditLog -Message "This is a test message."
|
||||
|
||||
Writes a test message with the default severity (Information) to the console and adds it to the log variable.
|
||||
.EXAMPLE
|
||||
Write-AuditLog -Message "This is a warning message." -Severity "Warning"
|
||||
|
||||
Writes a warning message to the console and adds it to the log variable.
|
||||
.EXAMPLE
|
||||
Write-AuditLog -Start
|
||||
|
||||
Initializes the log variable and sets the message to "Begin [FunctionName] Log.", where FunctionName is the name of the calling function.
|
||||
.EXAMPLE
|
||||
Write-AuditLog -BeginFunction
|
||||
|
||||
Sets the message to "Begin [FunctionName] function log.", where FunctionName is the name of the calling function, and adds it to the log variable.
|
||||
.EXAMPLE
|
||||
Write-AuditLog -EndFunction
|
||||
|
||||
Sets the message to "End [FunctionName] log.", where FunctionName is the name of the calling function, and adds it to the log variable.
|
||||
.EXAMPLE
|
||||
Write-AuditLog -End -OutputPath "C:\Logs\auditlog.csv"
|
||||
|
||||
Sets the message to "End Log", adds it to the log variable, and exports the log to a CSV file.
|
||||
.NOTES
|
||||
Author: DrIOSx
|
||||
#>
|
||||
[CmdletBinding(DefaultParameterSetName = 'Default')]
|
||||
param(
|
||||
###
|
||||
[Parameter(
|
||||
Mandatory = $false,
|
||||
HelpMessage = 'Input a Message string.',
|
||||
Position = 0,
|
||||
ParameterSetName = 'Default',
|
||||
ValueFromPipeline = $true
|
||||
)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]$Message,
|
||||
###
|
||||
[Parameter(
|
||||
Mandatory = $false,
|
||||
HelpMessage = 'Information, Warning or Error.',
|
||||
Position = 1,
|
||||
ParameterSetName = 'Default',
|
||||
ValueFromPipelineByPropertyName = $true
|
||||
)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[ValidateSet('Information', 'Warning', 'Error')]
|
||||
[string]$Severity = 'Information',
|
||||
###
|
||||
[Parameter(
|
||||
Mandatory = $false,
|
||||
ParameterSetName = 'End'
|
||||
)]
|
||||
[switch]$End,
|
||||
###
|
||||
[Parameter(
|
||||
Mandatory = $false,
|
||||
ParameterSetName = 'BeginFunction'
|
||||
)]
|
||||
[switch]$BeginFunction,
|
||||
[Parameter(
|
||||
Mandatory = $false,
|
||||
ParameterSetName = 'EndFunction'
|
||||
)]
|
||||
[switch]$EndFunction,
|
||||
###
|
||||
[Parameter(
|
||||
Mandatory = $false,
|
||||
ParameterSetName = 'Start'
|
||||
)]
|
||||
[switch]$Start,
|
||||
###
|
||||
[Parameter(
|
||||
Mandatory = $false,
|
||||
ParameterSetName = 'End'
|
||||
)]
|
||||
[string]$OutputPath
|
||||
)
|
||||
begin {
|
||||
$ErrorActionPreference = "SilentlyContinue"
|
||||
# Define variables to hold information about the command that was invoked.
|
||||
$ModuleName = $Script:MyInvocation.MyCommand.Name -replace '\..*'
|
||||
$callStack = Get-PSCallStack
|
||||
if ($callStack.Count -gt 1) {
|
||||
$FuncName = $callStack[1].Command
|
||||
} else {
|
||||
$FuncName = "DirectCall" # Or any other default name you prefer
|
||||
}
|
||||
#Write-Verbose "Funcname Name is $FuncName!" -Verbose
|
||||
$ModuleVer = $MyInvocation.MyCommand.Version.ToString()
|
||||
# Set the error action preference to continue.
|
||||
$ErrorActionPreference = "Continue"
|
||||
}
|
||||
process {
|
||||
try {
|
||||
if (-not $Start -and -not (Test-Path variable:script:LogString)) {
|
||||
throw "The logging variable is not initialized. Please call Write-AuditLog with the -Start switch or ensure $script:LogString is set."
|
||||
}
|
||||
$Function = $($FuncName + '.v' + $ModuleVer)
|
||||
if ($Start) {
|
||||
$script:LogString = @()
|
||||
$Message = '+++ Begin Log | ' + $Function + ' |'
|
||||
}
|
||||
elseif ($BeginFunction) {
|
||||
$Message = '>>> Begin Function Log | ' + $Function + ' |'
|
||||
}
|
||||
$logEntry = [pscustomobject]@{
|
||||
Time = ((Get-Date).ToString('yyyy-MM-dd hh:mmTss'))
|
||||
Module = $ModuleName
|
||||
PSVersion = ($PSVersionTable.PSVersion).ToString()
|
||||
PSEdition = ($PSVersionTable.PSEdition).ToString()
|
||||
IsAdmin = $(Test-IsAdmin)
|
||||
User = "$Env:USERDOMAIN\$Env:USERNAME"
|
||||
HostName = $Env:COMPUTERNAME
|
||||
InvokedBy = $Function
|
||||
Severity = $Severity
|
||||
Message = $Message
|
||||
RunID = -1
|
||||
}
|
||||
if ($BeginFunction) {
|
||||
$maxRunID = ($script:LogString | Where-Object { $_.InvokedBy -eq $Function } | Measure-Object -Property RunID -Maximum).Maximum
|
||||
if ($null -eq $maxRunID) { $maxRunID = -1 }
|
||||
$logEntry.RunID = $maxRunID + 1
|
||||
}
|
||||
else {
|
||||
$lastRunID = ($script:LogString | Where-Object { $_.InvokedBy -eq $Function } | Select-Object -Last 1).RunID
|
||||
if ($null -eq $lastRunID) { $lastRunID = 0 }
|
||||
$logEntry.RunID = $lastRunID
|
||||
}
|
||||
if ($EndFunction) {
|
||||
$FunctionStart = "$((($script:LogString | Where-Object {$_.InvokedBy -eq $Function -and $_.RunId -eq $lastRunID } | Sort-Object Time)[0]).Time)"
|
||||
$startTime = ([DateTime]::ParseExact("$FunctionStart", 'yyyy-MM-dd hh:mmTss', $null))
|
||||
$endTime = Get-Date
|
||||
$timeTaken = $endTime - $startTime
|
||||
$Message = '<<< End Function Log | ' + $Function + ' | Runtime: ' + "$($timeTaken.Minutes) min $($timeTaken.Seconds) sec"
|
||||
$logEntry.Message = $Message
|
||||
}
|
||||
elseif ($End) {
|
||||
$startTime = ([DateTime]::ParseExact($($script:LogString[0].Time), 'yyyy-MM-dd hh:mmTss', $null))
|
||||
$endTime = Get-Date
|
||||
$timeTaken = $endTime - $startTime
|
||||
$Message = '--- End Log | ' + $Function + ' | Runtime: ' + "$($timeTaken.Minutes) min $($timeTaken.Seconds) sec"
|
||||
$logEntry.Message = $Message
|
||||
}
|
||||
$script:LogString += $logEntry
|
||||
switch ($Severity) {
|
||||
'Warning' {
|
||||
Write-Warning ('[WARNING] ! ' + $Message)
|
||||
$UserInput = Read-Host "Warning encountered! Do you want to continue? (Y/N)"
|
||||
if ($UserInput -eq 'N') {
|
||||
throw "Script execution stopped by user."
|
||||
}
|
||||
}
|
||||
'Error' { Write-Error ('[ERROR] X - ' + $FuncName + ' ' + $Message) -ErrorAction Continue }
|
||||
'Verbose' { Write-Verbose ('[VERBOSE] ~ ' + $Message) }
|
||||
Default { Write-Information ('[INFO] * ' + $Message) -InformationAction Continue}
|
||||
}
|
||||
}
|
||||
catch {
|
||||
throw "Write-AuditLog encountered an error (process block): $($_)"
|
||||
}
|
||||
|
||||
}
|
||||
end {
|
||||
try {
|
||||
if ($End) {
|
||||
if (-not [string]::IsNullOrEmpty($OutputPath)) {
|
||||
$script:LogString | Export-Csv -Path $OutputPath -NoTypeInformation
|
||||
Write-Verbose "LogPath: $(Split-Path -Path $OutputPath -Parent)"
|
||||
}
|
||||
else {
|
||||
throw "OutputPath is not specified for End action."
|
||||
}
|
||||
}
|
||||
}
|
||||
catch {
|
||||
throw "Error in Write-AuditLog (end block): $($_.Exception.Message)"
|
||||
}
|
||||
}
|
||||
}
|
@@ -36,8 +36,8 @@ function Get-AdminRoleUserLicense {
|
||||
Connect-MgGraph -Scopes "Directory.Read.All", "Domain.Read.All", "Policy.Read.All", "Organization.Read.All" -NoWelcome
|
||||
}
|
||||
|
||||
$adminRoleUsers = @()
|
||||
$userIds = @()
|
||||
$adminRoleUsers = [System.Collections.ArrayList]::new()
|
||||
$userIds = [System.Collections.ArrayList]::new()
|
||||
}
|
||||
|
||||
Process {
|
||||
@@ -50,24 +50,28 @@ function Get-AdminRoleUserLicense {
|
||||
$userDetails = Get-MgUser -UserId $user.PrincipalId -Property "DisplayName, UserPrincipalName, Id, onPremisesSyncEnabled" -ErrorAction SilentlyContinue
|
||||
|
||||
if ($userDetails) {
|
||||
$userIds += $user.PrincipalId
|
||||
$adminRoleUsers += [PSCustomObject]@{
|
||||
RoleName = $role.DisplayName
|
||||
UserName = $userDetails.DisplayName
|
||||
UserPrincipalName = $userDetails.UserPrincipalName
|
||||
UserId = $userDetails.Id
|
||||
HybridUser = $userDetails.onPremisesSyncEnabled
|
||||
Licenses = $null # Initialize as $null
|
||||
}
|
||||
[void]($userIds.Add($user.PrincipalId))
|
||||
[void](
|
||||
$adminRoleUsers.Add(
|
||||
[PSCustomObject]@{
|
||||
RoleName = $role.DisplayName
|
||||
UserName = $userDetails.DisplayName
|
||||
UserPrincipalName = $userDetails.UserPrincipalName
|
||||
UserId = $userDetails.Id
|
||||
HybridUser = $userDetails.onPremisesSyncEnabled
|
||||
Licenses = $null # Initialize as $null
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($userId in $userIds | Select-Object -Unique) {
|
||||
foreach ($userId in $userIds.ToArray() | Select-Object -Unique) {
|
||||
$licenses = Get-MgUserLicenseDetail -UserId $userId -ErrorAction SilentlyContinue
|
||||
if ($licenses) {
|
||||
$licenseList = ($licenses.SkuPartNumber -join '|')
|
||||
$adminRoleUsers | Where-Object { $_.UserId -eq $userId } | ForEach-Object {
|
||||
$adminRoleUsers.ToArray() | Where-Object { $_.UserId -eq $userId } | ForEach-Object {
|
||||
$_.Licenses = $licenseList
|
||||
}
|
||||
}
|
||||
|
@@ -57,9 +57,8 @@
|
||||
- For full license details, visit: https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en
|
||||
- Register for CIS Benchmarks at: https://www.cisecurity.org/cis-benchmarks
|
||||
.LINK
|
||||
Online Version: https://github.com/CriticalSolutionsNetwork/M365FoundationsCISReport
|
||||
https://criticalsolutionsnetwork.github.io/M365FoundationsCISReport/#Invoke-M365SecurityAudit
|
||||
#>
|
||||
|
||||
function Invoke-M365SecurityAudit {
|
||||
[CmdletBinding(SupportsShouldProcess = $true, DefaultParameterSetName = 'Default')]
|
||||
[OutputType([CISAuditResult[]])]
|
||||
@@ -71,28 +70,28 @@ function Invoke-M365SecurityAudit {
|
||||
[string]$DomainName,
|
||||
|
||||
# E-Level with optional ProfileLevel selection
|
||||
[Parameter(ParameterSetName = 'ELevelFilter')]
|
||||
[Parameter(Mandatory = $true, ParameterSetName = 'ELevelFilter')]
|
||||
[ValidateSet('E3', 'E5')]
|
||||
[string]$ELevel,
|
||||
|
||||
[Parameter(ParameterSetName = 'ELevelFilter')]
|
||||
[Parameter(Mandatory = $true, ParameterSetName = 'ELevelFilter')]
|
||||
[ValidateSet('L1', 'L2')]
|
||||
[string]$ProfileLevel,
|
||||
|
||||
# IG Filters, one at a time
|
||||
[Parameter(ParameterSetName = 'IG1Filter')]
|
||||
[Parameter(Mandatory = $true, ParameterSetName = 'IG1Filter')]
|
||||
[switch]$IncludeIG1,
|
||||
|
||||
[Parameter(ParameterSetName = 'IG2Filter')]
|
||||
[Parameter(Mandatory = $true, ParameterSetName = 'IG2Filter')]
|
||||
[switch]$IncludeIG2,
|
||||
|
||||
[Parameter(ParameterSetName = 'IG3Filter')]
|
||||
[Parameter(Mandatory = $true, ParameterSetName = 'IG3Filter')]
|
||||
[switch]$IncludeIG3,
|
||||
|
||||
# Inclusion of specific recommendation numbers
|
||||
[Parameter(ParameterSetName = 'RecFilter')]
|
||||
[Parameter(Mandatory = $true, ParameterSetName = 'RecFilter')]
|
||||
[ValidateSet(
|
||||
'1.1.1','1.1.3', '1.2.1', '1.2.2', '1.3.1', '1.3.3', '1.3.6', '2.1.1', '2.1.2', `
|
||||
'1.1.1', '1.1.3', '1.2.1', '1.2.2', '1.3.1', '1.3.3', '1.3.6', '2.1.1', '2.1.2', `
|
||||
'2.1.3', '2.1.4', '2.1.5', '2.1.6', '2.1.7', '2.1.9', '3.1.1', '5.1.2.3', `
|
||||
'5.1.8.1', '6.1.1', '6.1.2', '6.1.3', '6.2.1', '6.2.2', '6.2.3', '6.3.1', `
|
||||
'6.5.1', '6.5.2', '6.5.3', '7.2.1', '7.2.10', '7.2.2', '7.2.3', '7.2.4', `
|
||||
@@ -103,9 +102,9 @@ function Invoke-M365SecurityAudit {
|
||||
[string[]]$IncludeRecommendation,
|
||||
|
||||
# Exclusion of specific recommendation numbers
|
||||
[Parameter(ParameterSetName = 'SkipRecFilter')]
|
||||
[Parameter(Mandatory = $true, ParameterSetName = 'SkipRecFilter')]
|
||||
[ValidateSet(
|
||||
'1.1.1','1.1.3', '1.2.1', '1.2.2', '1.3.1', '1.3.3', '1.3.6', '2.1.1', '2.1.2', `
|
||||
'1.1.1', '1.1.3', '1.2.1', '1.2.2', '1.3.1', '1.3.3', '1.3.6', '2.1.1', '2.1.2', `
|
||||
'2.1.3', '2.1.4', '2.1.5', '2.1.6', '2.1.7', '2.1.9', '3.1.1', '5.1.2.3', `
|
||||
'5.1.8.1', '6.1.1', '6.1.2', '6.1.3', '6.2.1', '6.2.2', '6.2.3', '6.3.1', `
|
||||
'6.5.1', '6.5.2', '6.5.3', '7.2.1', '7.2.10', '7.2.2', '7.2.3', '7.2.4', `
|
||||
@@ -152,53 +151,30 @@ function Invoke-M365SecurityAudit {
|
||||
# Loop through each required module and assert its availability
|
||||
|
||||
# Establishing connections
|
||||
#if (!($DoNotConnect -or $DoNotTest)) {
|
||||
# Establishing connections
|
||||
if (!($DoNotConnect)) {
|
||||
Connect-M365Suite -TenantAdminUrl $TenantAdminUrl
|
||||
}
|
||||
|
||||
# Load test definitions from CSV
|
||||
$testDefinitionsPath = Join-Path -Path $PSScriptRoot -ChildPath "helper\TestDefinitions.csv"
|
||||
$testDefinitions = Import-Csv -Path $testDefinitionsPath
|
||||
|
||||
# Load the Test Definitions into the script scope for use in other functions
|
||||
$script:TestDefinitionsObject = $testDefinitions
|
||||
# Apply filters based on parameter sets
|
||||
switch ($PSCmdlet.ParameterSetName) {
|
||||
'ELevelFilter' {
|
||||
if ($null -ne $ELevel -and $null -ne $ProfileLevel) {
|
||||
$testDefinitions = $testDefinitions | Where-Object {
|
||||
$_.ELevel -eq $ELevel -and $_.ProfileLevel -eq $ProfileLevel
|
||||
}
|
||||
}
|
||||
elseif ($null -ne $ELevel) {
|
||||
$testDefinitions = $testDefinitions | Where-Object {
|
||||
$_.ELevel -eq $ELevel
|
||||
}
|
||||
}
|
||||
elseif ($null -ne $ProfileLevel) {
|
||||
$testDefinitions = $testDefinitions | Where-Object {
|
||||
$_.ProfileLevel -eq $ProfileLevel
|
||||
}
|
||||
}
|
||||
}
|
||||
'IG1Filter' {
|
||||
$testDefinitions = $testDefinitions | Where-Object { $_.IG1 -eq 'TRUE' }
|
||||
}
|
||||
'IG2Filter' {
|
||||
$testDefinitions = $testDefinitions | Where-Object { $_.IG2 -eq 'TRUE' }
|
||||
}
|
||||
'IG3Filter' {
|
||||
$testDefinitions = $testDefinitions | Where-Object { $_.IG3 -eq 'TRUE' }
|
||||
}
|
||||
'RecFilter' {
|
||||
$testDefinitions = $testDefinitions | Where-Object { $IncludeRecommendation -contains $_.Rec }
|
||||
}
|
||||
'SkipRecFilter' {
|
||||
$testDefinitions = $testDefinitions | Where-Object { $SkipRecommendation -notcontains $_.Rec }
|
||||
}
|
||||
$params = @{
|
||||
TestDefinitions = $testDefinitions
|
||||
ParameterSetName = $PSCmdlet.ParameterSetName
|
||||
ELevel = $ELevel
|
||||
ProfileLevel = $ProfileLevel
|
||||
IncludeRecommendation = $IncludeRecommendation
|
||||
SkipRecommendation = $SkipRecommendation
|
||||
}
|
||||
$testDefinitions = Get-TestDefinitionsObject @params
|
||||
# End switch ($PSCmdlet.ParameterSetName)
|
||||
# Extract unique connections needed
|
||||
$requiredConnections = $testDefinitions.Connection | Sort-Object -Unique
|
||||
|
||||
# Establishing connections if required
|
||||
if (!($DoNotConnect)) {
|
||||
Connect-M365Suite -TenantAdminUrl $TenantAdminUrl -RequiredConnections $requiredConnections
|
||||
}
|
||||
# Determine which test files to load based on filtering
|
||||
$testsToLoad = $testDefinitions.TestFileName | ForEach-Object { $_ -replace '.ps1$', '' }
|
||||
|
||||
@@ -209,7 +185,7 @@ function Invoke-M365SecurityAudit {
|
||||
} # End Begin
|
||||
|
||||
Process {
|
||||
$allAuditResults = @() # Initialize a collection to hold all results
|
||||
$allAuditResults = [System.Collections.ArrayList]::new() #@() # Initialize a collection to hold all results
|
||||
|
||||
# Dynamically dot-source the test scripts
|
||||
$testsFolderPath = Join-Path -Path $PSScriptRoot -ChildPath "tests"
|
||||
@@ -242,7 +218,7 @@ function Invoke-M365SecurityAudit {
|
||||
Write-Host "Running $functionName..."
|
||||
$result = & $functionName @paramList
|
||||
# Assuming each function returns an array of CISAuditResult or a single CISAuditResult
|
||||
$allAuditResults += $result
|
||||
[void]($allAuditResults.add($Result))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -250,10 +226,22 @@ function Invoke-M365SecurityAudit {
|
||||
End {
|
||||
if (!($DoNotDisconnect)) {
|
||||
# Clean up sessions
|
||||
Disconnect-M365Suite
|
||||
Disconnect-M365Suite -RequiredConnections $requiredConnections
|
||||
}
|
||||
# Calculate the total number of tests
|
||||
$totalTests = $allAuditResults.Count
|
||||
|
||||
# Calculate the number of passed tests
|
||||
$passedTests = $allAuditResults.ToArray() | Where-Object { $_.Result -eq $true } | Measure-Object | Select-Object -ExpandProperty Count
|
||||
|
||||
# Calculate the pass percentage
|
||||
$passPercentage = if ($totalTests -eq 0) { 0 } else { [math]::Round(($passedTests / $totalTests) * 100, 2) }
|
||||
|
||||
# Display the pass percentage to the user
|
||||
Write-Host "Audit completed. $passedTests out of $totalTests tests passed." -ForegroundColor Cyan
|
||||
Write-Host "Your passing percentage is $passPercentage%."
|
||||
# Return all collected audit results
|
||||
return $allAuditResults
|
||||
return $allAuditResults.ToArray()
|
||||
# Check if the Disconnect switch is present
|
||||
}
|
||||
}
|
@@ -1,52 +1,52 @@
|
||||
Index,TestFileName,Rec,ELevel,ProfileLevel,IG1,IG2,IG3,Automated
|
||||
1,Test-AdministrativeAccountCompliance.ps1,1.1.1,E3,L1,TRUE,TRUE,TRUE,FALSE
|
||||
2,Test-GlobalAdminsCount.ps1,1.1.3,E3,L1,TRUE,TRUE,TRUE,TRUE
|
||||
3,Test-ManagedApprovedPublicGroups.ps1,1.2.1,E3,L2,TRUE,TRUE,TRUE,TRUE
|
||||
4,Test-BlockSharedMailboxSignIn.ps1,1.2.2,E3,L1,FALSE,FALSE,FALSE,TRUE
|
||||
5,Test-PasswordNeverExpirePolicy.ps1,1.3.1,E3,L1,TRUE,TRUE,TRUE,TRUE
|
||||
6,Test-ExternalSharingCalendars.ps1,1.3.3,E3,L2,FALSE,TRUE,TRUE,TRUE
|
||||
7,Test-CustomerLockbox.ps1,1.3.6,E5,L2,FALSE,FALSE,FALSE,TRUE
|
||||
8,Test-SafeLinksOfficeApps.ps1,2.1.1,E5,L2,TRUE,TRUE,TRUE,TRUE
|
||||
9,Test-CommonAttachmentFilter.ps1,2.1.2,E3,L1,FALSE,TRUE,TRUE,TRUE
|
||||
10,Test-NotifyMalwareInternal.ps1,2.1.3,E3,L1,FALSE,TRUE,TRUE,TRUE
|
||||
11,Test-SafeAttachmentsPolicy.ps1,2.1.4,E5,L2,FALSE,FALSE,TRUE,TRUE
|
||||
12,Test-SafeAttachmentsTeams.ps1,2.1.5,E5,L2,TRUE,TRUE,TRUE,TRUE
|
||||
13,Test-SpamPolicyAdminNotify.ps1,2.1.6,E3,L1,FALSE,TRUE,TRUE,TRUE
|
||||
14,Test-AntiPhishingPolicy.ps1,2.1.7,E5,L1,FALSE,FALSE,TRUE,TRUE
|
||||
15,Test-EnableDKIM.ps1,2.1.9,E3,L1,FALSE,TRUE,TRUE,TRUE
|
||||
16,Test-AuditLogSearch.ps1,3.1.1,E3,L1,TRUE,TRUE,TRUE,TRUE
|
||||
17,Test-RestrictTenantCreation.ps1,5.1.2.3,E3,L1,FALSE,FALSE,FALSE,TRUE
|
||||
18,Test-PasswordHashSync.ps1,5.1.8.1,E3,L1,FALSE,TRUE,TRUE,TRUE
|
||||
19,Test-AuditDisabledFalse.ps1,6.1.1,E3,L1,TRUE,TRUE,TRUE,TRUE
|
||||
20,Test-MailboxAuditingE3.ps1,6.1.2,E3,L1,TRUE,TRUE,TRUE,TRUE
|
||||
21,Test-MailboxAuditingE5.ps1,6.1.3,E5,L1,TRUE,TRUE,TRUE,TRUE
|
||||
22,Test-BlockMailForwarding.ps1,6.2.1,E3,L1,FALSE,FALSE,FALSE,TRUE
|
||||
23,Test-NoWhitelistDomains.ps1,6.2.2,E3,L1,FALSE,FALSE,FALSE,TRUE
|
||||
24,Test-IdentifyExternalEmail.ps1,6.2.3,E3,L1,FALSE,FALSE,FALSE,TRUE
|
||||
25,Test-RestrictOutlookAddins.ps1,6.3.1,E3,L2,FALSE,TRUE,TRUE,TRUE
|
||||
26,Test-ModernAuthExchangeOnline.ps1,6.5.1,E3,L1,FALSE,TRUE,TRUE,TRUE
|
||||
27,Test-MailTipsEnabled.ps1,6.5.2,E3,L2,FALSE,FALSE,FALSE,TRUE
|
||||
28,Test-RestrictStorageProvidersOutlook.ps1,6.5.3,E3,L2,TRUE,TRUE,TRUE,TRUE
|
||||
29,Test-ModernAuthSharePoint.ps1,7.2.1,E3,L1,FALSE,TRUE,TRUE,TRUE
|
||||
30,Test-SharePointAADB2B.ps1,7.2.2,E3,L1,FALSE,FALSE,FALSE,TRUE
|
||||
31,Test-RestrictExternalSharing.ps1,7.2.3,E3,L1,TRUE,TRUE,TRUE,TRUE
|
||||
32,Test-OneDriveContentRestrictions.ps1,7.2.4,E3,L2,TRUE,TRUE,TRUE,TRUE
|
||||
33,Test-SharePointGuestsItemSharing.ps1,7.2.5,E3,L2,TRUE,TRUE,TRUE,TRUE
|
||||
34,Test-SharePointExternalSharingDomains.ps1,7.2.6,E3,L2,TRUE,TRUE,TRUE,TRUE
|
||||
35,Test-LinkSharingRestrictions.ps1,7.2.7,E3,L1,TRUE,TRUE,TRUE,TRUE
|
||||
36,Test-GuestAccessExpiration.ps1,7.2.9,E3,L1,FALSE,FALSE,FALSE,TRUE
|
||||
37,Test-ReauthWithCode.ps1,7.2.10,E3,L1,FALSE,FALSE,FALSE,TRUE
|
||||
38,Test-DisallowInfectedFilesDownload.ps1,7.3.1,E5,L2,TRUE,TRUE,TRUE,TRUE
|
||||
39,Test-OneDriveSyncRestrictions.ps1,7.3.2,E3,L2,FALSE,FALSE,FALSE,TRUE
|
||||
40,Test-RestrictCustomScripts.ps1,7.3.4,E3,L1,FALSE,FALSE,TRUE,TRUE
|
||||
41,Test-TeamsExternalFileSharing.ps1,8.1.1,E3,L2,TRUE,TRUE,TRUE,TRUE
|
||||
42,Test-BlockChannelEmails.ps1,8.1.2,E3,L1,FALSE,FALSE,FALSE,TRUE
|
||||
43,Test-TeamsExternalAccess.ps1,8.2.1,E3,L2,FALSE,FALSE,FALSE,TRUE
|
||||
44,Test-NoAnonymousMeetingJoin.ps1,8.5.1,E3,L2,FALSE,FALSE,FALSE,TRUE
|
||||
45,Test-NoAnonymousMeetingStart.ps1,8.5.2,E3,L1,FALSE,FALSE,FALSE,TRUE
|
||||
46,Test-OrgOnlyBypassLobby.ps1,8.5.3,E3,L1,FALSE,FALSE,TRUE,TRUE
|
||||
47,Test-DialInBypassLobby.ps1,8.5.4,E3,L1,FALSE,FALSE,FALSE,TRUE
|
||||
48,Test-MeetingChatNoAnonymous.ps1,8.5.5,E3,L1,FALSE,FALSE,FALSE,TRUE
|
||||
49,Test-OrganizersPresent.ps1,8.5.6,E3,L1,FALSE,FALSE,FALSE,TRUE
|
||||
50,Test-ExternalNoControl.ps1,8.5.7,E3,L1,FALSE,FALSE,FALSE,TRUE
|
||||
51,Test-ReportSecurityInTeams.ps1,8.6.1,E3,L1,FALSE,FALSE,FALSE,TRUE
|
||||
Index,TestFileName,Rec,RecDescription,ELevel,ProfileLevel,CISControl,CISDescription,IG1,IG2,IG3,Automated,Connection
|
||||
1,Test-AdministrativeAccountCompliance.ps1,1.1.1,Ensure Administrative accounts are separate and cloud-only,E3,L1,5.4,Restrict Administrator Privileges to Dedicated Administrator Accounts,TRUE,TRUE,TRUE,FALSE,Microsoft Graph
|
||||
2,Test-GlobalAdminsCount.ps1,1.1.3,Ensure that between two and four global admins are designated,E3,L1,5.1,Establish and Maintain an Inventory of Accounts,TRUE,TRUE,TRUE,TRUE,Microsoft Graph
|
||||
3,Test-ManagedApprovedPublicGroups.ps1,1.2.1,Ensure that only organizationally managed/approved public groups exist,E3,L2,3.3,Configure Data Access Control Lists,TRUE,TRUE,TRUE,TRUE,Microsoft Graph
|
||||
4,Test-BlockSharedMailboxSignIn.ps1,1.2.2,Ensure sign-in to shared mailboxes is blocked,E3,L1,0,Explicitly Not Mapped,FALSE,FALSE,FALSE,TRUE,AzureAD | EXO
|
||||
5,Test-PasswordNeverExpirePolicy.ps1,1.3.1,Ensure the 'Password expiration policy' is set to 'Set passwords to never expire',E3,L1,5.2,Use Unique Passwords,TRUE,TRUE,TRUE,TRUE,Microsoft Graph
|
||||
6,Test-ExternalSharingCalendars.ps1,1.3.3,Ensure 'External sharing' of calendars is not available,E3,L2,4.8,Uninstall or Disable Unnecessary Services on Enterprise Assets and Software,FALSE,TRUE,TRUE,TRUE,EXO
|
||||
7,Test-CustomerLockbox.ps1,1.3.6,Ensure the customer lockbox feature is enabled,E5,L2,0,Explicitly Not Mapped,FALSE,FALSE,FALSE,TRUE,EXO
|
||||
8,Test-SafeLinksOfficeApps.ps1,2.1.1,Ensure Safe Links for Office Applications is Enabled,E5,L2,10.1,Deploy and Maintain Anti-Malware Software,TRUE,TRUE,TRUE,TRUE,EXO
|
||||
9,Test-CommonAttachmentFilter.ps1,2.1.2,Ensure the Common Attachment Types Filter is enabled,E3,L1,9.6,Block Unnecessary File Types,FALSE,TRUE,TRUE,TRUE,EXO
|
||||
10,Test-NotifyMalwareInternal.ps1,2.1.3,Ensure notifications for internal users sending malware is Enabled,E3,L1,17.5,Assign Key Roles and Responsibilities,FALSE,TRUE,TRUE,TRUE,EXO
|
||||
11,Test-SafeAttachmentsPolicy.ps1,2.1.4,Ensure Safe Attachments policy is enabled,E5,L2,9.7,Deploy and Maintain Email Server Anti-Malware Protections,FALSE,FALSE,TRUE,TRUE,EXO
|
||||
12,Test-SafeAttachmentsTeams.ps1,2.1.5,"Ensure Safe Attachments for SharePoint, OneDrive, and Microsoft Teams is Enabled",E5,L2,"9.7, 10.1","Deploy and Maintain Email Server Anti-Malware Protections, Deploy and Maintain Anti-Malware Software",TRUE,TRUE,TRUE,TRUE,EXO
|
||||
13,Test-SpamPolicyAdminNotify.ps1,2.1.6,Ensure Exchange Online Spam Policies are set to notify administrators,E3,L1,17.5,Assign Key Roles and Responsibilities,FALSE,TRUE,TRUE,TRUE,EXO
|
||||
14,Test-AntiPhishingPolicy.ps1,2.1.7,Ensure that an anti-phishing policy has been created,E5,L1,9.7,Deploy and Maintain Email Server Anti-Malware Protections,FALSE,FALSE,TRUE,TRUE,EXO
|
||||
15,Test-EnableDKIM.ps1,2.1.9,Ensure that DKIM is enabled for all Exchange Online Domains,E3,L1,9.5,Implement DMARC,FALSE,TRUE,TRUE,TRUE,EXO
|
||||
16,Test-AuditLogSearch.ps1,3.1.1,Ensure Microsoft 365 audit log search is Enabled,E3,L1,8.2,Collect Audit Logs,TRUE,TRUE,TRUE,TRUE,EXO
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
25,Test-RestrictOutlookAddins.ps1,6.3.1,Ensure users installing Outlook add-ins is not allowed,E3,L2,9.4,Restrict Unnecessary or Unauthorized Browser and Email Client Extensions,FALSE,TRUE,TRUE,TRUE,EXO
|
||||
26,Test-ModernAuthExchangeOnline.ps1,6.5.1,Ensure modern authentication for Exchange Online is enabled (Automated),E3,L1,3.1,Encrypt Sensitive Data in Transit,FALSE,TRUE,TRUE,TRUE,EXO
|
||||
27,Test-MailTipsEnabled.ps1,6.5.2,Ensure MailTips are enabled for end users,E3,L2,0,Explicitly Not Mapped,FALSE,FALSE,FALSE,TRUE,EXO
|
||||
28,Test-RestrictStorageProvidersOutlook.ps1,6.5.3,Ensure additional storage providers are restricted in Outlook on the web,E3,L2,3.3,Configure Data Access Control Lists,TRUE,TRUE,TRUE,TRUE,EXO
|
||||
29,Test-ModernAuthSharePoint.ps1,7.2.1,Modern Authentication for SharePoint Applications,E3,L1,3.1,Encrypt Sensitive Data in Transit,FALSE,TRUE,TRUE,TRUE,SPO
|
||||
30,Test-SharePointAADB2B.ps1,7.2.2,Ensure reauthentication with verification code is restricted,E3,L1,0,Explicitly Not Mapped,FALSE,FALSE,FALSE,TRUE,SPO
|
||||
31,Test-RestrictExternalSharing.ps1,7.2.3,Ensure SharePoint and OneDrive integration with Azure AD B2B is enabled,E3,L1,0,Explicitly Not Mapped,TRUE,TRUE,TRUE,TRUE,SPO
|
||||
32,Test-OneDriveContentRestrictions.ps1,7.2.4,Ensure external content sharing is restricted,E3,L2,3.3,Configure Data Access Control Lists,TRUE,TRUE,TRUE,TRUE,SPO
|
||||
33,Test-SharePointGuestsItemSharing.ps1,7.2.5,Ensure OneDrive content sharing is restricted,E3,L2,3.3,Configure Data Access Control Lists,TRUE,TRUE,TRUE,TRUE,SPO
|
||||
34,Test-SharePointExternalSharingDomains.ps1,7.2.6,Ensure that SharePoint guest users cannot share items they don't own,E3,L2,3.3,Configure Data Access Control Lists,TRUE,TRUE,TRUE,TRUE,SPO
|
||||
35,Test-LinkSharingRestrictions.ps1,7.2.7,Ensure SharePoint external sharing is managed through domain whitelist/blacklists,E3,L1,3.3,Configure Data Access Control Lists,TRUE,TRUE,TRUE,TRUE,SPO
|
||||
36,Test-GuestAccessExpiration.ps1,7.2.9,Ensure link sharing is restricted in SharePoint and OneDrive,E3,L1,3.3,Configure Data Access Control Lists,FALSE,FALSE,FALSE,TRUE,SPO
|
||||
37,Test-ReauthWithCode.ps1,7.2.10,Ensure guest access to a site or OneDrive will expire automatically,E3,L1,0,Explicitly Not Mapped,FALSE,FALSE,FALSE,TRUE,SPO
|
||||
38,Test-DisallowInfectedFilesDownload.ps1,7.3.1,Ensure Office 365 SharePoint infected files are disallowed for download,E5,L2,10.1,Deploy and Maintain Anti-Malware Software,TRUE,TRUE,TRUE,TRUE,SPO
|
||||
39,Test-OneDriveSyncRestrictions.ps1,7.3.2,Ensure OneDrive sync is restricted for unmanaged devices,E3,L2,0,Explicitly Not Mapped,FALSE,FALSE,FALSE,TRUE,SPO
|
||||
40,Test-RestrictCustomScripts.ps1,7.3.4,Ensure custom script execution is restricted on site collections,E3,L1,2.7,Allowlist Authorized Scripts,FALSE,FALSE,TRUE,TRUE,SPO
|
||||
41,Test-TeamsExternalFileSharing.ps1,8.1.1,Ensure external file sharing in Teams is enabled for only approved cloud storage services,E3,L2,3.3,Configure Data Access Control Lists,TRUE,TRUE,TRUE,TRUE,Microsoft Teams
|
||||
42,Test-BlockChannelEmails.ps1,8.1.2,Ensure users can't send emails to a channel email address,E3,L1,0,Explicitly Not Mapped,FALSE,FALSE,FALSE,TRUE,Microsoft Teams
|
||||
43,Test-TeamsExternalAccess.ps1,8.2.1,Ensure 'external access' is restricted in the Teams admin center,E3,L2,0,Explicitly Not Mapped,FALSE,FALSE,FALSE,TRUE,Microsoft Teams
|
||||
44,Test-NoAnonymousMeetingJoin.ps1,8.5.1,Ensure anonymous users can't join a meeting,E3,L2,0,Explicitly Not Mapped,FALSE,FALSE,FALSE,TRUE,Microsoft Teams
|
||||
45,Test-NoAnonymousMeetingStart.ps1,8.5.2,Ensure anonymous users and dial-in callers can't start a meeting,E3,L1,0,Explicitly Not Mapped,FALSE,FALSE,FALSE,TRUE,Microsoft Teams
|
||||
46,Test-OrgOnlyBypassLobby.ps1,8.5.3,Ensure only people in my org can bypass the lobby,E3,L1,6.8,Define and Maintain Role-Based Access Control,FALSE,FALSE,TRUE,TRUE,Microsoft Teams
|
||||
47,Test-DialInBypassLobby.ps1,8.5.4,Ensure users dialing in can't bypass the lobby,E3,L1,0,Explicitly Not Mapped,FALSE,FALSE,FALSE,TRUE,Microsoft Teams
|
||||
48,Test-MeetingChatNoAnonymous.ps1,8.5.5,Ensure meeting chat does not allow anonymous users,E3,L1,0,Explicitly Not Mapped,FALSE,FALSE,FALSE,TRUE,Microsoft Teams
|
||||
49,Test-OrganizersPresent.ps1,8.5.6,Ensure only organizers and co-organizers can present,E3,L1,0,Explicitly Not Mapped,FALSE,FALSE,FALSE,TRUE,Microsoft Teams
|
||||
50,Test-ExternalNoControl.ps1,8.5.7,Ensure external participants can't give or request control,E3,L1,0,Explicitly Not Mapped,FALSE,FALSE,FALSE,TRUE,Microsoft Teams
|
||||
51,Test-ReportSecurityInTeams.ps1,8.6.1,Ensure users can report security concerns in Teams,E3,L1,0,Explicitly Not Mapped,FALSE,FALSE,FALSE,TRUE,Microsoft Teams | EXO
|
||||
|
|
@@ -1,12 +1,15 @@
|
||||
function Test-AdministrativeAccountCompliance {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
# Aligned
|
||||
# Parameters can be added if needed
|
||||
)
|
||||
|
||||
begin {
|
||||
#. C:\Temp\CISAuditResult.ps1
|
||||
#. .\source\Classes\CISAuditResult.ps1
|
||||
$validLicenses = @('AAD_PREMIUM', 'AAD_PREMIUM_P2')
|
||||
}
|
||||
|
||||
process {
|
||||
$adminRoles = Get-MgRoleManagementDirectoryRoleDefinition | Where-Object { $_.DisplayName -like "*Admin*" }
|
||||
$adminRoleUsers = @()
|
||||
@@ -50,22 +53,27 @@ function Test-AdministrativeAccountCompliance {
|
||||
"$($_.UserName)|$($_.Roles)|$accountType|Missing: $($missingLicenses -join ',')"
|
||||
}
|
||||
$failureReasons = $failureReasons -join "`n"
|
||||
$details = if ($nonCompliantUsers) {
|
||||
"Non-Compliant Accounts: $($nonCompliantUsers.Count)`nDetails:`n" + ($nonCompliantUsers | ForEach-Object { $_.UserName }) -join "`n"
|
||||
}
|
||||
else {
|
||||
"Compliant Accounts: $($uniqueAdminRoleUsers.Count)"
|
||||
}
|
||||
|
||||
$auditResult = [CISAuditResult]::new()
|
||||
$auditResult.Status = if ($nonCompliantUsers) { 'Fail' } else { 'Pass' }
|
||||
$auditResult.ELevel = 'E3'
|
||||
$auditResult.ProfileLevel = 'L1'
|
||||
$auditResult.Rec = '1.1.1'
|
||||
$auditResult.RecDescription = "Ensure Administrative accounts are separate and cloud-only"
|
||||
$auditResult.CISControlVer = 'v8'
|
||||
$auditResult.CISControl = "5.4"
|
||||
$auditResult.CISDescription = "Restrict Administrator Privileges to Dedicated Administrator Accounts"
|
||||
$auditResult.IG1 = $true
|
||||
$auditResult.IG2 = $true
|
||||
$auditResult.IG3 = $true
|
||||
$auditResult.Result = $nonCompliantUsers.Count -eq 0
|
||||
$auditResult.Details = "Compliant Accounts: $($uniqueAdminRoleUsers.Count - $nonCompliantUsers.Count); Non-Compliant Accounts: $($nonCompliantUsers.Count)"
|
||||
$auditResult.FailureReason = if ($nonCompliantUsers) { "Non-compliant accounts: `nUsername | Roles | HybridStatus | Missing Licence`n$failureReasons" } else { "N/A" }
|
||||
$result = $nonCompliantUsers.Count -eq 0
|
||||
$status = if ($result) { 'Pass' } else { 'Fail' }
|
||||
$failureReason = if ($nonCompliantUsers) { "Non-compliant accounts: `nUsername | Roles | HybridStatus | Missing Licence`n$failureReasons" } else { "N/A" }
|
||||
|
||||
# Create the parameter splat
|
||||
$params = @{
|
||||
Rec = "1.1.1"
|
||||
Result = $result
|
||||
Status = $status
|
||||
Details = $details
|
||||
FailureReason = $failureReason
|
||||
}
|
||||
|
||||
$auditResult = Initialize-CISAuditResult @params
|
||||
}
|
||||
|
||||
end {
|
||||
|
@@ -1,17 +1,19 @@
|
||||
function Test-AntiPhishingPolicy {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
# Aligned
|
||||
# Parameters can be added if needed
|
||||
)
|
||||
|
||||
begin {
|
||||
# Dot source the class script
|
||||
|
||||
$auditResults = @()
|
||||
# Dot source the class script if necessary
|
||||
#. .\source\Classes\CISAuditResult.ps1
|
||||
# Initialization code, if needed
|
||||
#$auditResults = @()
|
||||
}
|
||||
|
||||
process {
|
||||
# 2.1.7 Ensure that an anti-phishing policy has been created
|
||||
# 2.1.7 Ensure that an anti-phishing policy has been created
|
||||
|
||||
# Retrieve and validate the anti-phishing policies
|
||||
$antiPhishPolicies = Get-AntiPhishPolicy
|
||||
@@ -24,37 +26,54 @@ function Test-AntiPhishingPolicy {
|
||||
}
|
||||
|
||||
# Check if there is at least one policy that meets the requirements
|
||||
$isCompliant = $validatedPolicies.Count -gt 0
|
||||
$nonCompliantItems = $antiPhishPolicies | Where-Object {
|
||||
$_.Enabled -ne $true -or
|
||||
$_.PhishThresholdLevel -lt 2 -or
|
||||
$_.EnableMailboxIntelligenceProtection -ne $true -or
|
||||
$_.EnableMailboxIntelligence -ne $true -or
|
||||
$_.EnableSpoofIntelligence -ne $true
|
||||
}
|
||||
$compliantItems = $validatedPolicies
|
||||
$isCompliant = $compliantItems.Count -gt 0
|
||||
|
||||
# Prepare failure details if policies are not compliant
|
||||
$failureDetails = if (-not $isCompliant) {
|
||||
"No anti-phishing policy is fully compliant with CIS benchmark requirements."
|
||||
} else {
|
||||
"Compliant Anti-Phish Policy Names: " + ($validatedPolicies.Name -join ', ')
|
||||
# Prepare failure reasons for non-compliant items
|
||||
$nonCompliantNames = $nonCompliantItems | ForEach-Object { $_.Name }
|
||||
$failureReasons = if ($nonCompliantNames.Count -gt 0) {
|
||||
"Reason: Does not meet one or more compliance criteria.`nNon-compliant Policies:`n" + ($nonCompliantNames -join "`n")
|
||||
}
|
||||
else {
|
||||
"N/A"
|
||||
}
|
||||
|
||||
# Create an instance of CISAuditResult and populate it
|
||||
$auditResult = [CISAuditResult]::new()
|
||||
$auditResult.Status = if ($isCompliant) { "Pass" } else { "Fail" }
|
||||
$auditResult.ELevel = "E5"
|
||||
$auditResult.ProfileLevel = "L1"
|
||||
$auditResult.Rec = "2.1.7"
|
||||
$auditResult.RecDescription = "Ensure that an anti-phishing policy has been created"
|
||||
$auditResult.CISControlVer = "v8"
|
||||
$auditResult.CISControl = "9.7"
|
||||
$auditResult.CISDescription = "Deploy and Maintain Email Server Anti-Malware Protections"
|
||||
$auditResult.IG1 = $false
|
||||
$auditResult.IG2 = $false
|
||||
$auditResult.IG3 = $true
|
||||
$auditResult.Result = $isCompliant
|
||||
$auditResult.Details = $failureDetails
|
||||
$auditResult.FailureReason = if (-not $isCompliant) { "Anti-phishing policies do not meet CIS benchmark requirements." } else { "N/A" }
|
||||
# Prepare details for non-compliant items
|
||||
$nonCompliantDetails = $nonCompliantItems | ForEach-Object {
|
||||
"Policy: $($_.Name)"
|
||||
}
|
||||
$nonCompliantDetails = $nonCompliantDetails -join "`n"
|
||||
|
||||
$auditResults += $auditResult
|
||||
# Prepare details based on compliance
|
||||
$details = if ($nonCompliantItems) {
|
||||
"Non-Compliant Items: $($nonCompliantItems.Count)`nDetails:`n$nonCompliantDetails"
|
||||
}
|
||||
else {
|
||||
"Compliant Items: $($compliantItems.Count)"
|
||||
}
|
||||
|
||||
# Parameter splat for Initialize-CISAuditResult function
|
||||
$params = @{
|
||||
Rec = "2.1.7"
|
||||
Result = $nonCompliantItems.Count -eq 0
|
||||
Status = if ($isCompliant) { "Pass" } else { "Fail" }
|
||||
Details = $details
|
||||
FailureReason = $failureReasons
|
||||
}
|
||||
|
||||
# Create and populate the CISAuditResult object
|
||||
$auditResult = Initialize-CISAuditResult @params
|
||||
}
|
||||
|
||||
end {
|
||||
# Return auditResults
|
||||
return $auditResults
|
||||
# Return auditResult
|
||||
return $auditResult
|
||||
}
|
||||
}
|
||||
|
@@ -1,43 +1,51 @@
|
||||
function Test-AuditDisabledFalse {
|
||||
[CmdletBinding()]
|
||||
# Aligned
|
||||
param (
|
||||
# Parameters can be added if needed
|
||||
)
|
||||
|
||||
begin {
|
||||
# Dot source the class script
|
||||
|
||||
$auditResults = @()
|
||||
# Dot source the class script if necessary
|
||||
#. .\source\Classes\CISAuditResult.ps1
|
||||
# Initialization code, if needed
|
||||
}
|
||||
|
||||
process {
|
||||
# 6.1.1 (L1) Ensure 'AuditDisabled' organizationally is set to 'False'
|
||||
# Pass if AuditDisabled is False. Fail otherwise.
|
||||
|
||||
# Retrieve the AuditDisabled configuration
|
||||
$auditDisabledConfig = Get-OrganizationConfig | Select-Object AuditDisabled
|
||||
$auditNotDisabled = -not $auditDisabledConfig.AuditDisabled
|
||||
|
||||
# Create an instance of CISAuditResult and populate it
|
||||
$auditResult = [CISAuditResult]::new()
|
||||
$auditResult.Status = if ($auditNotDisabled) { "Pass" } else { "Fail" }
|
||||
$auditResult.ELevel = "E3"
|
||||
$auditResult.ProfileLevel = "L1"
|
||||
$auditResult.Rec = "6.1.1"
|
||||
$auditResult.RecDescription = "Ensure 'AuditDisabled' organizationally is set to 'False'"
|
||||
$auditResult.CISControlVer = "v8"
|
||||
$auditResult.CISControl = "8.2"
|
||||
$auditResult.CISDescription = "Collect Audit Logs"
|
||||
$auditResult.IG1 = $true
|
||||
$auditResult.IG2 = $true
|
||||
$auditResult.IG3 = $true
|
||||
$auditResult.Result = $auditNotDisabled
|
||||
$auditResult.Details = if ($auditNotDisabled) { "Audit is not disabled organizationally" } else { "Audit is disabled organizationally" }
|
||||
$auditResult.FailureReason = if (-not $auditNotDisabled) { "AuditDisabled is set to True" } else { "N/A" }
|
||||
# Prepare failure reasons and details based on compliance
|
||||
$failureReasons = if (-not $auditNotDisabled) {
|
||||
"AuditDisabled is set to True"
|
||||
}
|
||||
else {
|
||||
"N/A"
|
||||
}
|
||||
|
||||
$auditResults += $auditResult
|
||||
$details = if ($auditNotDisabled) {
|
||||
"Audit is not disabled organizationally"
|
||||
}
|
||||
else {
|
||||
"Audit is disabled organizationally"
|
||||
}
|
||||
|
||||
# Create and populate the CISAuditResult object
|
||||
$params = @{
|
||||
Rec = "6.1.1"
|
||||
Result = $auditNotDisabled
|
||||
Status = if ($auditNotDisabled) { "Pass" } else { "Fail" }
|
||||
Details = $details
|
||||
FailureReason = $failureReasons
|
||||
}
|
||||
$auditResult = Initialize-CISAuditResult @params
|
||||
}
|
||||
|
||||
end {
|
||||
# Return auditResults
|
||||
return $auditResults
|
||||
# Return the audit result
|
||||
return $auditResult
|
||||
}
|
||||
}
|
||||
|
@@ -1,43 +1,52 @@
|
||||
function Test-AuditLogSearch {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
# Aligned
|
||||
# Parameters can be added if needed
|
||||
)
|
||||
|
||||
begin {
|
||||
# Dot source the class script
|
||||
|
||||
$auditResults = @()
|
||||
# Dot source the class script if necessary
|
||||
#. .\source\Classes\CISAuditResult.ps1
|
||||
# Initialization code, if needed
|
||||
}
|
||||
|
||||
process {
|
||||
# 3.1.1 (L1) Ensure Microsoft 365 audit log search is Enabled
|
||||
# Pass if UnifiedAuditLogIngestionEnabled is True. Fail otherwise.
|
||||
|
||||
# Retrieve the audit log configuration
|
||||
$auditLogConfig = Get-AdminAuditLogConfig | Select-Object UnifiedAuditLogIngestionEnabled
|
||||
$auditLogResult = $auditLogConfig.UnifiedAuditLogIngestionEnabled
|
||||
|
||||
# Create an instance of CISAuditResult and populate it
|
||||
$auditResult = [CISAuditResult]::new()
|
||||
$auditResult.Status = if ($auditLogResult) { "Pass" } else { "Fail" }
|
||||
$auditResult.ELevel = "E3"
|
||||
$auditResult.ProfileLevel = "L1"
|
||||
$auditResult.Rec = "3.1.1"
|
||||
$auditResult.RecDescription = "Ensure Microsoft 365 audit log search is Enabled"
|
||||
$auditResult.CISControlVer = "v8"
|
||||
$auditResult.CISControl = "8.2"
|
||||
$auditResult.CISDescription = "Collect Audit Logs"
|
||||
$auditResult.IG1 = $true
|
||||
$auditResult.IG2 = $true
|
||||
$auditResult.IG3 = $true
|
||||
$auditResult.Result = $auditLogResult
|
||||
$auditResult.Details = "UnifiedAuditLogIngestionEnabled: $($auditLogConfig.UnifiedAuditLogIngestionEnabled)"
|
||||
$auditResult.FailureReason = if (-not $auditLogResult) { "Audit log search is not enabled" } else { "N/A" }
|
||||
# Prepare failure reasons and details based on compliance
|
||||
$failureReasons = if (-not $auditLogResult) {
|
||||
"Audit log search is not enabled"
|
||||
}
|
||||
else {
|
||||
"N/A"
|
||||
}
|
||||
|
||||
$details = if ($auditLogResult) {
|
||||
"UnifiedAuditLogIngestionEnabled: True"
|
||||
}
|
||||
else {
|
||||
"UnifiedAuditLogIngestionEnabled: False"
|
||||
}
|
||||
|
||||
# Create and populate the CISAuditResult object
|
||||
$params = @{
|
||||
Rec = "3.1.1"
|
||||
Result = $auditLogResult
|
||||
Status = if ($auditLogResult) { "Pass" } else { "Fail" }
|
||||
Details = $details
|
||||
FailureReason = $failureReasons
|
||||
}
|
||||
$auditResult = Initialize-CISAuditResult @params
|
||||
|
||||
$auditResults += $auditResult
|
||||
}
|
||||
|
||||
end {
|
||||
# Return auditResults
|
||||
return $auditResults
|
||||
# Return the audit result
|
||||
return $auditResult
|
||||
}
|
||||
}
|
||||
|
@@ -1,44 +1,51 @@
|
||||
function Test-BlockChannelEmails {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
# Aligned
|
||||
# Parameters can be added here if needed
|
||||
)
|
||||
|
||||
begin {
|
||||
# Dot source the class script
|
||||
|
||||
$auditResults = @()
|
||||
# Dot source the class script if necessary
|
||||
#. .\source\Classes\CISAuditResult.ps1
|
||||
# Initialization code, if needed
|
||||
}
|
||||
|
||||
process {
|
||||
# 8.1.2 (L1) Ensure users can't send emails to a channel email address
|
||||
# Connect to Teams PowerShell using Connect-MicrosoftTeams
|
||||
|
||||
# Retrieve Teams client configuration
|
||||
$teamsClientConfig = Get-CsTeamsClientConfiguration -Identity Global
|
||||
$allowEmailIntoChannel = $teamsClientConfig.AllowEmailIntoChannel
|
||||
|
||||
# Create an instance of CISAuditResult and populate it
|
||||
$auditResult = [CISAuditResult]::new()
|
||||
$auditResult.CISControlVer = "v8"
|
||||
$auditResult.CISControl = "0.0" # This control is Explicitly Not Mapped as per the image provided
|
||||
$auditResult.CISDescription = "Explicitly Not Mapped"
|
||||
$auditResult.Rec = "8.1.2"
|
||||
$auditResult.ELevel = "E3"
|
||||
$auditResult.ProfileLevel = "L1"
|
||||
$auditResult.IG1 = $false # Set based on the benchmark
|
||||
$auditResult.IG2 = $false # Set based on the benchmark
|
||||
$auditResult.IG3 = $false # Set based on the benchmark
|
||||
$auditResult.RecDescription = "Ensure users can't send emails to a channel email address"
|
||||
$auditResult.Result = -not $allowEmailIntoChannel
|
||||
$auditResult.Details = "AllowEmailIntoChannel is set to $allowEmailIntoChannel"
|
||||
$auditResult.FailureReason = if ($allowEmailIntoChannel) { "Emails can be sent to a channel email address" } else { "N/A" }
|
||||
$auditResult.Status = if (-not $allowEmailIntoChannel) { "Pass" } else { "Fail" }
|
||||
# Prepare failure reasons and details based on compliance
|
||||
$failureReasons = if ($allowEmailIntoChannel) {
|
||||
"Emails can be sent to a channel email address"
|
||||
}
|
||||
else {
|
||||
"N/A"
|
||||
}
|
||||
|
||||
$auditResults += $auditResult
|
||||
$details = if ($allowEmailIntoChannel) {
|
||||
"AllowEmailIntoChannel is set to True"
|
||||
}
|
||||
else {
|
||||
"AllowEmailIntoChannel is set to False"
|
||||
}
|
||||
|
||||
# Create and populate the CISAuditResult object
|
||||
$params = @{
|
||||
Rec = "8.1.2"
|
||||
Result = -not $allowEmailIntoChannel
|
||||
Status = if (-not $allowEmailIntoChannel) { "Pass" } else { "Fail" }
|
||||
Details = $details
|
||||
FailureReason = $failureReasons
|
||||
}
|
||||
$auditResult = Initialize-CISAuditResult @params
|
||||
}
|
||||
|
||||
end {
|
||||
# Return auditResults
|
||||
return $auditResults
|
||||
# Return the audit result
|
||||
return $auditResult
|
||||
}
|
||||
}
|
||||
|
@@ -1,51 +1,52 @@
|
||||
function Test-BlockMailForwarding {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
# Aligned Compare
|
||||
# Parameters can be added if needed
|
||||
)
|
||||
|
||||
begin {
|
||||
|
||||
$auditResult = [CISAuditResult]::new()
|
||||
$auditResult.Rec = "6.2.1"
|
||||
$auditResult.ELevel = "E3"
|
||||
$auditResult.ProfileLevel = "L1"
|
||||
$auditResult.CISControlVer = "v8"
|
||||
$auditResult.CISControl = "0.0"
|
||||
$auditResult.CISDescription = "Explicitly Not Mapped"
|
||||
$auditResult.IG1 = $false
|
||||
$auditResult.IG2 = $false
|
||||
$auditResult.IG3 = $false
|
||||
$auditResult.RecDescription = "Ensure all forms of mail forwarding are blocked and/or disabled"
|
||||
# Dot source the class script if necessary
|
||||
#. .\source\Classes\CISAuditResult.ps1
|
||||
# Initialization code, if needed
|
||||
}
|
||||
|
||||
process {
|
||||
# Verify that no rules are forwarding the email to external domains
|
||||
$transportRules = Get-TransportRule | Where-Object { $_.RedirectMessageTo -ne $null }
|
||||
# 6.2.1 (L1) Ensure all forms of mail forwarding are blocked and/or disabled
|
||||
|
||||
# Retrieve the transport rules that redirect messages
|
||||
$transportRules = Get-TransportRule | Where-Object { $null -ne $_.RedirectMessageTo }
|
||||
$forwardingBlocked = $transportRules.Count -eq 0
|
||||
|
||||
$auditResult.Result = $forwardingBlocked
|
||||
$auditResult.Details = if ($transportRules.Count -gt 0) {
|
||||
# Prepare failure reasons and details based on compliance
|
||||
$failureReasons = if ($transportRules.Count -gt 0) {
|
||||
"Mail forwarding rules found: $($transportRules.Name -join ', ')"
|
||||
}
|
||||
else {
|
||||
"N/A"
|
||||
}
|
||||
|
||||
$details = if ($transportRules.Count -gt 0) {
|
||||
$transportRules | ForEach-Object {
|
||||
"$($_.Name) redirects to $($_.RedirectMessageTo)"
|
||||
} -join " | "
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
"Step 1: No forwarding rules found. Please proceed with Step 2 described in CIS Benchmark."
|
||||
}
|
||||
$auditResult.FailureReason = if (-not $forwardingBlocked) {
|
||||
"Mail forwarding rules found: $($transportRules.Name -join ', ')"
|
||||
} else {
|
||||
"N/A"
|
||||
|
||||
$params = @{
|
||||
Rec = "6.2.1"
|
||||
Result = $forwardingBlocked
|
||||
Status = if ($forwardingBlocked) { "Pass" } else { "Fail" }
|
||||
Details = $details
|
||||
FailureReason = $failureReasons
|
||||
}
|
||||
$auditResult.Status = if ($forwardingBlocked) { "Pass" } else { "Fail" }
|
||||
$auditResult = Initialize-CISAuditResult @params
|
||||
}
|
||||
|
||||
end {
|
||||
# Return the result object
|
||||
# Return the audit result
|
||||
return $auditResult
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@@ -1,48 +1,53 @@
|
||||
function Test-BlockSharedMailboxSignIn {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
# Aligned
|
||||
# Parameters can be added if needed
|
||||
)
|
||||
|
||||
begin {
|
||||
# Dot source the class script
|
||||
|
||||
$auditResults = @()
|
||||
# Dot source the class script if necessary
|
||||
#. .\source\Classes\CISAuditResult.ps1
|
||||
# Initialization code, if needed
|
||||
}
|
||||
|
||||
process {
|
||||
# 1.2.2 (L1) Ensure sign-in to shared mailboxes is blocked
|
||||
# Pass if all shared mailboxes have AccountEnabled set to False.
|
||||
# Fail if any shared mailbox has AccountEnabled set to True.
|
||||
# Review: Details property - Add verbosity.
|
||||
|
||||
# Retrieve shared mailbox details
|
||||
$MBX = Get-EXOMailbox -RecipientTypeDetails SharedMailbox
|
||||
$sharedMailboxDetails = $MBX | ForEach-Object { Get-AzureADUser -ObjectId $_.ExternalDirectoryObjectId }
|
||||
$enabledMailboxes = $sharedMailboxDetails | Where-Object { $_.AccountEnabled } | ForEach-Object { $_.DisplayName }
|
||||
$allBlocked = $enabledMailboxes.Count -eq 0
|
||||
|
||||
# Create an instance of CISAuditResult and populate it
|
||||
$auditResult = [CISAuditResult]::new()
|
||||
$auditResult.CISControlVer = "v8"
|
||||
$auditResult.CISControl = "0.0" # Control is explicitly not mapped
|
||||
$auditResult.CISDescription = "Explicitly Not Mapped"
|
||||
$auditResult.Rec = "1.2.2"
|
||||
$auditResult.ELevel = "E3"
|
||||
$auditResult.ProfileLevel = "L1"
|
||||
$auditResult.IG1 = $false # Control is not mapped, hence IG1 is false
|
||||
$auditResult.IG2 = $false # Control is not mapped, hence IG2 is false
|
||||
$auditResult.IG3 = $false # Control is not mapped, hence IG3 is false
|
||||
$auditResult.RecDescription = "Ensure sign-in to shared mailboxes is blocked"
|
||||
$auditResult.Result = $allBlocked
|
||||
$auditResult.Details = "Enabled Mailboxes: $($enabledMailboxes -join ', ')"
|
||||
$auditResult.FailureReason = if ($allBlocked) { "N/A" } else { "Some mailboxes have sign-in enabled: $($enabledMailboxes -join ', ')" }
|
||||
$auditResult.Status = if ($allBlocked) { "Pass" } else { "Fail" }
|
||||
# Prepare failure reasons and details based on compliance
|
||||
$failureReasons = if (-not $allBlocked) {
|
||||
"Some mailboxes have sign-in enabled: $($enabledMailboxes -join ', ')"
|
||||
}
|
||||
else {
|
||||
"N/A"
|
||||
}
|
||||
|
||||
$auditResults += $auditResult
|
||||
$details = if ($allBlocked) {
|
||||
"All shared mailboxes have sign-in blocked."
|
||||
}
|
||||
else {
|
||||
"Enabled Mailboxes: $($enabledMailboxes -join ', ')"
|
||||
}
|
||||
|
||||
# Create and populate the CISAuditResult object
|
||||
$params = @{
|
||||
Rec = "1.2.2"
|
||||
Result = $allBlocked
|
||||
Status = if ($allBlocked) { "Pass" } else { "Fail" }
|
||||
Details = $details
|
||||
FailureReason = $failureReasons
|
||||
}
|
||||
$auditResult = Initialize-CISAuditResult @params
|
||||
}
|
||||
|
||||
end {
|
||||
# Return auditResults
|
||||
return $auditResults
|
||||
# Return the audit result
|
||||
return $auditResult
|
||||
}
|
||||
}
|
||||
|
@@ -1,46 +1,51 @@
|
||||
function Test-CommonAttachmentFilter {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
# Aligned
|
||||
# Parameters can be added if needed
|
||||
)
|
||||
|
||||
begin {
|
||||
|
||||
$auditResults = @()
|
||||
# Dot source the class script if necessary
|
||||
#. .\source\Classes\CISAuditResult.ps1
|
||||
# Initialization code, if needed
|
||||
}
|
||||
|
||||
process {
|
||||
# 2.1.2 (L1) Ensure the Common Attachment Types Filter is enabled
|
||||
# Pass if EnableFileFilter is set to True. Fail otherwise.
|
||||
|
||||
# Retrieve the attachment filter policy
|
||||
$attachmentFilter = Get-MalwareFilterPolicy -Identity Default | Select-Object EnableFileFilter
|
||||
$result = $attachmentFilter.EnableFileFilter
|
||||
$details = "File Filter Enabled: $($attachmentFilter.EnableFileFilter)"
|
||||
$failureReason = if ($result) { "N/A" } else { "Common Attachment Types Filter is disabled" }
|
||||
$status = if ($result) { "Pass" } else { "Fail" }
|
||||
|
||||
# Create an instance of CISAuditResult and populate it
|
||||
$auditResult = [CISAuditResult]::new()
|
||||
$auditResult.Status = $status
|
||||
$auditResult.ELevel = "E3"
|
||||
$auditResult.ProfileLevel = "L1"
|
||||
$auditResult.Rec = "2.1.2"
|
||||
$auditResult.RecDescription = "Ensure the Common Attachment Types Filter is enabled"
|
||||
$auditResult.CISControlVer = "v8"
|
||||
$auditResult.CISControl = "9.6"
|
||||
$auditResult.CISDescription = "Block Unnecessary File Types"
|
||||
$auditResult.IG1 = $false
|
||||
$auditResult.IG2 = $true
|
||||
$auditResult.IG3 = $true
|
||||
$auditResult.Result = $result
|
||||
$auditResult.Details = $details
|
||||
$auditResult.FailureReason = $failureReason
|
||||
# Prepare failure reasons and details based on compliance
|
||||
$failureReasons = if (-not $result) {
|
||||
"Common Attachment Types Filter is disabled"
|
||||
}
|
||||
else {
|
||||
"N/A"
|
||||
}
|
||||
|
||||
$auditResults += $auditResult
|
||||
$details = if ($result) {
|
||||
"File Filter Enabled: True"
|
||||
}
|
||||
else {
|
||||
"File Filter Enabled: False"
|
||||
}
|
||||
|
||||
# Create and populate the CISAuditResult object
|
||||
$params = @{
|
||||
Rec = "2.1.2"
|
||||
Result = $result
|
||||
Status = if ($result) { "Pass" } else { "Fail" }
|
||||
Details = $details
|
||||
FailureReason = $failureReasons
|
||||
}
|
||||
$auditResult = Initialize-CISAuditResult @params
|
||||
}
|
||||
|
||||
end {
|
||||
# Return auditResults
|
||||
return $auditResults
|
||||
# Return the audit result
|
||||
return $auditResult
|
||||
}
|
||||
}
|
||||
|
@@ -1,40 +1,51 @@
|
||||
function Test-CustomerLockbox {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
# Define your parameters here
|
||||
# Aligned
|
||||
# Define your parameters here if needed
|
||||
)
|
||||
|
||||
begin {
|
||||
|
||||
$auditResults = @()
|
||||
# Dot source the class script if necessary
|
||||
#. .\source\Classes\CISAuditResult.ps1
|
||||
# Initialization code, if needed
|
||||
}
|
||||
|
||||
process {
|
||||
# 1.3.6 (L2) Ensure the customer lockbox feature is enabled
|
||||
|
||||
# Retrieve the organization configuration
|
||||
$orgConfig = Get-OrganizationConfig | Select-Object CustomerLockBoxEnabled
|
||||
$customerLockboxEnabled = $orgConfig.CustomerLockBoxEnabled
|
||||
|
||||
$auditResult = [CISAuditResult]::new()
|
||||
$auditResult.Status = if ($customerLockboxEnabled) { "Pass" } else { "Fail" }
|
||||
$auditResult.ELevel = "E5"
|
||||
$auditResult.ProfileLevel = "L2"
|
||||
$auditResult.Rec = "1.3.6"
|
||||
$auditResult.RecDescription = "Ensure the customer lockbox feature is enabled"
|
||||
$auditResult.CISControlVer = 'v8'
|
||||
$auditResult.CISControl = "0.0" # As per the snapshot provided, this is explicitly not mapped
|
||||
$auditResult.CISDescription = "Explicitly Not Mapped"
|
||||
$auditResult.IG1 = $false
|
||||
$auditResult.IG2 = $false
|
||||
$auditResult.IG3 = $false
|
||||
$auditResult.Result = $customerLockboxEnabled
|
||||
$auditResult.Details = "Customer Lockbox Enabled: $customerLockboxEnabled"
|
||||
$auditResult.FailureReason = if ($customerLockboxEnabled) { "N/A" } else { "Customer lockbox feature is not enabled." }
|
||||
# Prepare failure reasons and details based on compliance
|
||||
$failureReasons = if (-not $customerLockboxEnabled) {
|
||||
"Customer lockbox feature is not enabled."
|
||||
}
|
||||
else {
|
||||
"N/A"
|
||||
}
|
||||
|
||||
$auditResults += $auditResult
|
||||
$details = if ($customerLockboxEnabled) {
|
||||
"Customer Lockbox Enabled: True"
|
||||
}
|
||||
else {
|
||||
"Customer Lockbox Enabled: False"
|
||||
}
|
||||
|
||||
# Create and populate the CISAuditResult object #
|
||||
$params = @{
|
||||
Rec = "1.3.6"
|
||||
Result = $customerLockboxEnabled
|
||||
Status = if ($customerLockboxEnabled) { "Pass" } else { "Fail" }
|
||||
Details = $details
|
||||
FailureReason = $failureReasons
|
||||
}
|
||||
$auditResult = Initialize-CISAuditResult @params
|
||||
}
|
||||
|
||||
end {
|
||||
# Return auditResults
|
||||
return $auditResults
|
||||
# Return the audit result
|
||||
return $auditResult
|
||||
}
|
||||
}
|
||||
|
@@ -1,45 +1,51 @@
|
||||
function Test-DialInBypassLobby {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
# Aligned
|
||||
# Parameters can be defined here if needed
|
||||
)
|
||||
|
||||
begin {
|
||||
# Dot source the class script
|
||||
|
||||
$auditResults = @()
|
||||
# Dot source the class script if necessary
|
||||
#. .\source\Classes\CISAuditResult.ps1
|
||||
# Initialization code, if needed
|
||||
}
|
||||
|
||||
process {
|
||||
# 8.5.4 (L1) Ensure users dialing in can't bypass the lobby
|
||||
|
||||
# Connect to Teams PowerShell using Connect-MicrosoftTeams
|
||||
|
||||
# Retrieve Teams meeting policy for PSTN users
|
||||
$CsTeamsMeetingPolicyPSTN = Get-CsTeamsMeetingPolicy -Identity Global | Select-Object -Property AllowPSTNUsersToBypassLobby
|
||||
$PSTNBypassDisabled = -not $CsTeamsMeetingPolicyPSTN.AllowPSTNUsersToBypassLobby
|
||||
|
||||
# Create an instance of CISAuditResult and populate it
|
||||
$auditResult = [CISAuditResult]::new()
|
||||
$auditResult.CISControlVer = "v8"
|
||||
$auditResult.CISControl = "0.0" # Explicitly Not Mapped as per the image provided
|
||||
$auditResult.CISDescription = "Explicitly Not Mapped"
|
||||
$auditResult.Rec = "8.5.4"
|
||||
$auditResult.ELevel = "E3"
|
||||
$auditResult.ProfileLevel = "L1"
|
||||
$auditResult.IG1 = $false # Set based on the CIS Controls image
|
||||
$auditResult.IG2 = $false # Set based on the CIS Controls image
|
||||
$auditResult.IG3 = $false # Set based on the CIS Controls image
|
||||
$auditResult.RecDescription = "Ensure users dialing in can't bypass the lobby"
|
||||
$auditResult.Result = $PSTNBypassDisabled
|
||||
$auditResult.Details = "AllowPSTNUsersToBypassLobby is set to $($CsTeamsMeetingPolicyPSTN.AllowPSTNUsersToBypassLobby)"
|
||||
$auditResult.FailureReason = if ($PSTNBypassDisabled) { "N/A" } else { "Users dialing in can bypass the lobby" }
|
||||
$auditResult.Status = if ($PSTNBypassDisabled) { "Pass" } else { "Fail" }
|
||||
# Prepare failure reasons and details based on compliance
|
||||
$failureReasons = if (-not $PSTNBypassDisabled) {
|
||||
"Users dialing in can bypass the lobby"
|
||||
}
|
||||
else {
|
||||
"N/A"
|
||||
}
|
||||
|
||||
$auditResults += $auditResult
|
||||
$details = if ($PSTNBypassDisabled) {
|
||||
"AllowPSTNUsersToBypassLobby is set to False"
|
||||
}
|
||||
else {
|
||||
"AllowPSTNUsersToBypassLobby is set to True"
|
||||
}
|
||||
|
||||
# Create and populate the CISAuditResult object
|
||||
$params = @{
|
||||
Rec = "8.5.4"
|
||||
Result = $PSTNBypassDisabled
|
||||
Status = if ($PSTNBypassDisabled) { "Pass" } else { "Fail" }
|
||||
Details = $details
|
||||
FailureReason = $failureReasons
|
||||
}
|
||||
$auditResult = Initialize-CISAuditResult @params
|
||||
}
|
||||
|
||||
end {
|
||||
# Return auditResults
|
||||
return $auditResults
|
||||
# Return the audit result
|
||||
return $auditResult
|
||||
}
|
||||
}
|
||||
|
@@ -1,41 +1,53 @@
|
||||
function Test-DisallowInfectedFilesDownload {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
# Define your parameters here
|
||||
# Aligned
|
||||
# Define your parameters here if needed
|
||||
)
|
||||
|
||||
begin {
|
||||
# Initialization code
|
||||
# Dot source the class script if necessary
|
||||
#. .\source\Classes\CISAuditResult.ps1
|
||||
|
||||
$auditResult = [CISAuditResult]::new()
|
||||
# Initialization code, if needed
|
||||
}
|
||||
|
||||
process {
|
||||
# 7.3.1 (L2) Ensure Office 365 SharePoint infected files are disallowed for download
|
||||
|
||||
# Retrieve the SharePoint tenant configuration
|
||||
$SPOTenantDisallowInfectedFileDownload = Get-SPOTenant | Select-Object DisallowInfectedFileDownload
|
||||
$isDisallowInfectedFileDownloadEnabled = $SPOTenantDisallowInfectedFileDownload.DisallowInfectedFileDownload
|
||||
|
||||
# Populate the auditResult object with the required properties
|
||||
$auditResult.CISControlVer = "v8"
|
||||
$auditResult.CISControl = "10.1"
|
||||
$auditResult.CISDescription = "Deploy and Maintain Anti-Malware Software"
|
||||
# Prepare failure reasons and details based on compliance
|
||||
$failureReasons = if (-not $isDisallowInfectedFileDownloadEnabled) {
|
||||
"Downloading infected files is not disallowed."
|
||||
}
|
||||
else {
|
||||
"N/A"
|
||||
}
|
||||
|
||||
$auditResult.Rec = "7.3.1"
|
||||
$auditResult.ELevel = "E5"
|
||||
$auditResult.ProfileLevel = "L2"
|
||||
$auditResult.IG1 = $true
|
||||
$auditResult.IG2 = $true
|
||||
$auditResult.IG3 = $true
|
||||
$auditResult.RecDescription = "Ensure Office 365 SharePoint infected files are disallowed for download"
|
||||
$details = if ($isDisallowInfectedFileDownloadEnabled) {
|
||||
"DisallowInfectedFileDownload: True"
|
||||
}
|
||||
else {
|
||||
"DisallowInfectedFileDownload: False"
|
||||
}
|
||||
|
||||
# Create and populate the CISAuditResult object
|
||||
$params = @{
|
||||
Rec = "7.3.1"
|
||||
Result = $isDisallowInfectedFileDownloadEnabled
|
||||
Status = if ($isDisallowInfectedFileDownloadEnabled) { "Pass" } else { "Fail" }
|
||||
Details = $details
|
||||
FailureReason = $failureReasons
|
||||
}
|
||||
$auditResult = Initialize-CISAuditResult @params
|
||||
|
||||
$auditResult.Result = $isDisallowInfectedFileDownloadEnabled
|
||||
$auditResult.Details = "DisallowInfectedFileDownload: $($SPOTenantDisallowInfectedFileDownload.DisallowInfectedFileDownload)"
|
||||
$auditResult.FailureReason = if (-not $isDisallowInfectedFileDownloadEnabled) { "Downloading infected files is not disallowed." } else { "N/A" }
|
||||
$auditResult.Status = if ($isDisallowInfectedFileDownloadEnabled) { "Pass" } else { "Fail" }
|
||||
}
|
||||
|
||||
end {
|
||||
# Return auditResult
|
||||
# Return the audit result
|
||||
return $auditResult
|
||||
}
|
||||
}
|
||||
|
@@ -1,44 +1,52 @@
|
||||
function Test-EnableDKIM {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
# Aligned
|
||||
# Parameters can be added if needed
|
||||
)
|
||||
|
||||
begin {
|
||||
# Dot source the class script
|
||||
|
||||
$auditResults = @()
|
||||
# Dot source the class script if necessary
|
||||
#. .\source\Classes\CISAuditResult.ps1
|
||||
# Initialization code, if needed
|
||||
}
|
||||
|
||||
process {
|
||||
# 2.1.9 (L1) Ensure DKIM is enabled for all Exchange Online Domains
|
||||
# Pass if Enabled is True for all domains. Fail if any domain has Enabled set to False.
|
||||
|
||||
# Retrieve DKIM configuration for all domains
|
||||
$dkimConfig = Get-DkimSigningConfig | Select-Object Domain, Enabled
|
||||
$dkimResult = ($dkimConfig | ForEach-Object { $_.Enabled }) -notcontains $false
|
||||
$dkimFailedDomains = $dkimConfig | Where-Object { -not $_.Enabled } | ForEach-Object { $_.Domain }
|
||||
|
||||
# Create an instance of CISAuditResult and populate it
|
||||
$auditResult = [CISAuditResult]::new()
|
||||
$auditResult.Status = if ($dkimResult) { "Pass" } else { "Fail" }
|
||||
$auditResult.ELevel = "E3"
|
||||
$auditResult.ProfileLevel = "L1"
|
||||
$auditResult.Rec = "2.1.9"
|
||||
$auditResult.RecDescription = "Ensure that DKIM is enabled for all Exchange Online Domains"
|
||||
$auditResult.CISControlVer = "v8"
|
||||
$auditResult.CISControl = "9.5"
|
||||
$auditResult.CISDescription = "Implement DMARC"
|
||||
$auditResult.IG1 = $false
|
||||
$auditResult.IG2 = $true
|
||||
$auditResult.IG3 = $true
|
||||
$auditResult.Result = $dkimResult
|
||||
$auditResult.Details = if (-not $dkimResult) { "DKIM not enabled for: $($dkimFailedDomains -join ', ')" } else { "All domains have DKIM enabled" }
|
||||
$auditResult.FailureReason = if (-not $dkimResult) { "DKIM is not enabled for some domains" } else { "N/A" }
|
||||
# Prepare failure reasons and details based on compliance
|
||||
$failureReasons = if (-not $dkimResult) {
|
||||
"DKIM is not enabled for some domains"
|
||||
}
|
||||
else {
|
||||
"N/A"
|
||||
}
|
||||
|
||||
$auditResults += $auditResult
|
||||
$details = if ($dkimResult) {
|
||||
"All domains have DKIM enabled"
|
||||
}
|
||||
else {
|
||||
"DKIM not enabled for: $($dkimFailedDomains -join ', ')"
|
||||
}
|
||||
|
||||
# Create and populate the CISAuditResult object
|
||||
$params = @{
|
||||
Rec = "2.1.9"
|
||||
Result = $dkimResult
|
||||
Status = if ($dkimResult) { "Pass" } else { "Fail" }
|
||||
Details = $details
|
||||
FailureReason = $failureReasons
|
||||
}
|
||||
$auditResult = Initialize-CISAuditResult @params
|
||||
}
|
||||
|
||||
end {
|
||||
# Return auditResults
|
||||
return $auditResults
|
||||
# Return the audit result
|
||||
return $auditResult
|
||||
}
|
||||
}
|
@@ -1,45 +1,52 @@
|
||||
function Test-ExternalNoControl {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
# Aligned
|
||||
# Parameters can be defined here if needed
|
||||
)
|
||||
|
||||
begin {
|
||||
# Dot source the class script
|
||||
# Dot source the class script if necessary
|
||||
#. .\source\Classes\CISAuditResult.ps1
|
||||
|
||||
$auditResults = @()
|
||||
# Initialization code, if needed
|
||||
}
|
||||
|
||||
process {
|
||||
# 8.5.7 (L1) Ensure external participants can't give or request control
|
||||
|
||||
# Connect to Teams PowerShell using Connect-MicrosoftTeams
|
||||
|
||||
# Retrieve Teams meeting policy for external participant control
|
||||
$CsTeamsMeetingPolicyControl = Get-CsTeamsMeetingPolicy -Identity Global | Select-Object -Property AllowExternalParticipantGiveRequestControl
|
||||
$externalControlRestricted = -not $CsTeamsMeetingPolicyControl.AllowExternalParticipantGiveRequestControl
|
||||
|
||||
# Create an instance of CISAuditResult and populate it
|
||||
$auditResult = [CISAuditResult]::new()
|
||||
$auditResult.CISControlVer = "v8"
|
||||
$auditResult.CISControl = "0.0" # Explicitly Not Mapped as per the image provided
|
||||
$auditResult.CISDescription = "Explicitly Not Mapped"
|
||||
$auditResult.Rec = "8.5.7"
|
||||
$auditResult.ELevel = "E3"
|
||||
$auditResult.ProfileLevel = "L1"
|
||||
$auditResult.IG1 = $false # Set based on the CIS Controls image
|
||||
$auditResult.IG2 = $false # Set based on the CIS Controls image
|
||||
$auditResult.IG3 = $false # Set based on the CIS Controls image
|
||||
$auditResult.RecDescription = "Ensure external participants can't give or request control"
|
||||
$auditResult.Result = $externalControlRestricted
|
||||
$auditResult.Details = "AllowExternalParticipantGiveRequestControl is set to $($CsTeamsMeetingPolicyControl.AllowExternalParticipantGiveRequestControl)"
|
||||
$auditResult.FailureReason = if ($externalControlRestricted) { "N/A" } else { "External participants can give or request control" }
|
||||
$auditResult.Status = if ($externalControlRestricted) { "Pass" } else { "Fail" }
|
||||
# Prepare failure reasons and details based on compliance
|
||||
$failureReasons = if (-not $externalControlRestricted) {
|
||||
"External participants can give or request control"
|
||||
}
|
||||
else {
|
||||
"N/A"
|
||||
}
|
||||
|
||||
$auditResults += $auditResult
|
||||
$details = if ($externalControlRestricted) {
|
||||
"AllowExternalParticipantGiveRequestControl is set to False"
|
||||
}
|
||||
else {
|
||||
"AllowExternalParticipantGiveRequestControl is set to True"
|
||||
}
|
||||
|
||||
# Create and populate the CISAuditResult object
|
||||
$params = @{
|
||||
Rec = "8.5.7"
|
||||
Result = $externalControlRestricted
|
||||
Status = if ($externalControlRestricted) { "Pass" } else { "Fail" }
|
||||
Details = $details
|
||||
FailureReason = $failureReasons
|
||||
}
|
||||
$auditResult = Initialize-CISAuditResult @params
|
||||
}
|
||||
|
||||
end {
|
||||
# Return auditResults
|
||||
return $auditResults
|
||||
# Return the audit result
|
||||
return $auditResult
|
||||
}
|
||||
}
|
||||
|
@@ -1,17 +1,21 @@
|
||||
function Test-ExternalSharingCalendars {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
# Aligned
|
||||
# Parameters can be added if needed
|
||||
)
|
||||
|
||||
begin {
|
||||
# Dot source the class script
|
||||
# Dot source the class script if necessary
|
||||
#. .\source\Classes\CISAuditResult.ps1
|
||||
|
||||
$auditResults = @()
|
||||
# Initialization code, if needed
|
||||
}
|
||||
|
||||
process {
|
||||
# 1.3.3 (L2) Ensure 'External sharing' of calendars is not available (Automated)
|
||||
|
||||
# Retrieve sharing policies related to calendar sharing
|
||||
$sharingPolicies = Get-SharingPolicy | Where-Object { $_.Domains -like '*CalendarSharing*' }
|
||||
|
||||
# Check if calendar sharing is disabled in all applicable policies
|
||||
@@ -24,30 +28,34 @@ function Test-ExternalSharingCalendars {
|
||||
}
|
||||
}
|
||||
|
||||
# Create an instance of CISAuditResult and populate it
|
||||
$auditResult = [CISAuditResult]::new()
|
||||
$auditResult.Rec = "1.3.3"
|
||||
$auditResult.RecDescription = "Ensure 'External sharing' of calendars is not available"
|
||||
$auditResult.ELevel = "E3"
|
||||
$auditResult.ProfileLevel = "L2"
|
||||
# The following IG values are placeholders. Replace with actual values when known.
|
||||
$auditResult.IG1 = $false
|
||||
$auditResult.IG2 = $true
|
||||
$auditResult.IG3 = $true
|
||||
$auditResult.CISControlVer = "v8"
|
||||
# Placeholder for CIS Control, to be replaced with the actual value when available
|
||||
$auditResult.CISControl = "4.8"
|
||||
$auditResult.CISDescription = "Uninstall or Disable Unnecessary Services on Enterprise Assets and Software"
|
||||
$auditResult.Result = $isExternalSharingDisabled
|
||||
$auditResult.Details = if ($isExternalSharingDisabled) { "Calendar sharing with external users is disabled." } else { "Enabled Sharing Policies: $($sharingPolicyDetails -join ', ')" }
|
||||
$auditResult.FailureReason = if ($isExternalSharingDisabled) { "N/A" } else { "Calendar sharing with external users is enabled in one or more policies." }
|
||||
$auditResult.Status = if ($isExternalSharingDisabled) { "Pass" } else { "Fail" }
|
||||
# Prepare failure reasons and details based on compliance
|
||||
$failureReasons = if (-not $isExternalSharingDisabled) {
|
||||
"Calendar sharing with external users is enabled in one or more policies."
|
||||
}
|
||||
else {
|
||||
"N/A"
|
||||
}
|
||||
|
||||
$auditResults += $auditResult
|
||||
$details = if ($isExternalSharingDisabled) {
|
||||
"Calendar sharing with external users is disabled."
|
||||
}
|
||||
else {
|
||||
"Enabled Sharing Policies: $($sharingPolicyDetails -join ', ')"
|
||||
}
|
||||
|
||||
# Create and populate the CISAuditResult object
|
||||
$params = @{
|
||||
Rec = "1.3.3"
|
||||
Result = $isExternalSharingDisabled
|
||||
Status = if ($isExternalSharingDisabled) { "Pass" } else { "Fail" }
|
||||
Details = $details
|
||||
FailureReason = $failureReasons
|
||||
}
|
||||
$auditResult = Initialize-CISAuditResult @params
|
||||
}
|
||||
|
||||
end {
|
||||
# Return auditResults
|
||||
return $auditResults
|
||||
# Return the audit result
|
||||
return $auditResult
|
||||
}
|
||||
}
|
||||
|
@@ -1,46 +1,52 @@
|
||||
function Test-GlobalAdminsCount {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
# Define your parameters here
|
||||
# Aligned
|
||||
# Define your parameters here if needed
|
||||
)
|
||||
|
||||
begin {
|
||||
# Dot source the class script
|
||||
# Dot source the class script if necessary
|
||||
#. .\source\Classes\CISAuditResult.ps1
|
||||
|
||||
$auditResults = @()
|
||||
# Initialization code, if needed
|
||||
}
|
||||
|
||||
process {
|
||||
# 1.1.3 (L1) Ensure that between two and four global admins are designated
|
||||
# Pass if the count of global admins is between 2 and 4. Fail otherwise.
|
||||
|
||||
# Retrieve global admin role and members
|
||||
$globalAdminRole = Get-MgDirectoryRole -Filter "RoleTemplateId eq '62e90394-69f5-4237-9190-012177145e10'"
|
||||
$globalAdmins = Get-MgDirectoryRoleMember -DirectoryRoleId $globalAdminRole.Id
|
||||
$globalAdminCount = $globalAdmins.AdditionalProperties.Count
|
||||
$globalAdminUsernames = ($globalAdmins | ForEach-Object { $_.AdditionalProperties["displayName"] }) -join ', '
|
||||
|
||||
# Create an instance of CISAuditResult and populate it
|
||||
$auditResult = [CISAuditResult]::new()
|
||||
$auditResult.CISControlVer = "v8"
|
||||
$auditResult.CISControl = "5.1"
|
||||
$auditResult.CISDescription = "Establish and Maintain an Inventory of Accounts"
|
||||
$auditResult.Rec = "1.1.3"
|
||||
$auditResult.ELevel = "E3" # Based on your environment (E3, E5, etc.)
|
||||
$auditResult.ProfileLevel = "L1"
|
||||
$auditResult.IG1 = $true # Set based on the benchmark
|
||||
$auditResult.IG2 = $true # Set based on the benchmark
|
||||
$auditResult.IG3 = $true # Set based on the benchmark
|
||||
$auditResult.RecDescription = "Ensure that between two and four global admins are designated"
|
||||
$auditResult.Result = $globalAdminCount -ge 2 -and $globalAdminCount -le 4
|
||||
$auditResult.Details = "Count: $globalAdminCount; Users: $globalAdminUsernames"
|
||||
$auditResult.FailureReason = if ($globalAdminCount -lt 2) { "Less than 2 global admins: $globalAdminUsernames" } elseif ($globalAdminCount -gt 4) { "More than 4 global admins: $globalAdminUsernames" } else { "N/A" }
|
||||
$auditResult.Status = if ($globalAdminCount -ge 2 -and $globalAdminCount -le 4) { "Pass" } else { "Fail" }
|
||||
# Prepare failure reasons and details based on compliance
|
||||
$failureReasons = if ($globalAdminCount -lt 2) {
|
||||
"Less than 2 global admins: $globalAdminUsernames"
|
||||
}
|
||||
elseif ($globalAdminCount -gt 4) {
|
||||
"More than 4 global admins: $globalAdminUsernames"
|
||||
}
|
||||
else {
|
||||
"N/A"
|
||||
}
|
||||
|
||||
$auditResults += $auditResult
|
||||
$details = "Count: $globalAdminCount; Users: $globalAdminUsernames"
|
||||
|
||||
# Create and populate the CISAuditResult object
|
||||
$params = @{
|
||||
Rec = "1.1.3"
|
||||
Result = $globalAdminCount -ge 2 -and $globalAdminCount -le 4
|
||||
Status = if ($globalAdminCount -ge 2 -and $globalAdminCount -le 4) { "Pass" } else { "Fail" }
|
||||
Details = $details
|
||||
FailureReason = $failureReasons
|
||||
}
|
||||
$auditResult = Initialize-CISAuditResult @params
|
||||
}
|
||||
|
||||
end {
|
||||
# Return auditResults
|
||||
return $auditResults
|
||||
# Return the audit result
|
||||
return $auditResult
|
||||
}
|
||||
}
|
||||
|
@@ -1,41 +1,47 @@
|
||||
function Test-GuestAccessExpiration {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
# Define your parameters here
|
||||
# Aligned
|
||||
# Define your parameters here if needed
|
||||
)
|
||||
|
||||
begin {
|
||||
# Initialization code
|
||||
# Dot source the class script if necessary
|
||||
#. .\source\Classes\CISAuditResult.ps1
|
||||
|
||||
$auditResult = [CISAuditResult]::new()
|
||||
# Initialization code, if needed
|
||||
}
|
||||
|
||||
process {
|
||||
# 7.2.9 (L1) Ensure guest access to a site or OneDrive will expire automatically
|
||||
|
||||
# Retrieve SharePoint tenant settings related to guest access expiration
|
||||
$SPOTenantGuestAccess = Get-SPOTenant | Select-Object ExternalUserExpirationRequired, ExternalUserExpireInDays
|
||||
$isGuestAccessExpirationConfiguredCorrectly = $SPOTenantGuestAccess.ExternalUserExpirationRequired -and $SPOTenantGuestAccess.ExternalUserExpireInDays -le 30
|
||||
|
||||
# Populate the auditResult object with the required properties
|
||||
$auditResult.CISControlVer = "v8"
|
||||
$auditResult.CISControl = "0.0"
|
||||
$auditResult.CISDescription = "Explicitly Not Mapped"
|
||||
# Prepare failure reasons and details based on compliance
|
||||
$failureReasons = if (-not $isGuestAccessExpirationConfiguredCorrectly) {
|
||||
"Guest access expiration is not configured to automatically expire within 30 days or less."
|
||||
}
|
||||
else {
|
||||
"N/A"
|
||||
}
|
||||
|
||||
$auditResult.Rec = "7.2.9"
|
||||
$auditResult.ELevel = "E3"
|
||||
$auditResult.ProfileLevel = "L1"
|
||||
$auditResult.IG1 = $false
|
||||
$auditResult.IG2 = $false
|
||||
$auditResult.IG3 = $false
|
||||
$auditResult.RecDescription = "Ensure guest access to a site or OneDrive will expire automatically"
|
||||
$details = "ExternalUserExpirationRequired: $($SPOTenantGuestAccess.ExternalUserExpirationRequired); ExternalUserExpireInDays: $($SPOTenantGuestAccess.ExternalUserExpireInDays)"
|
||||
|
||||
$auditResult.Result = $isGuestAccessExpirationConfiguredCorrectly
|
||||
$auditResult.Details = "ExternalUserExpirationRequired: $($SPOTenantGuestAccess.ExternalUserExpirationRequired); ExternalUserExpireInDays: $($SPOTenantGuestAccess.ExternalUserExpireInDays)"
|
||||
$auditResult.FailureReason = if (-not $isGuestAccessExpirationConfiguredCorrectly) { "Guest access expiration is not configured to automatically expire within 30 days or less." } else { "N/A" }
|
||||
$auditResult.Status = if ($isGuestAccessExpirationConfiguredCorrectly) { "Pass" } else { "Fail" }
|
||||
# Create and populate the CISAuditResult object
|
||||
$params = @{
|
||||
Rec = "7.2.9"
|
||||
Result = $isGuestAccessExpirationConfiguredCorrectly
|
||||
Status = if ($isGuestAccessExpirationConfiguredCorrectly) { "Pass" } else { "Fail" }
|
||||
Details = $details
|
||||
FailureReason = $failureReasons
|
||||
}
|
||||
$auditResult = Initialize-CISAuditResult @params
|
||||
}
|
||||
|
||||
end {
|
||||
# Return auditResult
|
||||
# Return the audit result
|
||||
return $auditResult
|
||||
}
|
||||
}
|
||||
|
@@ -1,61 +1,54 @@
|
||||
function Test-GuestUsersBiweeklyReview {
|
||||
[CmdletBinding()]
|
||||
param ()
|
||||
param (
|
||||
# Aligned
|
||||
# Define your parameters here if needed
|
||||
)
|
||||
|
||||
begin {
|
||||
# Dot source the class script if necessary
|
||||
#. .\source\Classes\CISAuditResult.ps1
|
||||
$auditResults = @()
|
||||
|
||||
# Initialization code, if needed
|
||||
}
|
||||
|
||||
process {
|
||||
# 1.1.4 (L1) Ensure Guest Users are reviewed at least biweekly
|
||||
# The function will fail if guest users are found since they should be reviewed manually biweekly.
|
||||
|
||||
try {
|
||||
# Connect to Microsoft Graph - placeholder for connection command
|
||||
# Connect-MgGraph -Scopes "User.Read.All"
|
||||
$guestUsers = Get-MgUser -All -Filter "UserType eq 'Guest'"
|
||||
|
||||
# Create an instance of CISAuditResult and populate it
|
||||
$auditResult = [CISAuditResult]::new()
|
||||
$auditResult.CISControl = "5.1, 5.3"
|
||||
$auditResult.CISDescription = "Establish and Maintain an Inventory of Accounts, Disable Dormant Accounts"
|
||||
$auditResult.Rec = "1.1.4"
|
||||
$auditResult.RecDescription = "Ensure Guest Users are reviewed at least biweekly"
|
||||
$auditResult.ELevel = "E3"
|
||||
$auditResult.ProfileLevel = "L1"
|
||||
$auditResult.IG1 = $true
|
||||
$auditResult.IG2 = $true
|
||||
$auditResult.IG3 = $true
|
||||
$auditResult.CISControlVer = 'v8'
|
||||
# Retrieve guest users from Microsoft Graph
|
||||
# Connect-MgGraph -Scopes "User.Read.All"
|
||||
$guestUsers = Get-MgUser -All -Filter "UserType eq 'Guest'"
|
||||
|
||||
if ($guestUsers) {
|
||||
$auditCommand = "Get-MgUser -All -Property UserType,UserPrincipalName | Where {`$_.UserType -ne 'Member'} | Format-Table UserPrincipalName, UserType"
|
||||
$auditResult.Status = "Fail"
|
||||
$auditResult.Result = $false
|
||||
$auditResult.Details = "Manual review required. To list guest users, run: `"$auditCommand`"."
|
||||
$auditResult.FailureReason = "Guest users present: $($guestUsers.Count)"
|
||||
} else {
|
||||
$auditResult.Status = "Pass"
|
||||
$auditResult.Result = $true
|
||||
$auditResult.Details = "No guest users found."
|
||||
$auditResult.FailureReason = "N/A"
|
||||
}
|
||||
# Prepare failure reasons and details based on compliance
|
||||
$failureReasons = if ($guestUsers) {
|
||||
"Guest users present: $($guestUsers.Count)"
|
||||
}
|
||||
catch {
|
||||
$auditResult.Status = "Error"
|
||||
$auditResult.Result = $false
|
||||
$auditResult.Details = "Error while attempting to check guest users. Error message: $($_.Exception.Message)"
|
||||
$auditResult.FailureReason = "An error occurred during the audit check."
|
||||
else {
|
||||
"N/A"
|
||||
}
|
||||
|
||||
$auditResults += $auditResult
|
||||
$details = if ($guestUsers) {
|
||||
$auditCommand = "Get-MgUser -All -Property UserType,UserPrincipalName | Where {`$_.UserType -ne 'Member'} | Format-Table UserPrincipalName, UserType"
|
||||
"Manual review required. To list guest users, run: `"$auditCommand`"."
|
||||
}
|
||||
else {
|
||||
"No guest users found."
|
||||
}
|
||||
|
||||
# Create and populate the CISAuditResult object
|
||||
$params = @{
|
||||
Rec = "1.1.4"
|
||||
Result = -not $guestUsers
|
||||
Status = if ($guestUsers) { "Fail" } else { "Pass" }
|
||||
Details = $details
|
||||
FailureReason = $failureReasons
|
||||
}
|
||||
$auditResult = Initialize-CISAuditResult @params
|
||||
}
|
||||
|
||||
end {
|
||||
# Return auditResults
|
||||
return $auditResults
|
||||
# Return the audit result
|
||||
return $auditResult
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@@ -1,45 +1,47 @@
|
||||
function Test-IdentifyExternalEmail {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
# Aligned
|
||||
# Parameters can be defined here if needed
|
||||
)
|
||||
|
||||
begin {
|
||||
# Dot source the class script
|
||||
# Dot source the class script if necessary
|
||||
#. .\source\Classes\CISAuditResult.ps1
|
||||
|
||||
$auditResults = @()
|
||||
# Initialization code, if needed
|
||||
}
|
||||
|
||||
process {
|
||||
# 6.2.3 (L1) Ensure email from external senders is identified
|
||||
# Requirement is to have external sender tagging enabled
|
||||
# Review
|
||||
|
||||
# Retrieve external sender tagging configuration
|
||||
$externalInOutlook = Get-ExternalInOutlook
|
||||
$externalTaggingEnabled = ($externalInOutlook | ForEach-Object { $_.Enabled }) -contains $true
|
||||
|
||||
# Create an instance of CISAuditResult and populate it
|
||||
$auditResult = [CISAuditResult]::new()
|
||||
$auditResult.Status = if ($externalTaggingEnabled) { "Pass" } else { "Fail" }
|
||||
$auditResult.ELevel = "E3"
|
||||
$auditResult.ProfileLevel = "L1"
|
||||
$auditResult.Rec = "6.2.3"
|
||||
$auditResult.RecDescription = "Ensure email from external senders is identified"
|
||||
$auditResult.CISControlVer = "v8"
|
||||
$auditResult.CISControl = "0.0"
|
||||
$auditResult.CISDescription = "Explicitly Not Mapped"
|
||||
$auditResult.IG1 = $false
|
||||
$auditResult.IG2 = $false
|
||||
$auditResult.IG3 = $false
|
||||
$auditResult.Result = $externalTaggingEnabled
|
||||
$auditResult.Details = "Enabled: $($externalTaggingEnabled); AllowList: $($externalInOutlook.AllowList)"
|
||||
$auditResult.FailureReason = if (-not $externalTaggingEnabled) { "External sender tagging is disabled" } else { "N/A" }
|
||||
# Prepare failure reasons and details based on compliance
|
||||
$failureReasons = if (-not $externalTaggingEnabled) {
|
||||
"External sender tagging is disabled"
|
||||
}
|
||||
else {
|
||||
"N/A"
|
||||
}
|
||||
|
||||
$auditResults += $auditResult
|
||||
$details = "Enabled: $($externalTaggingEnabled); AllowList: $($externalInOutlook.AllowList)"
|
||||
|
||||
# Create and populate the CISAuditResult object
|
||||
$params = @{
|
||||
Rec = "6.2.3"
|
||||
Result = $externalTaggingEnabled
|
||||
Status = if ($externalTaggingEnabled) { "Pass" } else { "Fail" }
|
||||
Details = $details
|
||||
FailureReason = $failureReasons
|
||||
}
|
||||
$auditResult = Initialize-CISAuditResult @params
|
||||
}
|
||||
|
||||
end {
|
||||
# Return auditResults
|
||||
return $auditResults
|
||||
# Return the audit result
|
||||
return $auditResult
|
||||
}
|
||||
}
|
||||
|
@@ -1,42 +1,47 @@
|
||||
function Test-LinkSharingRestrictions {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
# Aligned
|
||||
# Define your parameters here
|
||||
# Test behavior in prod
|
||||
)
|
||||
|
||||
begin {
|
||||
# Initialization code
|
||||
|
||||
$auditResult = [CISAuditResult]::new()
|
||||
# Dot source the class script if necessary
|
||||
#. .\source\Classes\CISAuditResult.ps1
|
||||
# Initialization code, if needed
|
||||
}
|
||||
|
||||
process {
|
||||
# 7.2.7 (L1) Ensure link sharing is restricted in SharePoint and OneDrive
|
||||
|
||||
# Retrieve link sharing configuration for SharePoint and OneDrive
|
||||
$SPOTenantLinkSharing = Get-SPOTenant | Select-Object DefaultSharingLinkType
|
||||
$isLinkSharingRestricted = $SPOTenantLinkSharing.DefaultSharingLinkType -eq 'Direct' # Or 'SpecificPeople' as per the recommendation
|
||||
$isLinkSharingRestricted = $SPOTenantLinkSharing.DefaultSharingLinkType -eq 'Direct' # Or 'SpecificPeople' as per the recommendation
|
||||
|
||||
# Populate the auditResult object with the required properties
|
||||
$auditResult.CISControlVer = "v8"
|
||||
$auditResult.CISControl = "3.3"
|
||||
$auditResult.CISDescription = "Configure Data Access Control Lists"
|
||||
# Prepare failure reasons and details based on compliance
|
||||
$failureReasons = if (-not $isLinkSharingRestricted) {
|
||||
"Link sharing is not restricted to 'Specific people'. Current setting: $($SPOTenantLinkSharing.DefaultSharingLinkType)"
|
||||
}
|
||||
else {
|
||||
"N/A"
|
||||
}
|
||||
|
||||
$auditResult.Rec = "7.2.7"
|
||||
$auditResult.ELevel = "E3"
|
||||
$auditResult.ProfileLevel = "L1"
|
||||
$auditResult.IG1 = $true
|
||||
$auditResult.IG2 = $true
|
||||
$auditResult.IG3 = $true
|
||||
$auditResult.RecDescription = "Ensure link sharing is restricted in SharePoint and OneDrive"
|
||||
$details = "DefaultSharingLinkType: $($SPOTenantLinkSharing.DefaultSharingLinkType)"
|
||||
|
||||
$auditResult.Result = $isLinkSharingRestricted
|
||||
$auditResult.Details = "DefaultSharingLinkType: $($SPOTenantLinkSharing.DefaultSharingLinkType)"
|
||||
$auditResult.FailureReason = if (-not $isLinkSharingRestricted) { "Link sharing is not restricted to 'Specific people'. Current setting: $($SPOTenantLinkSharing.DefaultSharingLinkType)" } else { "N/A" }
|
||||
$auditResult.Status = if ($isLinkSharingRestricted) { "Pass" } else { "Fail" }
|
||||
# Create and populate the CISAuditResult object
|
||||
$params = @{
|
||||
Rec = "7.2.7"
|
||||
Result = $isLinkSharingRestricted
|
||||
Status = if ($isLinkSharingRestricted) { "Pass" } else { "Fail" }
|
||||
Details = $details
|
||||
FailureReason = $failureReasons
|
||||
}
|
||||
$auditResult = Initialize-CISAuditResult @params
|
||||
}
|
||||
|
||||
end {
|
||||
# Return auditResult
|
||||
# Return the audit result
|
||||
return $auditResult
|
||||
}
|
||||
}
|
||||
|
@@ -1,43 +1,54 @@
|
||||
function Test-MailTipsEnabled {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
# Define your parameters here
|
||||
# Aligned
|
||||
# Parameters can be added if needed
|
||||
)
|
||||
|
||||
begin {
|
||||
# Initialization code
|
||||
# Dot source the class script if necessary
|
||||
#. .\source\Classes\CISAuditResult.ps1
|
||||
# Initialization code, if needed
|
||||
|
||||
$auditResult = [CISAuditResult]::new()
|
||||
}
|
||||
|
||||
process {
|
||||
# 6.5.2 (L2) Ensure MailTips are enabled for end users
|
||||
|
||||
# Retrieve organization configuration for MailTips settings
|
||||
$orgConfig = Get-OrganizationConfig | Select-Object MailTipsAllTipsEnabled, MailTipsExternalRecipientsTipsEnabled, MailTipsGroupMetricsEnabled, MailTipsLargeAudienceThreshold
|
||||
$allTipsEnabled = $orgConfig.MailTipsAllTipsEnabled -and $orgConfig.MailTipsGroupMetricsEnabled -and $orgConfig.MailTipsLargeAudienceThreshold -eq 25
|
||||
$externalRecipientsTipsEnabled = $orgConfig.MailTipsExternalRecipientsTipsEnabled
|
||||
|
||||
# Since there is no direct CIS Control mapping, the control will be set as not applicable.
|
||||
$auditResult.CISControl = "0"
|
||||
$auditResult.CISControlVer = "v8"
|
||||
$auditResult.CISDescription = "Explicitly Not Mapped"
|
||||
# Prepare failure reasons and details based on compliance
|
||||
$failureReasons = if (-not ($allTipsEnabled -and $externalRecipientsTipsEnabled)) {
|
||||
"One or more MailTips settings are not configured as required."
|
||||
}
|
||||
else {
|
||||
"N/A"
|
||||
}
|
||||
|
||||
$auditResult.Rec = "6.5.2"
|
||||
$auditResult.ELevel = "E3"
|
||||
$auditResult.ProfileLevel = "L2"
|
||||
$auditResult.IG1 = $false
|
||||
$auditResult.IG2 = $false
|
||||
$auditResult.IG3 = $false
|
||||
$auditResult.RecDescription = "Ensure MailTips are enabled for end users"
|
||||
$details = if ($allTipsEnabled -and $externalRecipientsTipsEnabled) {
|
||||
"MailTipsAllTipsEnabled: $($orgConfig.MailTipsAllTipsEnabled); MailTipsExternalRecipientsTipsEnabled: $($orgConfig.MailTipsExternalRecipientsTipsEnabled); MailTipsGroupMetricsEnabled: $($orgConfig.MailTipsGroupMetricsEnabled); MailTipsLargeAudienceThreshold: $($orgConfig.MailTipsLargeAudienceThreshold)"
|
||||
}
|
||||
else {
|
||||
"One or more MailTips settings are not configured as required."
|
||||
}
|
||||
|
||||
$auditResult.Result = $allTipsEnabled -and $externalRecipientsTipsEnabled
|
||||
$auditResult.Details = "MailTipsAllTipsEnabled: $($orgConfig.MailTipsAllTipsEnabled); MailTipsExternalRecipientsTipsEnabled: $($orgConfig.MailTipsExternalRecipientsTipsEnabled); MailTipsGroupMetricsEnabled: $($orgConfig.MailTipsGroupMetricsEnabled); MailTipsLargeAudienceThreshold: $($orgConfig.MailTipsLargeAudienceThreshold)"
|
||||
$auditResult.FailureReason = if (-not $auditResult.Result) { "One or more MailTips settings are not configured as required." } else { "N/A" }
|
||||
$auditResult.Status = if ($auditResult.Result) { "Pass" } else { "Fail" }
|
||||
# Create and populate the CISAuditResult object
|
||||
$params = @{
|
||||
Rec = "6.5.2"
|
||||
Result = $allTipsEnabled -and $externalRecipientsTipsEnabled
|
||||
Status = if ($allTipsEnabled -and $externalRecipientsTipsEnabled) { "Pass" } else { "Fail" }
|
||||
Details = $details
|
||||
FailureReason = $failureReasons
|
||||
}
|
||||
$auditResult = Initialize-CISAuditResult @params
|
||||
}
|
||||
|
||||
end {
|
||||
# Return auditResult
|
||||
# Return the audit result
|
||||
return $auditResult
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,26 +1,20 @@
|
||||
function Test-MailboxAuditingE3 {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
# Aligned
|
||||
# Create Table for Details
|
||||
# Parameters can be added if needed
|
||||
)
|
||||
|
||||
begin {
|
||||
# Dot source the class script if necessary
|
||||
#. .\source\Classes\CISAuditResult.ps1
|
||||
|
||||
$e3SkuPartNumbers = @("ENTERPRISEPACK", "OFFICESUBSCRIPTION")
|
||||
$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")
|
||||
$OwnerActions = @("ApplyRecord", "Create", "HardDelete", "MailboxLogin", "Move", "MoveToDeletedItems", "SoftDelete", "Update", "UpdateCalendarDelegation", "UpdateFolderPermissions", "UpdateInboxRules")
|
||||
$auditResult = [CISAuditResult]::new()
|
||||
$auditResult.ELevel = "E3"
|
||||
$auditResult.ProfileLevel = "L1"
|
||||
$auditResult.Rec = "6.1.2"
|
||||
$auditResult.RecDescription = "Ensure mailbox auditing for Office E3 users is Enabled"
|
||||
$auditResult.CISControlVer = "v8"
|
||||
$auditResult.CISControl = "8.2"
|
||||
$auditResult.CISDescription = "Collect audit logs."
|
||||
$auditResult.IG1 = $true
|
||||
$auditResult.IG2 = $true
|
||||
$auditResult.IG3 = $true
|
||||
|
||||
|
||||
$allFailures = @()
|
||||
$allUsers = Get-AzureADUser -All $true
|
||||
@@ -72,10 +66,19 @@ function Test-MailboxAuditingE3 {
|
||||
}
|
||||
}
|
||||
|
||||
$auditResult.Result = $allFailures.Count -eq 0
|
||||
$auditResult.Status = if ($auditResult.Result) { "Pass" } else { "Fail" }
|
||||
$auditResult.Details = if ($auditResult.Result) { "All Office E3 users have correct mailbox audit settings." } else { $allFailures -join " | " }
|
||||
$auditResult.FailureReason = if (-not $auditResult.Result) { "Audit issues detected." } else { "N/A" }
|
||||
# Prepare failure reasons and details based on compliance
|
||||
$failureReasons = if ($allFailures.Count -eq 0) { "N/A" } else { "Audit issues detected." }
|
||||
$details = if ($allFailures.Count -eq 0) { "All Office E3 users have correct mailbox audit settings." } else { $allFailures -join " | " }
|
||||
|
||||
# Populate the audit result
|
||||
$params = @{
|
||||
Rec = "6.1.2"
|
||||
Result = $allFailures.Count -eq 0
|
||||
Status = if ($allFailures.Count -eq 0) { "Pass" } else { "Fail" }
|
||||
Details = $details
|
||||
FailureReason = $failureReasons
|
||||
}
|
||||
$auditResult = Initialize-CISAuditResult @params
|
||||
}
|
||||
|
||||
end {
|
||||
|
@@ -1,23 +1,21 @@
|
||||
function Test-MailboxAuditingE5 {
|
||||
[CmdletBinding()]
|
||||
param ()
|
||||
param (
|
||||
# Aligned
|
||||
# Create Table for Details
|
||||
# Parameters can be added if needed
|
||||
)
|
||||
|
||||
begin {
|
||||
# Dot source the class script if necessary
|
||||
#. .\source\Classes\CISAuditResult.ps1
|
||||
|
||||
$e5SkuPartNumbers = @("SPE_E5", "ENTERPRISEPREMIUM", "OFFICEE5")
|
||||
$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")
|
||||
$OwnerActions = @("ApplyRecord", "Create", "HardDelete", "MailboxLogin", "Move", "MailItemsAccessed", "MoveToDeletedItems", "Send", "SoftDelete", "Update", "UpdateCalendarDelegation", "UpdateFolderPermissions", "UpdateInboxRules")
|
||||
$auditResult = [CISAuditResult]::new()
|
||||
$auditResult.ELevel = "E5"
|
||||
$auditResult.ProfileLevel = "L1"
|
||||
$auditResult.Rec = "6.1.3"
|
||||
$auditResult.RecDescription = "Ensure mailbox auditing for Office E5 users is Enabled"
|
||||
$auditResult.CISControlVer = "v8"
|
||||
$auditResult.CISControl = "8.2"
|
||||
$auditResult.CISDescription = "Collect audit logs."
|
||||
$auditResult.IG1 = $true
|
||||
$auditResult.IG2 = $true
|
||||
$auditResult.IG3 = $true
|
||||
|
||||
|
||||
|
||||
$allFailures = @()
|
||||
$allUsers = Get-AzureADUser -All $true
|
||||
@@ -31,15 +29,11 @@ function Test-MailboxAuditingE5 {
|
||||
}
|
||||
|
||||
try {
|
||||
# Define SKU Part Numbers for Office E5 licenses
|
||||
# Define SKU Part Numbers for Office E5 licenses
|
||||
$e5SkuPartNumbers = @("SPE_E5", "ENTERPRISEPREMIUM", "OFFICEE5")
|
||||
$licenseDetails = Get-MgUserLicenseDetail -UserId $user.UserPrincipalName
|
||||
$hasOfficeE5 = ($licenseDetails | Where-Object { $_.SkuPartNumber -in $e5SkuPartNumbers }).Count -gt 0
|
||||
Write-Verbose "Evaluating user $($user.UserPrincipalName) for Office E5 license."
|
||||
if ($hasOfficeE5) {
|
||||
$userUPN = $user.UserPrincipalName
|
||||
|
||||
$mailbox = Get-EXOMailbox -Identity $userUPN -PropertySets Audit
|
||||
|
||||
$missingActions = @()
|
||||
@@ -78,13 +72,19 @@ function Test-MailboxAuditingE5 {
|
||||
}
|
||||
}
|
||||
|
||||
if ($allFailures.Count -eq 0) {
|
||||
Write-Verbose "All evaluated E5 users have correct mailbox audit settings."
|
||||
# Prepare failure reasons and details based on compliance
|
||||
$failureReasons = if ($allFailures.Count -eq 0) { "N/A" } else { "Audit issues detected." }
|
||||
$details = if ($allFailures.Count -eq 0) { "All Office E5 users have correct mailbox audit settings." } else { $allFailures -join " | " }
|
||||
|
||||
# Populate the audit result
|
||||
$params = @{
|
||||
Rec = "6.1.3"
|
||||
Result = $allFailures.Count -eq 0
|
||||
Status = if ($allFailures.Count -eq 0) { "Pass" } else { "Fail" }
|
||||
Details = $details
|
||||
FailureReason = $failureReasons
|
||||
}
|
||||
$auditResult.Result = $allFailures.Count -eq 0
|
||||
$auditResult.Status = if ($auditResult.Result) { "Pass" } else { "Fail" }
|
||||
$auditResult.Details = if ($auditResult.Result) { "All Office E5 users have correct mailbox audit settings." } else { $allFailures -join " | " }
|
||||
$auditResult.FailureReason = if (-not $auditResult.Result) { "Audit issues detected." } else { "N/A" }
|
||||
$auditResult = Initialize-CISAuditResult @params
|
||||
}
|
||||
|
||||
end {
|
||||
|
@@ -1,54 +1,52 @@
|
||||
function Test-ManagedApprovedPublicGroups {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
# Define your parameters here
|
||||
# Aligned
|
||||
# Parameters can be added if needed
|
||||
)
|
||||
|
||||
begin {
|
||||
# Dot source the class script
|
||||
# Dot source the class script if necessary
|
||||
#. .\source\Classes\CISAuditResult.ps1
|
||||
# Initialization code, if needed
|
||||
|
||||
$auditResults = @()
|
||||
}
|
||||
|
||||
process {
|
||||
# 1.2.1 (L2) Ensure that only organizationally managed/approved public groups exist (Automated)
|
||||
|
||||
# Retrieve all public groups
|
||||
$allGroups = Get-MgGroup -All | Where-Object { $_.Visibility -eq "Public" } | Select-Object DisplayName, Visibility
|
||||
|
||||
# Check if there are public groups and if they are organizationally managed/approved
|
||||
$auditResult = [CISAuditResult]::new()
|
||||
$auditResult.CISControlVer = "v8"
|
||||
$auditResult.CISControl = "3.3"
|
||||
$auditResult.CISDescription = "Configure Data Access Control Lists"
|
||||
$auditResult.Rec = "1.2.1"
|
||||
$auditResult.ELevel = "E3"
|
||||
$auditResult.ProfileLevel = "L2"
|
||||
$auditResult.IG1 = $true
|
||||
$auditResult.IG2 = $true
|
||||
$auditResult.IG3 = $true # Based on the provided CIS Control image, IG3 is not applicable
|
||||
$auditResult.RecDescription = "Ensure that only organizationally managed/approved public groups exist"
|
||||
# Prepare failure reasons and details based on compliance
|
||||
$failureReasons = if ($null -ne $allGroups -and $allGroups.Count -gt 0) {
|
||||
"There are public groups present that are not organizationally managed/approved."
|
||||
}
|
||||
else {
|
||||
"N/A"
|
||||
}
|
||||
|
||||
if ($null -eq $allGroups -or $allGroups.Count -eq 0) {
|
||||
$auditResult.Result = $true
|
||||
$auditResult.Details = "No public groups found."
|
||||
$auditResult.FailureReason = "N/A"
|
||||
$auditResult.Status = "Pass"
|
||||
$details = if ($null -eq $allGroups -or $allGroups.Count -eq 0) {
|
||||
"No public groups found."
|
||||
}
|
||||
else {
|
||||
$groupDetails = $allGroups | ForEach-Object { $_.DisplayName + " (" + $_.Visibility + ")" }
|
||||
$detailsString = $groupDetails -join ', '
|
||||
|
||||
$auditResult.Result = $false
|
||||
$auditResult.Details = "Public groups found: $detailsString"
|
||||
$auditResult.FailureReason = "There are public groups present that are not organizationally managed/approved."
|
||||
$auditResult.Status = "Fail"
|
||||
"Public groups found: $($groupDetails -join ', ')"
|
||||
}
|
||||
|
||||
$auditResults += $auditResult
|
||||
# Create and populate the CISAuditResult object
|
||||
$params = @{
|
||||
Rec = "1.2.1"
|
||||
Result = $null -eq $allGroups -or $allGroups.Count -eq 0
|
||||
Status = if ($null -eq $allGroups -or $allGroups.Count -eq 0) { "Pass" } else { "Fail" }
|
||||
Details = $details
|
||||
FailureReason = $failureReasons
|
||||
}
|
||||
$auditResult = Initialize-CISAuditResult @params
|
||||
}
|
||||
|
||||
end {
|
||||
# Return auditResults
|
||||
return $auditResults
|
||||
return $auditResult
|
||||
}
|
||||
}
|
||||
|
@@ -1,46 +1,48 @@
|
||||
function Test-MeetingChatNoAnonymous {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
# Aligned
|
||||
# Parameters can be defined here if needed
|
||||
)
|
||||
|
||||
begin {
|
||||
# Dot source the class script
|
||||
|
||||
$auditResults = @()
|
||||
# Dot source the class script if necessary
|
||||
#. .\source\Classes\CISAuditResult.ps1
|
||||
# Initialization code, if needed
|
||||
}
|
||||
|
||||
process {
|
||||
# 8.5.5 (L2) Ensure meeting chat does not allow anonymous users
|
||||
# Name doesn't match profile level in benchmarks either.
|
||||
|
||||
# Connect to Teams PowerShell using Connect-MicrosoftTeams
|
||||
|
||||
# Retrieve the Teams meeting policy for meeting chat
|
||||
$CsTeamsMeetingPolicyChat = Get-CsTeamsMeetingPolicy -Identity Global | Select-Object -Property MeetingChatEnabledType
|
||||
$chatAnonDisabled = $CsTeamsMeetingPolicyChat.MeetingChatEnabledType -eq 'EnabledExceptAnonymous'
|
||||
|
||||
# Create an instance of CISAuditResult and populate it
|
||||
$auditResult = [CISAuditResult]::new()
|
||||
$auditResult.CISControlVer = "v8"
|
||||
$auditResult.CISControl = "0.0" # Explicitly Not Mapped as per the image provided
|
||||
$auditResult.CISDescription = "Explicitly Not Mapped"
|
||||
$auditResult.Rec = "8.5.5"
|
||||
$auditResult.ELevel = "E3"
|
||||
$auditResult.ProfileLevel = "L1"
|
||||
$auditResult.IG1 = $false # Set based on the CIS Controls image
|
||||
$auditResult.IG2 = $false # Set based on the CIS Controls image
|
||||
$auditResult.IG3 = $false # Set based on the CIS Controls image
|
||||
$auditResult.RecDescription = "Ensure meeting chat does not allow anonymous users"
|
||||
$auditResult.Result = $chatAnonDisabled
|
||||
$auditResult.Details = "MeetingChatEnabledType is set to $($CsTeamsMeetingPolicyChat.MeetingChatEnabledType)"
|
||||
$auditResult.FailureReason = if ($chatAnonDisabled) { "N/A" } else { "Meeting chat allows anonymous users" }
|
||||
$auditResult.Status = if ($chatAnonDisabled) { "Pass" } else { "Fail" }
|
||||
# Prepare failure reasons and details based on compliance
|
||||
$failureReasons = if ($chatAnonDisabled) {
|
||||
"N/A"
|
||||
}
|
||||
else {
|
||||
"Meeting chat allows anonymous users"
|
||||
}
|
||||
|
||||
$auditResults += $auditResult
|
||||
$details = "MeetingChatEnabledType is set to $($CsTeamsMeetingPolicyChat.MeetingChatEnabledType)"
|
||||
|
||||
# Create and populate the CISAuditResult object
|
||||
$params = @{
|
||||
Rec = "8.5.5"
|
||||
Result = $chatAnonDisabled
|
||||
Status = if ($chatAnonDisabled) { "Pass" } else { "Fail" }
|
||||
Details = $details
|
||||
FailureReason = $failureReasons
|
||||
}
|
||||
$auditResult = Initialize-CISAuditResult @params
|
||||
}
|
||||
|
||||
end {
|
||||
# Return auditResults
|
||||
return $auditResults
|
||||
# Return the audit result
|
||||
return $auditResult
|
||||
}
|
||||
}
|
||||
|
@@ -1,40 +1,42 @@
|
||||
function Test-ModernAuthExchangeOnline {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
# Aligned
|
||||
# Define your parameters here
|
||||
)
|
||||
|
||||
begin {
|
||||
|
||||
$auditResults = [CISAuditResult]::new()
|
||||
# Initialization code
|
||||
# Dot source the class script if necessary
|
||||
#. .\source\Classes\CISAuditResult.ps1
|
||||
# Initialization code, if needed
|
||||
}
|
||||
|
||||
process {
|
||||
try {
|
||||
# Ensuring the ExchangeOnlineManagement module is available
|
||||
|
||||
|
||||
# 6.5.1 (L1) Ensure modern authentication for Exchange Online is enabled
|
||||
$orgConfig = Get-OrganizationConfig | Select-Object -Property Name, OAuth2ClientProfileEnabled
|
||||
|
||||
# Create an instance of CISAuditResult and populate it
|
||||
# Prepare failure reasons and details based on compliance
|
||||
$failureReasons = if (-not $orgConfig.OAuth2ClientProfileEnabled) {
|
||||
"Modern authentication is disabled"
|
||||
}
|
||||
else {
|
||||
"N/A"
|
||||
}
|
||||
|
||||
$auditResults.CISControlVer = "v8"
|
||||
$auditResults.CISControl = "3.10"
|
||||
$auditResults.CISDescription = "Encrypt Sensitive Data in Transit"
|
||||
$auditResults.IG1 = $false # As per CIS Control v8 mapping for IG1
|
||||
$auditResults.IG2 = $true # As per CIS Control v8 mapping for IG2
|
||||
$auditResults.IG3 = $true # As per CIS Control v8 mapping for IG3
|
||||
$auditResults.ELevel = "E3" # Based on your environment (E3, E5, etc.)
|
||||
$auditResults.ProfileLevel = "L1"
|
||||
$auditResults.Rec = "6.5.1"
|
||||
$auditResults.RecDescription = "Ensure modern authentication for Exchange Online is enabled (Automated)"
|
||||
$auditResults.Result = $orgConfig.OAuth2ClientProfileEnabled
|
||||
$auditResults.Details = $auditResults.Details = $orgConfig.Name + " OAuth2ClientProfileEnabled: " + $orgConfig.OAuth2ClientProfileEnabled
|
||||
$auditResults.FailureReason = if (-not $orgConfig.OAuth2ClientProfileEnabled) { "Modern authentication is disabled" } else { "N/A" }
|
||||
$auditResults.Status = if ($orgConfig.OAuth2ClientProfileEnabled) { "Pass" } else { "Fail" }
|
||||
$details = "OAuth2ClientProfileEnabled: $($orgConfig.OAuth2ClientProfileEnabled) for Organization: $($orgConfig.Name)"
|
||||
|
||||
# Create and populate the CISAuditResult object
|
||||
$params = @{
|
||||
Rec = "6.5.1"
|
||||
Result = $orgConfig.OAuth2ClientProfileEnabled
|
||||
Status = if ($orgConfig.OAuth2ClientProfileEnabled) { "Pass" } else { "Fail" }
|
||||
Details = $details
|
||||
FailureReason = $failureReasons
|
||||
}
|
||||
$auditResult = Initialize-CISAuditResult @params
|
||||
|
||||
}
|
||||
catch {
|
||||
@@ -43,12 +45,7 @@ function Test-ModernAuthExchangeOnline {
|
||||
}
|
||||
|
||||
end {
|
||||
# Return auditResults
|
||||
return $auditResults
|
||||
# Return the audit result
|
||||
return $auditResult
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@@ -1,13 +1,14 @@
|
||||
function Test-ModernAuthSharePoint {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
# Aligned
|
||||
# Define your parameters here
|
||||
)
|
||||
|
||||
begin {
|
||||
# Initialization code
|
||||
|
||||
$auditResult = [CISAuditResult]::new()
|
||||
# Dot source the class script if necessary
|
||||
#. .\source\Classes\CISAuditResult.ps1
|
||||
# Initialization code, if needed
|
||||
}
|
||||
|
||||
process {
|
||||
@@ -15,25 +16,29 @@ function Test-ModernAuthSharePoint {
|
||||
$SPOTenant = Get-SPOTenant | Select-Object -Property LegacyAuthProtocolsEnabled
|
||||
$modernAuthForSPRequired = -not $SPOTenant.LegacyAuthProtocolsEnabled
|
||||
|
||||
# Populate the auditResult object with the required properties
|
||||
$auditResult.CISControlVer = "v8"
|
||||
$auditResult.CISControl = "3.10"
|
||||
$auditResult.CISDescription = "Encrypt Sensitive Data in Transit"
|
||||
$auditResult.Rec = "7.2.1"
|
||||
$auditResult.ELevel = "E3"
|
||||
$auditResult.ProfileLevel = "L1"
|
||||
$auditResult.IG1 = $false
|
||||
$auditResult.IG2 = $true
|
||||
$auditResult.IG3 = $true
|
||||
$auditResult.RecDescription = "Modern Authentication for SharePoint Applications"
|
||||
$auditResult.Result = $modernAuthForSPRequired
|
||||
$auditResult.Details = "LegacyAuthProtocolsEnabled: $($SPOTenant.LegacyAuthProtocolsEnabled)"
|
||||
$auditResult.FailureReason = if (-not $modernAuthForSPRequired) { "Legacy authentication protocols are enabled" } else { "N/A" }
|
||||
$auditResult.Status = if ($modernAuthForSPRequired) { "Pass" } else { "Fail" }
|
||||
# Prepare failure reasons and details based on compliance
|
||||
$failureReasons = if (-not $modernAuthForSPRequired) {
|
||||
"Legacy authentication protocols are enabled"
|
||||
}
|
||||
else {
|
||||
"N/A"
|
||||
}
|
||||
|
||||
$details = "LegacyAuthProtocolsEnabled: $($SPOTenant.LegacyAuthProtocolsEnabled)"
|
||||
|
||||
# Create and populate the CISAuditResult object
|
||||
$params = @{
|
||||
Rec = "7.2.1"
|
||||
Result = $modernAuthForSPRequired
|
||||
Status = if ($modernAuthForSPRequired) { "Pass" } else { "Fail" }
|
||||
Details = $details
|
||||
FailureReason = $failureReasons
|
||||
}
|
||||
$auditResult = Initialize-CISAuditResult @params
|
||||
}
|
||||
|
||||
end {
|
||||
# Return auditResult
|
||||
# Return the audit result
|
||||
return $auditResult
|
||||
}
|
||||
}
|
||||
|
@@ -1,13 +1,14 @@
|
||||
function Test-NoAnonymousMeetingJoin {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
# Aligned
|
||||
# Parameters can be defined here if needed
|
||||
)
|
||||
|
||||
begin {
|
||||
# Dot source the class script
|
||||
|
||||
$auditResults = @()
|
||||
# Dot source the class script if necessary
|
||||
#. .\source\Classes\CISAuditResult.ps1
|
||||
# Initialization code, if needed
|
||||
}
|
||||
|
||||
process {
|
||||
@@ -18,28 +19,29 @@ function Test-NoAnonymousMeetingJoin {
|
||||
$teamsMeetingPolicy = Get-CsTeamsMeetingPolicy -Identity Global
|
||||
$allowAnonymousUsersToJoinMeeting = $teamsMeetingPolicy.AllowAnonymousUsersToJoinMeeting
|
||||
|
||||
# Create an instance of CISAuditResult and populate it
|
||||
$auditResult = [CISAuditResult]::new()
|
||||
$auditResult.CISControlVer = "v8"
|
||||
$auditResult.CISControl = "0.0" # The control is Explicitly Not Mapped as per the image provided
|
||||
$auditResult.CISDescription = "Explicitly Not Mapped"
|
||||
$auditResult.Rec = "8.5.1"
|
||||
$auditResult.ELevel = "E3"
|
||||
$auditResult.ProfileLevel = "L2"
|
||||
$auditResult.IG1 = $false # Set based on the CIS Controls image
|
||||
$auditResult.IG2 = $false # Set based on the CIS Controls image
|
||||
$auditResult.IG3 = $false # Set based on the CIS Controls image
|
||||
$auditResult.RecDescription = "Ensure anonymous users can't join a meeting"
|
||||
$auditResult.Result = -not $allowAnonymousUsersToJoinMeeting
|
||||
$auditResult.Details = "AllowAnonymousUsersToJoinMeeting is set to $allowAnonymousUsersToJoinMeeting"
|
||||
$auditResult.FailureReason = if ($allowAnonymousUsersToJoinMeeting) { "Anonymous users are allowed to join meetings" } else { "N/A" }
|
||||
$auditResult.Status = if (-not $allowAnonymousUsersToJoinMeeting) { "Pass" } else { "Fail" }
|
||||
# Prepare failure reasons and details based on compliance
|
||||
$failureReasons = if ($allowAnonymousUsersToJoinMeeting) {
|
||||
"Anonymous users are allowed to join meetings"
|
||||
}
|
||||
else {
|
||||
"N/A"
|
||||
}
|
||||
|
||||
$auditResults += $auditResult
|
||||
$details = "AllowAnonymousUsersToJoinMeeting is set to $allowAnonymousUsersToJoinMeeting"
|
||||
|
||||
# Create and populate the CISAuditResult object
|
||||
$params = @{
|
||||
Rec = "8.5.1"
|
||||
Result = -not $allowAnonymousUsersToJoinMeeting
|
||||
Status = if (-not $allowAnonymousUsersToJoinMeeting) { "Pass" } else { "Fail" }
|
||||
Details = $details
|
||||
FailureReason = $failureReasons
|
||||
}
|
||||
$auditResult = Initialize-CISAuditResult @params
|
||||
}
|
||||
|
||||
end {
|
||||
# Return auditResults
|
||||
return $auditResults
|
||||
# Return the audit result
|
||||
return $auditResult
|
||||
}
|
||||
}
|
||||
|
@@ -1,13 +1,14 @@
|
||||
function Test-NoAnonymousMeetingStart {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
# Aligned
|
||||
# Parameters can be defined here if needed
|
||||
)
|
||||
|
||||
begin {
|
||||
# Dot source the class script
|
||||
|
||||
$auditResults = @()
|
||||
# Dot source the class script if necessary
|
||||
#. .\source\Classes\CISAuditResult.ps1
|
||||
# Initialization code, if needed
|
||||
}
|
||||
|
||||
process {
|
||||
@@ -18,28 +19,29 @@ function Test-NoAnonymousMeetingStart {
|
||||
$CsTeamsMeetingPolicyAnonymous = Get-CsTeamsMeetingPolicy -Identity Global | Select-Object -Property AllowAnonymousUsersToStartMeeting
|
||||
$anonymousStartDisabled = -not $CsTeamsMeetingPolicyAnonymous.AllowAnonymousUsersToStartMeeting
|
||||
|
||||
# Create an instance of CISAuditResult and populate it
|
||||
$auditResult = [CISAuditResult]::new()
|
||||
$auditResult.CISControlVer = "v8"
|
||||
$auditResult.CISControl = "0.0" # Explicitly Not Mapped as per the image provided
|
||||
$auditResult.CISDescription = "Explicitly Not Mapped"
|
||||
$auditResult.Rec = "8.5.2"
|
||||
$auditResult.ELevel = "E3"
|
||||
$auditResult.ProfileLevel = "L1"
|
||||
$auditResult.IG1 = $false # Set based on the CIS Controls image
|
||||
$auditResult.IG2 = $false # Set based on the CIS Controls image
|
||||
$auditResult.IG3 = $false # Set based on the CIS Controls image
|
||||
$auditResult.RecDescription = "Ensure anonymous users and dial-in callers can't start a meeting"
|
||||
$auditResult.Result = $anonymousStartDisabled
|
||||
$auditResult.Details = "AllowAnonymousUsersToStartMeeting is set to $($CsTeamsMeetingPolicyAnonymous.AllowAnonymousUsersToStartMeeting)"
|
||||
$auditResult.FailureReason = if ($anonymousStartDisabled) { "N/A" } else { "Anonymous users and dial-in callers can start a meeting" }
|
||||
$auditResult.Status = if ($anonymousStartDisabled) { "Pass" } else { "Fail" }
|
||||
# Prepare failure reasons and details based on compliance
|
||||
$failureReasons = if ($anonymousStartDisabled) {
|
||||
"N/A"
|
||||
}
|
||||
else {
|
||||
"Anonymous users and dial-in callers can start a meeting"
|
||||
}
|
||||
|
||||
$auditResults += $auditResult
|
||||
$details = "AllowAnonymousUsersToStartMeeting is set to $($CsTeamsMeetingPolicyAnonymous.AllowAnonymousUsersToStartMeeting)"
|
||||
|
||||
# Create and populate the CISAuditResult object
|
||||
$params = @{
|
||||
Rec = "8.5.2"
|
||||
Result = $anonymousStartDisabled
|
||||
Status = if ($anonymousStartDisabled) { "Pass" } else { "Fail" }
|
||||
Details = $details
|
||||
FailureReason = $failureReasons
|
||||
}
|
||||
$auditResult = Initialize-CISAuditResult @params
|
||||
}
|
||||
|
||||
end {
|
||||
# Return auditResults
|
||||
return $auditResults
|
||||
# Return the audit result
|
||||
return $auditResult
|
||||
}
|
||||
}
|
||||
|
@@ -1,43 +1,47 @@
|
||||
function Test-NoWhitelistDomains {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
# Aligned
|
||||
# Define your parameters here
|
||||
)
|
||||
|
||||
begin {
|
||||
# Initialization code
|
||||
|
||||
$auditResult = [CISAuditResult]::new()
|
||||
# Dot source the class script if necessary
|
||||
#. .\source\Classes\CISAuditResult.ps1
|
||||
# Initialization code, if needed
|
||||
}
|
||||
|
||||
process {
|
||||
# 6.2.2 (L1) Ensure mail transport rules do not whitelist specific domains
|
||||
$whitelistedRules = Get-TransportRule | Where-Object { $_.SetSCL -eq -1 -and $_.SenderDomainIs -ne $null }
|
||||
|
||||
$auditResult.CISControl = "0.0"
|
||||
$auditResult.CISControlVer = "v8"
|
||||
$auditResult.CISDescription = "Explicitly Not Mapped"
|
||||
# Retrieve transport rules that whitelist specific domains
|
||||
$whitelistedRules = Get-TransportRule | Where-Object { $_.SetSCL -eq -1 -and $null -ne $_.SenderDomainIs }
|
||||
|
||||
$auditResult.Rec = "6.2.2"
|
||||
$auditResult.ELevel = "E3"
|
||||
$auditResult.ProfileLevel = "L1"
|
||||
$auditResult.IG1 = $false
|
||||
$auditResult.IG2 = $false
|
||||
$auditResult.IG3 = $false
|
||||
$auditResult.RecDescription = "Ensure mail transport rules do not whitelist specific domains"
|
||||
|
||||
if ($whitelistedRules) {
|
||||
$ruleDetails = $whitelistedRules | ForEach-Object { "{0}: {1}" -f $_.Name, ($_.SenderDomainIs -join ', ') }
|
||||
$auditResult.Result = $false
|
||||
$auditResult.Details = "Whitelisted Rules: $($ruleDetails -join '; ')"
|
||||
$auditResult.FailureReason = "There are transport rules whitelisting specific domains."
|
||||
$auditResult.Status = "Fail"
|
||||
} else {
|
||||
$auditResult.Result = $true
|
||||
$auditResult.Details = "No transport rules whitelisting specific domains found."
|
||||
$auditResult.FailureReason = "N/A"
|
||||
$auditResult.Status = "Pass"
|
||||
# Prepare failure reasons and details based on compliance
|
||||
$failureReasons = if ($whitelistedRules) {
|
||||
"There are transport rules whitelisting specific domains."
|
||||
}
|
||||
else {
|
||||
"N/A"
|
||||
}
|
||||
|
||||
$details = if ($whitelistedRules) {
|
||||
$ruleDetails = $whitelistedRules | ForEach-Object { "{0}: {1}" -f $_.Name, ($_.SenderDomainIs -join ', ') }
|
||||
"Whitelisted Rules: $($ruleDetails -join '; ')"
|
||||
}
|
||||
else {
|
||||
"No transport rules whitelisting specific domains found."
|
||||
}
|
||||
|
||||
# Create and populate the CISAuditResult object
|
||||
$params = @{
|
||||
Rec = "6.2.2"
|
||||
Result = -not $whitelistedRules
|
||||
Status = if ($whitelistedRules) { "Fail" } else { "Pass" }
|
||||
Details = $details
|
||||
FailureReason = $failureReasons
|
||||
}
|
||||
$auditResult = Initialize-CISAuditResult @params
|
||||
}
|
||||
|
||||
end {
|
||||
|
@@ -1,12 +1,14 @@
|
||||
function Test-NotifyMalwareInternal {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
# Aligned
|
||||
# Parameters can be added if needed
|
||||
)
|
||||
|
||||
begin {
|
||||
|
||||
$auditResults = @()
|
||||
# Dot source the class script if necessary
|
||||
#. .\source\Classes\CISAuditResult.ps1
|
||||
# Initialization code, if needed
|
||||
}
|
||||
|
||||
process {
|
||||
@@ -24,31 +26,35 @@ function Test-NotifyMalwareInternal {
|
||||
|
||||
# Determine the result based on the presence of custom policies without notifications
|
||||
$result = $policiesToReport.Count -eq 0
|
||||
$details = if ($result) { "All custom malware policies have notifications enabled." } else { "Misconfigured Policies: $($policiesToReport -join ', ')" }
|
||||
$failureReason = if ($result) { "N/A" } else { "Some custom policies do not have notifications for internal users sending malware enabled." }
|
||||
|
||||
# Create an instance of CISAuditResult and populate it
|
||||
$auditResult = [CISAuditResult]::new()
|
||||
$auditResult.Status = if ($result) { "Pass" } else { "Fail" }
|
||||
$auditResult.ELevel = "E3"
|
||||
$auditResult.ProfileLevel = "L1"
|
||||
$auditResult.Rec = "2.1.3"
|
||||
$auditResult.RecDescription = "Ensure notifications for internal users sending malware is Enabled"
|
||||
$auditResult.CISControlVer = "v8"
|
||||
$auditResult.CISControl = "17.5"
|
||||
$auditResult.CISDescription = "Assign Key Roles and Responsibilities"
|
||||
$auditResult.IG1 = $false
|
||||
$auditResult.IG2 = $true
|
||||
$auditResult.IG3 = $true
|
||||
$auditResult.Result = $result
|
||||
$auditResult.Details = $details
|
||||
$auditResult.FailureReason = $failureReason
|
||||
# Prepare failure reasons and details based on compliance
|
||||
$failureReasons = if ($result) {
|
||||
"N/A"
|
||||
}
|
||||
else {
|
||||
"Some custom policies do not have notifications for internal users sending malware enabled."
|
||||
}
|
||||
|
||||
$auditResults += $auditResult
|
||||
$details = if ($result) {
|
||||
"All custom malware policies have notifications enabled."
|
||||
}
|
||||
else {
|
||||
"Misconfigured Policies: $($policiesToReport -join ', ')"
|
||||
}
|
||||
|
||||
# Create and populate the CISAuditResult object
|
||||
$params = @{
|
||||
Rec = "2.1.3"
|
||||
Result = $result
|
||||
Status = if ($result) { "Pass" } else { "Fail" }
|
||||
Details = $details
|
||||
FailureReason = $failureReasons
|
||||
}
|
||||
$auditResult = Initialize-CISAuditResult @params
|
||||
}
|
||||
|
||||
end {
|
||||
# Return auditResults
|
||||
return $auditResults
|
||||
# Return the audit result
|
||||
return $auditResult
|
||||
}
|
||||
}
|
||||
|
@@ -1,37 +1,47 @@
|
||||
function Test-OneDriveContentRestrictions {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
# Aligned
|
||||
# Define your parameters here
|
||||
)
|
||||
|
||||
begin {
|
||||
# Initialization code
|
||||
|
||||
$auditResult = [CISAuditResult]::new()
|
||||
# Dot source the class script if necessary
|
||||
#. .\source\Classes\CISAuditResult.ps1
|
||||
# Initialization code, if needed
|
||||
}
|
||||
|
||||
process {
|
||||
# 7.2.4 (L2) Ensure OneDrive content sharing is restricted
|
||||
|
||||
# Retrieve OneDrive sharing capability settings
|
||||
$SPOTenant = Get-SPOTenant | Select-Object OneDriveSharingCapability
|
||||
$isOneDriveSharingRestricted = $SPOTenant.OneDriveSharingCapability -eq 'Disabled'
|
||||
|
||||
# Populate the auditResult object with the required properties
|
||||
$auditResult.CISControlVer = "v8"
|
||||
$auditResult.CISControl = "3.3"
|
||||
$auditResult.CISDescription = "Configure Data Access Control Lists"
|
||||
# Prepare failure reasons and details based on compliance
|
||||
$failureReasons = if (-not $isOneDriveSharingRestricted) {
|
||||
"OneDrive content sharing is not restricted to 'Disabled'. Current setting: $($SPOTenant.OneDriveSharingCapability)"
|
||||
}
|
||||
else {
|
||||
"N/A"
|
||||
}
|
||||
|
||||
$auditResult.Rec = "7.2.4"
|
||||
$auditResult.ELevel = "E3"
|
||||
$auditResult.ProfileLevel = "L2"
|
||||
$auditResult.IG1 = $true
|
||||
$auditResult.IG2 = $true
|
||||
$auditResult.IG3 = $true
|
||||
$auditResult.RecDescription = "Ensure OneDrive content sharing is restricted"
|
||||
$details = if ($isOneDriveSharingRestricted) {
|
||||
"OneDrive content sharing is restricted."
|
||||
}
|
||||
else {
|
||||
"OneDriveSharingCapability: $($SPOTenant.OneDriveSharingCapability)"
|
||||
}
|
||||
|
||||
$auditResult.Result = $isOneDriveSharingRestricted
|
||||
$auditResult.Details = "OneDriveSharingCapability: $($SPOTenant.OneDriveSharingCapability)"
|
||||
$auditResult.FailureReason = if (-not $isOneDriveSharingRestricted) { "OneDrive content sharing is not restricted to 'Disabled'. Current setting: $($SPOTenant.OneDriveSharingCapability)" } else { "N/A" }
|
||||
$auditResult.Status = if ($isOneDriveSharingRestricted) { "Pass" } else { "Fail" }
|
||||
# Create and populate the CISAuditResult object
|
||||
$params = @{
|
||||
Rec = "7.2.4"
|
||||
Result = $isOneDriveSharingRestricted
|
||||
Status = if ($isOneDriveSharingRestricted) { "Pass" } else { "Fail" }
|
||||
Details = $details
|
||||
FailureReason = $failureReasons
|
||||
}
|
||||
$auditResult = Initialize-CISAuditResult @params
|
||||
}
|
||||
|
||||
end {
|
||||
|
@@ -1,37 +1,47 @@
|
||||
function Test-OneDriveSyncRestrictions {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
# Aligned
|
||||
# Define your parameters here
|
||||
)
|
||||
|
||||
begin {
|
||||
# Initialization code
|
||||
|
||||
$auditResult = [CISAuditResult]::new()
|
||||
# Dot source the class script if necessary
|
||||
#. .\source\Classes\CISAuditResult.ps1
|
||||
# Initialization code, if needed
|
||||
}
|
||||
|
||||
process {
|
||||
# 7.3.2 (L2) Ensure OneDrive sync is restricted for unmanaged devices
|
||||
|
||||
# Retrieve OneDrive sync client restriction settings
|
||||
$SPOTenantSyncClientRestriction = Get-SPOTenantSyncClientRestriction | Select-Object TenantRestrictionEnabled, AllowedDomainList
|
||||
$isSyncRestricted = $SPOTenantSyncClientRestriction.TenantRestrictionEnabled -and $SPOTenantSyncClientRestriction.AllowedDomainList
|
||||
|
||||
# Populate the auditResult object with the required properties
|
||||
$auditResult.CISControlVer = "v8"
|
||||
$auditResult.CISControl = "0.0"
|
||||
$auditResult.CISDescription = "Explicitly Not Mapped"
|
||||
# Prepare failure reasons and details based on compliance
|
||||
$failureReasons = if (-not $isSyncRestricted) {
|
||||
"OneDrive sync is not restricted to managed devices. TenantRestrictionEnabled should be True and AllowedDomainList should contain trusted domains GUIDs."
|
||||
}
|
||||
else {
|
||||
"N/A"
|
||||
}
|
||||
|
||||
$auditResult.Rec = "7.3.2"
|
||||
$auditResult.ELevel = "E3"
|
||||
$auditResult.ProfileLevel = "L2"
|
||||
$auditResult.IG1 = $false
|
||||
$auditResult.IG2 = $false
|
||||
$auditResult.IG3 = $false
|
||||
$auditResult.RecDescription = "Ensure OneDrive sync is restricted for unmanaged devices"
|
||||
$details = if ($isSyncRestricted) {
|
||||
"OneDrive sync is restricted for unmanaged devices."
|
||||
}
|
||||
else {
|
||||
"TenantRestrictionEnabled: $($SPOTenantSyncClientRestriction.TenantRestrictionEnabled); AllowedDomainList: $($SPOTenantSyncClientRestriction.AllowedDomainList -join ', ')"
|
||||
}
|
||||
|
||||
$auditResult.Result = $isSyncRestricted
|
||||
$auditResult.Details = "TenantRestrictionEnabled: $($SPOTenantSyncClientRestriction.TenantRestrictionEnabled); AllowedDomainList: $($SPOTenantSyncClientRestriction.AllowedDomainList -join ', ')"
|
||||
$auditResult.FailureReason = if (-not $isSyncRestricted) { "OneDrive sync is not restricted to managed devices. TenantRestrictionEnabled should be True and AllowedDomainList should contain trusted domains GUIDs." } else { "N/A" }
|
||||
$auditResult.Status = if ($isSyncRestricted) { "Pass" } else { "Fail" }
|
||||
# Create and populate the CISAuditResult object
|
||||
$params = @{
|
||||
Rec = "7.3.2"
|
||||
Result = $isSyncRestricted
|
||||
Status = if ($isSyncRestricted) { "Pass" } else { "Fail" }
|
||||
Details = $details
|
||||
FailureReason = $failureReasons
|
||||
}
|
||||
$auditResult = Initialize-CISAuditResult @params
|
||||
}
|
||||
|
||||
end {
|
||||
|
@@ -1,13 +1,14 @@
|
||||
function Test-OrgOnlyBypassLobby {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
# Aligned
|
||||
# Parameters can be defined here if needed
|
||||
)
|
||||
|
||||
begin {
|
||||
# Dot source the class script
|
||||
|
||||
$auditResults = @()
|
||||
# Dot source the class script if necessary
|
||||
#. .\source\Classes\CISAuditResult.ps1
|
||||
# Initialization code, if needed
|
||||
}
|
||||
|
||||
process {
|
||||
@@ -15,31 +16,38 @@ function Test-OrgOnlyBypassLobby {
|
||||
|
||||
# Connect to Teams PowerShell using Connect-MicrosoftTeams
|
||||
|
||||
# Retrieve the Teams meeting policy for lobby bypass settings
|
||||
$CsTeamsMeetingPolicyLobby = Get-CsTeamsMeetingPolicy -Identity Global | Select-Object -Property AutoAdmittedUsers
|
||||
$lobbyBypassRestricted = $CsTeamsMeetingPolicyLobby.AutoAdmittedUsers -eq 'EveryoneInCompanyExcludingGuests'
|
||||
|
||||
# Create an instance of CISAuditResult and populate it
|
||||
$auditResult = [CISAuditResult]::new()
|
||||
$auditResult.CISControlVer = "v8"
|
||||
$auditResult.CISControl = "6.8"
|
||||
$auditResult.CISDescription = "Define and Maintain Role-Based Access Control"
|
||||
$auditResult.Rec = "8.5.3"
|
||||
$auditResult.ELevel = "E3"
|
||||
$auditResult.ProfileLevel = "L1"
|
||||
$auditResult.IG1 = $false # Set based on the CIS Controls image
|
||||
$auditResult.IG2 = $false # Set based on the CIS Controls image
|
||||
$auditResult.IG3 = $true # Set based on the CIS Controls image
|
||||
$auditResult.RecDescription = "Ensure only people in my org can bypass the lobby"
|
||||
$auditResult.Result = $lobbyBypassRestricted
|
||||
$auditResult.Details = "AutoAdmittedUsers is set to $($CsTeamsMeetingPolicyLobby.AutoAdmittedUsers)"
|
||||
$auditResult.FailureReason = if ($lobbyBypassRestricted) { "N/A" } else { "External participants can bypass the lobby" }
|
||||
$auditResult.Status = if ($lobbyBypassRestricted) { "Pass" } else { "Fail" }
|
||||
# Prepare failure reasons and details based on compliance
|
||||
$failureReasons = if (-not $lobbyBypassRestricted) {
|
||||
"External participants can bypass the lobby"
|
||||
}
|
||||
else {
|
||||
"N/A"
|
||||
}
|
||||
|
||||
$auditResults += $auditResult
|
||||
$details = if ($lobbyBypassRestricted) {
|
||||
"Only people in the organization can bypass the lobby."
|
||||
}
|
||||
else {
|
||||
"AutoAdmittedUsers is set to $($CsTeamsMeetingPolicyLobby.AutoAdmittedUsers)"
|
||||
}
|
||||
|
||||
# Create and populate the CISAuditResult object
|
||||
$params = @{
|
||||
Rec = "8.5.3"
|
||||
Result = $lobbyBypassRestricted
|
||||
Status = if ($lobbyBypassRestricted) { "Pass" } else { "Fail" }
|
||||
Details = $details
|
||||
FailureReason = $failureReasons
|
||||
}
|
||||
$auditResult = Initialize-CISAuditResult @params
|
||||
}
|
||||
|
||||
end {
|
||||
# Return auditResults
|
||||
return $auditResults
|
||||
# Return the audit result
|
||||
return $auditResult
|
||||
}
|
||||
}
|
||||
|
@@ -1,13 +1,14 @@
|
||||
function Test-OrganizersPresent {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
# Aligned
|
||||
# Parameters can be defined here if needed
|
||||
)
|
||||
|
||||
begin {
|
||||
# Dot source the class script
|
||||
|
||||
$auditResults = @()
|
||||
# Dot source the class script if necessary
|
||||
#. .\source\Classes\CISAuditResult.ps1
|
||||
# Initialization code, if needed
|
||||
}
|
||||
|
||||
process {
|
||||
@@ -15,31 +16,38 @@ function Test-OrganizersPresent {
|
||||
|
||||
# Connect to Teams PowerShell using Connect-MicrosoftTeams
|
||||
|
||||
# Retrieve the Teams meeting policy for presenters
|
||||
$CsTeamsMeetingPolicyPresenters = Get-CsTeamsMeetingPolicy -Identity Global | Select-Object -Property DesignatedPresenterRoleMode
|
||||
$presenterRoleRestricted = $CsTeamsMeetingPolicyPresenters.DesignatedPresenterRoleMode -eq 'OrganizerOnlyUserOverride'
|
||||
|
||||
# Create an instance of CISAuditResult and populate it
|
||||
$auditResult = [CISAuditResult]::new()
|
||||
$auditResult.CISControlVer = "v8"
|
||||
$auditResult.CISControl = "0.0" # Explicitly Not Mapped as per the image provided
|
||||
$auditResult.CISDescription = "Explicitly Not Mapped"
|
||||
$auditResult.Rec = "8.5.6"
|
||||
$auditResult.ELevel = "E3"
|
||||
$auditResult.ProfileLevel = "L1"
|
||||
$auditResult.IG1 = $false # Set based on the CIS Controls image
|
||||
$auditResult.IG2 = $false # Set based on the CIS Controls image
|
||||
$auditResult.IG3 = $false # Set based on the CIS Controls image
|
||||
$auditResult.RecDescription = "Ensure only organizers and co-organizers can present"
|
||||
$auditResult.Result = $presenterRoleRestricted
|
||||
$auditResult.Details = "DesignatedPresenterRoleMode is set to $($CsTeamsMeetingPolicyPresenters.DesignatedPresenterRoleMode)"
|
||||
$auditResult.FailureReason = if ($presenterRoleRestricted) { "N/A" } else { "Others besides organizers and co-organizers can present" }
|
||||
$auditResult.Status = if ($presenterRoleRestricted) { "Pass" } else { "Fail" }
|
||||
# Prepare failure reasons and details based on compliance
|
||||
$failureReasons = if (-not $presenterRoleRestricted) {
|
||||
"Others besides organizers and co-organizers can present"
|
||||
}
|
||||
else {
|
||||
"N/A"
|
||||
}
|
||||
|
||||
$auditResults += $auditResult
|
||||
$details = if ($presenterRoleRestricted) {
|
||||
"Only organizers and co-organizers can present."
|
||||
}
|
||||
else {
|
||||
"DesignatedPresenterRoleMode is set to $($CsTeamsMeetingPolicyPresenters.DesignatedPresenterRoleMode)"
|
||||
}
|
||||
|
||||
# Create and populate the CISAuditResult object
|
||||
$params = @{
|
||||
Rec = "8.5.6"
|
||||
Result = $presenterRoleRestricted
|
||||
Status = if ($presenterRoleRestricted) { "Pass" } else { "Fail" }
|
||||
Details = $details
|
||||
FailureReason = $failureReasons
|
||||
}
|
||||
$auditResult = Initialize-CISAuditResult @params
|
||||
}
|
||||
|
||||
end {
|
||||
# Return auditResults
|
||||
return $auditResults
|
||||
# Return the audit result
|
||||
return $auditResult
|
||||
}
|
||||
}
|
||||
|
@@ -1,43 +1,47 @@
|
||||
function Test-PasswordHashSync {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
# Aligned
|
||||
# Parameters can be added if needed
|
||||
)
|
||||
|
||||
begin {
|
||||
# Dot source the class script
|
||||
|
||||
$auditResults = @()
|
||||
# Dot source the class script if necessary
|
||||
#. .\source\Classes\CISAuditResult.ps1
|
||||
# Initialization code, if needed
|
||||
}
|
||||
|
||||
process {
|
||||
# 5.1.8.1 (L1) Ensure password hash sync is enabled for hybrid deployments
|
||||
# Pass if OnPremisesSyncEnabled is True. Fail otherwise.
|
||||
$passwordHashSync = Get-MgOrganization | Select-Object OnPremisesSyncEnabled
|
||||
$hashSyncResult = $passwordHashSync.OnPremisesSyncEnabled
|
||||
|
||||
# Create an instance of CISAuditResult and populate it
|
||||
$auditResult = [CISAuditResult]::new()
|
||||
$auditResult.Status = if ($hashSyncResult) { "Pass" } else { "Fail" }
|
||||
$auditResult.ELevel = "E3"
|
||||
$auditResult.ProfileLevel = "L1"
|
||||
$auditResult.Rec = "5.1.8.1"
|
||||
$auditResult.RecDescription = "Ensure password hash sync is enabled for hybrid deployments"
|
||||
$auditResult.CISControlVer = "v8"
|
||||
$auditResult.CISControl = "6.7"
|
||||
$auditResult.CISDescription = "Centralize Access Control"
|
||||
$auditResult.IG1 = $false
|
||||
$auditResult.IG2 = $true
|
||||
$auditResult.IG3 = $true
|
||||
$auditResult.Result = $hashSyncResult
|
||||
$auditResult.Details = "OnPremisesSyncEnabled: $($passwordHashSync.OnPremisesSyncEnabled)"
|
||||
$auditResult.FailureReason = if (-not $hashSyncResult) { "Password hash sync for hybrid deployments is not enabled" } else { "N/A" }
|
||||
# Retrieve password hash sync status
|
||||
$passwordHashSync = Get-MgOrganization | Select-Object -ExpandProperty OnPremisesSyncEnabled
|
||||
$hashSyncResult = $passwordHashSync
|
||||
|
||||
$auditResults += $auditResult
|
||||
# Prepare failure reasons and details based on compliance
|
||||
$failureReasons = if (-not $hashSyncResult) {
|
||||
"Password hash sync for hybrid deployments is not enabled"
|
||||
}
|
||||
else {
|
||||
"N/A"
|
||||
}
|
||||
|
||||
$details = "OnPremisesSyncEnabled: $($passwordHashSync)"
|
||||
|
||||
# Create and populate the CISAuditResult object
|
||||
$params = @{
|
||||
Rec = "5.1.8.1"
|
||||
Result = $hashSyncResult
|
||||
Status = if ($hashSyncResult) { "Pass" } else { "Fail" }
|
||||
Details = $details
|
||||
FailureReason = $failureReasons
|
||||
}
|
||||
$auditResult = Initialize-CISAuditResult @params
|
||||
}
|
||||
|
||||
end {
|
||||
# Return auditResults
|
||||
return $auditResults
|
||||
# Return the audit result
|
||||
return $auditResult
|
||||
}
|
||||
}
|
||||
|
@@ -1,45 +1,47 @@
|
||||
function Test-PasswordNeverExpirePolicy {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
# Aligned
|
||||
[Parameter(Mandatory)]
|
||||
[string]$DomainName # DomainName parameter is now mandatory
|
||||
)
|
||||
|
||||
begin {
|
||||
# Dot source the class script
|
||||
|
||||
$auditResults = @()
|
||||
# Dot source the class script if necessary
|
||||
#. .\source\Classes\CISAuditResult.ps1
|
||||
# Initialization code, if needed
|
||||
}
|
||||
|
||||
process {
|
||||
# 1.3.1 (L1) Ensure the 'Password expiration policy' is set to 'Set passwords to never expire'
|
||||
# Pass if PasswordValidityPeriodInDays is 0.
|
||||
# Fail otherwise.
|
||||
# Pass if PasswordValidityPeriodInDays is 0. Fail otherwise.
|
||||
|
||||
$passwordPolicy = Get-MgDomain -DomainId $DomainName | Select-Object PasswordValidityPeriodInDays
|
||||
# Retrieve password expiration policy
|
||||
$passwordPolicy = Get-MgDomain -DomainId $DomainName | Select-Object -ExpandProperty PasswordValidityPeriodInDays
|
||||
|
||||
# Create an instance of CISAuditResult and populate it
|
||||
$auditResult = [CISAuditResult]::new()
|
||||
$auditResult.Rec = "1.3.1"
|
||||
$auditResult.RecDescription = "Ensure the 'Password expiration policy' is set to 'Set passwords to never expire'"
|
||||
$auditResult.ELevel = "E3"
|
||||
$auditResult.ProfileLevel = "L1"
|
||||
$auditResult.CISControlVer = "v8"
|
||||
$auditResult.CISControl = "5.2"
|
||||
$auditResult.CISDescription = "Use Unique Passwords"
|
||||
$auditResult.IG1 = $true
|
||||
$auditResult.IG2 = $true
|
||||
$auditResult.IG3 = $true # All are true
|
||||
$auditResult.Result = $passwordPolicy.PasswordValidityPeriodInDays -eq 0
|
||||
$auditResult.Details = "Validity Period: $($passwordPolicy.PasswordValidityPeriodInDays) days"
|
||||
$auditResult.FailureReason = if ($passwordPolicy.PasswordValidityPeriodInDays -eq 0) { "N/A" } else { "Password expiration is not set to never expire" }
|
||||
$auditResult.Status = if ($passwordPolicy.PasswordValidityPeriodInDays -eq 0) { "Pass" } else { "Fail" }
|
||||
# Prepare failure reasons and details based on compliance
|
||||
$failureReasons = if ($passwordPolicy -ne 0) {
|
||||
"Password expiration is not set to never expire"
|
||||
}
|
||||
else {
|
||||
"N/A"
|
||||
}
|
||||
|
||||
$auditResults += $auditResult
|
||||
$details = "Validity Period: $passwordPolicy days"
|
||||
|
||||
# Create and populate the CISAuditResult object
|
||||
$params = @{
|
||||
Rec = "1.3.1"
|
||||
Result = $passwordPolicy -eq 0
|
||||
Status = if ($passwordPolicy -eq 0) { "Pass" } else { "Fail" }
|
||||
Details = $details
|
||||
FailureReason = $failureReasons
|
||||
}
|
||||
$auditResult = Initialize-CISAuditResult @params
|
||||
}
|
||||
|
||||
end {
|
||||
# Return auditResults
|
||||
return $auditResults
|
||||
# Return the audit result
|
||||
return $auditResult
|
||||
}
|
||||
}
|
||||
|
@@ -1,37 +1,42 @@
|
||||
function Test-ReauthWithCode {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
# Aligned
|
||||
# Define your parameters here
|
||||
)
|
||||
|
||||
begin {
|
||||
# Initialization code
|
||||
|
||||
$auditResult = [CISAuditResult]::new()
|
||||
# Dot source the class script if necessary
|
||||
#. .\source\Classes\CISAuditResult.ps1
|
||||
# Initialization code, if needed
|
||||
}
|
||||
|
||||
process {
|
||||
# 7.2.10 (L1) Ensure reauthentication with verification code is restricted
|
||||
|
||||
# Retrieve reauthentication settings for SharePoint Online
|
||||
$SPOTenantReauthentication = Get-SPOTenant | Select-Object EmailAttestationRequired, EmailAttestationReAuthDays
|
||||
$isReauthenticationRestricted = $SPOTenantReauthentication.EmailAttestationRequired -and $SPOTenantReauthentication.EmailAttestationReAuthDays -le 15
|
||||
|
||||
# Populate the auditResult object with the required properties
|
||||
$auditResult.CISControlVer = "v8"
|
||||
$auditResult.CISControl = "0.0"
|
||||
$auditResult.CISDescription = "Explicitly Not Mapped"
|
||||
# Prepare failure reasons and details based on compliance
|
||||
$failureReasons = if (-not $isReauthenticationRestricted) {
|
||||
"Reauthentication with verification code does not require reauthentication within 15 days or less."
|
||||
}
|
||||
else {
|
||||
"N/A"
|
||||
}
|
||||
|
||||
$auditResult.Rec = "7.2.10"
|
||||
$auditResult.ELevel = "E3"
|
||||
$auditResult.ProfileLevel = "L1"
|
||||
$auditResult.IG1 = $false
|
||||
$auditResult.IG2 = $false
|
||||
$auditResult.IG3 = $false
|
||||
$auditResult.RecDescription = "Ensure reauthentication with verification code is restricted"
|
||||
$details = "EmailAttestationRequired: $($SPOTenantReauthentication.EmailAttestationRequired); EmailAttestationReAuthDays: $($SPOTenantReauthentication.EmailAttestationReAuthDays)"
|
||||
|
||||
$auditResult.Result = $isReauthenticationRestricted
|
||||
$auditResult.Details = "EmailAttestationRequired: $($SPOTenantReauthentication.EmailAttestationRequired); EmailAttestationReAuthDays: $($SPOTenantReauthentication.EmailAttestationReAuthDays)"
|
||||
$auditResult.FailureReason = if (-not $isReauthenticationRestricted) { "Reauthentication with verification code does not require reauthentication within 15 days or less." } else { "N/A" }
|
||||
$auditResult.Status = if ($isReauthenticationRestricted) { "Pass" } else { "Fail" }
|
||||
# Create and populate the CISAuditResult object
|
||||
$params = @{
|
||||
Rec = "7.2.10"
|
||||
Result = $isReauthenticationRestricted
|
||||
Status = if ($isReauthenticationRestricted) { "Pass" } else { "Fail" }
|
||||
Details = $details
|
||||
FailureReason = $failureReasons
|
||||
}
|
||||
$auditResult = Initialize-CISAuditResult @params
|
||||
}
|
||||
|
||||
end {
|
||||
|
@@ -1,21 +1,20 @@
|
||||
function Test-ReportSecurityInTeams {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
# Aligned
|
||||
# Parameters can be defined here if needed
|
||||
)
|
||||
|
||||
begin {
|
||||
# Dot source the class script
|
||||
|
||||
$auditResults = @()
|
||||
# Dot source the class script if necessary
|
||||
#. .\source\Classes\CISAuditResult.ps1
|
||||
# Initialization code, if needed
|
||||
}
|
||||
|
||||
process {
|
||||
# 8.6.1 (L1) Ensure users can report security concerns in Teams
|
||||
|
||||
# Connect to Teams PowerShell using Connect-MicrosoftTeams
|
||||
# Connect to Exchange Online PowerShell using Connect-ExchangeOnline
|
||||
|
||||
# Retrieve the necessary settings for Teams and Exchange Online
|
||||
$CsTeamsMessagingPolicy = Get-CsTeamsMessagingPolicy -Identity Global | Select-Object -Property AllowSecurityEndUserReporting
|
||||
$ReportSubmissionPolicy = Get-ReportSubmissionPolicy | Select-Object -Property ReportJunkToCustomizedAddress, ReportNotJunkToCustomizedAddress, ReportPhishToCustomizedAddress, ReportChatMessageToCustomizedAddressEnabled
|
||||
|
||||
@@ -25,32 +24,33 @@ function Test-ReportSecurityInTeams {
|
||||
$ReportSubmissionPolicy.ReportPhishToCustomizedAddress -and
|
||||
$ReportSubmissionPolicy.ReportChatMessageToCustomizedAddressEnabled
|
||||
|
||||
# Create an instance of CISAuditResult and populate it
|
||||
$auditResult = [CISAuditResult]::new()
|
||||
$auditResult.CISControlVer = "v8"
|
||||
$auditResult.CISControl = "0.0" # Explicitly Not Mapped as per the image provided
|
||||
$auditResult.CISDescription = "Explicitly Not Mapped"
|
||||
$auditResult.Rec = "8.6.1"
|
||||
$auditResult.ELevel = "E3"
|
||||
$auditResult.ProfileLevel = "L1"
|
||||
$auditResult.IG1 = $false # Set based on the CIS Controls image
|
||||
$auditResult.IG2 = $false # Set based on the CIS Controls image
|
||||
$auditResult.IG3 = $false # Set based on the CIS Controls image
|
||||
$auditResult.RecDescription = "Ensure users can report security concerns in Teams"
|
||||
$auditResult.Result = $securityReportEnabled
|
||||
$auditResult.Details = "AllowSecurityEndUserReporting: $($CsTeamsMessagingPolicy.AllowSecurityEndUserReporting); " +
|
||||
# Prepare failure reasons and details based on compliance
|
||||
$failureReasons = if (-not $securityReportEnabled) {
|
||||
"Users cannot report security concerns in Teams due to one or more incorrect settings"
|
||||
}
|
||||
else {
|
||||
"N/A"
|
||||
}
|
||||
|
||||
$details = "AllowSecurityEndUserReporting: $($CsTeamsMessagingPolicy.AllowSecurityEndUserReporting); " +
|
||||
"ReportJunkToCustomizedAddress: $($ReportSubmissionPolicy.ReportJunkToCustomizedAddress); " +
|
||||
"ReportNotJunkToCustomizedAddress: $($ReportSubmissionPolicy.ReportNotJunkToCustomizedAddress); " +
|
||||
"ReportPhishToCustomizedAddress: $($ReportSubmissionPolicy.ReportPhishToCustomizedAddress); " +
|
||||
"ReportChatMessageToCustomizedAddressEnabled: $($ReportSubmissionPolicy.ReportChatMessageToCustomizedAddressEnabled)"
|
||||
$auditResult.FailureReason = if (-not $securityReportEnabled) { "Users cannot report security concerns in Teams due to one or more incorrect settings" } else { "N/A" }
|
||||
$auditResult.Status = if ($securityReportEnabled) { "Pass" } else { "Fail" }
|
||||
|
||||
$auditResults += $auditResult
|
||||
# Create and populate the CISAuditResult object
|
||||
$params = @{
|
||||
Rec = "8.6.1"
|
||||
Result = $securityReportEnabled
|
||||
Status = if ($securityReportEnabled) { "Pass" } else { "Fail" }
|
||||
Details = $details
|
||||
FailureReason = $failureReasons
|
||||
}
|
||||
$auditResult = Initialize-CISAuditResult @params
|
||||
}
|
||||
|
||||
end {
|
||||
# Return auditResults
|
||||
return $auditResults
|
||||
# Return auditResult
|
||||
return $auditResult
|
||||
}
|
||||
}
|
||||
|
@@ -1,21 +1,20 @@
|
||||
function Test-RestrictCustomScripts {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
# Aligned
|
||||
# Define your parameters here if needed
|
||||
)
|
||||
#Limit All
|
||||
begin {
|
||||
# .TODO Test behavior in Prod
|
||||
# Dot source the class script
|
||||
|
||||
$auditResults = @()
|
||||
begin {
|
||||
# Dot source the class script if necessary
|
||||
#. .\source\Classes\CISAuditResult.ps1
|
||||
# Initialization code, if needed
|
||||
}
|
||||
|
||||
process {
|
||||
# CIS 2.7 Ensure custom script execution is restricted on site collections
|
||||
# Pass if DenyAddAndCustomizePages is set to true (Enabled). Fail otherwise.
|
||||
# 7.3.4 (L1) Ensure custom script execution is restricted on site collections
|
||||
|
||||
# Get all site collections and select necessary properties
|
||||
# Retrieve all site collections and select necessary properties
|
||||
$SPOSitesCustomScript = Get-SPOSite -Limit All | Select-Object Title, Url, DenyAddAndCustomizePages
|
||||
|
||||
# Find sites where custom scripts are allowed (DenyAddAndCustomizePages is not 'Enabled')
|
||||
@@ -29,42 +28,34 @@ function Test-RestrictCustomScripts {
|
||||
"$($_.Title) ($($_.Url)): Custom Script Allowed"
|
||||
}
|
||||
|
||||
# Create an instance of CISAuditResult and populate it
|
||||
$auditResult = [CISAuditResult]::new()
|
||||
$auditResult.CISControlVer = "v8"
|
||||
$auditResult.CISControl = "2.7"
|
||||
$auditResult.CISDescription = "Allowlist Authorized Scripts"
|
||||
$auditResult.Rec = "7.3.4"
|
||||
$auditResult.ELevel = "E3"
|
||||
$auditResult.ProfileLevel = "L1"
|
||||
$auditResult.IG1 = $false
|
||||
$auditResult.IG2 = $false
|
||||
$auditResult.IG3 = $true
|
||||
$auditResult.RecDescription = "Ensure custom script execution is restricted on site collections"
|
||||
$auditResult.Result = $complianceResult
|
||||
$auditResult.Details = if (-not $complianceResult) {
|
||||
$nonCompliantSiteDetails -join "; "
|
||||
} else {
|
||||
"All site collections have custom script execution restricted"
|
||||
}
|
||||
$auditResult.FailureReason = if (-not $complianceResult) {
|
||||
# Prepare failure reasons and details based on compliance
|
||||
$failureReasons = if (-not $complianceResult) {
|
||||
"The following site collections allow custom script execution: " + ($nonCompliantSiteDetails -join "; ")
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
"N/A"
|
||||
}
|
||||
$auditResult.Status = if ($complianceResult) {
|
||||
"Pass"
|
||||
} else {
|
||||
"Fail"
|
||||
|
||||
$details = if ($complianceResult) {
|
||||
"All site collections have custom script execution restricted"
|
||||
}
|
||||
else {
|
||||
$nonCompliantSiteDetails -join "; "
|
||||
}
|
||||
|
||||
$auditResults += $auditResult
|
||||
# Create and populate the CISAuditResult object
|
||||
$params = @{
|
||||
Rec = "7.3.4"
|
||||
Result = $complianceResult
|
||||
Status = if ($complianceResult) { "Pass" } else { "Fail" }
|
||||
Details = $details
|
||||
FailureReason = $failureReasons
|
||||
}
|
||||
$auditResult = Initialize-CISAuditResult @params
|
||||
}
|
||||
|
||||
|
||||
|
||||
end {
|
||||
# Return auditResults
|
||||
return $auditResults
|
||||
# Return auditResult
|
||||
return $auditResult
|
||||
}
|
||||
}
|
||||
|
@@ -1,37 +1,42 @@
|
||||
function Test-RestrictExternalSharing {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
# Aligned
|
||||
# Define your parameters here
|
||||
)
|
||||
|
||||
begin {
|
||||
# Initialization code
|
||||
|
||||
$auditResult = [CISAuditResult]::new()
|
||||
# Dot source the class script if necessary
|
||||
#. .\source\Classes\CISAuditResult.ps1
|
||||
# Initialization code, if needed
|
||||
}
|
||||
|
||||
process {
|
||||
# 7.2.3 (L1) Ensure external content sharing is restricted
|
||||
|
||||
# Retrieve the SharingCapability setting for the SharePoint tenant
|
||||
$SPOTenantSharingCapability = Get-SPOTenant | Select-Object SharingCapability
|
||||
$isRestricted = $SPOTenantSharingCapability.SharingCapability -in @('ExternalUserSharingOnly', 'ExistingExternalUserSharingOnly', 'Disabled')
|
||||
|
||||
# Populate the auditResult object with the required properties
|
||||
$auditResult.CISControlVer = "v8"
|
||||
$auditResult.CISControl = "3.3"
|
||||
$auditResult.CISDescription = "Configure Data Access Control Lists"
|
||||
# Prepare failure reasons and details based on compliance
|
||||
$failureReasons = if (-not $isRestricted) {
|
||||
"External content sharing is not adequately restricted. Current setting: $($SPOTenantSharingCapability.SharingCapability)"
|
||||
}
|
||||
else {
|
||||
"N/A"
|
||||
}
|
||||
|
||||
$auditResult.Rec = "7.2.3"
|
||||
$auditResult.ELevel = "E3"
|
||||
$auditResult.ProfileLevel = "L1"
|
||||
$auditResult.IG1 = $true
|
||||
$auditResult.IG2 = $true
|
||||
$auditResult.IG3 = $true
|
||||
$auditResult.RecDescription = "Ensure external content sharing is restricted"
|
||||
$details = "SharingCapability: $($SPOTenantSharingCapability.SharingCapability)"
|
||||
|
||||
$auditResult.Result = $isRestricted
|
||||
$auditResult.Details = "SharingCapability: $($SPOTenantSharingCapability.SharingCapability)"
|
||||
$auditResult.FailureReason = if (-not $isRestricted) { "External content sharing is not adequately restricted. Current setting: $($SPOTenantSharingCapability.SharingCapability)" } else { "N/A" }
|
||||
$auditResult.Status = if ($isRestricted) { "Pass" } else { "Fail" }
|
||||
# Create and populate the CISAuditResult object
|
||||
$params = @{
|
||||
Rec = "7.2.3"
|
||||
Result = $isRestricted
|
||||
Status = if ($isRestricted) { "Pass" } else { "Fail" }
|
||||
Details = $details
|
||||
FailureReason = $failureReasons
|
||||
}
|
||||
$auditResult = Initialize-CISAuditResult @params
|
||||
}
|
||||
|
||||
end {
|
||||
|
@@ -1,20 +1,20 @@
|
||||
function Test-RestrictOutlookAddins {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
# Aligned
|
||||
# Parameters could include credentials or other necessary data
|
||||
)
|
||||
|
||||
begin {
|
||||
# Dot source the class script if necessary
|
||||
#. .\source\Classes\CISAuditResult.ps1
|
||||
# Initialization code
|
||||
|
||||
$auditResult = [CISAuditResult]::new()
|
||||
$customPolicyFailures = @()
|
||||
$defaultPolicyFailureDetails = @()
|
||||
$relevantRoles = @('My Custom Apps', 'My Marketplace Apps', 'My ReadWriteMailbox Apps')
|
||||
}
|
||||
|
||||
process {
|
||||
# Main functionality
|
||||
# 6.3.1 (L2) Ensure users installing Outlook add-ins is not allowed
|
||||
|
||||
# Check all mailboxes for custom policies with unallowed add-ins
|
||||
@@ -38,24 +38,11 @@ function Test-RestrictOutlookAddins {
|
||||
if ($defaultPolicyRoles) {
|
||||
$defaultPolicyFailureDetails = $defaultPolicyRoles
|
||||
}
|
||||
}
|
||||
|
||||
end {
|
||||
# Prepare result object
|
||||
$auditResult.Rec = "6.3.1"
|
||||
$auditResult.CISControl = "9.4"
|
||||
$auditResult.CISDescription = "Restrict Unnecessary or Unauthorized Browser and Email Client Extensions"
|
||||
$auditResult.ELevel = "E3"
|
||||
$auditResult.ProfileLevel = "L2"
|
||||
$auditResult.IG1 = $false
|
||||
$auditResult.IG2 = $true
|
||||
$auditResult.IG3 = $true
|
||||
$auditResult.RecDescription = "Ensure users installing Outlook add-ins is not allowed"
|
||||
|
||||
# Prepare result details string
|
||||
$detailsString = ""
|
||||
if ($customPolicyFailures) {
|
||||
$detailsString += "Custom Policy Failures: | "
|
||||
# Use pipes or tabs here instead of newlines
|
||||
$detailsString += ($customPolicyFailures -join " | ")
|
||||
}
|
||||
else {
|
||||
@@ -70,20 +57,22 @@ function Test-RestrictOutlookAddins {
|
||||
$detailsString += "Compliant"
|
||||
}
|
||||
|
||||
if ($customPolicyFailures -or $defaultPolicyFailureDetails) {
|
||||
$auditResult.Result = $false
|
||||
$auditResult.Status = "Fail"
|
||||
$auditResult.Details = $detailsString
|
||||
$auditResult.FailureReason = "Unauthorized Outlook add-ins found in custom or default policies."
|
||||
}
|
||||
else {
|
||||
$auditResult.Result = $true
|
||||
$auditResult.Status = "Pass"
|
||||
$auditResult.Details = "No unauthorized Outlook add-ins found in custom or default policies."
|
||||
$auditResult.FailureReason = "N/A"
|
||||
}
|
||||
# Determine result based on findings
|
||||
$isCompliant = -not ($customPolicyFailures -or $defaultPolicyFailureDetails)
|
||||
|
||||
# Return auditResult
|
||||
# Create and populate the CISAuditResult object
|
||||
$params = @{
|
||||
Rec = "6.3.1"
|
||||
Result = $isCompliant
|
||||
Status = if ($isCompliant) { "Pass" } else { "Fail" }
|
||||
Details = $detailsString
|
||||
FailureReason = if ($isCompliant) { "N/A" } else { "Unauthorized Outlook add-ins found in custom or default policies." }
|
||||
}
|
||||
$auditResult = Initialize-CISAuditResult @params
|
||||
}
|
||||
|
||||
end {
|
||||
# Return the audit result
|
||||
return $auditResult
|
||||
}
|
||||
}
|
@@ -1,48 +1,56 @@
|
||||
function Test-RestrictStorageProvidersOutlook {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
# Aligned
|
||||
# Parameters can be added here if needed
|
||||
)
|
||||
|
||||
begin {
|
||||
# Dot source the class script
|
||||
|
||||
$auditResult = [CISAuditResult]::new()
|
||||
# Dot source the class script if necessary
|
||||
#. .\source\Classes\CISAuditResult.ps1
|
||||
# Initialization code, if needed
|
||||
}
|
||||
|
||||
process {
|
||||
# 6.5.3 (L2) Ensure additional storage providers are restricted in Outlook on the web
|
||||
$owaPolicies = Get-OwaMailboxPolicy
|
||||
$allPoliciesRestricted = $owaPolicies | ForEach-Object { $_.AdditionalStorageProvidersAvailable } | ForEach-Object { -not $_ }
|
||||
|
||||
# Create an instance of CISAuditResult and populate it
|
||||
$auditResult.CISControlVer = "v8"
|
||||
$auditResult.CISControl = "3.3"
|
||||
$auditResult.CISDescription = "Configure Data Access Control Lists"
|
||||
$auditResult.Rec = "6.5.3"
|
||||
$auditResult.ELevel = "E3" # Based on your environment
|
||||
$auditResult.ProfileLevel = "L2"
|
||||
$auditResult.IG1 = $true
|
||||
$auditResult.IG2 = $true
|
||||
$auditResult.IG3 = $true
|
||||
$auditResult.RecDescription = "Ensure additional storage providers are restricted in Outlook on the web"
|
||||
$auditResult.Result = $allPoliciesRestricted
|
||||
$auditResult.Details = if($allPoliciesRestricted) {
|
||||
"All OwaMailbox policies restrict AdditionalStorageProvidersAvailable"
|
||||
} else {
|
||||
$nonCompliantPolicies = $owaPolicies | Where-Object { $_.AdditionalStorageProvidersAvailable } | Select-Object -ExpandProperty Name
|
||||
"Non-compliant OwaMailbox policies: $($nonCompliantPolicies -join ', ')"
|
||||
# Retrieve all OwaMailbox policies
|
||||
$owaPolicies = Get-OwaMailboxPolicy
|
||||
$nonCompliantPolicies = $owaPolicies | Where-Object { $_.AdditionalStorageProvidersAvailable }
|
||||
|
||||
# Determine compliance
|
||||
$allPoliciesRestricted = $nonCompliantPolicies.Count -eq 0
|
||||
|
||||
# Prepare failure reasons and details based on compliance
|
||||
$failureReasons = if ($allPoliciesRestricted) {
|
||||
"N/A"
|
||||
}
|
||||
$auditResult.FailureReason = if(-not $allPoliciesRestricted) { "One or more OwaMailbox policies allow AdditionalStorageProvidersAvailable." } else { "N/A" }
|
||||
$auditResult.Status = if($allPoliciesRestricted) { "Pass" } else { "Fail" }
|
||||
else {
|
||||
"One or more OwaMailbox policies allow AdditionalStorageProvidersAvailable."
|
||||
}
|
||||
|
||||
$details = if ($allPoliciesRestricted) {
|
||||
"All OwaMailbox policies restrict AdditionalStorageProvidersAvailable"
|
||||
}
|
||||
else {
|
||||
"Non-compliant OwaMailbox policies: $($nonCompliantPolicies.Name -join ', ')"
|
||||
}
|
||||
|
||||
# Create and populate the CISAuditResult object
|
||||
$params = @{
|
||||
Rec = "6.5.3"
|
||||
Result = $allPoliciesRestricted
|
||||
Status = if ($allPoliciesRestricted) { "Pass" } else { "Fail" }
|
||||
Details = $details
|
||||
FailureReason = $failureReasons
|
||||
}
|
||||
$auditResult = Initialize-CISAuditResult @params
|
||||
}
|
||||
|
||||
end {
|
||||
# Return auditResult
|
||||
# Return the audit result
|
||||
return $auditResult
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Additional helper functions (if any)
|
||||
|
||||
|
@@ -1,43 +1,48 @@
|
||||
function Test-RestrictTenantCreation {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
# Aligned
|
||||
# Parameters can be added if needed
|
||||
)
|
||||
|
||||
begin {
|
||||
# Dot source the class script
|
||||
|
||||
$auditResults = @()
|
||||
# Dot source the class script if necessary
|
||||
#. .\source\Classes\CISAuditResult.ps1
|
||||
# Initialization code, if needed
|
||||
}
|
||||
|
||||
process {
|
||||
# 5.1.2.3 (L1) Ensure 'Restrict non-admin users from creating tenants' is set to 'Yes'
|
||||
# Pass if AllowedToCreateTenants is False. Fail otherwise.
|
||||
|
||||
# Retrieve the tenant creation policy
|
||||
$tenantCreationPolicy = (Get-MgPolicyAuthorizationPolicy).DefaultUserRolePermissions | Select-Object AllowedToCreateTenants
|
||||
$tenantCreationResult = -not $tenantCreationPolicy.AllowedToCreateTenants
|
||||
|
||||
# Create an instance of CISAuditResult and populate it
|
||||
$auditResult = [CISAuditResult]::new()
|
||||
$auditResult.Status = if ($tenantCreationResult) { "Pass" } else { "Fail" }
|
||||
$auditResult.ELevel = "E3"
|
||||
$auditResult.ProfileLevel = "L1"
|
||||
$auditResult.Rec = "5.1.2.3"
|
||||
$auditResult.RecDescription = "Ensure 'Restrict non-admin users from creating tenants' is set to 'Yes'"
|
||||
$auditResult.CISControlVer = "v8"
|
||||
$auditResult.CISControl = "0.0"
|
||||
$auditResult.CISDescription = "Explicitly Not Mapped"
|
||||
$auditResult.IG1 = $false
|
||||
$auditResult.IG2 = $false
|
||||
$auditResult.IG3 = $false
|
||||
$auditResult.Result = $tenantCreationResult
|
||||
$auditResult.Details = "AllowedToCreateTenants: $($tenantCreationPolicy.AllowedToCreateTenants)"
|
||||
$auditResult.FailureReason = if (-not $tenantCreationResult) { "Non-admin users can create tenants" } else { "N/A" }
|
||||
# Prepare failure reasons and details based on compliance
|
||||
$failureReasons = if ($tenantCreationResult) {
|
||||
"N/A"
|
||||
}
|
||||
else {
|
||||
"Non-admin users can create tenants"
|
||||
}
|
||||
|
||||
$auditResults += $auditResult
|
||||
$details = "AllowedToCreateTenants: $($tenantCreationPolicy.AllowedToCreateTenants)"
|
||||
|
||||
# Create and populate the CISAuditResult object
|
||||
$params = @{
|
||||
Rec = "5.1.2.3"
|
||||
Result = $tenantCreationResult
|
||||
Status = if ($tenantCreationResult) { "Pass" } else { "Fail" }
|
||||
Details = $details
|
||||
FailureReason = $failureReasons
|
||||
}
|
||||
$auditResult = Initialize-CISAuditResult @params
|
||||
}
|
||||
|
||||
end {
|
||||
# Return auditResults
|
||||
return $auditResults
|
||||
# Return the audit result
|
||||
return $auditResult
|
||||
}
|
||||
}
|
||||
|
||||
# Additional helper functions (if any)
|
||||
|
@@ -1,49 +1,53 @@
|
||||
function Test-SafeAttachmentsPolicy {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
# Aligned
|
||||
# Parameters can be added if needed
|
||||
)
|
||||
|
||||
begin {
|
||||
|
||||
$auditResults = @()
|
||||
# Dot source the class script if necessary
|
||||
#. .\source\Classes\CISAuditResult.ps1
|
||||
# Initialization code, if needed
|
||||
}
|
||||
|
||||
process {
|
||||
# 2.1.4 (L2) Ensure Safe Attachments policy is enabled
|
||||
|
||||
# Retrieve all Safe Attachment policies where Enable is set to True
|
||||
$safeAttachmentPolicies = Get-SafeAttachmentPolicy | Where-Object { $_.Enable -eq $true }
|
||||
|
||||
# If there are any enabled policies, the result is Pass. If not, it's Fail.
|
||||
$result = $safeAttachmentPolicies -ne $null -and $safeAttachmentPolicies.Count -gt 0
|
||||
# Determine result and details based on the presence of enabled policies
|
||||
$result = $null -ne $safeAttachmentPolicies -and $safeAttachmentPolicies.Count -gt 0
|
||||
$details = if ($result) {
|
||||
"Enabled Safe Attachments Policies: $($safeAttachmentPolicies.Name -join ', ')"
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
"No Safe Attachments Policies are enabled."
|
||||
}
|
||||
$failureReason = if ($result) { "N/A" } else { "Safe Attachments policy is not enabled." }
|
||||
|
||||
# Create an instance of CISAuditResult and populate it
|
||||
$auditResult = [CISAuditResult]::new()
|
||||
$auditResult.Status = if ($result) { "Pass" } else { "Fail" }
|
||||
$auditResult.ELevel = "E5"
|
||||
$auditResult.ProfileLevel = "L2"
|
||||
$auditResult.Rec = "2.1.4"
|
||||
$auditResult.RecDescription = "Ensure Safe Attachments policy is enabled"
|
||||
$auditResult.CISControlVer = "v8"
|
||||
$auditResult.CISControl = "9.7"
|
||||
$auditResult.CISDescription = "Deploy and Maintain Email Server Anti-Malware Protections"
|
||||
$auditResult.IG1 = $false
|
||||
$auditResult.IG2 = $false
|
||||
$auditResult.IG3 = $true
|
||||
$auditResult.Result = $result
|
||||
$auditResult.Details = $details
|
||||
$auditResult.FailureReason = $failureReason
|
||||
$failureReasons = if ($result) {
|
||||
"N/A"
|
||||
}
|
||||
else {
|
||||
"Safe Attachments policy is not enabled."
|
||||
}
|
||||
|
||||
$auditResults += $auditResult
|
||||
# Create and populate the CISAuditResult object
|
||||
$params = @{
|
||||
Rec = "2.1.4"
|
||||
Result = $result
|
||||
Status = if ($result) { "Pass" } else { "Fail" }
|
||||
Details = $details
|
||||
FailureReason = $failureReasons
|
||||
}
|
||||
$auditResult = Initialize-CISAuditResult @params
|
||||
}
|
||||
|
||||
end {
|
||||
# Return auditResults
|
||||
return $auditResults
|
||||
# Return the audit result
|
||||
return $auditResult
|
||||
}
|
||||
}
|
||||
|
||||
# Additional helper functions (if any)
|
||||
|
@@ -1,16 +1,19 @@
|
||||
function Test-SafeAttachmentsTeams {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
# Aligned
|
||||
# Parameters can be added if needed
|
||||
)
|
||||
|
||||
begin {
|
||||
|
||||
$auditResults = @()
|
||||
# Dot source the class script if necessary
|
||||
#. .\source\Classes\CISAuditResult.ps1
|
||||
# Initialization code, if needed
|
||||
}
|
||||
|
||||
process {
|
||||
# Requires E5 license
|
||||
# 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
|
||||
$atpPolicies = Get-AtpPolicyForO365
|
||||
|
||||
@@ -25,33 +28,33 @@ function Test-SafeAttachmentsTeams {
|
||||
$result = $null -ne $atpPolicyResult
|
||||
$details = if ($result) {
|
||||
"ATP for SharePoint, OneDrive, and Teams is enabled with correct settings."
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
"ATP for SharePoint, OneDrive, and Teams is not enabled with correct settings."
|
||||
}
|
||||
$failureReason = if ($result) { "N/A" } else { "ATP policy for SharePoint, OneDrive, and Microsoft Teams is not correctly configured." }
|
||||
|
||||
# Create an instance of CISAuditResult and populate it
|
||||
$auditResult = [CISAuditResult]::new()
|
||||
$auditResult.Status = if ($result) { "Pass" } else { "Fail" }
|
||||
$auditResult.ELevel = "E5"
|
||||
$auditResult.ProfileLevel = "L2"
|
||||
$auditResult.Rec = "2.1.5"
|
||||
$auditResult.RecDescription = "Ensure Safe Attachments for SharePoint, OneDrive, and Microsoft Teams is Enabled"
|
||||
$auditResult.CISControlVer = "v8"
|
||||
$auditResult.CISControl = "9.7, 10.1"
|
||||
$auditResult.CISDescription = "Deploy and Maintain Email Server Anti-Malware Protections, Deploy and Maintain Anti-Malware Software"
|
||||
$auditResult.IG1 = $true
|
||||
$auditResult.IG2 = $true
|
||||
$auditResult.IG3 = $true
|
||||
$auditResult.Result = $result
|
||||
$auditResult.Details = $details
|
||||
$auditResult.FailureReason = $failureReason
|
||||
$failureReasons = if ($result) {
|
||||
"N/A"
|
||||
}
|
||||
else {
|
||||
"ATP policy for SharePoint, OneDrive, and Microsoft Teams is not correctly configured."
|
||||
}
|
||||
|
||||
$auditResults += $auditResult
|
||||
# Create and populate the CISAuditResult object
|
||||
$params = @{
|
||||
Rec = "2.1.5"
|
||||
Result = $result
|
||||
Status = if ($result) { "Pass" } else { "Fail" }
|
||||
Details = $details
|
||||
FailureReason = $failureReasons
|
||||
}
|
||||
$auditResult = Initialize-CISAuditResult @params
|
||||
}
|
||||
|
||||
end {
|
||||
# Return auditResults
|
||||
return $auditResults
|
||||
# Return the audit result
|
||||
return $auditResult
|
||||
}
|
||||
}
|
||||
|
||||
# Additional helper functions (if any)
|
||||
|
@@ -1,16 +1,19 @@
|
||||
function Test-SafeLinksOfficeApps {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
# Aligned
|
||||
# Define your parameters here if needed
|
||||
)
|
||||
|
||||
begin {
|
||||
# Initialization code
|
||||
|
||||
$auditResults = @()
|
||||
# Dot source the class script if necessary
|
||||
#. .\source\Classes\CISAuditResult.ps1
|
||||
# Initialization code, if needed
|
||||
}
|
||||
|
||||
process {
|
||||
# 2.1.1 (L2) Ensure Safe Links for Office Applications is Enabled
|
||||
|
||||
# Retrieve all Safe Links policies
|
||||
$policies = Get-SafeLinksPolicy
|
||||
|
||||
@@ -42,29 +45,21 @@ function Test-SafeLinksOfficeApps {
|
||||
# Prepare the final result
|
||||
$result = $misconfiguredDetails.Count -eq 0
|
||||
$details = if ($result) { "All Safe Links policies are correctly configured." } else { $misconfiguredDetails -join ' | ' }
|
||||
$failureReasons = if ($result) { "N/A" } else { "The following Safe Links policies settings do not meet the recommended configuration: $($misconfiguredDetails -join ' | ')" }
|
||||
|
||||
# Create the audit result object
|
||||
$auditResult = [CISAuditResult]::new()
|
||||
$auditResult.Status = if ($result) { "Pass" } else { "Fail" }
|
||||
$auditResult.ELevel = "E5"
|
||||
$auditResult.ProfileLevel = "L2"
|
||||
$auditResult.Rec = "2.1.1"
|
||||
$auditResult.RecDescription = "Ensure Safe Links for Office Applications is Enabled"
|
||||
$auditResult.CISControlVer = "v8"
|
||||
$auditResult.CISControl = "10.1"
|
||||
$auditResult.CISDescription = "Deploy and Maintain Anti-Malware Software"
|
||||
$auditResult.IG1 = $true
|
||||
$auditResult.IG2 = $true
|
||||
$auditResult.IG3 = $true
|
||||
$auditResult.Result = $result
|
||||
$auditResult.Details = $details
|
||||
$auditResult.FailureReason = if ($result) { "N/A" } else { "The following Safe Links policies settings do not meet the recommended configuration: $($misconfiguredDetails -join ' | ')" }
|
||||
|
||||
$auditResults += $auditResult
|
||||
# Create and populate the CISAuditResult object
|
||||
$params = @{
|
||||
Rec = "2.1.1"
|
||||
Result = $result
|
||||
Status = if ($result) { "Pass" } else { "Fail" }
|
||||
Details = $details
|
||||
FailureReason = $failureReasons
|
||||
}
|
||||
$auditResult = Initialize-CISAuditResult @params
|
||||
}
|
||||
|
||||
end {
|
||||
# Return auditResults
|
||||
return $auditResults
|
||||
# Return the audit result
|
||||
return $auditResult
|
||||
}
|
||||
}
|
||||
|
@@ -1,11 +1,14 @@
|
||||
function Test-SharePointAADB2B {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
# Aligned
|
||||
# Define your parameters here
|
||||
)
|
||||
|
||||
begin {
|
||||
# Initialization code
|
||||
# Dot source the class script if necessary
|
||||
#. .\source\Classes\CISAuditResult.ps1
|
||||
# Initialization code, if needed
|
||||
|
||||
$auditResult = [CISAuditResult]::new()
|
||||
}
|
||||
@@ -15,22 +18,14 @@ function Test-SharePointAADB2B {
|
||||
$SPOTenantAzureADB2B = Get-SPOTenant | Select-Object EnableAzureADB2BIntegration
|
||||
|
||||
# Populate the auditResult object with the required properties
|
||||
$auditResult.CISControlVer = "v8"
|
||||
$auditResult.CISControl = "0.0"
|
||||
$auditResult.CISDescription = "Explicitly Not Mapped"
|
||||
|
||||
$auditResult.Rec = "7.2.2"
|
||||
$auditResult.ELevel = "E3"
|
||||
$auditResult.ProfileLevel = "L1"
|
||||
$auditResult.IG1 = $false
|
||||
$auditResult.IG2 = $false
|
||||
$auditResult.IG3 = $false
|
||||
$auditResult.RecDescription = "Ensure SharePoint and OneDrive integration with Azure AD B2B is enabled"
|
||||
|
||||
$auditResult.Result = $SPOTenantAzureADB2B.EnableAzureADB2BIntegration
|
||||
$auditResult.Details = "EnableAzureADB2BIntegration: $($SPOTenantAzureADB2B.EnableAzureADB2BIntegration)"
|
||||
$auditResult.FailureReason = if (-not $SPOTenantAzureADB2B.EnableAzureADB2BIntegration) { "Azure AD B2B integration is not enabled" } else { "N/A" }
|
||||
$auditResult.Status = if ($SPOTenantAzureADB2B.EnableAzureADB2BIntegration) { "Pass" } else { "Fail" }
|
||||
$params = @{
|
||||
Rec = "7.2.2"
|
||||
Result = $SPOTenantAzureADB2B.EnableAzureADB2BIntegration
|
||||
Status = if ($SPOTenantAzureADB2B.EnableAzureADB2BIntegration) { "Pass" } else { "Fail" }
|
||||
Details = "EnableAzureADB2BIntegration: $($SPOTenantAzureADB2B.EnableAzureADB2BIntegration)"
|
||||
FailureReason = if (-not $SPOTenantAzureADB2B.EnableAzureADB2BIntegration) { "Azure AD B2B integration is not enabled" } else { "N/A" }
|
||||
}
|
||||
$auditResult = Initialize-CISAuditResult @params
|
||||
}
|
||||
|
||||
end {
|
||||
|
@@ -1,11 +1,14 @@
|
||||
function Test-SharePointExternalSharingDomains {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
# Aligned
|
||||
# Define your parameters here
|
||||
)
|
||||
|
||||
begin {
|
||||
# Initialization code
|
||||
# Dot source the class script if necessary
|
||||
#. .\source\Classes\CISAuditResult.ps1
|
||||
# Initialization code, if needed
|
||||
|
||||
$auditResult = [CISAuditResult]::new()
|
||||
}
|
||||
@@ -16,22 +19,14 @@ function Test-SharePointExternalSharingDomains {
|
||||
$isDomainRestrictionConfigured = $SPOTenant.SharingDomainRestrictionMode -eq 'AllowList'
|
||||
|
||||
# Populate the auditResult object with the required properties
|
||||
$auditResult.CISControlVer = "v8"
|
||||
$auditResult.CISControl = "3.3"
|
||||
$auditResult.CISDescription = "Configure Data Access Control Lists"
|
||||
|
||||
$auditResult.Rec = "7.2.6"
|
||||
$auditResult.ELevel = "E3"
|
||||
$auditResult.ProfileLevel = "L2"
|
||||
$auditResult.IG1 = $true
|
||||
$auditResult.IG2 = $true
|
||||
$auditResult.IG3 = $true
|
||||
$auditResult.RecDescription = "Ensure SharePoint external sharing is managed through domain whitelist/blacklists"
|
||||
|
||||
$auditResult.Result = $isDomainRestrictionConfigured
|
||||
$auditResult.Details = "SharingDomainRestrictionMode: $($SPOTenant.SharingDomainRestrictionMode); SharingAllowedDomainList: $($SPOTenant.SharingAllowedDomainList)"
|
||||
$auditResult.FailureReason = if (-not $isDomainRestrictionConfigured) { "Domain restrictions for SharePoint external sharing are not configured to 'AllowList'. Current setting: $($SPOTenant.SharingDomainRestrictionMode)" } else { "N/A" }
|
||||
$auditResult.Status = if ($isDomainRestrictionConfigured) { "Pass" } else { "Fail" }
|
||||
$params = @{
|
||||
Rec = "7.2.6"
|
||||
Result = $isDomainRestrictionConfigured
|
||||
Status = if ($isDomainRestrictionConfigured) { "Pass" } else { "Fail" }
|
||||
Details = "SharingDomainRestrictionMode: $($SPOTenant.SharingDomainRestrictionMode); SharingAllowedDomainList: $($SPOTenant.SharingAllowedDomainList)"
|
||||
FailureReason = if (-not $isDomainRestrictionConfigured) { "Domain restrictions for SharePoint external sharing are not configured to 'AllowList'. Current setting: $($SPOTenant.SharingDomainRestrictionMode)" } else { "N/A" }
|
||||
}
|
||||
$auditResult = Initialize-CISAuditResult @params
|
||||
}
|
||||
|
||||
end {
|
||||
|
@@ -1,11 +1,14 @@
|
||||
function Test-SharePointGuestsItemSharing {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
# Aligned
|
||||
# Define your parameters here
|
||||
)
|
||||
|
||||
begin {
|
||||
# Initialization code
|
||||
# Dot source the class script if necessary
|
||||
#. .\source\Classes\CISAuditResult.ps1
|
||||
# Initialization code, if needed
|
||||
|
||||
$auditResult = [CISAuditResult]::new()
|
||||
}
|
||||
@@ -16,22 +19,14 @@ function Test-SharePointGuestsItemSharing {
|
||||
$isGuestResharingPrevented = $SPOTenant.PreventExternalUsersFromResharing
|
||||
|
||||
# Populate the auditResult object with the required properties
|
||||
$auditResult.CISControlVer = "v8"
|
||||
$auditResult.CISControl = "3.3"
|
||||
$auditResult.CISDescription = "Configure Data Access Control Lists"
|
||||
|
||||
$auditResult.Rec = "7.2.5"
|
||||
$auditResult.ELevel = "E3"
|
||||
$auditResult.ProfileLevel = "L2"
|
||||
$auditResult.IG1 = $true
|
||||
$auditResult.IG2 = $true
|
||||
$auditResult.IG3 = $true
|
||||
$auditResult.RecDescription = "Ensure that SharePoint guest users cannot share items they don't own"
|
||||
|
||||
$auditResult.Result = $isGuestResharingPrevented
|
||||
$auditResult.Details = "PreventExternalUsersFromResharing: $isGuestResharingPrevented"
|
||||
$auditResult.FailureReason = if (-not $isGuestResharingPrevented) { "Guest users can reshare items they don't own." } else { "N/A" }
|
||||
$auditResult.Status = if ($isGuestResharingPrevented) { "Pass" } else { "Fail" }
|
||||
$params = @{
|
||||
Rec = "7.2.5"
|
||||
Result = $isGuestResharingPrevented
|
||||
Status = if ($isGuestResharingPrevented) { "Pass" } else { "Fail" }
|
||||
Details = "PreventExternalUsersFromResharing: $isGuestResharingPrevented"
|
||||
FailureReason = if (-not $isGuestResharingPrevented) { "Guest users can reshare items they don't own." } else { "N/A" }
|
||||
}
|
||||
$auditResult = Initialize-CISAuditResult @params
|
||||
}
|
||||
|
||||
end {
|
||||
|
@@ -1,16 +1,20 @@
|
||||
function Test-SpamPolicyAdminNotify {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
# Aligned
|
||||
# Parameters can be added if needed
|
||||
)
|
||||
|
||||
begin {
|
||||
# Dot source the class script if necessary
|
||||
#. .\source\Classes\CISAuditResult.ps1
|
||||
# Initialization code, if needed
|
||||
|
||||
$auditResults = @()
|
||||
$auditResult = [CISAuditResult]::new()
|
||||
}
|
||||
|
||||
process {
|
||||
# 2.1.6 Ensure Exchange Online Spam Policies are set to notify administrators
|
||||
# 2.1.6 Ensure Exchange Online Spam Policies are set to notify administrators
|
||||
|
||||
# Get the default hosted outbound spam filter policy
|
||||
$hostedOutboundSpamFilterPolicy = Get-HostedOutboundSpamFilterPolicy | Where-Object { $_.IsDefault -eq $true }
|
||||
@@ -30,29 +34,18 @@ function Test-SpamPolicyAdminNotify {
|
||||
}
|
||||
|
||||
# Create an instance of CISAuditResult and populate it
|
||||
$auditResult = [CISAuditResult]::new()
|
||||
$auditResult.Status = if ($areSettingsEnabled) { "Pass" } else { "Fail" }
|
||||
$auditResult.ELevel = "E3"
|
||||
$auditResult.ProfileLevel = "L1"
|
||||
$auditResult.Rec = "2.1.6"
|
||||
$auditResult.RecDescription = "Ensure Exchange Online Spam Policies are set to notify administrators"
|
||||
$auditResult.CISControlVer = "v8"
|
||||
$auditResult.CISControl = "17.5"
|
||||
$auditResult.CISDescription = "Assign Key Roles and Responsibilities"
|
||||
$auditResult.IG1 = $false
|
||||
$auditResult.IG2 = $true
|
||||
$auditResult.IG3 = $true
|
||||
$auditResult.Result = $areSettingsEnabled
|
||||
$auditResult.Details = if ($areSettingsEnabled) { "Both BccSuspiciousOutboundMail and NotifyOutboundSpam are enabled." } else { $failureDetails -join ' ' }
|
||||
$auditResult.FailureReason = if (-not $areSettingsEnabled) { "One or both spam policies are not set to notify administrators." } else { "N/A" }
|
||||
|
||||
$auditResults += $auditResult
|
||||
$params = @{
|
||||
Rec = "2.1.6"
|
||||
Result = $areSettingsEnabled
|
||||
Status = if ($areSettingsEnabled) { "Pass" } else { "Fail" }
|
||||
Details = if ($areSettingsEnabled) { "Both BccSuspiciousOutboundMail and NotifyOutboundSpam are enabled." } else { $failureDetails -join ' ' }
|
||||
FailureReason = if (-not $areSettingsEnabled) { "One or both spam policies are not set to notify administrators." } else { "N/A" }
|
||||
}
|
||||
$auditResult = Initialize-CISAuditResult @params
|
||||
}
|
||||
|
||||
end {
|
||||
# Return auditResults
|
||||
return $auditResults
|
||||
# Return auditResult
|
||||
return $auditResult
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@@ -1,13 +1,16 @@
|
||||
function Test-TeamsExternalAccess {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
# Aligned
|
||||
# Parameters can be defined here if needed
|
||||
)
|
||||
|
||||
begin {
|
||||
# Dot source the class script
|
||||
# Dot source the class script if necessary
|
||||
#. .\source\Classes\CISAuditResult.ps1
|
||||
# Initialization code, if needed
|
||||
|
||||
$auditResults = @()
|
||||
$auditResult = [CISAuditResult]::new()
|
||||
}
|
||||
|
||||
process {
|
||||
@@ -26,27 +29,18 @@ function Test-TeamsExternalAccess {
|
||||
$isCompliant = -not $externalAccessConfig.AllowTeamsConsumer -and -not $externalAccessConfig.AllowPublicUsers -and (-not $externalAccessConfig.AllowFederatedUsers -or $allowedDomainsLimited)
|
||||
|
||||
# Create an instance of CISAuditResult and populate it
|
||||
$auditResult = [CISAuditResult]::new()
|
||||
$auditResult.CISControlVer = "v8"
|
||||
$auditResult.CISControl = "0.0" # The control is Explicitly Not Mapped as per the image provided
|
||||
$auditResult.CISDescription = "Explicitly Not Mapped"
|
||||
$auditResult.Rec = "8.2.1"
|
||||
$auditResult.ELevel = "E3"
|
||||
$auditResult.ProfileLevel = "L2"
|
||||
$auditResult.IG1 = $false # Set based on the CIS Controls image
|
||||
$auditResult.IG2 = $false # Set based on the CIS Controls image
|
||||
$auditResult.IG3 = $false # Set based on the CIS Controls image
|
||||
$auditResult.RecDescription = "Ensure 'external access' is restricted in the Teams admin center"
|
||||
$auditResult.Result = $isCompliant
|
||||
$auditResult.Details = "AllowTeamsConsumer: $($externalAccessConfig.AllowTeamsConsumer); AllowPublicUsers: $($externalAccessConfig.AllowPublicUsers); AllowFederatedUsers: $($externalAccessConfig.AllowFederatedUsers); AllowedDomains limited: $allowedDomainsLimited"
|
||||
$auditResult.FailureReason = if (-not $isCompliant) { "One or more external access configurations are not compliant." } else { "N/A" }
|
||||
$auditResult.Status = if ($isCompliant) { "Pass" } else { "Fail" }
|
||||
|
||||
$auditResults += $auditResult
|
||||
$params = @{
|
||||
Rec = "8.2.1"
|
||||
Result = $isCompliant
|
||||
Status = if ($isCompliant) { "Pass" } else { "Fail" }
|
||||
Details = "AllowTeamsConsumer: $($externalAccessConfig.AllowTeamsConsumer); AllowPublicUsers: $($externalAccessConfig.AllowPublicUsers); AllowFederatedUsers: $($externalAccessConfig.AllowFederatedUsers); AllowedDomains limited: $allowedDomainsLimited"
|
||||
FailureReason = if (-not $isCompliant) { "One or more external access configurations are not compliant." } else { "N/A" }
|
||||
}
|
||||
$auditResult = Initialize-CISAuditResult @params
|
||||
}
|
||||
|
||||
end {
|
||||
# Return auditResults
|
||||
return $auditResults
|
||||
# Return auditResult
|
||||
return $auditResult
|
||||
}
|
||||
}
|
||||
|
@@ -1,13 +1,16 @@
|
||||
function Test-TeamsExternalFileSharing {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
# Aligned
|
||||
# Parameters can be added here if needed
|
||||
)
|
||||
|
||||
begin {
|
||||
# Dot source the class script
|
||||
# Dot source the class script if necessary
|
||||
#. .\source\Classes\CISAuditResult.ps1
|
||||
# Initialization code, if needed
|
||||
|
||||
$auditResults = @()
|
||||
$auditResult = [CISAuditResult]::new()
|
||||
}
|
||||
|
||||
process {
|
||||
@@ -30,27 +33,18 @@ function Test-TeamsExternalFileSharing {
|
||||
}
|
||||
|
||||
# Create an instance of CISAuditResult and populate it
|
||||
$auditResult = [CISAuditResult]::new()
|
||||
$auditResult.CISControlVer = "v8"
|
||||
$auditResult.CISControl = "3.3"
|
||||
$auditResult.CISDescription = "Configure Data Access Control Lists"
|
||||
$auditResult.Rec = "8.1.1"
|
||||
$auditResult.ELevel = "E3"
|
||||
$auditResult.ProfileLevel = "L2"
|
||||
$auditResult.IG1 = $true # Set based on the benchmark
|
||||
$auditResult.IG2 = $true # Set based on the benchmark
|
||||
$auditResult.IG3 = $true # Set based on the benchmark
|
||||
$auditResult.RecDescription = "Ensure external file sharing in Teams is enabled for only approved cloud storage services"
|
||||
$auditResult.Result = $isCompliant
|
||||
$auditResult.Details = if (-not $isCompliant) { "Non-approved providers enabled: $($nonCompliantProviders -join ', ')" } else { "All cloud storage services are approved providers" }
|
||||
$auditResult.FailureReason = if (-not $isCompliant) { "The following non-approved providers are enabled: $($nonCompliantProviders -join ', ')" } else { "N/A" }
|
||||
$auditResult.Status = if ($isCompliant) { "Pass" } else { "Fail" }
|
||||
|
||||
$auditResults += $auditResult
|
||||
$params = @{
|
||||
Rec = "8.1.1"
|
||||
Result = $isCompliant
|
||||
Status = if ($isCompliant) { "Pass" } else { "Fail" }
|
||||
Details = if (-not $isCompliant) { "Non-approved providers enabled: $($nonCompliantProviders -join ', ')" } else { "All cloud storage services are approved providers" }
|
||||
FailureReason = if (-not $isCompliant) { "The following non-approved providers are enabled: $($nonCompliantProviders -join ', ')" } else { "N/A" }
|
||||
}
|
||||
$auditResult = Initialize-CISAuditResult @params
|
||||
}
|
||||
|
||||
end {
|
||||
# Return auditResults
|
||||
return $auditResults
|
||||
# Return auditResult
|
||||
return $auditResult
|
||||
}
|
||||
}
|
27
tests/Unit/Private/Get-TestDefinitionsObject.tests.ps1
Normal file
27
tests/Unit/Private/Get-TestDefinitionsObject.tests.ps1
Normal file
@@ -0,0 +1,27 @@
|
||||
$ProjectPath = "$PSScriptRoot\..\..\.." | Convert-Path
|
||||
$ProjectName = ((Get-ChildItem -Path $ProjectPath\*\*.psd1).Where{
|
||||
($_.Directory.Name -match 'source|src' -or $_.Directory.Name -eq $_.BaseName) -and
|
||||
$(try { Test-ModuleManifest $_.FullName -ErrorAction Stop } catch { $false } )
|
||||
}).BaseName
|
||||
|
||||
|
||||
Import-Module $ProjectName
|
||||
|
||||
InModuleScope $ProjectName {
|
||||
Describe Get-PrivateFunction {
|
||||
Context 'Default' {
|
||||
BeforeEach {
|
||||
$return = Get-PrivateFunction -PrivateData 'string'
|
||||
}
|
||||
|
||||
It 'Returns a single object' {
|
||||
($return | Measure-Object).Count | Should -Be 1
|
||||
}
|
||||
|
||||
It 'Returns a string based on the parameter PrivateData' {
|
||||
$return | Should -Be 'string'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
27
tests/Unit/Private/Initialize-CISAuditResult.tests.ps1
Normal file
27
tests/Unit/Private/Initialize-CISAuditResult.tests.ps1
Normal file
@@ -0,0 +1,27 @@
|
||||
$ProjectPath = "$PSScriptRoot\..\..\.." | Convert-Path
|
||||
$ProjectName = ((Get-ChildItem -Path $ProjectPath\*\*.psd1).Where{
|
||||
($_.Directory.Name -match 'source|src' -or $_.Directory.Name -eq $_.BaseName) -and
|
||||
$(try { Test-ModuleManifest $_.FullName -ErrorAction Stop } catch { $false } )
|
||||
}).BaseName
|
||||
|
||||
|
||||
Import-Module $ProjectName
|
||||
|
||||
InModuleScope $ProjectName {
|
||||
Describe Get-PrivateFunction {
|
||||
Context 'Default' {
|
||||
BeforeEach {
|
||||
$return = Get-PrivateFunction -PrivateData 'string'
|
||||
}
|
||||
|
||||
It 'Returns a single object' {
|
||||
($return | Measure-Object).Count | Should -Be 1
|
||||
}
|
||||
|
||||
It 'Returns a string based on the parameter PrivateData' {
|
||||
$return | Should -Be 'string'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
27
tests/Unit/Private/Test-IsAdmin.tests.ps1
Normal file
27
tests/Unit/Private/Test-IsAdmin.tests.ps1
Normal file
@@ -0,0 +1,27 @@
|
||||
$ProjectPath = "$PSScriptRoot\..\..\.." | Convert-Path
|
||||
$ProjectName = ((Get-ChildItem -Path $ProjectPath\*\*.psd1).Where{
|
||||
($_.Directory.Name -match 'source|src' -or $_.Directory.Name -eq $_.BaseName) -and
|
||||
$(try { Test-ModuleManifest $_.FullName -ErrorAction Stop } catch { $false } )
|
||||
}).BaseName
|
||||
|
||||
|
||||
Import-Module $ProjectName
|
||||
|
||||
InModuleScope $ProjectName {
|
||||
Describe Get-PrivateFunction {
|
||||
Context 'Default' {
|
||||
BeforeEach {
|
||||
$return = Get-PrivateFunction -PrivateData 'string'
|
||||
}
|
||||
|
||||
It 'Returns a single object' {
|
||||
($return | Measure-Object).Count | Should -Be 1
|
||||
}
|
||||
|
||||
It 'Returns a string based on the parameter PrivateData' {
|
||||
$return | Should -Be 'string'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
27
tests/Unit/Private/Write-AuditLog.tests.ps1
Normal file
27
tests/Unit/Private/Write-AuditLog.tests.ps1
Normal file
@@ -0,0 +1,27 @@
|
||||
$ProjectPath = "$PSScriptRoot\..\..\.." | Convert-Path
|
||||
$ProjectName = ((Get-ChildItem -Path $ProjectPath\*\*.psd1).Where{
|
||||
($_.Directory.Name -match 'source|src' -or $_.Directory.Name -eq $_.BaseName) -and
|
||||
$(try { Test-ModuleManifest $_.FullName -ErrorAction Stop } catch { $false } )
|
||||
}).BaseName
|
||||
|
||||
|
||||
Import-Module $ProjectName
|
||||
|
||||
InModuleScope $ProjectName {
|
||||
Describe Get-PrivateFunction {
|
||||
Context 'Default' {
|
||||
BeforeEach {
|
||||
$return = Get-PrivateFunction -PrivateData 'string'
|
||||
}
|
||||
|
||||
It 'Returns a single object' {
|
||||
($return | Measure-Object).Count | Should -Be 1
|
||||
}
|
||||
|
||||
It 'Returns a string based on the parameter PrivateData' {
|
||||
$return | Should -Be 'string'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user