-
Notifications
You must be signed in to change notification settings - Fork 247
Microsoft 365 Secure Score Foundry Script
The o365-secure-score-foundry.ps1 script is a comprehensive PowerShell tool that collects Microsoft 365 security posture data and leverages Azure OpenAI Foundry agents to provide AI-powered security analysis and recommendations. The script generates a detailed HTML report with actionable insights to improve your tenant's security posture.
-
Automated Data Collection: Gathers security data from Microsoft Graph API including:
- Secure Score metrics and trends
- Security control implementations
- Conditional Access policies
- MFA adoption statistics
- Security defaults configuration
-
AI-Powered Analysis: Sends collected data to Azure OpenAI Foundry agents for intelligent analysis
- Identifies security gaps and vulnerabilities
- Provides prioritized recommendations
- Generates implementation roadmaps
- Explains business impact and threat protection
-
Professional HTML Reports: Creates interactive, visually appealing reports with:
- Executive summaries
- Detailed security findings
- Interactive sections with collapsible content
- Mermaid diagrams for visual representations
- Markdown-rendered AI analysis
- Dark/light theme support
-
Flexible Operation Modes: Three modes to suit different workflows
- Collect: Gather data and save to JSON file
- Analyze: Use existing JSON data for analysis
- Both: Collect data and analyze in one run (default)
-
Token Caching: Intelligent authentication caching to minimize re-authentication
- Caches both Microsoft Graph and Azure AD tokens
- Automatic token expiry handling
- Reduces authentication prompts for better user experience
- PowerShell 5.1 or later (PowerShell 7+ recommended)
-
Microsoft.Graph PowerShell Module
Install-Module Microsoft.Graph -Scope CurrentUser
-
Azure AD App Registration (for Foundry authentication)
- Application (Client) ID
- Tenant ID where Foundry is deployed
- Device code flow enabled
-
Azure OpenAI Foundry Instance
- Foundry deployment URL
- Foundry Agent ID
The script requires the following Microsoft Graph API permissions:
-
SecurityEvents.Read.All- Read security events and Secure Score -
Policy.Read.All- Read Conditional Access policies -
Reports.Read.All- Read usage reports and MFA statistics -
Directory.Read.All- Read directory data
These permissions can be granted through:
- Interactive consent during first connection
- Pre-consented admin permissions in your tenant
The primary domain of your Microsoft 365 tenant (e.g., "contoso.onmicrosoft.com").
Example:
-TenantDomain "contoso.onmicrosoft.com"Operation mode for the script.
Valid Values:
-
Collect- Only collect data and save to JSON file -
Analyze- Use existing JSON data for analysis (requires -DataFile) -
Both- Collect data and analyze (default)
Default: Both
Example:
-Mode "Collect" # Only gather data
-Mode "Analyze" # Only analyze existing data
-Mode "Both" # Do both in one runPath to save/load the JSON data file.
Default: Auto-generated filename with timestamp in script directory
Example:
-DataFile "C:\Reports\tenant-data.json"The Azure OpenAI Foundry endpoint URL.
Default: https://ciafoundry1-resource.openai.azure.com/openai/deployments/model-router/chat/completions
Example:
-FoundryInstanceUrl "https://your-foundry.openai.azure.com/openai/deployments/model-router/chat/completions"The Foundry Agent ID to use for analysis.
Default: Agent508new:47
Example:
-FoundryAgentId "Agent123:45"Application (Client) ID of your Azure AD app registration.
Required for Foundry authentication.
Example:
-AzureADClientId "12345678-1234-1234-1234-123456789abc"Tenant ID where your Foundry instance is deployed.
Required for Foundry authentication.
Example:
-AzureADTenantId "87654321-4321-4321-4321-cba987654321"Enable detailed analysis mode for comprehensive reports.
When enabled:
- AI provides more thorough analysis
- More detailed recommendations
- Implementation roadmaps
- Business impact explanations
- Longer analysis time (60-120 seconds vs 30-60 seconds)
- Higher token usage
Example:
-DetailedCollect data from tenant and generate AI-powered report in one run.
.\o365-secure-score-foundry.ps1 `
-TenantDomain "contoso.onmicrosoft.com" `
-AzureADClientId "12345678-1234-1234-1234-123456789abc" `
-AzureADTenantId "87654321-4321-4321-4321-cba987654321"Generate comprehensive report with detailed recommendations.
.\o365-secure-score-foundry.ps1 `
-TenantDomain "contoso.onmicrosoft.com" `
-AzureADClientId "12345678-1234-1234-1234-123456789abc" `
-AzureADTenantId "87654321-4321-4321-4321-cba987654321" `
-DetailedCollect data and save to JSON for later analysis.
.\o365-secure-score-foundry.ps1 `
-TenantDomain "contoso.onmicrosoft.com" `
-Mode "Collect" `
-DataFile "C:\Reports\tenant-2026-01-22.json"Analyze previously collected data without re-collecting.
.\o365-secure-score-foundry.ps1 `
-TenantDomain "contoso.onmicrosoft.com" `
-Mode "Analyze" `
-DataFile "C:\Reports\tenant-2026-01-22.json" `
-AzureADClientId "12345678-1234-1234-1234-123456789abc" `
-AzureADTenantId "87654321-4321-4321-4321-cba987654321" `
-DetailedUse a custom Foundry deployment.
.\o365-secure-score-foundry.ps1 `
-TenantDomain "contoso.onmicrosoft.com" `
-FoundryInstanceUrl "https://my-foundry.openai.azure.com/openai/deployments/model-router/chat/completions" `
-FoundryAgentId "MyAgent:10" `
-AzureADClientId "12345678-1234-1234-1234-123456789abc" `
-AzureADTenantId "87654321-4321-4321-4321-cba987654321"-
Authentication
- Checks for existing Microsoft Graph session
- Connects to Microsoft Graph with required scopes
- Tests Graph API connectivity
-
Data Collection (5 sequential steps)
- Step 1: Secure Score data (current score, trends, max possible)
- Step 2: Security controls (recommendations, implementation status)
- Step 3: Conditional Access policies (configurations, states, conditions)
- Step 4: MFA adoption metrics (registration, usage statistics)
- Step 5: Security defaults status (enabled/disabled)
-
Data Persistence
- Saves collected data to JSON file
- Creates timestamped filename if not specified
- Compresses data for efficient storage
-
Foundry Authentication
- Checks for cached token
- Initiates device code flow if needed
- Displays code for browser authentication
- Polls for authentication completion
- Caches token for future use
-
Data Preparation
- Loads JSON data (from file or memory)
- Summarizes large datasets to optimize AI analysis
- Validates data structure
-
AI Processing
- Sends security data to Foundry agent
- AI analyzes security posture
- Generates recommendations and insights
- Model router automatically selects best AI model
- Typical processing time: 30-90 seconds
-
Report Generation
- Parses AI response (Markdown + JSON)
- Extracts structured recommendations
- Builds interactive HTML report
- Includes:
- Executive summary
- Security score trends
- Control recommendations
- Conditional Access policies
- MFA statistics
- AI analysis with diagrams
- Implementation guides
-
HTML Report
- Saved to script directory
- Timestamped filename
- Automatically opens in default browser
- Features:
- Responsive design
- Collapsible sections
- Syntax highlighting
- Mermaid diagram rendering
- Dark/light theme support
-
Console Summary
- Displays execution time
- Shows file locations
- Provides quick statistics
- Method: Interactive browser-based OAuth
- Caching: Session-based (survives for duration of PowerShell session)
- Scopes: Dynamically requested based on required permissions
- Re-authentication: Only when session expires or different tenant
- Method: Device code flow
- Caching: File-based token cache (expires after token lifetime - 5 min buffer)
-
Flow:
- Script requests device code
- Displays code and URL to user
- User opens browser and enters code
- Script polls for completion
- Token cached for future runs
-
Cache Location:
%TEMP%\O365SecureScore\foundry-token-{TenantId}.json
Location: Script directory (or specified path)
Naming: SecureScoreData-YYYY-MM-DD-HHmmss.json
Contents:
- Secure Score metrics
- Security controls
- Conditional Access policies
- MFA statistics
- Security defaults status
- Collection timestamp
Example:
SecureScoreData-2026-01-22-153045.json
Location: Script directory
Naming: M365-SecureScore-Analysis-YYYY-MM-DD-HHmmss.html
Contents:
- Interactive security report
- AI-powered analysis
- Recommendations and implementation guides
- Visual diagrams and charts
Example:
M365-SecureScore-Analysis-2026-01-22-153245.html
- Tenant information
- Report metadata (agent, mode, timestamp)
- AI-Powered Security Posture Assessment subtitle
- Latest score (current/max/percentage)
- Trend table (if historical data available)
- Active and licensed user counts
- Collapsible table of unimplemented controls
- Ranked by priority
- Impact, score potential, threats mitigated
- Implementation state
- Collapsible policy listing
- Policy state (enabled/disabled/report-only)
- Scope (users, groups, applications)
- Grant and session controls
- Last modified dates
- User registration statistics
- MFA-capable vs registered users
- Registration percentages
- Executive summary
- Critical findings
- Detailed security assessment
- Risk analysis
- Recommendations with:
- Why critical
- Business impact
- Implementation steps
- Testing procedures
- References and documentation
- Step-by-step implementation roadmap
- Prerequisites and dependencies
- Testing and validation procedures
- Rollback procedures
- Additional resources
Solution:
Install-Module Microsoft.Graph -Scope CurrentUser -ForceCause: Device code authentication not completed in time
Solution:
- Ensure you entered the code in browser within 15 minutes
- Check internet connectivity
- Try running script again
Cause: Network issues or insufficient permissions
Solution:
- Check internet connection
- Verify you have required Graph permissions
- Ensure you're logged in as appropriate user
Cause: Tenant has extensive security configurations
Solution:
- Script automatically summarizes data
- Consider using
-Mode Collectto save data for review - Large payloads may still work but take longer
Solution:
# Clear token cache manually
Remove-Item "$env:TEMP\O365SecureScore\*" -ForceCause: Corrupted token cache
Solution: Script automatically removes corrupted cache and re-authenticates
Enable verbose output for troubleshooting:
.\o365-secure-score-foundry.ps1 -TenantDomain "contoso.onmicrosoft.com" -Verbose| Phase | Standard Mode | Detailed Mode |
|---|---|---|
| Data Collection | 2-5 minutes | 2-5 minutes |
| AI Analysis | 30-60 seconds | 60-120 seconds |
| Report Generation | 2-5 seconds | 2-5 seconds |
| Total | 3-6 minutes | 4-8 minutes |
Times vary based on tenant size, network speed, and AI model load
- Use token caching: Run script multiple times without re-authenticating
-
Collect once, analyze multiple times: Use
-Mode Collectthen multiple-Mode Analyzeruns - Standard mode for quick insights: Use detailed mode only when needed
- Check network speed: Slow connections impact Graph API calls
- Never hardcode credentials in scripts
- Use Azure AD app registrations with minimal required permissions
- Regularly rotate app secrets
- Enable Conditional Access for admin accounts
- JSON files contain sensitive security data
- Store data files securely
- Delete old data files when no longer needed
- Restrict file permissions appropriately
- HTML reports contain sensitive information
- Share only with authorized personnel
- Consider using password-protected archives
- Remove old reports after review
Create a scheduled task to run weekly reports:
# Create scheduled script
$scriptPath = "C:\Scripts\o365-secure-score-foundry.ps1"
$outputPath = "C:\Reports"
# Script content with parameters
$scriptContent = @"
.\o365-secure-score-foundry.ps1 ``
-TenantDomain "contoso.onmicrosoft.com" ``
-AzureADClientId "12345678-1234-1234-1234-123456789abc" ``
-AzureADTenantId "87654321-4321-4321-4321-cba987654321" ``
-DataFile "$outputPath\weekly-$(Get-Date -Format 'yyyy-MM-dd').json" ``
-Detailed
"@
# Save to file and create scheduled task
$scriptContent | Out-File "C:\Scripts\weekly-security-report.ps1"Analyze multiple tenants in sequence:
$tenants = @(
@{ Domain = "contoso.onmicrosoft.com"; ClientId = "guid1"; TenantId = "guid1" }
@{ Domain = "fabrikam.onmicrosoft.com"; ClientId = "guid2"; TenantId = "guid2" }
)
foreach ($tenant in $tenants) {
Write-Host "Processing $($tenant.Domain)..." -ForegroundColor Cyan
.\o365-secure-score-foundry.ps1 `
-TenantDomain $tenant.Domain `
-AzureADClientId $tenant.ClientId `
-AzureADTenantId $tenant.TenantId `
-Detailed
}Use collected JSON for custom analysis:
# Collect data only
.\o365-secure-score-foundry.ps1 -TenantDomain "contoso.onmicrosoft.com" -Mode Collect
# Load and process JSON
$data = Get-Content "SecureScoreData-*.json" -Raw | ConvertFrom-Json
# Custom analysis
$openControls = $data.securityControls | Where-Object { $_.implementationStatus -ne "Implemented" }
Write-Host "Open controls: $($openControls.Count)"
# Export to CSV for Excel analysis
$openControls | Export-Csv "open-controls.csv" -NoTypeInformationCurrent Version: Foundry Agent Version
Last Updated: January 2026
- Token caching for improved user experience
- Automatic token expiry handling
- Enhanced error reporting
- Improved data summarization
- Better HTML report styling with high-contrast headings
- Mermaid diagram support
- Collapsible report sections
- Responsive design improvements
This script is provided as-is for security assessment purposes. Review and test in non-production environments before production use.
For issues, enhancements, or questions, please contact your Microsoft 365 security team or Azure OpenAI Foundry administrators.
Script: o365-secure-score-foundry.ps1
Documentation Version: 1.0
Last Updated: January 22, 2026