d3e0769799
- 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
264 lines
7.3 KiB
PowerShell
264 lines
7.3 KiB
PowerShell
[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
|