Microsoft-Secure-Score-Assessment-Toolkit.psm1
|
# # Microsoft Secure Score Assessment Toolkit # PowerShell Module - Refactored Architecture # # Module base path $script:ModuleRoot = $PSScriptRoot # Import all required modules $CoreModules = @( 'Core\GraphApiClient.ps1', 'Core\Models.ps1', 'Core\Logger.ps1' ) $ProcessorModules = @( 'Processors\ComplianceProcessor.ps1', 'Processors\UrlProcessor.ps1' ) $ReportModules = @( 'Reports\HtmlReportGenerator.ps1' ) # Import all modules $AllModules = $CoreModules + $ProcessorModules + $ReportModules foreach ($module in $AllModules) { $modulePath = Join-Path $script:ModuleRoot $module if (Test-Path $modulePath) { . $modulePath } else { Write-Warning "Module file not found: $modulePath" } } # Module-level variables $script:CurrentContext = $null function Connect-MicrosoftSecureScore { <# .SYNOPSIS Authenticate to Microsoft Graph for Secure Score API access. .DESCRIPTION Establishes a connection to Microsoft Graph with the required permissions to access Microsoft Secure Score data. This function must be run before using Invoke-MicrosoftSecureScore. .PARAMETER UseDeviceCode Use device code authentication instead of interactive browser authentication. Useful for headless environments or remote sessions. .EXAMPLE Connect-MicrosoftSecureScore Connects using interactive browser authentication. .EXAMPLE Connect-MicrosoftSecureScore -UseDeviceCode Connects using device code authentication. .NOTES Requires SecurityEvents.Read.All permission in Microsoft Graph. #> [CmdletBinding()] param( [Parameter(Mandatory = $false)] [switch]$UseDeviceCode ) try { Write-Host "`n=== Microsoft Secure Score Authentication ===" -ForegroundColor Cyan Write-Host "Connecting to Microsoft Graph..." -ForegroundColor Yellow # Check if Microsoft.Graph modules are installed $requiredModules = @( 'Microsoft.Graph.Authentication', 'Microsoft.Graph.Security' ) foreach ($moduleName in $requiredModules) { if (-not (Get-Module -ListAvailable -Name $moduleName)) { Write-Host "$moduleName module not found. Installing..." -ForegroundColor Yellow try { Install-Module -Name $moduleName -Scope CurrentUser -Force -AllowClobber Write-Host "$moduleName module installed successfully." -ForegroundColor Green } catch { throw "Failed to install $moduleName module: $_" } } } # Import required modules Import-Module Microsoft.Graph.Authentication -ErrorAction Stop Import-Module Microsoft.Graph.Security -ErrorAction Stop # Connect using the GraphApiClient if ($UseDeviceCode) { $script:CurrentContext = Connect-SecureScoreGraph -UseDeviceCode } else { $script:CurrentContext = Connect-SecureScoreGraph } Write-Host "`nAuthentication successful!" -ForegroundColor Green Write-Host "Tenant ID: $($script:CurrentContext.TenantId)" -ForegroundColor Cyan Write-Host "Account: $($script:CurrentContext.Account)" -ForegroundColor Cyan Write-Host "`nYou can now run: Invoke-MicrosoftSecureScore" -ForegroundColor Yellow } catch { Write-Error "Authentication failed: $_" Write-Host "`nTroubleshooting:" -ForegroundColor Yellow Write-Host "1. Ensure you have Security Reader or Global Reader role" -ForegroundColor White Write-Host "2. Check your internet connection" -ForegroundColor White Write-Host "3. Try using -UseDeviceCode parameter for alternative authentication" -ForegroundColor White throw } } function Invoke-MicrosoftSecureScore { <# .SYNOPSIS Generate Microsoft Secure Score assessment report. .DESCRIPTION Fetches 411+ security controls from Microsoft Graph Secure Score API and generates a comprehensive HTML report with interactive filtering and assessment guidance. .PARAMETER TenantName Display name for your organization in the report. Defaults to "Your Organization". .PARAMETER ApplicableOnly Generate report showing only controls applicable to your tenant (typically ~70 controls). By default, shows all 411+ available controls. .PARAMETER ReportPath Path where the HTML report will be saved. Defaults to current directory with timestamp. .PARAMETER LogPath Path where the log file will be saved. If not specified, logging to file is disabled. .PARAMETER InlineAssets Inline CSS and JavaScript into the HTML file (creates single-file report). .EXAMPLE Invoke-MicrosoftSecureScore Generates a full report with all 411+ controls. .EXAMPLE Invoke-MicrosoftSecureScore -ApplicableOnly Generates a report showing only applicable controls for your tenant. .EXAMPLE Invoke-MicrosoftSecureScore -TenantName "Contoso Corporation" Generates a report with custom organization name. .EXAMPLE Invoke-MicrosoftSecureScore -ReportPath "C:\Reports\SecureScore.html" -LogPath "C:\Logs\SecureScore.log" Generates a report and log at specified locations. .NOTES You must run Connect-MicrosoftSecureScore before using this function. #> [CmdletBinding()] param( [Parameter(Mandatory = $false)] [string]$TenantName = "Your Organization", [Parameter(Mandatory = $false)] [switch]$ApplicableOnly, [Parameter(Mandatory = $false)] [string]$ReportPath, [Parameter(Mandatory = $false)] [string]$LogPath, [Parameter(Mandatory = $false)] [switch]$InlineAssets ) try { # Restore context from Graph if we lost it (e.g., module reload) if (-not $script:CurrentContext) { $context = Get-MgContext if ($context) { $script:CurrentContext = @{ TenantId = $context.TenantId Account = $context.Account } Write-Verbose "Restored context from active Graph connection" } } # Check if authenticated if (-not (Test-GraphConnection)) { throw "Not authenticated to Microsoft Graph. Please run Connect-MicrosoftSecureScore first." } # Set default report path if not provided if (-not $ReportPath) { $timestamp = Get-Date -Format 'yyyyMMdd-HHmmss' $ReportPath = Join-Path (Get-Location) "SecureScore-Report-$timestamp.html" } # Initialize logger if ($LogPath) { Initialize-Logger -LogPath $LogPath -LogToConsole $true -LogToFile $true } else { Initialize-Logger -LogToConsole $true -LogToFile $false } Write-LogSection -Title "Microsoft Secure Score Assessment" -Level Info Write-Log "Tenant: $TenantName" -Level Info Write-Log "Mode: $(if ($ApplicableOnly) { 'Applicable Controls Only' } else { 'All Controls' })" -Level Info Write-Log "Report Path: $ReportPath" -Level Info if ($LogPath) { Write-Log "Log Path: $LogPath" -Level Info } # Initialize URL processor with config $configPath = Join-Path $script:ModuleRoot "Config\control-mappings.json" Initialize-UrlProcessor -ConfigPath $configPath Write-Log "URL processor initialized with mappings from config" -Level Success # Fetch organization information Write-LogSection -Title "Fetching Organization Information" -Level Info $orgInfo = Get-OrganizationInfo $actualTenantName = if ($TenantName -ne "Your Organization") { $TenantName } elseif ($orgInfo.DisplayName) { $orgInfo.DisplayName } else { "Organization" } Write-Log "Organization Name: $actualTenantName" -Level Success # Fetch secure score data Write-LogSection -Title "Fetching Secure Score Data" -Level Info $scoreData = Get-SecureScoreData Write-Log "Current Score: $($scoreData.CurrentScore) / $($scoreData.MaxScore)" -Level Success $scorePercentage = [math]::Round(($scoreData.CurrentScore / $scoreData.MaxScore) * 100, 1) Write-Log "Percentage: $scorePercentage%" -Level Success # Fetch control profiles Write-LogSection -Title "Fetching Control Profiles" -Level Info $scoredControlsList = $scoreData.ControlScores.Keys $controlParams = @{ FilterApplicableOnly = $ApplicableOnly } if ($ApplicableOnly) { $controlParams['ScoredControlsList'] = $scoredControlsList } $controls = Get-SecureScoreControlProfiles @controlParams Write-Log "Retrieved $($controls.Count) control profiles" -Level Success # Group by category for summary $categories = $controls | Group-Object -Property ControlCategory | Sort-Object Count -Descending Write-Log "Control Summary by Category:" -Level Info foreach ($category in $categories) { Write-Log " $($category.Name): $($category.Count) controls" -Level Info } # Initialize report data Write-LogSection -Title "Processing Controls" -Level Info $reportData = New-ReportData # Update report metadata Update-ReportMetadata -ReportData $reportData ` -TenantId $script:CurrentContext.TenantId ` -TenantName $actualTenantName ` -GeneratedBy $script:CurrentContext.Account ` -GeneratedDate (Get-Date -Format "MMMM dd, yyyy HH:mm:ss") ` -CurrentScore $scoreData.CurrentScore ` -MaxScore $scoreData.MaxScore # Process each control $processedCount = 0 $skippedCount = 0 foreach ($control in $controls) { $processedCount++ # Log progress Write-LogProgress -Activity "Processing Secure Score Controls" ` -Current $processedCount ` -Total $controls.Count ` -FileLogInterval 50 # Validate control data if (-not (Test-ControlDataValid -Control $control)) { $skippedCount++ Write-Log "Skipped invalid control: $($control.Id)" -Level Warning -NoConsole continue } # Extract control properties $controlId = $control.Id $title = $control.Title $category = $control.ControlCategory $maxScore = $control.MaxScore $implementationCost = $control.ImplementationCost $userImpact = $control.UserImpact $threats = $control.Threats -join ", " $remediation = ConvertFrom-HtmlString -HtmlText $control.Remediation # Optimize action URL $actionUrl = Optimize-ControlUrl -Url $control.ActionUrl ` -ControlName $title ` -TenantId $script:CurrentContext.TenantId # Determine compliance status and risk $complianceStatus = Get-ComplianceStatus -ControlId $controlId ` -ControlScores $scoreData.ControlScores ` -MaxScore $maxScore $riskLevel = Get-RiskLevel -MaxScore $maxScore ` -UserImpact $userImpact ` -Threats $threats # Build values $currentValue = Get-ControlCurrentValue -ControlId $controlId ` -ControlScores $scoreData.ControlScores ` -MaxScore $maxScore $proposedValue = Get-ControlProposedValue -MaxScore $maxScore ` -ImplementationCost $implementationCost ` -UserImpact $userImpact $justification = Get-ControlJustification -Threats $threats ` -Remediation $remediation $scoreImpact = Get-ScoreImpact -ControlMaxScore $maxScore ` -TotalMaxScore $scoreData.MaxScore # Add to report Add-ReportItem -ReportData $reportData ` -Category $category ` -SettingName $title ` -CurrentValue $currentValue ` -ProposedValue $proposedValue ` -Justification $justification ` -Risk $riskLevel ` -Status $complianceStatus ` -SecureScoreImpact $scoreImpact ` -Reference $actionUrl ` -ActionUrl $actionUrl } # Clear progress bar Write-Progress -Activity "Processing Secure Score Controls" -Completed Write-Log -Level Info Write-Log "Processed $($controls.Count) controls" -Level Success if ($skippedCount -gt 0) { Write-Log "Skipped $skippedCount invalid controls" -Level Warning } Write-Log "Collected $($reportData.ProposedChanges.Count) configuration items" -Level Success # Generate HTML report Write-LogSection -Title "Generating HTML Report" -Level Info $templatePath = Join-Path $script:ModuleRoot "Templates" $reportParams = @{ ReportData = $reportData TemplatePath = $templatePath OutputPath = $ReportPath InlineAssets = $true # Always inline for single-file portability } $generatedReport = New-HtmlReport @reportParams Write-Log "Report generated successfully!" -Level Success Write-Log "Report location: $generatedReport" -Level Info # Close logger Close-Logger # Open report in browser Write-Host "`nOpening report in default browser..." -ForegroundColor Cyan Start-Process $generatedReport Write-Host "`n=== Assessment Complete ===" -ForegroundColor Green Write-Host "Report: $generatedReport" -ForegroundColor Cyan if ($LogPath) { Write-Host "Log: $LogPath" -ForegroundColor Cyan } } catch { Write-Error "Failed to generate secure score assessment: $_" Write-Log "Error: $_" -Level Error Close-Logger throw } } function Get-MicrosoftSecureScoreInfo { <# .SYNOPSIS Display information about the Microsoft Secure Score Assessment Toolkit. .DESCRIPTION Shows version information, usage instructions, and helpful links for the toolkit. .EXAMPLE Get-MicrosoftSecureScoreInfo Displays toolkit information and usage guide. #> [CmdletBinding()] param() $version = "2.0.0" Write-Host "`n╔════════════════════════════════════════════════════════════════╗" -ForegroundColor Cyan Write-Host "║ Microsoft Secure Score Assessment Toolkit v$version ║" -ForegroundColor Cyan Write-Host "║ Refactored Architecture - Modular Design ║" -ForegroundColor Cyan Write-Host "╚════════════════════════════════════════════════════════════════╝" -ForegroundColor Cyan Write-Host "`nDESCRIPTION:" -ForegroundColor Yellow Write-Host " Generate comprehensive security reports with over 400 Microsoft" -ForegroundColor White Write-Host " Secure Score controls fetched directly from Microsoft Graph API." -ForegroundColor White Write-Host "`nQUICK START:" -ForegroundColor Yellow Write-Host " 1. Connect-MicrosoftSecureScore" -ForegroundColor Green Write-Host " Authenticate to Microsoft Graph" -ForegroundColor Gray Write-Host "" Write-Host " 2. Invoke-MicrosoftSecureScore" -ForegroundColor Green Write-Host " Generate full assessment report with 411+ controls" -ForegroundColor Gray Write-Host "`nCOMMON EXAMPLES:" -ForegroundColor Yellow Write-Host " # Full report with all controls" -ForegroundColor Gray Write-Host " Invoke-MicrosoftSecureScore" -ForegroundColor White Write-Host "" Write-Host " # Only applicable controls with logging" -ForegroundColor Gray Write-Host " Invoke-MicrosoftSecureScore -ApplicableOnly -LogPath 'C:\Logs\assessment.log'" -ForegroundColor White Write-Host "" Write-Host " # Custom organization name with inline assets" -ForegroundColor Gray Write-Host " Invoke-MicrosoftSecureScore -TenantName 'Contoso Corp' -InlineAssets" -ForegroundColor White Write-Host "`nNEW IN v2.0:" -ForegroundColor Yellow Write-Host " • Modular architecture with separated concerns" -ForegroundColor Green Write-Host " • File-based logging support" -ForegroundColor Green Write-Host " • Externalized configuration (JSON)" -ForegroundColor Green Write-Host " • Template-based HTML generation" -ForegroundColor Green Write-Host " • Comprehensive error handling" -ForegroundColor Green Write-Host "`nREQUIREMENTS:" -ForegroundColor Yellow Write-Host " • Microsoft Graph PowerShell SDK" -ForegroundColor White Write-Host " • SecurityEvents.Read.All permission" -ForegroundColor White Write-Host " • Security Reader or Global Reader role" -ForegroundColor White Write-Host "`nLINKS:" -ForegroundColor Yellow Write-Host " GitHub: https://github.com/mohammedsiddiqui6872/Microsoft-Secure-Score-remediation-toolkit" -ForegroundColor Cyan Write-Host " Issues: https://github.com/mohammedsiddiqui6872/Microsoft-Secure-Score-remediation-toolkit/issues" -ForegroundColor Cyan Write-Host "`nSUPPORT:" -ForegroundColor Yellow Write-Host " Buy Me a Coffee: https://buymeacoffee.com/mohammedsiddiqui" -ForegroundColor Magenta Write-Host "" } # Export module members Export-ModuleMember -Function @( 'Connect-MicrosoftSecureScore', 'Invoke-MicrosoftSecureScore', 'Get-MicrosoftSecureScoreInfo' ) |