release: v4.1.0 — restructure entry points, add CIS baselines, reporting tools and fzf hints

- Restructure launchers: Start-IntuneToolkit.ps1 moves to repo root;
  Start-HeadlessIntune.ps1 moves to Scripts/; TUI helper moves to Scripts/Private/
- Add AGENTS.md with project architecture, entry points, and security notes
- Add CIS M365 baseline assets (CISM365-v7, M365-CIS-Rapid) and reporting scripts
- Add Python reporting utilities (Export-SettingsReport, Export-AssignmentReport,
  Export-ObjectInventoryReport) and CA wizard helpers
- Update Deploy-IntuneBaseline.ps1 with Merge conflict resolution, ReportPath,
  and optimized group loading
- Update Initialize-IntuneAuth.ps1 with -RotateSecret and configurable secret expiry
- Update Extensions for Settings Catalog definition auto-export
- Update README with v4.1.0, new entry points and script catalog
- Bump VERSION to 4.1.0
- Harden .gitignore against .DS_Store, __pycache__, .venv-pdf/, local exports,
  Settings.json and IntuneManagement.log
This commit is contained in:
2026-06-14 15:24:42 +02:00
parent e333af978c
commit d3e0769799
30 changed files with 8711 additions and 175 deletions
+263
View File
@@ -0,0 +1,263 @@
[CmdletBinding()]
param(
[ValidateSet("Export","Import","DeployCISBaseline","GenerateReports")]
[string]$Action,
[string]$BaselinePath,
[ValidateSet("Assess","Deploy")]
[string]$Mode = "Assess",
[string[]]$Workloads,
[switch]$Apply,
[string]$TenantId,
[string]$AppId,
[string]$Secret,
[string]$Certificate,
[ValidateSet("AppOnly","Browser","DeviceCode")]
[string]$AuthMode = "AppOnly",
[string]$RedirectUri,
[string]$SettingsFile,
[string]$BatchFile,
[string]$NameFilter = "",
[string]$NameSearchPattern = "",
[string]$NameReplacePattern = "",
[string[]]$ObjectTypes,
[string]$ExportPath,
[string]$ImportPath,
[ValidateSet("alwaysImport","skipIfExist","replace","replace_with_assignments","update")]
[string]$ImportType = "alwaysImport",
[switch]$IncludeAssignments,
[switch]$AddCompanyName,
[switch]$IncludeScopeTags,
[switch]$ReplaceDependencyIds,
[switch]$Interactive,
# GenerateReports params
[ValidateSet("Settings","Assignments","ObjectInventory","All")]
[string]$ReportType = "All",
[string]$BackupRoot,
[string]$OutputDir,
[string]$DataSource,
[switch]$IncludeAssignmentsInSettings
)
$modulePath = Join-Path (Split-Path -Parent $PSScriptRoot) "Headless/IntuneManagement.Headless.psd1"
Import-Module $modulePath -Force
if($Interactive -and -not $Action)
{
Write-Host "Interactive mode will prompt for the action and other settings." -ForegroundColor Cyan
}
elseif(-not $Action)
{
throw "Action is required. Use -Interactive to select it in a terminal UI."
}
if($Interactive)
{
$tuiScript = Join-Path (Split-Path -Parent $PSScriptRoot) "Scripts/Private/Start-IntuneManagementTui.ps1"
if(Test-Path $tuiScript)
{
$tuiResult = & $tuiScript
if(-not $tuiResult) { Write-Host "No selection made. Exiting." -ForegroundColor Yellow; exit 0 }
foreach($prop in $tuiResult.PSObject.Properties)
{
if($null -ne $prop.Value -and $prop.Name -ne "Action")
{
Set-Variable -Name $prop.Name -Value $prop.Value
}
elseif($prop.Name -eq "Action")
{
$Action = $prop.Value
}
}
}
else
{
throw "TUI script not found: $tuiScript"
}
}
if($Action -eq "GenerateReports")
{
if([string]::IsNullOrWhiteSpace($OutputDir)) { throw "OutputDir is required for GenerateReports." }
if($DataSource -like "*fresh*")
{
if([string]::IsNullOrWhiteSpace($TenantId)) { throw "TenantId is required when pulling fresh data." }
$freshDest = if(-not [string]::IsNullOrWhiteSpace($ExportPath)) { $ExportPath } else { $BackupRoot }
if([string]::IsNullOrWhiteSpace($freshDest)) { throw "ExportPath or BackupRoot required for fresh data pull." }
Write-Host "Pulling fresh data from tenant $TenantId ..." -ForegroundColor Cyan
$freshParams = @{ Action = "Export"; TenantId = $TenantId; ExportPath = $freshDest; IncludeAssignments = $true; AuthMode = $AuthMode }
if($AppId) { $freshParams.AppId = $AppId }
if($Secret) { $freshParams.Secret = $Secret }
elseif($Certificate) { $freshParams.Certificate = $Certificate }
if($SettingsFile) { $freshParams.SettingsFile = $SettingsFile }
Invoke-IntunePolicyAction @freshParams
$BackupRoot = $freshDest
}
# Validate inputs
if([string]::IsNullOrWhiteSpace($BackupRoot)) { throw "BackupRoot is required for GenerateReports." }
if(-not (Test-Path $BackupRoot)) { throw "BackupRoot not found: $BackupRoot" }
$python = Get-Command python3 -ErrorAction SilentlyContinue
if(-not $python) { $python = Get-Command python -ErrorAction SilentlyContinue }
if(-not $python) { throw "python3 not found. Install Python 3 to use GenerateReports." }
$pythonExe = $python.Source
$scriptsDir = Split-Path -Parent $PSScriptRoot
if(-not (Test-Path (Join-Path $scriptsDir "Scripts/Export-SettingsReport.py")))
{
$scriptsDir = $PSScriptRoot
}
New-Item -ItemType Directory -Path $OutputDir -Force | Out-Null
function Invoke-Report
{
param([string]$Script, [string[]]$ScriptArgs)
$fullScript = Join-Path $scriptsDir "Scripts/$Script"
if(-not (Test-Path $fullScript)) { Write-Warning "Report script not found: $fullScript"; return }
Write-Host "Running $Script ..." -ForegroundColor Cyan
& $pythonExe $fullScript @ScriptArgs
}
if($ReportType -in @("Settings","All"))
{
$settingsArgs = @("--root", $BackupRoot, "--output", (Join-Path $OutputDir "settings-report.csv"))
if($IncludeAssignmentsInSettings) { $settingsArgs += "--include-assignments" }
Invoke-Report -Script "Export-SettingsReport.py" -ScriptArgs $settingsArgs
}
if($ReportType -in @("Assignments","All"))
{
Invoke-Report -Script "Export-AssignmentReport.py" -ScriptArgs @(
"--root", $BackupRoot,
"--output", (Join-Path $OutputDir "assignment-report.csv")
)
}
if($ReportType -in @("ObjectInventory","All"))
{
Invoke-Report -Script "Export-ObjectInventoryReport.py" -ScriptArgs @(
"--root", $BackupRoot,
"--output", (Join-Path $OutputDir "object-inventory.csv")
)
}
Write-Host "`nReports written to: $OutputDir" -ForegroundColor Green
return
}
if($Action -eq "DeployCISBaseline")
{
$deployScript = Join-Path (Split-Path -Parent $PSScriptRoot) "Scripts/Deploy-CISM365Baseline.ps1"
if(-not (Test-Path $deployScript))
{
throw "CIS baseline deployment script not found: $deployScript"
}
$deployParams = @{
BaselinePath = $BaselinePath
TenantId = $TenantId
Mode = $Mode
AuthMode = $AuthMode
}
if($Apply) { $deployParams.Apply = $true }
if($PSBoundParameters.ContainsKey("Workloads") -or $Workloads)
{
$deployParams.Workloads = $Workloads
}
if($Secret)
{
$deployParams.Secret = $Secret
}
elseif($Certificate)
{
$deployParams.Certificate = $Certificate
}
if($AppId) { $deployParams.AppId = $AppId }
if($RedirectUri) { $deployParams.RedirectUri = $RedirectUri }
& $deployScript @deployParams
return
}
if([string]::IsNullOrWhiteSpace($TenantId))
{
throw "TenantId is required for Action '$Action'."
}
$invokeParams = @{
Action = $Action
TenantId = $TenantId
AppId = $AppId
AuthMode = $AuthMode
SettingsFile = $SettingsFile
BatchFile = $BatchFile
NameFilter = $NameFilter
NameSearchPattern = $NameSearchPattern
NameReplacePattern = $NameReplacePattern
ExportPath = $ExportPath
ImportPath = $ImportPath
ImportType = $ImportType
IncludeAssignments = $IncludeAssignments
AddCompanyName = $AddCompanyName
IncludeScopeTags = $IncludeScopeTags
ReplaceDependencyIds = $ReplaceDependencyIds
}
if($Interactive -and $Action) { $invokeParams.Action = $Action }
if($PSBoundParameters.ContainsKey("ObjectTypes") -or $ObjectTypes)
{
$invokeParams.ObjectTypes = $ObjectTypes
}
if($Secret)
{
$invokeParams.Secret = $Secret
}
elseif($Certificate)
{
$invokeParams.Certificate = $Certificate
}
if($RedirectUri)
{
$invokeParams.RedirectUri = $RedirectUri
}
Invoke-IntunePolicyAction @invokeParams