From 0beeb85cddc23ce7d0bcef282ac57a4255298538 Mon Sep 17 00:00:00 2001 From: TheAbider <51920546+TheAbider@users.noreply.github.com> Date: Fri, 29 May 2026 15:19:59 -0700 Subject: [PATCH] Add VHDX encryption-at-rest audit (BitLocker) New read-only check in BitLocker Management ([7] VHDX Encryption-at-Rest Audit) and via the VHDXEncryptionAudit CLI action: report whether each Hyper-V VM's virtual disk (VHD/VHDX) sits on a BitLocker-protected volume. Enumerates the virtual disks attached to the host's VMs, resolves the volume each lives on, and reports encrypted / unencrypted / unknown per disk plus a summary. Volumes BitLocker can't enumerate (CSV / UNC / remote) are reported as "unknown", not guessed. JSON-aware for fleet auditing. Makes no changes. Addition to 31-BitLocker (no new module). CLI actions 191 -> 192; README / Help / dist counts updated in lockstep (doc-freshness guard). 5032 tests, 0 failures; PSScriptAnalyzer clean. --- CONTRIBUTING.md | 2 +- Changelog.md | 6 ++ Header.ps1 | 4 +- Modules/00-Initialization.ps1 | 2 +- Modules/31-BitLocker.ps1 | 73 ++++++++++++++++++- Modules/34-Help.ps1 | 2 +- Modules/50-EntryPoint.ps1 | 6 ++ README.md | 12 +-- RackStack.ps1 | 2 +- RackStack.psd1 | 2 +- Tests/Run-Tests.ps1 | 32 ++++++-- dist/chocolatey/rackstack.nuspec | 2 +- dist/scoop/rackstack.json | 2 +- .../TheAbider.RackStack.locale.en-US.yaml | 2 +- 14 files changed, 127 insertions(+), 22 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 27f938b..3178dff 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -30,7 +30,7 @@ powershell -ExecutionPolicy Bypass -File Tests\pssa-check.ps1 ## Pull Request Checklist -- [ ] All 5,025 tests pass (`Run-Tests.ps1` exits with code 0) +- [ ] All 5,032 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 824d199..2851e0a 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,5 +1,11 @@ # Changelog +## v1.109.0 + +VHDX encryption-at-rest verification — added to **BitLocker Management** (`[7] VHDX Encryption-at-Rest Audit`) and via the `VHDXEncryptionAudit` CLI action. A **read-only** check that reports whether each Hyper-V VM's virtual disk (VHD/VHDX) sits on a BitLocker-protected volume — so you can confirm VM storage is encrypted at rest. + +It enumerates the virtual disks attached to the host's VMs, resolves the volume each one lives on, and reports **encrypted / unencrypted / unknown** per disk plus a summary count. Volumes that BitLocker can't enumerate (Cluster Shared Volumes, UNC, remote storage) are reported as "unknown" rather than guessed. `-Action VHDXEncryptionAudit -OutputFormat JSON` emits the per-disk result for fleet auditing. Makes no changes. + ## v1.108.0 Windows Admin Center — new module (77-WindowsAdminCenter.ps1), reachable from **Roles & Features → [13] Windows Admin Center (WAC)** and via the `WACSetup` / `WACStatus` CLI actions. Installs and configures the WAC gateway on this host. diff --git a/Header.ps1 b/Header.ps1 index ce09a70..99932c0 100644 --- a/Header.ps1 +++ b/Header.ps1 @@ -30,7 +30,7 @@ 7h3 4b1d3r .VERSION - 1.108.0 + 1.109.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')] + [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')] [string]$Action, [ValidateSet('Light', 'Standard', 'Aggressive')] diff --git a/Modules/00-Initialization.ps1 b/Modules/00-Initialization.ps1 index 5e6f97d..8d35193 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.108.0" +$script:ScriptVersion = "1.109.0" $script:ScriptStartTime = Get-Date # Post-update cleanup: UpdateSelf / Rollback leave a `.pending-delete` sibling next to RackStack.exe. diff --git a/Modules/31-BitLocker.ps1 b/Modules/31-BitLocker.ps1 index e0cb9ae..09e9c95 100644 --- a/Modules/31-BitLocker.ps1 +++ b/Modules/31-BitLocker.ps1 @@ -178,6 +178,7 @@ function Show-BitLockerManagement { Write-MenuItem -Text "[4] Show Recovery Key" Write-MenuItem -Text "[5] Check Encryption Progress" Write-MenuItem -Text "[6] Verify Recovery Key Backup" + Write-MenuItem -Text "[7] VHDX Encryption-at-Rest Audit" Write-OutputColor " └────────────────────────────────────────────────────────────────────────┘" -color "Info" Write-OutputColor "" -color "Info" Write-OutputColor " [B] ◄ Back" -color "Info" @@ -492,11 +493,81 @@ function Show-BitLockerManagement { Write-OutputColor "" -color "Info" Test-BitLockerRecoveryBackup } + "7" { Show-VHDXEncryptionAudit } { $_ -eq "b" -or $_ -eq "B" } { return } - default { Write-OutputColor " Invalid choice. Enter 1-6 or B." -color "Error"; Start-Sleep -Seconds 1 } + default { Write-OutputColor " Invalid choice. Enter 1-7 or B." -color "Error"; Start-Sleep -Seconds 1 } } Write-PressEnter } } + +# Read-only encryption-at-rest verification: report whether each VHD/VHDX +# backing a Hyper-V VM sits on a BitLocker-protected volume. No changes made. +function Get-VHDXEncryptionStatus { + $paths = New-Object System.Collections.Generic.List[string] + try { + if (Get-Command -Name Get-VM -ErrorAction SilentlyContinue) { + foreach ($d in (Get-VM -ErrorAction SilentlyContinue | Get-VMHardDiskDrive -ErrorAction SilentlyContinue)) { + if (-not [string]::IsNullOrWhiteSpace($d.Path)) { $paths.Add($d.Path) } + } + } + } + catch { } + $unique = @($paths | Sort-Object -Unique) + # Cache volume -> protection status from BitLocker once. + $blByMount = @{} + try { foreach ($v in (Get-BitLockerVolume -ErrorAction SilentlyContinue)) { $blByMount["$($v.MountPoint)"] = "$($v.ProtectionStatus)" } } catch { } + $results = @() + foreach ($p in $unique) { + $root = $null + try { $root = ([System.IO.Path]::GetPathRoot($p)).TrimEnd('\') } catch { } + $prot = if ($root -and $blByMount.ContainsKey($root)) { $blByMount[$root] } else { "Unknown" } + $results += [PSCustomObject]@{ + Path = $p; Volume = $root; Protection = $prot; Encrypted = ($prot -eq 'On') + } + } + return $results +} + +# Interactive display of the VHDX encryption-at-rest audit. +function Show-VHDXEncryptionAudit { + Clear-Host + Write-CenteredOutput "VHDX Encryption-at-Rest Audit" -color "Info" + if ($null -eq (Get-Command -Name Get-BitLockerVolume -ErrorAction SilentlyContinue)) { + Write-OutputColor " BitLocker is not available on this system." -color "Warning"; return + } + $r = @(Get-VHDXEncryptionStatus) + if ($r.Count -eq 0) { + Write-OutputColor " No VHD/VHDX virtual disks found (no Hyper-V VMs, or none attached)." -color "Info"; return + } + Write-OutputColor "" -color "Info" + foreach ($item in $r) { + $label = if ($item.Encrypted) { "ENCRYPTED" } elseif ($item.Protection -eq 'Off') { "UNENCRYPTED" } else { "UNKNOWN" } + $c = if ($item.Encrypted) { "Success" } elseif ($item.Protection -eq 'Off') { "Error" } else { "Warning" } + Write-OutputColor (" [{0}] {1}" -f $label, $item.Path) -color $c + Write-OutputColor (" volume: $(if ($item.Volume) { $item.Volume } else { 'unresolved (CSV/UNC/remote)' })") -color "Debug" + } + $enc = @($r | Where-Object { $_.Encrypted }).Count + Write-OutputColor "" -color "Info" + Write-OutputColor " $enc of $($r.Count) virtual disk(s) sit on BitLocker-protected volumes." -color "Info" + Write-OutputColor " 'Unknown' volumes (CSV / UNC / remote storage) are not enumerable by Get-BitLockerVolume." -color "Debug" +} + +# CLI entry: VHDXEncryptionAudit — read-only, JSON-aware. +function Start-VHDXEncryptionAudit { + $r = @(Get-VHDXEncryptionStatus) + if ($script:CLIOutputFormat -eq 'JSON') { + Write-Output (@{ + Tool = $script:ToolFullName; Version = $script:ScriptVersion; Action = 'VHDXEncryptionAudit' + Timestamp = (Get-Date -Format "yyyy-MM-ddTHH:mm:ss"); Hostname = $env:COMPUTERNAME + TotalDisks = $r.Count; EncryptedDisks = @($r | Where-Object { $_.Encrypted }).Count + Disks = @($r | ForEach-Object { @{ Path = $_.Path; Volume = $_.Volume; Protection = $_.Protection; Encrypted = $_.Encrypted } }) + } | ConvertTo-Json -Depth 5) + } + else { + Show-VHDXEncryptionAudit + } + return $true +} #endregion \ No newline at end of file diff --git a/Modules/34-Help.ps1 b/Modules/34-Help.ps1 index 490c740..f18b7b3 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 = "191 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 = "192 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 708b19f..f1c1d55 100644 --- a/Modules/50-EntryPoint.ps1 +++ b/Modules/50-EntryPoint.ps1 @@ -409,6 +409,7 @@ function Assert-Elevation { @{ Action = 'SIEMStatus'; Description = 'Show SIEM log-forwarder readiness (WEF / WinRM / agents / Arc)' } @{ Action = 'WACSetup'; Description = 'Install + configure the Windows Admin Center gateway (verified MSI, port, certificate)' } @{ 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 = 'Batch'; Description = 'JSON-driven full configuration' } ) if ($script:CLIOutputFormat -eq 'JSON') { @@ -2041,6 +2042,11 @@ footer{text-align:center;color:#999;font-size:12px;padding:16px} $wacOk = Start-WACSetup [Environment]::Exit([int](-not $wacOk)) } + 'VHDXEncryptionAudit' { + # Read-only: which VM virtual disks sit on BitLocker-protected volumes (JSON-aware). + $vhdxOk = Start-VHDXEncryptionAudit + [Environment]::Exit([int](-not $vhdxOk)) + } 'Batch' { if (-not $script:CLIConfig) { Write-OutputColor " ERROR: -Action Batch requires -Config " -color "Error" diff --git a/README.md b/README.md index 4feb343..fac6c91 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ OpenSSF Best Practices codecov PSScriptAnalyzer 0 errors - 5025 structural tests + 5032 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 191 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 192 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** -- 191 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** -- 192 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). -### 191 CLI Actions +### 192 CLI Actions | Category | Actions | |----------|---------| @@ -487,7 +487,7 @@ RackStack/ │ ├── ... # 75 more modules │ └── 77-WindowsAdminCenter.ps1 ├── Tests/ -│ ├── Run-Tests.ps1 # 5,025 automated tests +│ ├── Run-Tests.ps1 # 5,032 automated tests │ ├── Validate-Release.ps1 # Pre-release validation suite │ └── ... └── docs/ @@ -525,7 +525,7 @@ RackStack/ ## Testing ```powershell -# Full test suite (5,025 tests, ~4 minutes) +# Full test suite (5,032 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 b37577a..92a450e 100644 --- a/RackStack.ps1 +++ b/RackStack.ps1 @@ -13,7 +13,7 @@ Environment-specific settings are configured via defaults.json. .VERSION - 1.108.0 + 1.109.0 .NOTES - Requires Windows Server 2012 R2 or later (or Windows 10/11 for testing) diff --git a/RackStack.psd1 b/RackStack.psd1 index b0e8cb0..437f641 100644 --- a/RackStack.psd1 +++ b/RackStack.psd1 @@ -1,6 +1,6 @@ @{ RootModule = 'RackStack.psm1' - ModuleVersion = '1.108.0' + ModuleVersion = '1.109.0' GUID = 'c19b8e71-4a35-4f2b-9d06-8a24f7bc0e91' Author = 'TheAbider' CompanyName = 'TheAbider' diff --git a/Tests/Run-Tests.ps1 b/Tests/Run-Tests.ps1 index a9f8fe1..471e0e0 100644 --- a/Tests/Run-Tests.ps1 +++ b/Tests/Run-Tests.ps1 @@ -9023,6 +9023,28 @@ catch { Write-TestResult "Windows Admin Center Tests" $false $_.Exception.Message } +# ============================================================================ +# SECTION 176: VHDX ENCRYPTION-AT-REST AUDIT (v1.109.0, addition to 31-BitLocker) +# ============================================================================ +Write-SectionHeader "SECTION 176: VHDX ENCRYPTION-AT-REST AUDIT (31-BitLocker)" + +try { + $blC = Get-Content "$modulesPath\31-BitLocker.ps1" -Raw + Write-TestResult "31-BitLocker: Get-VHDXEncryptionStatus exists" ($blC -match 'function\s+Get-VHDXEncryptionStatus\b') + Write-TestResult "31-BitLocker: Start-VHDXEncryptionAudit exists" ($blC -match 'function\s+Start-VHDXEncryptionAudit\b') + Write-TestResult "31-BitLocker: Show-VHDXEncryptionAudit exists" ($blC -match 'function\s+Show-VHDXEncryptionAudit\b') + # Read-only: the audit path must not mutate (no Enable-BitLocker / Set- / Remove-). + Write-TestResult "31-BitLocker: VHDX audit is read-only" (-not ($blC -match 'function\s+Get-VHDXEncryptionStatus[\s\S]{0,800}(Enable-BitLocker|Set-ItemProperty|Remove-Item)')) + $vhdxEntry = Get-Content "$modulesPath\50-EntryPoint.ps1" -Raw + Write-TestResult "50-EntryPoint: VHDXEncryptionAudit dispatch case" ($vhdxEntry -match "'VHDXEncryptionAudit'\s*\{") + $vhdxHeader = Get-Content (Join-Path $script:ModuleRoot "Header.ps1") -Raw + Write-TestResult "Header.ps1: VHDXEncryptionAudit in -Action ValidateSet" ($vhdxHeader -match "'VHDXEncryptionAudit'") + Write-TestResult "31-BitLocker: menu routes [7] to Show-VHDXEncryptionAudit" ($blC -match '"7"\s*\{\s*Show-VHDXEncryptionAudit') +} +catch { + Write-TestResult "VHDX Encryption Audit Tests" $false $_.Exception.Message +} + # ============================================================================ # SECTION 174: DOCUMENTATION FRESHNESS (counts must match the codebase) # ============================================================================ @@ -9303,7 +9325,7 @@ Write-TestResult "31-BitLocker: decrypt volume nav check" ($blContent -match 'nu # All bare "Enter volume number" Read-Hosts (options 3,4) should have nav checks $blBareVolNum = ([regex]::Matches($blContent, 'Read-Host " Enter volume number"\s+\$navResult')).Count Write-TestResult "31-BitLocker: bare volume number nav checks ($blBareVolNum/2)" ($blBareVolNum -ge 2) -Write-TestResult "31-BitLocker: specific invalid msg" ($blContent -match 'Enter 1-6 or B') +Write-TestResult "31-BitLocker: specific invalid msg" ($blContent -match 'Enter 1-7 or B') # Deduplication sub-prompt nav checks $ddContent = Get-Content -LiteralPath "$modulesPath\32-Deduplication.ps1" -Raw @@ -13034,7 +13056,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 191 entries" ($listActionCount -eq 191) "Found $listActionCount" + Write-TestResult "50-EntryPoint: action list has 192 entries" ($listActionCount -eq 192) "Found $listActionCount" } catch { Write-TestResult "v1.91.0 Tests" $false $_.Exception.Message } @@ -13067,7 +13089,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 191 entries" ($actionCount2 -eq 191) "Found $actionCount2" + Write-TestResult "50-EntryPoint: action list has 192 entries" ($actionCount2 -eq 192) "Found $actionCount2" } catch { Write-TestResult "v1.92.0 Tests" $false $_.Exception.Message } @@ -13093,7 +13115,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 191 entries" ($actionCount3 -eq 191) "Found $actionCount3" + Write-TestResult "50-EntryPoint: action list has 192 entries" ($actionCount3 -eq 192) "Found $actionCount3" } catch { Write-TestResult "v1.93.0 Tests" $false $_.Exception.Message } @@ -13131,7 +13153,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 191 entries" ($actionCount4 -eq 191) "Found $actionCount4" + Write-TestResult "50-EntryPoint: action list has 192 entries" ($actionCount4 -eq 192) "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 6d70e03..222a123 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." 191 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." 192 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 5a1f1ca..4ae3c3f 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 191 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 192 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 a24cc85..e85a82f 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 191 CLI + "Windows is installed" and "server is in production." It provides 192 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,