Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
# Changelog

## v1.121.7

Active Directory — the new-forest wizard now catches two problems up front instead of failing partway through promotion.

- **Invalid NetBIOS name is caught before you start.** If the domain name's first label is longer than 15 characters, the wizard now tells you immediately (before asking for the DSRM password) instead of failing several minutes into the promotion.
- **Wrong starting state is caught up front.** Creating a new forest requires a standalone (workgroup) server; if the machine is already joined to a domain, the wizard now says so and points you to "Add Domain Controller" instead of failing during promotion.

(A deep audit of the AD module confirmed its security-critical parts — DSRM password handling, credentials, and promotion parameters — are already correct; these were the only two gaps.)

No module or CLI action changes (81 modules, 201 actions).

## v1.121.6

Failover Clustering safety — fixes found by a deep audit of the clustering module.
Expand Down
2 changes: 1 addition & 1 deletion Header.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
7h3 4b1d3r

.VERSION
1.121.6
1.121.7
.LAST UPDATED
07/01/2026

Expand Down
2 changes: 1 addition & 1 deletion Modules/00-Initialization.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,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.121.6"
$script:ScriptVersion = "1.121.7"
$script:ScriptStartTime = Get-Date

# Post-update cleanup: UpdateSelf / Rollback leave a `.pending-delete` sibling next to RackStack.exe.
Expand Down
29 changes: 29 additions & 0 deletions Modules/61-ActiveDirectory.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -769,6 +769,23 @@ function Install-NewForest {
return
}

# New-forest-only guard: Install-ADDSForest requires a STANDALONE (workgroup) server. A
# domain-joined member (DomainRole 1 = member workstation, 3 = member server) cannot create a
# new forest — catch it now, before the domain prompt and DSRM password entry, instead of
# failing minutes into promotion. Scoped HERE, not in the shared Test-ADDSPrerequisites (which
# Add-DC / RODC reuse, where a member server is the valid starting state).
try {
$newForestCompSys = Get-CimInstance -ClassName Win32_ComputerSystem -OperationTimeoutSec 8 -ErrorAction Stop
if ($newForestCompSys.DomainRole -in @(1, 3)) {
Write-OutputColor "" -color "Error"
Write-OutputColor " This server is joined to an existing domain ('$($newForestCompSys.Domain)')." -color "Error"
Write-OutputColor " A NEW forest must be created on a standalone (workgroup) server." -color "Error"
Write-OutputColor " To add a DC to the existing domain, use 'Add Domain Controller' instead." -color "Warning"
Write-PressEnter
return
}
} catch { }

# Step 3: Domain name
Write-OutputColor "" -color "Info"
$domainName = Read-Host " Enter domain name (e.g., corp.contoso.com)"
Expand All @@ -789,6 +806,18 @@ function Install-NewForest {

$netbiosName = Get-NetBIOSNameFromFQDN -DomainName $domainName

# Install-ADDSForest enforces a 15-character NetBIOS limit and fails several minutes into
# promotion (after the DSRM password has already been entered). Validate the derived NetBIOS
# name now so the operator can fix the domain name before committing anything.
if ($netbiosName.Length -gt 15) {
Write-OutputColor "" -color "Error"
Write-OutputColor " The NetBIOS name derived from '$domainName' is '$netbiosName' ($($netbiosName.Length) chars)." -color "Error"
Write-OutputColor " NetBIOS names must be 15 characters or fewer — use a domain whose first label" -color "Error"
Write-OutputColor " is 15 characters or fewer (e.g. 'corp.$domainName'), then retry." -color "Warning"
Write-PressEnter
return
}

# Step 4: Functional level
$level = Select-FunctionalLevel
if ($null -eq $level) { return }
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
<a href="https://www.bestpractices.dev/projects/12921"><img alt="OpenSSF Best Practices" src="https://www.bestpractices.dev/projects/12921/badge"></a>
<a href="https://codecov.io/gh/TheAbider/RackStack"><img alt="codecov" src="https://codecov.io/gh/TheAbider/RackStack/branch/master/graph/badge.svg"></a>
<img alt="PSScriptAnalyzer 0 errors" src="https://img.shields.io/badge/PSScriptAnalyzer-0%20errors-brightgreen">
<img alt="5279 structural tests" src="https://img.shields.io/badge/structural%20tests-5279-brightgreen">
<img alt="5284 structural tests" src="https://img.shields.io/badge/structural%20tests-5284-brightgreen">
<img alt="Pester 312 tests" src="https://img.shields.io/badge/Pester-312%20tests-brightgreen">
<img alt="SLSA Level 3" src="https://slsa.dev/images/gh-badge-level3.svg">
</p>
Expand Down
2 changes: 1 addition & 1 deletion RackStack.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
Environment-specific settings are configured via defaults.json.

.VERSION
1.121.6
1.121.7
.NOTES
- Requires Windows Server 2012 R2 or later (or Windows 10/11 for testing)
- Must be run as Administrator
Expand Down
2 changes: 1 addition & 1 deletion RackStack.psd1
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
@{
RootModule = 'RackStack.psm1'
ModuleVersion = '1.121.6'
ModuleVersion = '1.121.7'
GUID = 'c19b8e71-4a35-4f2b-9d06-8a24f7bc0e91'
Author = 'TheAbider'
CompanyName = 'TheAbider'
Expand Down
27 changes: 26 additions & 1 deletion Tests/Run-Tests.ps1
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<#
.SYNOPSIS
Automated Test Runner for RackStack v1.121.6
Automated Test Runner for RackStack v1.121.7

.DESCRIPTION
Comprehensive non-interactive test suite covering:
Expand Down Expand Up @@ -9779,6 +9779,31 @@ catch {
Write-TestResult "Failover Clustering Safety Tests" $false $_.Exception.Message
}

# ============================================================================
# SECTION 194: NEW-FOREST PRE-PROMOTION VALIDATION (v1.121.7)
# ============================================================================
# Guards the two new-forest input-validation fixes: fail fast on an invalid NetBIOS name and on a
# domain-joined member server, BEFORE the DSRM password is collected.
Write-SectionHeader "SECTION 194: NEW-FOREST PRE-PROMOTION VALIDATION"

try {
$adR = Get-Content "$modulesPath\61-ActiveDirectory.ps1" -Raw

# NetBIOS length validation happens in Install-NewForest, BEFORE Read-DSRMPassword.
Write-TestResult "61-AD: new forest validates NetBIOS length" ($adR -match '\$netbiosName\.Length -gt 15')
Write-TestResult "61-AD: NetBIOS check precedes DSRM password prompt" ($adR -match '\$netbiosName\.Length -gt 15[\s\S]{0,1200}Read-DSRMPassword')

# New-forest-only member-server guard (scoped locally, not in the shared prereq check).
Write-TestResult "61-AD: new forest rejects domain-joined member server" ($adR -match 'DomainRole -in @\(1, 3\)[\s\S]{0,300}standalone \(workgroup\)')
Write-TestResult "61-AD: member-server guard is new-forest-scoped (shared prereq unchanged)" ($adR -match 'function Test-ADDSPrerequisites[\s\S]{0,4000}DomainRole[\s\S]{0,60}-ge 4')

# Regression guard: the shared prereq still uses -ge 4 (so Add-DC / RODC keep working on members).
Write-TestResult "61-AD: shared prereq still uses -ge 4 (not -ge 3)" (-not ($adR -match 'function Test-ADDSPrerequisites[\s\S]{0,4000}DomainRole[\s\S]{0,40}-ge 3'))
}
catch {
Write-TestResult "New-Forest Validation Tests" $false $_.Exception.Message
}

# ============================================================================
# SECTION 174: DOCUMENTATION FRESHNESS (counts must match the codebase)
# ============================================================================
Expand Down
Loading