diff --git a/source/Private/Assert-ModuleAvailability.ps1 b/source/Private/Assert-ModuleAvailability.ps1 index 81274fe..70bb68c 100644 --- a/source/Private/Assert-ModuleAvailability.ps1 +++ b/source/Private/Assert-ModuleAvailability.ps1 @@ -2,32 +2,35 @@ function Assert-ModuleAvailability { param( [string]$ModuleName, [string]$RequiredVersion, - [string]$SubModuleName + [string[]]$SubModules = @() ) try { $module = Get-Module -ListAvailable -Name $ModuleName | Where-Object { $_.Version -ge [version]$RequiredVersion } - if ($null -eq $module) {$auditResult.Profile - Write-Host "Installing $ModuleName module..." + if ($null -eq $module) { + Write-Information "Installing $ModuleName module..." -InformationAction Continue Install-Module -Name $ModuleName -RequiredVersion $RequiredVersion -Force -AllowClobber -Scope CurrentUser | Out-Null } elseif ($module.Version -lt [version]$RequiredVersion) { - Write-Host "Updating $ModuleName module to required version..." + Write-Information "Updating $ModuleName module to required version..." -InformationAction Continue Update-Module -Name $ModuleName -RequiredVersion $RequiredVersion -Force | Out-Null } else { - Write-Host "$ModuleName module is already at required version or newer." + Write-Information "$ModuleName module is already at required version or newer." -InformationAction Continue } - if ($SubModuleName) { - Import-Module -Name "$ModuleName.$SubModuleName" -RequiredVersion $RequiredVersion -ErrorAction Stop | Out-Null - } - else { + if ($SubModules.Count -gt 0) { + foreach ($subModule in $SubModules) { + Write-Information "Importing submodule $ModuleName.$subModule..." -InformationAction Continue + Import-Module -Name "$ModuleName.$subModule" -RequiredVersion $RequiredVersion -ErrorAction Stop | Out-Null + } + } else { + Write-Information "Importing module $ModuleName..." -InformationAction Continue Import-Module -Name $ModuleName -RequiredVersion $RequiredVersion -ErrorAction Stop | Out-Null } } catch { Write-Warning "An error occurred with module $ModuleName`: $_" } -} \ No newline at end of file +} diff --git a/source/Private/Get-RequiredModule.ps1 b/source/Private/Get-RequiredModule.ps1 index 015036b..e3b410a 100644 --- a/source/Private/Get-RequiredModule.ps1 +++ b/source/Private/Get-RequiredModule.ps1 @@ -12,22 +12,16 @@ function Get-RequiredModule { switch ($PSCmdlet.ParameterSetName) { 'AuditFunction' { return @( - @{ ModuleName = "ExchangeOnlineManagement"; RequiredVersion = "3.3.0" }, - @{ ModuleName = "AzureAD"; RequiredVersion = "2.0.2.182" }, - @{ ModuleName = "Microsoft.Graph"; RequiredVersion = "2.4.0"; SubModuleName = "Authentication" }, - @{ ModuleName = "Microsoft.Graph"; RequiredVersion = "2.4.0"; SubModuleName = "Users" }, - @{ ModuleName = "Microsoft.Graph"; RequiredVersion = "2.4.0"; SubModuleName = "Groups" }, - @{ ModuleName = "Microsoft.Graph"; RequiredVersion = "2.4.0"; SubModuleName = "DirectoryObjects" }, - @{ ModuleName = "Microsoft.Graph"; RequiredVersion = "2.4.0"; SubModuleName = "Domains" }, - @{ ModuleName = "Microsoft.Graph"; RequiredVersion = "2.4.0"; SubModuleName = "Reports" }, - @{ ModuleName = "Microsoft.Graph"; RequiredVersion = "2.4.0"; SubModuleName = "Mail" }, - @{ ModuleName = "Microsoft.Online.SharePoint.PowerShell"; RequiredVersion = "16.0.24009.12000" }, - @{ ModuleName = "MicrosoftTeams"; RequiredVersion = "5.5.0" } + @{ ModuleName = "ExchangeOnlineManagement"; RequiredVersion = "3.3.0"; SubModules = @() }, + @{ ModuleName = "AzureAD"; RequiredVersion = "2.0.2.182"; SubModules = @() }, + @{ ModuleName = "Microsoft.Graph"; RequiredVersion = "2.4.0"; SubModules = @("Groups", "DeviceManagement", "Users", "Identity.DirectoryManagement", "Identity.SignIns") }, + @{ ModuleName = "Microsoft.Online.SharePoint.PowerShell"; RequiredVersion = "16.0.24009.12000"; SubModules = @() }, + @{ ModuleName = "MicrosoftTeams"; RequiredVersion = "5.5.0"; SubModules = @() } ) } 'SyncFunction' { return @( - @{ ModuleName = "ImportExcel"; RequiredVersion = "7.8.9" } + @{ ModuleName = "ImportExcel"; RequiredVersion = "7.8.9"; SubModules = @() } ) } default { diff --git a/source/Public/Invoke-M365SecurityAudit.ps1 b/source/Public/Invoke-M365SecurityAudit.ps1 index e3db882..231c5d9 100644 --- a/source/Public/Invoke-M365SecurityAudit.ps1 +++ b/source/Public/Invoke-M365SecurityAudit.ps1 @@ -114,7 +114,6 @@ .LINK https://criticalsolutionsnetwork.github.io/M365FoundationsCISReport/#Invoke-M365SecurityAudit #> - function Invoke-M365SecurityAudit { [CmdletBinding(SupportsShouldProcess = $true, DefaultParameterSetName = 'Default')] [OutputType([CISAuditResult[]])] @@ -186,8 +185,9 @@ function Invoke-M365SecurityAudit { $requiredModules = Get-RequiredModule -AuditFunction $requiredModulesFormatted = "" foreach ($module in $requiredModules) { - if ($module.SubModuleName) { - $requiredModulesFormatted += "$($module.ModuleName) - SubModule: $($module.SubModuleName), " + if ($module.SubModules -and $module.SubModules.Count -gt 0) { + $subModulesFormatted = $module.SubModules -join ', ' + $requiredModulesFormatted += "$($module.ModuleName) (SubModules: $subModulesFormatted), " } else { $requiredModulesFormatted += "$($module.ModuleName), " @@ -197,9 +197,10 @@ function Invoke-M365SecurityAudit { if (!($NoModuleCheck) -and $PSCmdlet.ShouldProcess("Check for required modules: $requiredModulesFormatted", "Check")) { foreach ($module in $requiredModules) { - Assert-ModuleAvailability -ModuleName $module.ModuleName -RequiredVersion $module.RequiredVersion -SubModuleName $module.SubModuleName + Assert-ModuleAvailability -ModuleName $module.ModuleName -RequiredVersion $module.RequiredVersion -SubModules $module.SubModules } } + # Load test definitions from CSV $testDefinitionsPath = Join-Path -Path $PSScriptRoot -ChildPath "helper\TestDefinitions.csv" $testDefinitions = Import-Csv -Path $testDefinitionsPath @@ -248,6 +249,7 @@ function Invoke-M365SecurityAudit { # Establishing connections if required $actualUniqueConnections = Get-UniqueConnection -Connections $requiredConnections if (!($DoNotConnect) -and $PSCmdlet.ShouldProcess("Establish connections to Microsoft 365 services: $($actualUniqueConnections -join ', ')", "Connect")) { + Write-Information "Establishing connections to Microsoft 365 services: $($actualUniqueConnections -join ', ')" -InformationAction Continue Connect-M365Suite -TenantAdminUrl $TenantAdminUrl -RequiredConnections $requiredConnections } @@ -295,3 +297,4 @@ function Invoke-M365SecurityAudit { } } } + diff --git a/source/tests/Test-PasswordNeverExpirePolicy.ps1 b/source/tests/Test-PasswordNeverExpirePolicy.ps1 index 7cf400a..b94a22e 100644 --- a/source/tests/Test-PasswordNeverExpirePolicy.ps1 +++ b/source/tests/Test-PasswordNeverExpirePolicy.ps1 @@ -42,7 +42,7 @@ function Test-PasswordNeverExpirePolicy { $failureReasons = if ($isCompliant) { "N/A" } else { - "Password expiration is not set to never expire for domain $domainName. Run the following command to remediate: `nUpdate-MgDomain -DomainId $domainName -PasswordValidityPeriodInDays 2147483647 -PasswordNotificationWindowInDays 30" + "Password expiration is not set to never expire for domain $domainName. Run the following command to remediate: `nUpdate-MgDomain -DomainId $domainName -PasswordValidityPeriodInDays 2147483647 -PasswordNotificationWindowInDays 30`n" } $details = "$domainName|$passwordPolicy days|$isDefault"