From 7e395e0c4a71705513fb9c10c8789d79a1cadc30 Mon Sep 17 00:00:00 2001 From: TheAbider <51920546+TheAbider@users.noreply.github.com> Date: Fri, 29 May 2026 15:57:15 -0700 Subject: [PATCH] Add cluster validation report CLI action (Failover Clustering) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New ClusterValidationReport CLI action: run a non-disruptive failover-cluster validation (Inventory + Network + System Configuration) against the cluster's nodes (or this node if not yet clustered), archive the native HTML report to an admin-only path, and report a best-effort overall result + pass/warn/fail counts. Read-only — makes no changes. Complements the interactive Cluster Management -> [3] Validate Configuration (which can run the full, potentially disruptive suite). The saved HTML report is authoritative for per-test detail; storage / Hyper-V categories stay in the interactive validator. JSON-aware for fleet pre-flight. Addition to 27-FailoverClustering (no new module). CLI actions 193 -> 194; docs in lockstep. 5045 tests, 0 failures; PSScriptAnalyzer clean. --- CONTRIBUTING.md | 2 +- Changelog.md | 8 ++ Header.ps1 | 4 +- Modules/00-Initialization.ps1 | 2 +- Modules/27-FailoverClustering.ps1 | 74 +++++++++++++++++++ Modules/34-Help.ps1 | 2 +- Modules/50-EntryPoint.ps1 | 6 ++ README.md | 12 +-- RackStack.ps1 | 2 +- RackStack.psd1 | 2 +- Tests/Run-Tests.ps1 | 29 +++++++- dist/chocolatey/rackstack.nuspec | 2 +- dist/scoop/rackstack.json | 2 +- .../TheAbider.RackStack.locale.en-US.yaml | 2 +- 14 files changed, 129 insertions(+), 20 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 495f808..56274d1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -30,7 +30,7 @@ powershell -ExecutionPolicy Bypass -File Tests\pssa-check.ps1 ## Pull Request Checklist -- [ ] All 5,040 tests pass (`Run-Tests.ps1` exits with code 0) +- [ ] All 5,045 tests pass (`Run-Tests.ps1` exits with code 0) - [ ] PSScriptAnalyzer reports 0 errors (`pssa-check.ps1`) - [ ] Monolithic synced (`sync-to-monolithic.ps1` shows 0 parse errors) - [ ] New functions follow PowerShell verb-noun naming (`Get-`, `Set-`, `Test-`, `Show-`) diff --git a/Changelog.md b/Changelog.md index 55819f4..f1e212b 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,5 +1,13 @@ # Changelog +## v1.111.0 + +Failover Cluster validation report — new `ClusterValidationReport` CLI action. Runs a **non-disruptive** failover-cluster validation (Inventory + Network + System Configuration categories) against the cluster's nodes (or this node if it isn't yet clustered), archives the native HTML report to an admin-only path, and reports a best-effort overall result (pass / warning / failed counts). + +It complements the interactive **Cluster Management → [3] Validate Configuration** (which can run the full, potentially disruptive suite). Read-only — it makes no changes. `-Action ClusterValidationReport -OutputFormat JSON` emits the overall result + report path for fleet pre-flight checks; the saved HTML report is authoritative for per-test detail. Storage and Hyper-V validation categories (which need shared storage / offline VMs) stay in the interactive validator. + +Addition to 27-FailoverClustering (no new module). CLI actions: 193 → 194. + ## v1.110.0 Enable AD Recycle Bin — added to **AD DS Domain Controller Promotion** (`[6] Enable AD Recycle Bin`) and via the `ADRecycleBin` CLI action. Turns on Active Directory object recovery so deleted users/groups/OUs can be restored with their attributes intact. diff --git a/Header.ps1 b/Header.ps1 index 4aa5ece..e6ca5f2 100644 --- a/Header.ps1 +++ b/Header.ps1 @@ -30,7 +30,7 @@ 7h3 4b1d3r .VERSION - 1.110.0 + 1.111.0 .LAST UPDATED 05/23/2026 @@ -1391,7 +1391,7 @@ param( # CLI headless mode: run a specific action without interactive menus # Usage: RackStack.exe -Action Cleanup [-Tier Standard] [-Silent] [-OutputFormat JSON] - [ValidateSet('Cleanup', 'Debloat', 'HealthCheck', 'Batch', 'QuickScan', 'Inventory', 'DriftCheck', 'Snapshot', 'Compliance', 'Harden', 'Remediate', 'Aggregate', 'Compare', 'Export', 'Trend', 'CertCheck', 'ReportHTML', 'ListeningPorts', 'SoftwareList', 'Uptime', 'ServiceAudit', 'EventAudit', 'NetInfo', 'ScheduledExport', 'ValidateConfig', 'Watch', 'Query', 'Diff', 'Baseline', 'Alert', 'FleetScan', 'PatchStatus', 'UserAudit', 'FirewallAudit', 'TaskAudit', 'DiskAudit', 'TLSAudit', 'SMBAudit', 'DriverAudit', 'TimeAudit', 'BootAudit', 'GPOAudit', 'MemoryAudit', 'ProcessAudit', 'BackupAudit', 'ShareAudit', 'DNSAudit', 'PowerAudit', 'RegistryAudit', 'ProfileAudit', 'HyperVAudit', 'NetworkAudit', 'StorageAudit', 'FeatureAudit', 'AutoStartAudit', 'BIOSAudit', 'ClusterAudit', 'AuditPolicyAudit', 'EnvAudit', 'CrashAudit', 'LocalGroupAudit', 'WMIAudit', 'TempAudit', 'UpdatePolicyAudit', 'IISAudit', 'SSHAudit', 'BitLockerAudit', 'PrintAudit', 'CredGuardAudit', 'PortAudit', 'AntivirusAudit', 'DotNetAudit', 'RDPAudit', 'VPNAudit', 'HostsFileAudit', 'NetStatAudit', 'LicenseAudit', 'USBDeviceAudit', 'AppLockerAudit', 'EventSubAudit', 'HotfixAudit', 'SysInfoAudit', 'LogonAudit', 'ACLAudit', 'RecoveryAudit', 'ServiceAccountAudit', 'ProxyAudit', 'PendingRebootAudit', 'PageFileAudit', 'CPUAudit', 'DefenderExclusionAudit', 'KerberosAudit', 'DHCPAudit', 'NUMAAudit', 'SymlinkAudit', 'StartupScriptAudit', 'SecureChannelAudit', 'ComObjectAudit', 'FirewallLogAudit', 'ScheduledRebootAudit', 'PowerShellAudit', 'RouteTableAudit', 'TokenPrivilegeAudit', 'WindowsCapabilityAudit', 'ARPTableAudit', 'LocaleAudit', 'TaskHistoryAudit', 'NTFSAudit', 'Win11Cleanup', 'DarkMode', 'LightMode', 'iSCSIAudit', 'NICTeamAudit', 'SMBSessionAudit', 'WindowsUpdateAudit', 'ClusterQuorumAudit', 'S2DAudit', 'VirtualSwitchAudit', 'MPIOPathAudit', 'ServiceRecoveryAudit', 'VMOvercommitAudit', 'DedupAudit', 'ClusterNetworkAudit', 'ReplicaLagAudit', 'HandleLeakAudit', 'ShadowCopyAudit', 'QoSPolicyAudit', 'LiveMigrationAudit', 'DomainTrustAudit', 'DiskLatencyAudit', 'NICOffloadAudit', 'StorageTimeoutAudit', 'EventLogCapacityAudit', 'TcpSettingsAudit', 'WinRMAudit', 'ClusterHealthScore', 'VMInventoryExport', 'VMSnapshotAudit', 'StorageHealthScore', 'CSVSpaceAudit', 'SMBConnectionAudit', 'VolumeLabelAudit', 'NICErrorAudit', 'VMResourceWaste', 'HealthDashboard', 'SCCMClientAudit', 'SCOMAgentAudit', 'WACConnectivityAudit', 'AzureADAudit', 'ServerScore', 'FleetReport', 'PasswordPolicy', 'FirewallRuleAudit', 'GPResultAudit', 'DNSCacheAudit', 'TPMAudit', 'SecureBootAudit', 'TimeSkewAudit', 'NetworkProfileAudit', 'InsecureServiceAudit', 'SelfTest', 'CheckForUpdate', 'ExportLogs', 'UpdateSelf', 'Rollback', 'ScheduleUpdateCheck', 'Dashboard', 'History', 'Replay', 'AzureArcEnroll', 'DefenderEndpointOnboard', 'WSUSSetup', 'ADCSSetup', 'StorageMigrationSetup', 'GPOBackup', 'GPODrift', 'JEAList', 'NPSSetup', 'AlwaysOnVPNSetup', 'CISScan', 'SIEMSetup', 'SIEMStatus', 'WACSetup', 'WACStatus', 'VHDXEncryptionAudit', 'ADRecycleBin')] + [ValidateSet('Cleanup', 'Debloat', 'HealthCheck', 'Batch', 'QuickScan', 'Inventory', 'DriftCheck', 'Snapshot', 'Compliance', 'Harden', 'Remediate', 'Aggregate', 'Compare', 'Export', 'Trend', 'CertCheck', 'ReportHTML', 'ListeningPorts', 'SoftwareList', 'Uptime', 'ServiceAudit', 'EventAudit', 'NetInfo', 'ScheduledExport', 'ValidateConfig', 'Watch', 'Query', 'Diff', 'Baseline', 'Alert', 'FleetScan', 'PatchStatus', 'UserAudit', 'FirewallAudit', 'TaskAudit', 'DiskAudit', 'TLSAudit', 'SMBAudit', 'DriverAudit', 'TimeAudit', 'BootAudit', 'GPOAudit', 'MemoryAudit', 'ProcessAudit', 'BackupAudit', 'ShareAudit', 'DNSAudit', 'PowerAudit', 'RegistryAudit', 'ProfileAudit', 'HyperVAudit', 'NetworkAudit', 'StorageAudit', 'FeatureAudit', 'AutoStartAudit', 'BIOSAudit', 'ClusterAudit', 'AuditPolicyAudit', 'EnvAudit', 'CrashAudit', 'LocalGroupAudit', 'WMIAudit', 'TempAudit', 'UpdatePolicyAudit', 'IISAudit', 'SSHAudit', 'BitLockerAudit', 'PrintAudit', 'CredGuardAudit', 'PortAudit', 'AntivirusAudit', 'DotNetAudit', 'RDPAudit', 'VPNAudit', 'HostsFileAudit', 'NetStatAudit', 'LicenseAudit', 'USBDeviceAudit', 'AppLockerAudit', 'EventSubAudit', 'HotfixAudit', 'SysInfoAudit', 'LogonAudit', 'ACLAudit', 'RecoveryAudit', 'ServiceAccountAudit', 'ProxyAudit', 'PendingRebootAudit', 'PageFileAudit', 'CPUAudit', 'DefenderExclusionAudit', 'KerberosAudit', 'DHCPAudit', 'NUMAAudit', 'SymlinkAudit', 'StartupScriptAudit', 'SecureChannelAudit', 'ComObjectAudit', 'FirewallLogAudit', 'ScheduledRebootAudit', 'PowerShellAudit', 'RouteTableAudit', 'TokenPrivilegeAudit', 'WindowsCapabilityAudit', 'ARPTableAudit', 'LocaleAudit', 'TaskHistoryAudit', 'NTFSAudit', 'Win11Cleanup', 'DarkMode', 'LightMode', 'iSCSIAudit', 'NICTeamAudit', 'SMBSessionAudit', 'WindowsUpdateAudit', 'ClusterQuorumAudit', 'S2DAudit', 'VirtualSwitchAudit', 'MPIOPathAudit', 'ServiceRecoveryAudit', 'VMOvercommitAudit', 'DedupAudit', 'ClusterNetworkAudit', 'ReplicaLagAudit', 'HandleLeakAudit', 'ShadowCopyAudit', 'QoSPolicyAudit', 'LiveMigrationAudit', 'DomainTrustAudit', 'DiskLatencyAudit', 'NICOffloadAudit', 'StorageTimeoutAudit', 'EventLogCapacityAudit', 'TcpSettingsAudit', 'WinRMAudit', 'ClusterHealthScore', 'VMInventoryExport', 'VMSnapshotAudit', 'StorageHealthScore', 'CSVSpaceAudit', 'SMBConnectionAudit', 'VolumeLabelAudit', 'NICErrorAudit', 'VMResourceWaste', 'HealthDashboard', 'SCCMClientAudit', 'SCOMAgentAudit', 'WACConnectivityAudit', 'AzureADAudit', 'ServerScore', 'FleetReport', 'PasswordPolicy', 'FirewallRuleAudit', 'GPResultAudit', 'DNSCacheAudit', 'TPMAudit', 'SecureBootAudit', 'TimeSkewAudit', 'NetworkProfileAudit', 'InsecureServiceAudit', 'SelfTest', 'CheckForUpdate', 'ExportLogs', 'UpdateSelf', 'Rollback', 'ScheduleUpdateCheck', 'Dashboard', 'History', 'Replay', 'AzureArcEnroll', 'DefenderEndpointOnboard', 'WSUSSetup', 'ADCSSetup', 'StorageMigrationSetup', 'GPOBackup', 'GPODrift', 'JEAList', 'NPSSetup', 'AlwaysOnVPNSetup', 'CISScan', 'SIEMSetup', 'SIEMStatus', 'WACSetup', 'WACStatus', 'VHDXEncryptionAudit', 'ADRecycleBin', 'ClusterValidationReport')] [string]$Action, [ValidateSet('Light', 'Standard', 'Aggressive')] diff --git a/Modules/00-Initialization.ps1 b/Modules/00-Initialization.ps1 index 514b839..839f9aa 100644 --- a/Modules/00-Initialization.ps1 +++ b/Modules/00-Initialization.ps1 @@ -225,7 +225,7 @@ if (-not $PSCommandPath -and $script:ScriptPath) { if (-not $script:ModuleRoot -and $script:ScriptPath) { $script:ModuleRoot = [System.IO.Path]::GetDirectoryName($script:ScriptPath) } -$script:ScriptVersion = "1.110.0" +$script:ScriptVersion = "1.111.0" $script:ScriptStartTime = Get-Date # Post-update cleanup: UpdateSelf / Rollback leave a `.pending-delete` sibling next to RackStack.exe. diff --git a/Modules/27-FailoverClustering.ps1 b/Modules/27-FailoverClustering.ps1 index cdfcedb..77752e1 100644 --- a/Modules/27-FailoverClustering.ps1 +++ b/Modules/27-FailoverClustering.ps1 @@ -1354,4 +1354,78 @@ function Test-ClusterQuorumHealth { Write-PressEnter } + +# CLI: ClusterValidationReport — run a non-disruptive cluster validation +# headlessly, archive the HTML report to the hardened state dir, and report a +# best-effort overall result. Read-only (validation makes no changes). The HTML +# report is the authoritative artifact; the tally is a best-effort scan. +function Start-ClusterValidationReport { + $jsonOut = ($script:CLIOutputFormat -eq 'JSON') + if (-not (Test-FailoverClusteringInstalled)) { + if ($jsonOut) { Write-Output (@{ Tool = $script:ToolFullName; Version = $script:ScriptVersion; Action = 'ClusterValidationReport'; Hostname = $env:COMPUTERNAME; Available = $false } | ConvertTo-Json) } + else { Write-OutputColor " Failover Clustering is not installed." -color "Error" } + return $false + } + # Validate the existing cluster's nodes if clustered, else this node. + $nodes = @($env:COMPUTERNAME) + try { + if (Get-Command -Name Get-Cluster -ErrorAction SilentlyContinue) { + if (Get-Cluster -ErrorAction SilentlyContinue) { + $cn = @(Get-ClusterNode -ErrorAction SilentlyContinue | ForEach-Object { "$($_.Name)" }) + if ($cn.Count -gt 0) { $nodes = $cn } + } + } + } + catch { } + + $secureDir = Get-RackStackSecureStateDir + if ([string]::IsNullOrWhiteSpace($secureDir)) { $secureDir = $script:TempPath } + $reportDir = Join-Path $secureDir "ClusterValidation" + if (-not (Test-Path -LiteralPath $reportDir)) { $null = New-Item -LiteralPath $reportDir -ItemType Directory -Force -ErrorAction SilentlyContinue } + $base = Join-Path $reportDir "ClusterValidation_$(Get-Date -Format 'yyyyMMdd-HHmmss')" + + if (-not $jsonOut) { + Clear-Host + Write-CenteredOutput "Cluster Validation Report" -color "Info" + Write-OutputColor " Validating: $($nodes -join ', ') (non-disruptive: Inventory + Network + System Config)" -color "Info" + Write-OutputColor " This may take a few minutes..." -color "Info" + } + + $reportFile = "$base.htm"; $failed = 0; $warned = 0; $overall = 'Unknown' + try { + # Non-disruptive categories only — storage/Hyper-V tests can disrupt and + # need shared storage / offline VMs; those stay in the interactive validator. + $r = Test-Cluster -Node $nodes -Include 'Inventory', 'Network', 'System Configuration' -ReportName $base -ErrorAction Stop + if ($r -and $r.FullName) { $reportFile = "$($r.FullName)" } + if (Test-Path -LiteralPath $reportFile) { + $html = Get-Content -LiteralPath $reportFile -Raw -ErrorAction SilentlyContinue + $failed = @([regex]::Matches($html, '>\s*Failed\s*<')).Count + $warned = @([regex]::Matches($html, '>\s*Warning\s*<')).Count + $overall = if ($failed -gt 0) { 'Failed' } elseif ($warned -gt 0) { 'Warning' } else { 'Pass' } + } + else { $overall = 'Completed' } + } + catch { + $overall = 'Error' + if (-not $jsonOut) { Write-OutputColor " Validation error: $($_.Exception.Message)" -color "Error" } + } + + if ($jsonOut) { + Write-Output (@{ + Tool = $script:ToolFullName; Version = $script:ScriptVersion; Action = 'ClusterValidationReport' + Timestamp = (Get-Date -Format "yyyy-MM-ddTHH:mm:ss"); Hostname = $env:COMPUTERNAME + Available = $true; Nodes = $nodes; OverallResult = $overall + FailedCount = $failed; WarningCount = $warned; ReportPath = $reportFile + } | ConvertTo-Json) + } + else { + $c = switch ($overall) { 'Pass' { 'Success' } 'Warning' { 'Warning' } default { 'Error' } } + Write-OutputColor "" -color "Info" + Write-OutputColor " Overall result: $overall (failed: $failed, warnings: $warned)" -color $c + Write-OutputColor " Report: $reportFile" -color "Info" + Write-OutputColor " The HTML report is authoritative — open it for per-test detail." -color "Debug" + Add-SessionChange -Category "Cluster" -Description "Ran cluster validation report ($overall)" + } + return ($overall -ne 'Error') +} #endregion diff --git a/Modules/34-Help.ps1 b/Modules/34-Help.ps1 index b1a469e..b4a3d7b 100644 --- a/Modules/34-Help.ps1 +++ b/Modules/34-Help.ps1 @@ -253,7 +253,7 @@ function Search-HelpTopics { @{ Title = "Performance"; Keywords = @("performance", "cpu", "memory", "disk", "io", "bandwidth", "dashboard", "process"); Description = "Live performance dashboard with CPU, memory, disk I/O, and network bandwidth monitoring" } @{ Title = "Licensing & NTP"; Keywords = @("license", "activation", "kms", "avma", "ntp", "time", "timezone", "clock"); Description = "Windows licensing status (KMS/AVMA/Retail), NTP configuration, time sync, and timezone setup" } @{ Title = "VM Management"; Keywords = @("checkpoint", "snapshot", "export", "import", "migration", "vhd", "iso"); Description = "VM checkpoints, export/import, migration readiness, VHD health, and ISO inventory" } - @{ Title = "CLI Actions"; Keywords = @("cli", "action", "headless", "automation", "fleet", "json", "audit", "scan", "score", "dashboard", "monitor", "policy", "sla", "netmap", "validate"); Description = "193 CLI actions for headless automation. Run -ListActions to see all. JSON output via -OutputFormat JSON. Key: ServerScore, HealthDashboard, FleetReport, CISScan, NPSSetup, AlwaysOnVPNSetup, SIEMStatus." } + @{ Title = "CLI Actions"; Keywords = @("cli", "action", "headless", "automation", "fleet", "json", "audit", "scan", "score", "dashboard", "monitor", "policy", "sla", "netmap", "validate"); Description = "194 CLI actions for headless automation. Run -ListActions to see all. JSON output via -OutputFormat JSON. Key: ServerScore, HealthDashboard, FleetReport, CISScan, NPSSetup, AlwaysOnVPNSetup, SIEMStatus." } @{ Title = "SelfTest Action"; Keywords = @("selftest", "self-test", "diagnose", "diagnostic", "verify", "healthcheck", "sanity"); Description = "Internal diagnostic. -Action SelfTest checks PS version, elevation, module count, version consistency, defaults.json validity, temp path writability, FileServer reachability, and agent installer config. Exit 1 on any failure. Use -OutputFormat JSON for structured output." } @{ Title = "Security Audits"; Keywords = @("security", "audit", "hardening", "compliance", "tls", "smb", "kerberos", "credguard", "applocker", "bitlockeraudit", "defenderexclusionaudit", "audit-policy", "secureboot", "tpm"); Description = "Security-focused CLI audits: TLSAudit, SMBAudit, KerberosAudit, CredGuardAudit, AppLockerAudit, BitLockerAudit, DefenderExclusionAudit, AuditPolicyAudit, SecureBootAudit, TPMAudit, UserAudit, LogonAudit, InsecureServiceAudit, RegistryAudit. All support -OutputFormat JSON." } @{ Title = "Network Audits"; Keywords = @("netaudit", "dns", "firewall-audit", "firewalllog", "arp", "route", "tcp", "netstat", "dhcp", "netprofile", "winrm", "qos", "nicoffload"); Description = "Network audits: DNSAudit, DNSCacheAudit, FirewallAudit, FirewallRuleAudit, FirewallLogAudit, ARPTableAudit, RouteTableAudit, TcpSettingsAudit, NetStatAudit, DHCPAudit, NetworkProfileAudit, WinRMAudit, QoSPolicyAudit, NICOffloadAudit, NICErrorAudit, HostsFileAudit, VPNAudit, ProxyAudit." } diff --git a/Modules/50-EntryPoint.ps1 b/Modules/50-EntryPoint.ps1 index 8b9a636..1690054 100644 --- a/Modules/50-EntryPoint.ps1 +++ b/Modules/50-EntryPoint.ps1 @@ -411,6 +411,7 @@ function Assert-Elevation { @{ Action = 'WACStatus'; Description = 'Show Windows Admin Center gateway status (service, port, listening)' } @{ Action = 'VHDXEncryptionAudit'; Description = 'Read-only: report whether each VM virtual disk sits on a BitLocker-protected volume' } @{ Action = 'ADRecycleBin'; Description = 'Show AD Recycle Bin status (JSON) or enable it interactively (irreversible)' } + @{ Action = 'ClusterValidationReport'; Description = 'Run a non-disruptive failover-cluster validation and archive the HTML report (JSON-aware)' } @{ Action = 'Batch'; Description = 'JSON-driven full configuration' } ) if ($script:CLIOutputFormat -eq 'JSON') { @@ -2053,6 +2054,11 @@ footer{text-align:center;color:#999;font-size:12px;padding:16px} $adrbOk = Start-ADRecycleBin [Environment]::Exit([int](-not $adrbOk)) } + 'ClusterValidationReport' { + # Non-disruptive cluster validation + archived HTML report (JSON-aware). + $cvrOk = Start-ClusterValidationReport + [Environment]::Exit([int](-not $cvrOk)) + } 'Batch' { if (-not $script:CLIConfig) { Write-OutputColor " ERROR: -Action Batch requires -Config " -color "Error" diff --git a/README.md b/README.md index ac22b6d..1beabbf 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ OpenSSF Best Practices codecov PSScriptAnalyzer 0 errors - 5040 structural tests + 5045 structural tests Pester 312 tests SLSA Level 3

@@ -37,7 +37,7 @@ --- -RackStack is a menu-driven PowerShell tool that automates everything between "Windows is installed" and "server is in production." Where sconfig gives you 15 options, RackStack gives you 193 CLI actions and 60+ interactive menus covering networking, Hyper-V, SAN/iSCSI, clustering, VM deployment, cloud onboarding, and batch automation, all with undo, transaction rollback, and audit logging. +RackStack is a menu-driven PowerShell tool that automates everything between "Windows is installed" and "server is in production." Where sconfig gives you 15 options, RackStack gives you 194 CLI actions and 60+ interactive menus covering networking, Hyper-V, SAN/iSCSI, clustering, VM deployment, cloud onboarding, and batch automation, all with undo, transaction rollback, and audit logging. Built for MSPs, sysadmins, and infrastructure teams who build servers repeatedly and want it done right every time. @@ -61,7 +61,7 @@ Built for MSPs, sysadmins, and infrastructure teams who build servers repeatedly **Automation** -- JSON-driven batch mode (24 idempotent steps with transaction rollback), Quick Setup Wizard, configuration export/import, HTML reports, JSON audit logging with rotation -**Monitoring** -- 193 CLI actions with JSON output for fleet automation, `ServerScore` (unified 0-100 health grade), `HealthDashboard` (all-in-one monitoring endpoint), `ClusterHealthScore`, `StorageHealthScore`, System Center (SCCM/SCOM/WAC) + Azure AD/Intune integration +**Monitoring** -- 194 CLI actions with JSON output for fleet automation, `ServerScore` (unified 0-100 health grade), `HealthDashboard` (all-in-one monitoring endpoint), `ClusterHealthScore`, `StorageHealthScore`, System Center (SCCM/SCOM/WAC) + Azure AD/Intune integration **Cloud & Security** -- Azure Arc server onboarding (install the Connected Machine Agent, connect the host to Azure's hybrid management plane via service-principal auth); Microsoft Defender for Endpoint onboarding (activate the built-in EDR sensor against your tenant, with a built-in detection test) @@ -439,7 +439,7 @@ $report.Issues **Tiers:** `Light` (minimal, safe for prod), `Standard` (recommended), `Aggressive` (maximum cleanup/debloat). -### 193 CLI Actions +### 194 CLI Actions | Category | Actions | |----------|---------| @@ -487,7 +487,7 @@ RackStack/ │ ├── ... # 75 more modules │ └── 77-WindowsAdminCenter.ps1 ├── Tests/ -│ ├── Run-Tests.ps1 # 5,040 automated tests +│ ├── Run-Tests.ps1 # 5,045 automated tests │ ├── Validate-Release.ps1 # Pre-release validation suite │ └── ... └── docs/ @@ -525,7 +525,7 @@ RackStack/ ## Testing ```powershell -# Full test suite (5,040 tests, ~4 minutes) +# Full test suite (5,045 tests, ~4 minutes) powershell -ExecutionPolicy Bypass -File Tests\Run-Tests.ps1 # PSScriptAnalyzer (0 errors on all 78 modules + monolithic) diff --git a/RackStack.ps1 b/RackStack.ps1 index 1411ebc..3f194a7 100644 --- a/RackStack.ps1 +++ b/RackStack.ps1 @@ -13,7 +13,7 @@ Environment-specific settings are configured via defaults.json. .VERSION - 1.110.0 + 1.111.0 .NOTES - Requires Windows Server 2012 R2 or later (or Windows 10/11 for testing) diff --git a/RackStack.psd1 b/RackStack.psd1 index 74d06ad..2b2eb87 100644 --- a/RackStack.psd1 +++ b/RackStack.psd1 @@ -1,6 +1,6 @@ @{ RootModule = 'RackStack.psm1' - ModuleVersion = '1.110.0' + ModuleVersion = '1.111.0' GUID = 'c19b8e71-4a35-4f2b-9d06-8a24f7bc0e91' Author = 'TheAbider' CompanyName = 'TheAbider' diff --git a/Tests/Run-Tests.ps1 b/Tests/Run-Tests.ps1 index 912b8dd..683b203 100644 --- a/Tests/Run-Tests.ps1 +++ b/Tests/Run-Tests.ps1 @@ -9068,6 +9068,27 @@ catch { Write-TestResult "AD Recycle Bin Tests" $false $_.Exception.Message } +# ============================================================================ +# SECTION 178: CLUSTER VALIDATION REPORT (v1.111.0, addition to 27-FailoverClustering) +# ============================================================================ +Write-SectionHeader "SECTION 178: CLUSTER VALIDATION REPORT (27-FailoverClustering)" + +try { + $fcC = Get-Content "$modulesPath\27-FailoverClustering.ps1" -Raw + Write-TestResult "27-Cluster: Start-ClusterValidationReport exists" ($fcC -match 'function\s+Start-ClusterValidationReport\b') + # Non-disruptive: only the safe Inventory/Network/System categories headlessly. + Write-TestResult "27-Cluster: validation report uses non-disruptive categories" ($fcC -match "Test-Cluster -Node[\s\S]{0,80}-Include 'Inventory', 'Network', 'System Configuration'") + # Report archived to the hardened state dir. + Write-TestResult "27-Cluster: validation report uses hardened state dir" ($fcC -match 'Start-ClusterValidationReport[\s\S]{0,1500}Get-RackStackSecureStateDir') + $cvrEntry = Get-Content "$modulesPath\50-EntryPoint.ps1" -Raw + Write-TestResult "50-EntryPoint: ClusterValidationReport dispatch case" ($cvrEntry -match "'ClusterValidationReport'\s*\{") + $cvrHeader = Get-Content (Join-Path $script:ModuleRoot "Header.ps1") -Raw + Write-TestResult "Header.ps1: ClusterValidationReport in -Action ValidateSet" ($cvrHeader -match "'ClusterValidationReport'") +} +catch { + Write-TestResult "Cluster Validation Report Tests" $false $_.Exception.Message +} + # ============================================================================ # SECTION 174: DOCUMENTATION FRESHNESS (counts must match the codebase) # ============================================================================ @@ -13079,7 +13100,7 @@ try { # Action list in -ListActions block has 160 entries $listBlock = [regex]::Match($ep5, '\$actionList = @\([\s\S]*?\)[\s\S]{0,50}CLIOutputFormat').Value $listActionCount = @([regex]::Matches($listBlock, "Action\s*=\s*'")).Count - Write-TestResult "50-EntryPoint: action list has 193 entries" ($listActionCount -eq 193) "Found $listActionCount" + Write-TestResult "50-EntryPoint: action list has 194 entries" ($listActionCount -eq 194) "Found $listActionCount" } catch { Write-TestResult "v1.91.0 Tests" $false $_.Exception.Message } @@ -13112,7 +13133,7 @@ try { # Action list count (should be 167 now) $listBlock2 = [regex]::Match($ep6, '\$actionList = @\([\s\S]*?\)[\s\S]{0,50}CLIOutputFormat').Value $actionCount2 = @([regex]::Matches($listBlock2, "Action\s*=\s*'")).Count - Write-TestResult "50-EntryPoint: action list has 193 entries" ($actionCount2 -eq 193) "Found $actionCount2" + Write-TestResult "50-EntryPoint: action list has 194 entries" ($actionCount2 -eq 194) "Found $actionCount2" } catch { Write-TestResult "v1.92.0 Tests" $false $_.Exception.Message } @@ -13138,7 +13159,7 @@ try { # Action count updated $listBlock3 = [regex]::Match($ep7, '\$actionList = @\([\s\S]*?\)[\s\S]{0,50}CLIOutputFormat').Value $actionCount3 = @([regex]::Matches($listBlock3, "Action\s*=\s*'")).Count - Write-TestResult "50-EntryPoint: action list has 193 entries" ($actionCount3 -eq 193) "Found $actionCount3" + Write-TestResult "50-EntryPoint: action list has 194 entries" ($actionCount3 -eq 194) "Found $actionCount3" } catch { Write-TestResult "v1.93.0 Tests" $false $_.Exception.Message } @@ -13176,7 +13197,7 @@ try { # Action list count $listBlock4 = [regex]::Match($ep8, '\$actionList = @\([\s\S]*?\)[\s\S]{0,50}CLIOutputFormat').Value $actionCount4 = @([regex]::Matches($listBlock4, "Action\s*=\s*'")).Count - Write-TestResult "50-EntryPoint: action list has 193 entries" ($actionCount4 -eq 193) "Found $actionCount4" + Write-TestResult "50-EntryPoint: action list has 194 entries" ($actionCount4 -eq 194) "Found $actionCount4" } catch { Write-TestResult "v1.94.1 Tests" $false $_.Exception.Message } diff --git a/dist/chocolatey/rackstack.nuspec b/dist/chocolatey/rackstack.nuspec index 3339524..697eba2 100644 --- a/dist/chocolatey/rackstack.nuspec +++ b/dist/chocolatey/rackstack.nuspec @@ -18,7 +18,7 @@ windows-server hyper-v iscsi clustering powershell sysadmin automation msp admin-tools PowerShell automation toolkit for configuring Windows Server hosts -RackStack is a menu-driven PowerShell tool that automates everything between "Windows is installed" and "server is in production." 193 CLI actions and 60+ interactive menus covering networking, Hyper-V, SAN/iSCSI, clustering, VM deployment, and batch automation, all with undo, transaction rollback, and audit logging. +RackStack is a menu-driven PowerShell tool that automates everything between "Windows is installed" and "server is in production." 194 CLI actions and 60+ interactive menus covering networking, Hyper-V, SAN/iSCSI, clustering, VM deployment, and batch automation, all with undo, transaction rollback, and audit logging. Built for MSPs, sysadmins, and infrastructure teams who build servers repeatedly and want it done right every time. diff --git a/dist/scoop/rackstack.json b/dist/scoop/rackstack.json index 639712f..e000861 100644 --- a/dist/scoop/rackstack.json +++ b/dist/scoop/rackstack.json @@ -1,7 +1,7 @@ { "$schema": "https://raw.githubusercontent.com/ScoopInstaller/Scoop/master/schema.json", "version": "0.0.0", - "description": "PowerShell automation toolkit for configuring Windows Server hosts — Hyper-V virtualization hosts, failover cluster nodes, iSCSI storage clients, Active Directory members, and standalone servers. Ships as a code-signed EXE plus a PowerShell Gallery wrapper module exposing 193 structured CLI actions.", + "description": "PowerShell automation toolkit for configuring Windows Server hosts — Hyper-V virtualization hosts, failover cluster nodes, iSCSI storage clients, Active Directory members, and standalone servers. Ships as a code-signed EXE plus a PowerShell Gallery wrapper module exposing 194 structured CLI actions.", "homepage": "https://github.com/TheAbider/RackStack", "license": "MIT", "url": "https://github.com/TheAbider/RackStack/releases/download/v0.0.0/RackStack.exe", diff --git a/dist/winget/1.99.1/TheAbider.RackStack.locale.en-US.yaml b/dist/winget/1.99.1/TheAbider.RackStack.locale.en-US.yaml index dee1fe9..d52876b 100644 --- a/dist/winget/1.99.1/TheAbider.RackStack.locale.en-US.yaml +++ b/dist/winget/1.99.1/TheAbider.RackStack.locale.en-US.yaml @@ -13,7 +13,7 @@ Copyright: Copyright (c) 2026 TheAbider ShortDescription: PowerShell automation toolkit for configuring Windows Server hosts. Description: |- RackStack is a menu-driven PowerShell tool that automates everything between - "Windows is installed" and "server is in production." It provides 193 CLI + "Windows is installed" and "server is in production." It provides 194 CLI actions and 60+ interactive menus covering networking, Hyper-V, SAN/iSCSI, clustering, VM deployment, cloud onboarding, and batch automation, all with undo, transaction rollback, and audit logging. Built for MSPs, sysadmins,