Public/Core/New-IDBridgeConfig.ps1
|
<# .SYNOPSIS First-run scaffold: create the IDBridge folder tree and a default IDBridgeConfig.psd1. .DESCRIPTION One-time setup helper for a fresh install. It: - creates the runtime directory tree under RootPath (Config/Logs/Exports/Plugins/Data/Vault); - writes a default <RootPath>\Config\IDBridgeConfig.psd1 with every feature disabled and placeholder values for all site-specific settings. An existing config file is NEVER overwritten — the function throws instead (there is deliberately no -Force). The generated config is safe to load immediately: ReadOnly stays $true, AD/Google processing and every plugin are disabled, and all site-specific values are obvious placeholders to fill in before enabling anything. This runs before any state exists, so it does not use Write-Log or require Initialize-IDBridge — run it first, edit the config, then run Initialize-IDBridge. .PARAMETER RootPath Base directory for Config/Logs/Exports/Plugins/Data/Vault. Defaults to C:\IDBridge. Missing directories are created. .OUTPUTS None. Writes the default config file and prints its path. .EXAMPLE New-IDBridgeConfig .EXAMPLE New-IDBridgeConfig -RootPath 'D:\IDBridge' .NOTES Created by: Sam Cattanach Modified: 2026-07-09 #> function New-IDBridgeConfig { [CmdletBinding()] param ( [string]$RootPath = "C:\IDBridge" ) $configFilePath = Join-Path $RootPath "Config\IDBridgeConfig.psd1" if (Test-Path $configFilePath) { Throw "Config file already exists and will not be overwritten: $configFilePath" } #region Create Directories $directories = @( $RootPath "$RootPath\Config" "$RootPath\Logs" "$RootPath\Exports" "$RootPath\Plugins" "$RootPath\Data" "$RootPath\Vault" ) foreach ($directory in $directories) { if (-not (Test-Path $directory)) { New-Item -ItemType Directory -Path $directory -Force | Out-Null Write-Host "Created missing directory: $directory" -ForegroundColor Yellow } } #endregion Create Directories #region Write Default Config $defaultConfig = @' # IDBridgeConfig.psd1 — generated by New-IDBridgeConfig # Every feature is disabled. Replace the placeholder values, then enable features one at a time. @{ # ── Debug / Run Modes ───────────────────────────────────────────────────── Debug = @{ ReadOnly = $true # Set $false to actually write changes TestRun = $false # Set $true to only process a subset of users for faster testing SkipADCheck = $false # Set $true to skip the AD module check at startup TraceLogging = $true # Set $false to disable verbose/trace logging } # ── Change Safety ───────────────────────────────────────────────────────── ChangeThreshold = @{ Enabled = $true # Set $false (or run -SkipChangeThreshold) to bypass the guard Percentage = 25 # Abort the run if proposed lifecycle changes exceed this % of the managed population } # ── Google Token ────────────────────────────────────────────────────────── GoogleToken = @{ Enabled = $false # Set $true once the GoogleAuth-ServiceAccount secret is seeded } # ── Google Workspace ────────────────────────────────────────────────────── Google = @{ enabled = $false customerID = 'C00000000' # Workspace customer ID userRootOU = '/YourDistrict' # Managed root OU path; anchors the ChangeThreshold safety guard's population count enableGroupProcessing = $false enableGroupProcessingWhatIf = $true # Log-only while $true; set $false to actually apply group changes enableGroupProcessingRemove = $false # Set $true to allow group membership removals enableGroupProcessingTrash = $false # Set $true to strip group memberships on deactivate enableLicenseRemoval = $false # Set $true to remove paid license assignments on deactivate (the base license self-releases when the user is archived) groupsExcluded = @('classroom_teachers@*') # Group email patterns IDBridge never touches (no adds/removes/deactivate strips) # licenseProductIds = @('101031', '101037') # Paid products searched for license assignments } # ── Active Directory ────────────────────────────────────────────────────── AD = @{ enabled = $false userRootOU = 'OU=YourDistrict,DC=yourdomain,DC=local' # Managed root OU DN; anchors the ChangeThreshold safety guard's population count enableGroupProcessing = $false enableGroupProcessingWhatIf = $true # Log-only while $true; set $false to actually apply group changes enableGroupProcessingRemove = $false # Set $true to allow group membership removals enableGroupProcessingTrash = $false # Set $true to strip group memberships on deactivate groupsExcluded = @() # Group name patterns IDBridge never touches (no adds/removes/deactivate strips) } # ── Google Log ──────────────────────────────────────────────────────────── Logging = @{ GoogleSheetLoggingEnabled = $false SheetID = 'your-log-spreadsheet-id' # Target spreadsheet ID for logs } # ── Telemetry (see PRIVACY.md) ──────────────────────────────────────────── Telemetry = @{ Tier = 'Basic' # 'Basic' (default - anonymous counts) | 'Enhanced' (adds install SiteID + error class on failures) | 'Off' } # ── Secrets ─────────────────────────────────────────────────────────────── Secrets = @{ Provider = 'Cms' # 'Cms' (certificate, default) | 'DpapiNG' (gMSA) | 'AzKeyVault' (Azure Key Vault, remote) Cms = @{ Thumbprint = '' # From New-IDBridgeSecretCertificate; empty = find the single 'CN=IDBridge Secrets' cert } # DpapiNG provider: uncomment and set Provider = 'DpapiNG' to use it. # DpapiNG = @{ # ProtectionDescriptor = 'SID=<gMSA SID> OR SID=<admins group SID>' # AD principal(s) secrets are protected to # } # AzKeyVault provider: uncomment and set Provider = 'AzKeyVault' to use it. # AzKeyVault = @{ # VaultUri = 'https://your-vault.vault.azure.net/' # Key Vault URI # TenantId = 'yourtenant.onmicrosoft.com' # Entra tenant ID or domain # ClientId = '00000000-0000-0000-0000-000000000000' # App registration (client) ID # CertThumbprint = '' # Auth certificate thumbprint # } } # ── Plugins ─────────────────────────────────────────────────────────────── Plugins = @( @{ Enabled = $false; Type = "Source"; Function = 'Invoke-PluginGSheetStaff' } @{ Enabled = $false; Type = "Source"; Function = 'Invoke-PluginSkywardSMSStudents' } @{ Enabled = $false; Type = "Override"; Function = 'Invoke-PluginStaffOverride' } ) } '@ try { Set-Content -Path $configFilePath -Value $defaultConfig -ErrorAction Stop } catch { Throw "Error writing default config file: $_" } #endregion Write Default Config Write-Host "Created default config: $configFilePath" -ForegroundColor Green Write-Host "Edit the placeholder values, then run Initialize-IDBridge to load it." } |