Compare commits
20 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
014c42b3fe | ||
|
fbfb5b5986 | ||
|
03b5bb47e2 | ||
|
9dc99636d3 | ||
|
afe657ffc0 | ||
|
702f557579 | ||
|
f855ef7d0b | ||
|
270e980a57 | ||
|
ff90669984 | ||
|
f2e799af2f | ||
|
4a4d200197 | ||
|
9199d97fc2 | ||
|
5d681f3d72 | ||
|
f926c63533 | ||
|
d5044f0bf4 | ||
|
055ab42261 | ||
|
0d97b95c6c | ||
|
c185878674 | ||
|
61063ee63c | ||
|
4115f1e83e |
16
CHANGELOG.md
16
CHANGELOG.md
@@ -6,6 +6,20 @@ The format is based on and uses the types of changes according to [Keep a Change
|
|||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
|
- Added pipeline support to `Sync-CISExcelAndCsvData` function for `[CISAuditResult[]]` input.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Updated `Connect-M365Suite` to make `TenantAdminUrl` an optional parameter.
|
||||||
|
- Updated `Invoke-M365SecurityAudit` to make `TenantAdminUrl` an optional parameter.
|
||||||
|
- Improved connection handling and error messaging in `Connect-M365Suite`.
|
||||||
|
- Enhanced `Invoke-M365SecurityAudit` to allow flexible inclusion and exclusion of specific recommendations, IG filters, and profile levels.
|
||||||
|
- SupportsShoudProcess to also bypass connection checks in `Invoke-M365SecurityAudit` as well as Disconnect-M365Suite.
|
||||||
|
|
||||||
|
## [0.1.5] - 2024-06-08
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
- Updated test definitions for CIS Microsoft 365 Foundations Benchmark for better error handling and object output when errors occur.
|
- Updated test definitions for CIS Microsoft 365 Foundations Benchmark for better error handling and object output when errors occur.
|
||||||
- Added a parameter to the `Initialize-CISAuditResult` function to allow for a static failed object to be created when an error occurs.
|
- Added a parameter to the `Initialize-CISAuditResult` function to allow for a static failed object to be created when an error occurs.
|
||||||
- Refactored `Invoke-M365SecurityAudit` to include a new private function `Invoke-TestFunction` for executing test functions and handling errors.
|
- Refactored `Invoke-M365SecurityAudit` to include a new private function `Invoke-TestFunction` for executing test functions and handling errors.
|
||||||
@@ -34,8 +48,6 @@ The format is based on and uses the types of changes according to [Keep a Change
|
|||||||
- Added step 1 and step 2 in `Test-BlockMailForwarding` details to ensure comprehensive compliance checks.
|
- Added step 1 and step 2 in `Test-BlockMailForwarding` details to ensure comprehensive compliance checks.
|
||||||
- Fixed the issue with the output in `Test-RestrictCustomScripts` to ensure no extra spaces between table headers and data.
|
- Fixed the issue with the output in `Test-RestrictCustomScripts` to ensure no extra spaces between table headers and data.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [0.1.4] - 2024-05-30
|
## [0.1.4] - 2024-05-30
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
BIN
docs/index.html
BIN
docs/index.html
Binary file not shown.
@@ -4,7 +4,7 @@ Import-Module .\output\module\M365FoundationsCISReport\*\*.psd1
|
|||||||
|
|
||||||
|
|
||||||
<#
|
<#
|
||||||
$ver = "v0.1.5"
|
$ver = "v0.1.6"
|
||||||
git checkout main
|
git checkout main
|
||||||
git pull origin main
|
git pull origin main
|
||||||
git tag -a $ver -m "Release version $ver refactor Update"
|
git tag -a $ver -m "Release version $ver refactor Update"
|
||||||
@@ -14,4 +14,72 @@ Import-Module .\output\module\M365FoundationsCISReport\*\*.psd1
|
|||||||
# git tag -d $ver
|
# git tag -d $ver
|
||||||
#>
|
#>
|
||||||
|
|
||||||
|
# Refresh authentication to ensure the correct scopes
|
||||||
|
gh auth refresh -s project,read:project,write:project,repo
|
||||||
|
|
||||||
|
# Create the project
|
||||||
|
gh project create --owner CriticalSolutionsNetwork --title "Test Validation Project"
|
||||||
|
|
||||||
|
$repoOwner = "CriticalSolutionsNetwork"
|
||||||
|
$repoName = "M365FoundationsCISReport"
|
||||||
|
$directoryPath = ".\source\tests"
|
||||||
|
$projectName = "Test Validation Project"
|
||||||
|
|
||||||
|
# Function to create GitHub issues
|
||||||
|
function Create-GitHubIssue {
|
||||||
|
param (
|
||||||
|
[string]$title,
|
||||||
|
[string]$body,
|
||||||
|
[string]$project
|
||||||
|
)
|
||||||
|
|
||||||
|
# Create the issue and add it to the specified project
|
||||||
|
$issue = gh issue create --repo "$repoOwner/$repoName" --title "$title" --body "$body" --project "$project"
|
||||||
|
return $issue
|
||||||
|
}
|
||||||
|
|
||||||
|
# Load test definitions from CSV
|
||||||
|
$testDefinitionsPath = ".\source\helper\TestDefinitions.csv"
|
||||||
|
$testDefinitions = Import-Csv -Path $testDefinitionsPath
|
||||||
|
|
||||||
|
# Iterate over each .ps1 file in the directory
|
||||||
|
Get-ChildItem -Path $directoryPath -Filter "*.ps1" | ForEach-Object {
|
||||||
|
$fileName = $_.Name
|
||||||
|
$testDefinition = $testDefinitions | Where-Object { $_.TestFileName -eq $fileName }
|
||||||
|
|
||||||
|
if ($testDefinition) {
|
||||||
|
$rec = $testDefinition.Rec
|
||||||
|
$elevel = $testDefinition.ELevel
|
||||||
|
$profileLevel = $testDefinition.ProfileLevel
|
||||||
|
$ig1 = $testDefinition.IG1
|
||||||
|
$ig2 = $testDefinition.IG2
|
||||||
|
$ig3 = $testDefinition.IG3
|
||||||
|
$connection = $testDefinition.Connection
|
||||||
|
|
||||||
|
$issueTitle = "Rec: $rec - Validate $fileName, ELevel: $elevel, ProfileLevel: $profileLevel, IG1: $ig1, IG2: $ig2, IG3: $ig3, Connection: $connection"
|
||||||
|
$issueBody = @"
|
||||||
|
# Validation for $fileName
|
||||||
|
|
||||||
|
## Tasks
|
||||||
|
- [ ] Validate test for a pass
|
||||||
|
- Description of passing criteria:
|
||||||
|
- [ ] Validate test for a fail
|
||||||
|
- Description of failing criteria:
|
||||||
|
- [ ] Add notes and observations
|
||||||
|
- Placeholder for additional notes:
|
||||||
|
"@
|
||||||
|
|
||||||
|
# Create the issue using GitHub CLI
|
||||||
|
try {
|
||||||
|
Create-GitHubIssue -title "$issueTitle" -body "$issueBody" -project "$projectName"
|
||||||
|
Write-Output "Created issue for $fileName"
|
||||||
|
} catch {
|
||||||
|
Write-Error "Failed to create issue for $fileName : $_"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Introduce a delay of 2 seconds
|
||||||
|
Start-Sleep -Seconds 2
|
||||||
|
} else {
|
||||||
|
Write-Warning "No matching test definition found for $fileName"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
function Connect-M365Suite {
|
function Connect-M365Suite {
|
||||||
[CmdletBinding()]
|
[CmdletBinding()]
|
||||||
param (
|
param (
|
||||||
[Parameter(Mandatory)]
|
[Parameter(Mandatory=$false)]
|
||||||
[string]$TenantAdminUrl,
|
[string]$TenantAdminUrl,
|
||||||
|
|
||||||
[Parameter(Mandatory)]
|
[Parameter(Mandatory)]
|
||||||
|
@@ -4,7 +4,7 @@
|
|||||||
.DESCRIPTION
|
.DESCRIPTION
|
||||||
The Invoke-M365SecurityAudit cmdlet performs a comprehensive security audit based on the specified parameters. It allows auditing of various configurations and settings within a Microsoft 365 environment, such as compliance with CIS benchmarks.
|
The Invoke-M365SecurityAudit cmdlet performs a comprehensive security audit based on the specified parameters. It allows auditing of various configurations and settings within a Microsoft 365 environment, such as compliance with CIS benchmarks.
|
||||||
.PARAMETER TenantAdminUrl
|
.PARAMETER TenantAdminUrl
|
||||||
The URL of the tenant admin. This parameter is mandatory.
|
The URL of the tenant admin. If not specified, none of the SharePoint Online tests will run.
|
||||||
.PARAMETER M365DomainForPWPolicyTest
|
.PARAMETER M365DomainForPWPolicyTest
|
||||||
The domain name of the Microsoft 365 environment to test. This parameter is not mandatory and by default it will pass/fail all found domains as a group if a specific domain is not specified.
|
The domain name of the Microsoft 365 environment to test. This parameter is not mandatory and by default it will pass/fail all found domains as a group if a specific domain is not specified.
|
||||||
.PARAMETER ELevel
|
.PARAMETER ELevel
|
||||||
@@ -28,42 +28,98 @@
|
|||||||
.PARAMETER NoModuleCheck
|
.PARAMETER NoModuleCheck
|
||||||
If specified, the cmdlet will not check for the presence of required modules.
|
If specified, the cmdlet will not check for the presence of required modules.
|
||||||
.EXAMPLE
|
.EXAMPLE
|
||||||
PS> Invoke-M365SecurityAudit -TenantAdminUrl "https://contoso-admin.sharepoint.com" -DomainName "contoso.com" -ELevel "E5" -ProfileLevel "L1"
|
PS> Invoke-M365SecurityAudit
|
||||||
|
Performs a security audit using default parameters.
|
||||||
|
Output:
|
||||||
|
Status : Fail
|
||||||
|
ELevel : E3
|
||||||
|
ProfileLevel: L1
|
||||||
|
Connection : Microsoft Graph
|
||||||
|
Rec : 1.1.1
|
||||||
|
Result : False
|
||||||
|
Details : Non-compliant accounts:
|
||||||
|
Username | Roles | HybridStatus | Missing Licence
|
||||||
|
user1@domain.com| Global Administrator | Cloud-Only | AAD_PREMIUM
|
||||||
|
user2@domain.com| Global Administrator | Hybrid | AAD_PREMIUM, AAD_PREMIUM_P2
|
||||||
|
FailureReason: Non-Compliant Accounts: 2
|
||||||
|
.EXAMPLE
|
||||||
|
PS> Invoke-M365SecurityAudit -TenantAdminUrl "https://contoso-admin.sharepoint.com" -M365DomainForPWPolicyTest "contoso.com" -ELevel "E5" -ProfileLevel "L1"
|
||||||
Performs a security audit for the E5 level and L1 profile in the specified Microsoft 365 environment.
|
Performs a security audit for the E5 level and L1 profile in the specified Microsoft 365 environment.
|
||||||
|
Output:
|
||||||
|
Status : Fail
|
||||||
|
ELevel : E5
|
||||||
|
ProfileLevel: L1
|
||||||
|
Connection : Microsoft Graph
|
||||||
|
Rec : 1.1.1
|
||||||
|
Result : False
|
||||||
|
Details : Non-compliant accounts:
|
||||||
|
Username | Roles | HybridStatus | Missing Licence
|
||||||
|
user1@domain.com| Global Administrator | Cloud-Only | AAD_PREMIUM
|
||||||
|
user2@domain.com| Global Administrator | Hybrid | AAD_PREMIUM, AAD_PREMIUM_P2
|
||||||
|
FailureReason: Non-Compliant Accounts: 2
|
||||||
.EXAMPLE
|
.EXAMPLE
|
||||||
PS> Invoke-M365SecurityAudit -TenantAdminUrl "https://contoso-admin.sharepoint.com" -DomainName "contoso.com" -IncludeIG1
|
PS> Invoke-M365SecurityAudit -TenantAdminUrl "https://contoso-admin.sharepoint.com" -M365DomainForPWPolicyTest "contoso.com" -IncludeIG1
|
||||||
|
|
||||||
Performs an audit including all tests where IG1 is true.
|
Performs an audit including all tests where IG1 is true.
|
||||||
|
Output:
|
||||||
|
Status : Fail
|
||||||
|
ELevel : E3
|
||||||
|
ProfileLevel: L1
|
||||||
|
Connection : Microsoft Graph
|
||||||
|
Rec : 1.1.1
|
||||||
|
Result : False
|
||||||
|
Details : Non-compliant accounts:
|
||||||
|
Username | Roles | HybridStatus | Missing Licence
|
||||||
|
user1@domain.com| Global Administrator | Cloud-Only | AAD_PREMIUM
|
||||||
|
user2@domain.com| Global Administrator | Hybrid | AAD_PREMIUM, AAD_PREMIUM_P2
|
||||||
|
FailureReason: Non-Compliant Accounts: 2
|
||||||
.EXAMPLE
|
.EXAMPLE
|
||||||
PS> Invoke-M365SecurityAudit -TenantAdminUrl "https://contoso-admin.sharepoint.com" -DomainName "contoso.com" -SkipRecommendation '1.1.3', '2.1.1'
|
PS> Invoke-M365SecurityAudit -TenantAdminUrl "https://contoso-admin.sharepoint.com" -M365DomainForPWPolicyTest "contoso.com" -SkipRecommendation '1.1.3', '2.1.1'
|
||||||
|
|
||||||
Performs an audit while excluding specific recommendations 1.1.3 and 2.1.1.
|
Performs an audit while excluding specific recommendations 1.1.3 and 2.1.1.
|
||||||
|
Output:
|
||||||
|
Status : Fail
|
||||||
|
ELevel : E3
|
||||||
|
ProfileLevel: L1
|
||||||
|
Connection : Microsoft Graph
|
||||||
|
Rec : 1.1.1
|
||||||
|
Result : False
|
||||||
|
Details : Non-compliant accounts:
|
||||||
|
Username | Roles | HybridStatus | Missing Licence
|
||||||
|
user1@domain.com| Global Administrator | Cloud-Only | AAD_PREMIUM
|
||||||
|
user2@domain.com| Global Administrator | Hybrid | AAD_PREMIUM, AAD_PREMIUM_P2
|
||||||
|
FailureReason: Non-Compliant Accounts: 2
|
||||||
.EXAMPLE
|
.EXAMPLE
|
||||||
PS> $auditResults = Invoke-M365SecurityAudit -TenantAdminUrl "https://contoso-admin.sharepoint.com" -DomainName "contoso.com"
|
PS> $auditResults = Invoke-M365SecurityAudit -TenantAdminUrl "https://contoso-admin.sharepoint.com" -M365DomainForPWPolicyTest "contoso.com"
|
||||||
PS> $auditResults | Export-Csv -Path "auditResults.csv" -NoTypeInformation
|
PS> $auditResults | Export-Csv -Path "auditResults.csv" -NoTypeInformation
|
||||||
|
|
||||||
Captures the audit results into a variable and exports them to a CSV file.
|
Captures the audit results into a variable and exports them to a CSV file.
|
||||||
|
Output:
|
||||||
|
CISAuditResult[]
|
||||||
|
auditResults.csv
|
||||||
|
.EXAMPLE
|
||||||
|
PS> Invoke-M365SecurityAudit -WhatIf
|
||||||
|
Displays what would happen if the cmdlet is run without actually performing the audit.
|
||||||
|
Output:
|
||||||
|
What if: Performing the operation "Invoke-M365SecurityAudit" on target "Microsoft 365 environment".
|
||||||
.INPUTS
|
.INPUTS
|
||||||
None. You cannot pipe objects to Invoke-M365SecurityAudit.
|
None. You cannot pipe objects to Invoke-M365SecurityAudit.
|
||||||
.OUTPUTS
|
.OUTPUTS
|
||||||
CISAuditResult[]
|
CISAuditResult[]
|
||||||
The cmdlet returns an array of CISAuditResult objects representing the results of the security audit.
|
The cmdlet returns an array of CISAuditResult objects representing the results of the security audit.
|
||||||
.NOTES
|
.NOTES
|
||||||
- This module is based on CIS benchmarks.
|
- This module is based on CIS benchmarks.
|
||||||
- Governed by the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
|
- Governed by the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
|
||||||
- Commercial use is not permitted. This module cannot be sold or used for commercial purposes.
|
- Commercial use is not permitted. This module cannot be sold or used for commercial purposes.
|
||||||
- Modifications and sharing are allowed under the same license.
|
- Modifications and sharing are allowed under the same license.
|
||||||
- For full license details, visit: https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en
|
- 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
|
- Register for CIS Benchmarks at: https://www.cisecurity.org/cis-benchmarks
|
||||||
.LINK
|
.LINK
|
||||||
https://criticalsolutionsnetwork.github.io/M365FoundationsCISReport/#Invoke-M365SecurityAudit
|
https://criticalsolutionsnetwork.github.io/M365FoundationsCISReport/#Invoke-M365SecurityAudit
|
||||||
#>
|
#>
|
||||||
|
|
||||||
function Invoke-M365SecurityAudit {
|
function Invoke-M365SecurityAudit {
|
||||||
[CmdletBinding(SupportsShouldProcess = $true, DefaultParameterSetName = 'Default')]
|
[CmdletBinding(SupportsShouldProcess = $true, DefaultParameterSetName = 'Default')]
|
||||||
[OutputType([CISAuditResult[]])]
|
[OutputType([CISAuditResult[]])]
|
||||||
param (
|
param (
|
||||||
[Parameter(Mandatory = $true, HelpMessage = "The SharePoint tenant admin URL, which should end with '-admin.sharepoint.com'.")]
|
[Parameter(Mandatory = $false, HelpMessage = "The SharePoint tenant admin URL, which should end with '-admin.sharepoint.com'. If not specified none of the Sharepoint Online tests will run.")]
|
||||||
[ValidatePattern('^https://[a-zA-Z0-9-]+-admin\.sharepoint\.com$')]
|
[ValidatePattern('^https://[a-zA-Z0-9-]+-admin\.sharepoint\.com$')]
|
||||||
[string]$TenantAdminUrl,
|
[string]$TenantAdminUrl,
|
||||||
|
|
||||||
@@ -127,7 +183,7 @@ function Invoke-M365SecurityAudit {
|
|||||||
$script:MaximumFunctionCount = 8192
|
$script:MaximumFunctionCount = 8192
|
||||||
}
|
}
|
||||||
# Ensure required modules are installed
|
# Ensure required modules are installed
|
||||||
if (!($NoModuleCheck)) {
|
if (!($NoModuleCheck) -and $PSCmdlet.ShouldProcess("Check for required modules", "Check")) {
|
||||||
$requiredModules = Get-RequiredModule -AuditFunction
|
$requiredModules = Get-RequiredModule -AuditFunction
|
||||||
foreach ($module in $requiredModules) {
|
foreach ($module in $requiredModules) {
|
||||||
Assert-ModuleAvailability -ModuleName $module.ModuleName -RequiredVersion $module.RequiredVersion -SubModuleName $module.SubModuleName
|
Assert-ModuleAvailability -ModuleName $module.ModuleName -RequiredVersion $module.RequiredVersion -SubModuleName $module.SubModuleName
|
||||||
@@ -151,9 +207,14 @@ function Invoke-M365SecurityAudit {
|
|||||||
$testDefinitions = Get-TestDefinitionsObject @params
|
$testDefinitions = Get-TestDefinitionsObject @params
|
||||||
# Extract unique connections needed
|
# Extract unique connections needed
|
||||||
$requiredConnections = $testDefinitions.Connection | Sort-Object -Unique
|
$requiredConnections = $testDefinitions.Connection | Sort-Object -Unique
|
||||||
# Establishing connections if required
|
if ($requiredConnections -contains 'SPO'){
|
||||||
if (!($DoNotConnect)) {
|
if (-not $TenantAdminUrl) {
|
||||||
Connect-M365Suite -TenantAdminUrl $TenantAdminUrl -RequiredConnections $requiredConnections
|
$requiredConnections = $requiredConnections | Where-Object { $_ -ne 'SPO' }
|
||||||
|
$testDefinitions = $testDefinitions | Where-Object { $_.Connection -ne 'SPO' }
|
||||||
|
if ($null -eq $testDefinitions) {
|
||||||
|
throw "No tests to run as no SharePoint Online tests are available."
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
# Determine which test files to load based on filtering
|
# Determine which test files to load based on filtering
|
||||||
$testsToLoad = $testDefinitions.TestFileName | ForEach-Object { $_ -replace '.ps1$', '' }
|
$testsToLoad = $testDefinitions.TestFileName | ForEach-Object { $_ -replace '.ps1$', '' }
|
||||||
@@ -162,6 +223,7 @@ function Invoke-M365SecurityAudit {
|
|||||||
# Initialize a collection to hold failed test details
|
# Initialize a collection to hold failed test details
|
||||||
$script:FailedTests = [System.Collections.ArrayList]::new()
|
$script:FailedTests = [System.Collections.ArrayList]::new()
|
||||||
} # End Begin
|
} # End Begin
|
||||||
|
|
||||||
Process {
|
Process {
|
||||||
$allAuditResults = [System.Collections.ArrayList]::new() # 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
|
# Dynamically dot-source the test scripts
|
||||||
@@ -172,6 +234,11 @@ function Invoke-M365SecurityAudit {
|
|||||||
$totalTests = $testFiles.Count
|
$totalTests = $testFiles.Count
|
||||||
$currentTestIndex = 0
|
$currentTestIndex = 0
|
||||||
|
|
||||||
|
# Establishing connections if required
|
||||||
|
if (!($DoNotConnect) -and $PSCmdlet.ShouldProcess("Establish connections to Microsoft 365 services", "Connect")) {
|
||||||
|
Connect-M365Suite -TenantAdminUrl $TenantAdminUrl -RequiredConnections $requiredConnections
|
||||||
|
}
|
||||||
|
|
||||||
# Import the test functions
|
# Import the test functions
|
||||||
$testFiles | ForEach-Object {
|
$testFiles | ForEach-Object {
|
||||||
$currentTestIndex++
|
$currentTestIndex++
|
||||||
@@ -202,14 +269,15 @@ function Invoke-M365SecurityAudit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
End {
|
End {
|
||||||
if (!($DoNotDisconnect)) {
|
if (!($DoNotDisconnect) -and $PSCmdlet.ShouldProcess("Disconnect from Microsoft 365 services", "Disconnect")) {
|
||||||
# Clean up sessions
|
# Clean up sessions
|
||||||
Disconnect-M365Suite -RequiredConnections $requiredConnections
|
Disconnect-M365Suite -RequiredConnections $requiredConnections
|
||||||
}
|
}
|
||||||
# Call the private function to calculate and display results
|
if ($PSCmdlet.ShouldProcess("Measure and display audit results", "Measure")) {
|
||||||
Measure-AuditResult -AllAuditResults $allAuditResults -FailedTests $script:FailedTests
|
# Call the private function to calculate and display results
|
||||||
# Return all collected audit results
|
Measure-AuditResult -AllAuditResults $allAuditResults -FailedTests $script:FailedTests
|
||||||
return $allAuditResults.ToArray() | Sort-Object -Property Rec
|
# Return all collected audit results
|
||||||
|
return $allAuditResults.ToArray() | Sort-Object -Property Rec
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,43 +1,47 @@
|
|||||||
<#
|
<#
|
||||||
.SYNOPSIS
|
.SYNOPSIS
|
||||||
Synchronizes data between an Excel file and either a CSV file or an output object from Invoke-M365SecurityAudit, and optionally updates the Excel worksheet.
|
Synchronizes data between an Excel file and either a CSV file or an output object from Invoke-M365SecurityAudit, and optionally updates the Excel worksheet.
|
||||||
.DESCRIPTION
|
.DESCRIPTION
|
||||||
The Sync-CISExcelAndCsvData function merges data from a specified Excel file with data from either a CSV file or an output object from Invoke-M365SecurityAudit based on a common key. It can also update the Excel worksheet with the merged data. This function is particularly useful for updating Excel records with additional data from a CSV file or audit results while preserving the original formatting and structure of the Excel worksheet.
|
The Sync-CISExcelAndCsvData function merges data from a specified Excel file with data from either a CSV file or an output object from Invoke-M365SecurityAudit based on a common key. It can also update the Excel worksheet with the merged data. This function is particularly useful for updating Excel records with additional data from a CSV file or audit results while preserving the original formatting and structure of the Excel worksheet.
|
||||||
.PARAMETER ExcelPath
|
.PARAMETER ExcelPath
|
||||||
The path to the Excel file that contains the original data. This parameter is mandatory.
|
The path to the Excel file that contains the original data. This parameter is mandatory.
|
||||||
.PARAMETER WorksheetName
|
.PARAMETER WorksheetName
|
||||||
The name of the worksheet within the Excel file that contains the data to be synchronized. This parameter is mandatory.
|
The name of the worksheet within the Excel file that contains the data to be synchronized. This parameter is mandatory.
|
||||||
.PARAMETER CsvPath
|
.PARAMETER CsvPath
|
||||||
The path to the CSV file containing data to be merged with the Excel data. This parameter is mandatory when using the CsvInput parameter set.
|
The path to the CSV file containing data to be merged with the Excel data. This parameter is mandatory when using the CsvInput parameter set.
|
||||||
.PARAMETER AuditResults
|
.PARAMETER AuditResults
|
||||||
An array of CISAuditResult objects from Invoke-M365SecurityAudit to be merged with the Excel data. This parameter is mandatory when using the ObjectInput parameter set.
|
An array of CISAuditResult objects from Invoke-M365SecurityAudit to be merged with the Excel data. This parameter is mandatory when using the ObjectInput parameter set. It can also accept pipeline input.
|
||||||
.PARAMETER SkipUpdate
|
.PARAMETER SkipUpdate
|
||||||
If specified, the function will return the merged data object without updating the Excel worksheet. This is useful for previewing the merged data.
|
If specified, the function will return the merged data object without updating the Excel worksheet. This is useful for previewing the merged data.
|
||||||
.EXAMPLE
|
.EXAMPLE
|
||||||
PS> Sync-CISExcelAndCsvData -ExcelPath "path\to\excel.xlsx" -WorksheetName "DataSheet" -CsvPath "path\to\data.csv"
|
PS> Sync-CISExcelAndCsvData -ExcelPath "path\to\excel.xlsx" -WorksheetName "DataSheet" -CsvPath "path\to\data.csv"
|
||||||
Merges data from 'data.csv' into 'excel.xlsx' on the 'DataSheet' worksheet and updates the worksheet with the merged data.
|
Merges data from 'data.csv' into 'excel.xlsx' on the 'DataSheet' worksheet and updates the worksheet with the merged data.
|
||||||
.EXAMPLE
|
.EXAMPLE
|
||||||
PS> $mergedData = Sync-CISExcelAndCsvData -ExcelPath "path\to\excel.xlsx" -WorksheetName "DataSheet" -CsvPath "path\to\data.csv" -SkipUpdate
|
PS> $mergedData = Sync-CISExcelAndCsvData -ExcelPath "path\to\excel.xlsx" -WorksheetName "DataSheet" -CsvPath "path\to\data.csv" -SkipUpdate
|
||||||
Retrieves the merged data object for preview without updating the Excel worksheet.
|
Retrieves the merged data object for preview without updating the Excel worksheet.
|
||||||
.EXAMPLE
|
.EXAMPLE
|
||||||
PS> $auditResults = Invoke-M365SecurityAudit -TenantAdminUrl "https://tenant-admin.url" -DomainName "example.com"
|
PS> $auditResults = Invoke-M365SecurityAudit -TenantAdminUrl "https://tenant-admin.url" -DomainName "example.com"
|
||||||
PS> Sync-CISExcelAndCsvData -ExcelPath "path\to\excel.xlsx" -WorksheetName "DataSheet" -AuditResults $auditResults
|
PS> Sync-CISExcelAndCsvData -ExcelPath "path\to\excel.xlsx" -WorksheetName "DataSheet" -AuditResults $auditResults
|
||||||
Merges data from the audit results into 'excel.xlsx' on the 'DataSheet' worksheet and updates the worksheet with the merged data.
|
Merges data from the audit results into 'excel.xlsx' on the 'DataSheet' worksheet and updates the worksheet with the merged data.
|
||||||
.EXAMPLE
|
.EXAMPLE
|
||||||
PS> $auditResults = Invoke-M365SecurityAudit -TenantAdminUrl "https://tenant-admin.url" -DomainName "example.com"
|
PS> $auditResults = Invoke-M365SecurityAudit -TenantAdminUrl "https://tenant-admin.url" -DomainName "example.com"
|
||||||
PS> $mergedData = Sync-CISExcelAndCsvData -ExcelPath "path\to\excel.xlsx" -WorksheetName "DataSheet" -AuditResults $auditResults -SkipUpdate
|
PS> $mergedData = Sync-CISExcelAndCsvData -ExcelPath "path\to\excel.xlsx" -WorksheetName "DataSheet" -AuditResults $auditResults -SkipUpdate
|
||||||
Retrieves the merged data object for preview without updating the Excel worksheet.
|
Retrieves the merged data object for preview without updating the Excel worksheet.
|
||||||
.INPUTS
|
.EXAMPLE
|
||||||
None. You cannot pipe objects to Sync-CISExcelAndCsvData.
|
PS> Invoke-M365SecurityAudit -TenantAdminUrl "https://tenant-admin.url" -DomainName "example.com" | Sync-CISExcelAndCsvData -ExcelPath "path\to\excel.xlsx" -WorksheetName "DataSheet"
|
||||||
.OUTPUTS
|
Pipes the audit results into Sync-CISExcelAndCsvData to merge data into 'excel.xlsx' on the 'DataSheet' worksheet and updates the worksheet with the merged data.
|
||||||
Object[]
|
.INPUTS
|
||||||
If the SkipUpdate switch is used, the function returns an array of custom objects representing the merged data.
|
System.String, CISAuditResult[]
|
||||||
.NOTES
|
You can pipe CISAuditResult objects to Sync-CISExcelAndCsvData.
|
||||||
- Ensure that the 'ImportExcel' module is installed and up to date.
|
.OUTPUTS
|
||||||
- It is recommended to backup the Excel file before running this script to prevent accidental data loss.
|
Object[]
|
||||||
- This function is part of the CIS Excel and CSV Data Management Toolkit.
|
If the SkipUpdate switch is used, the function returns an array of custom objects representing the merged data.
|
||||||
.LINK
|
.NOTES
|
||||||
https://criticalsolutionsnetwork.github.io/M365FoundationsCISReport/#Sync-CISExcelAndCsvData
|
- Ensure that the 'ImportExcel' module is installed and up to date.
|
||||||
|
- It is recommended to backup the Excel file before running this script to prevent accidental data loss.
|
||||||
|
- This function is part of the CIS Excel and CSV Data Management Toolkit.
|
||||||
|
.LINK
|
||||||
|
https://criticalsolutionsnetwork.github.io/M365FoundationsCISReport/#Sync-CISExcelAndCsvData
|
||||||
#>
|
#>
|
||||||
function Sync-CISExcelAndCsvData {
|
function Sync-CISExcelAndCsvData {
|
||||||
[CmdletBinding(DefaultParameterSetName = 'CsvInput')]
|
[CmdletBinding(DefaultParameterSetName = 'CsvInput')]
|
||||||
@@ -53,7 +57,7 @@ function Sync-CISExcelAndCsvData {
|
|||||||
[ValidateScript({ Test-Path $_ })]
|
[ValidateScript({ Test-Path $_ })]
|
||||||
[string]$CsvPath,
|
[string]$CsvPath,
|
||||||
|
|
||||||
[Parameter(Mandatory = $true, ParameterSetName = 'ObjectInput')]
|
[Parameter(Mandatory = $true, ParameterSetName = 'ObjectInput', ValueFromPipeline = $true)]
|
||||||
[CISAuditResult[]]$AuditResults,
|
[CISAuditResult[]]$AuditResults,
|
||||||
|
|
||||||
[Parameter(Mandatory = $false)]
|
[Parameter(Mandatory = $false)]
|
||||||
@@ -83,5 +87,3 @@ function Sync-CISExcelAndCsvData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user