Add Setup-HyperVHost-Standalone-v3.ps1 script#2
Add Setup-HyperVHost-Standalone-v3.ps1 script#2AlrightLad wants to merge 2 commits intoDTC-Inc:mainfrom
Conversation
Here's an extended description for your GitHub PR: Hyper-V Host Setup Script v3.4 - MSP RMM Template Overview A comprehensive, production-ready PowerShell script for automated Hyper-V host deployment in MSP environments. Designed for both RMM-driven unattended execution and interactive technician-led installations, this script transforms a bare Windows Server into a fully configured Hyper-V host with standardized naming, storage layout, network teaming, and security hardening. Key Features Dual-Mode Operation RMM Mode ($RMM=1): Fully non-interactive deployment with pre-configured variables, automatic reboots, and detailed logging for remote management platforms Interactive Mode: Guided setup with prompts for technicians performing manual deployments Intelligent Reboot Handling Two-phase architecture separates reboot-requiring operations (Phase 1) from configuration tasks (Phase 2) Script is re-runnable and idempotent—safely re-execute after each reboot to continue setup Clear logging of pending reboot reasons with automatic or prompted restart options Dell Hardware Integration Auto-detects Dell servers and installs OpenManage Server Administrator, iDRAC Service Module, and Dell System Update Downloads from Backblaze B2 public repository with BITS transfer fallback Runs DSU post-install to apply firmware and driver updates Optional iDRAC root password configuration via RACADM RAID Configuration Validation Detects single virtual disk configurations where OS and data share the same RAID array Provides detailed remediation instructions specific to Dell PERC controllers Blocks unsafe configurations in RMM mode unless explicitly accepted ($AcceptRAIDWarning) Storage Automation Caps OS partition at 127GB and reclaims unallocated space for data volumes Auto-initializes and formats additional data disks with standardized naming (ers-ssd-01, rrs-hdd-02, etc.) Configures Hyper-V default paths on data drives Supports multiple redundancy naming conventions (ers/rrs/zrs/grs) Network Teaming (SET) Creates Switch Embedded Teaming virtual switches with Dynamic load balancing Configurable NICs per team (2 or 4) with automatic PCIe slot grouping option Renames management vNICs for easy identification Security & Compliance BitLocker encryption with TPM protector and auto-generated recovery passwords Auto-unlock for data drives using TPM chain Recovery keys saved locally with clear operator instructions LocalAccountTokenFilterPolicy enabled for admin share access in workgroup scenarios Windows Configuration Hyper-V role with all management tools and PowerShell modules High Performance power plan RDP enabled with firewall rules Configurable time zone Server Manager auto-start disabled Registry backup enabled Application Deployment WinGet-based installation of Firefox, 7-Zip, Notepad++, and Windows Terminal Graceful fallback when WinGet unavailable Parameters ParameterTypeDefaultDescription$RMMInt0Set to 1 for non-interactive RMM execution$ServerSequenceStringRequiredServer number 01-99 (generates HV01, HV02, etc.)$SkipWindowsUpdateBoolfalseSkip Windows Update installation$SkipBitLockerBoolfalseSkip BitLocker configuration$SkipNetworkTeamingBoolfalseSkip SET team creation$TeamsOfInt2NICs per SET team (2 or 4)$AutoNICTeamingBoolfalseAuto-group NICs by PCIe slot$StorageRedundancyString"ers"Volume label prefix (ers/rrs/zrs/grs)$TimeZoneString"Eastern Standard Time"Target time zone$iDRACPasswordString""iDRAC root password (Dell only)$AcceptRAIDWarningBoolfalseBypass single RAID disk warning Requirements Windows Server 2019/2022/2025 PowerShell 5.1+ Administrator privileges TPM 2.0 (for BitLocker) Network connectivity for Dell tools and Windows Updates Typical Deployment Flow First Run: Renames computer, installs Hyper-V and Windows features → Reboot Second Run: Installs Dell tools (if applicable), runs Windows Updates → Reboot Third Run: Configures storage, networking, BitLocker, applications → Complete
|
Important Review skippedReview was skipped as selected files did not have any reviewable changes. 💤 Files selected but had no reviewable changes (1)
You can disable this status message by setting the
📝 WalkthroughWalkthroughReplaces interactive deploy.ps1 script with new comprehensive Setup-HyperVHost-Standalone-v3.ps1 that automates non-interactive Hyper-V host configuration. New script adds RMM/non-RMM modes, Dell tooling integration, phase-based execution with reboot orchestration, storage provisioning, network teaming, Windows settings tuning, and extensive logging throughout. Changes
Sequence DiagramsequenceDiagram
participant RMM as RMM/User Input
participant Phase1 as Phase 1:<br/>Reboot-Needed
participant Phase2 as Phase 2:<br/>No-Reboot Config
participant DellTools as Dell Tools<br/>(OpenManage/DSU)
participant WinUpdate as Windows Update
participant Storage as Storage<br/>Provisioning
participant Network as Network<br/>Teaming
participant Settings as System<br/>Settings
RMM->>Phase1: Input handling & defaults
Phase1->>Phase1: OS rename
Phase1->>Phase1: Hyper-V feature install
Phase1->>DellTools: Download OpenManage (BITS/MSI)
DellTools->>DellTools: Extract, validate, manage service
DellTools->>Phase1: Complete
Phase1->>DellTools: Execute DSU updates
DellTools->>Phase1: Exit code & reboot handling
Phase1->>WinUpdate: PSWindowsUpdate installation flow
WinUpdate->>Phase1: Complete
Phase1->>Phase1: Reboot Gate
Phase1->>Phase2: Post-reboot resume
Phase2->>Storage: RAID validation & remediation
Storage->>Storage: Provision volumes (resize, partition, format, letters)
Storage->>Phase2: Complete
Phase2->>Network: Optional teaming (auto/manual)
Network->>Phase2: SETx switches & NICs aggregation
Phase2->>Settings: Registry tuning (RDP, firewall, time zone, power plan)
Phase2->>Settings: Optional BitLocker (TPM recovery logging)
Phase2->>Phase2: WinGet app installation
Phase2->>Phase2: Final reporting & Next Steps
Estimated code review effort🎯 5 (Critical) | ⏱️ ~75 minutes
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 10
🤖 Fix all issues with AI agents
In `@Setup-HyperVHost-Standalone-v3.ps1`:
- Around line 380-388: The catch block for Rename-Computer currently logs the
error and only prompts when $RMM -ne 1, which causes silent continuation in RMM
mode; update the catch to handle $RMM -eq 1 by either calling throw or setting a
persistent failure flag so the script halts or reports at completion.
Specifically, inside the catch after Write-LogProgress, if ($RMM -eq 1) then
throw "Setup cancelled due to computer rename failure: $_" (or set a global flag
like $Script:RenameFailed = $true and ensure later code checks and aborts/report
based on that flag); keep the existing interactive Read-Host/throw behavior for
non-RMM ($RMM -ne 1).
- Around line 1600-1601: The script currently disables the Windows Firewall with
Set-NetFirewallProfile -Profile Domain, Public, Private -Enabled False and never
re-enables it; either remove that disable call or add a re-enable step before
the "Setup Complete" section (Phase 2 end) that calls Set-NetFirewallProfile
-Profile Domain, Public, Private -Enabled True and logs the action (e.g.,
Write-LogProgress "Re-enabling Windows Firewall..." "Info") so the firewall is
restored after setup.
- Around line 893-895: The script currently calls Add-RebootReason "Dell
OpenManage and Tools Installation" unconditionally; change this so the reboot
reason is only added when one or more Dell components were actually installed by
introducing and updating a boolean flag (e.g., $dellInstalled) or checking the
install result from the Dell install steps, and wrap the Add-RebootReason and
the Write-Host "Dell tools installed (MAY REQUIRE REBOOT)" call in a conditional
that runs only if that flag/result indicates an installation occurred (refer to
the existing Dell install block and the Add-RebootReason and Write-Host calls to
locate where to add the flag and conditional).
- Around line 1713-1717: The script currently writes BitLocker recovery files to
$recoveryKeyPath on the OS drive and then builds $recoveryFile, which risks
losing keys if the system is encrypted and also leaks the password to the
transcript; change the logic so that when creating the recovery output you (1)
prefer a configurable external location (network share or removable media) and
fall back to prompting the user if not provided, (2) if domain-joined call the
BitLocker backup routine to Active Directory instead of writing locally, and (3)
suppress the recovery password from the PowerShell transcript/console by
ensuring the code paths that produce the password (the code that assigns/outputs
the recovery password variable used to create $recoveryFile) use secure output
methods (e.g., write to a redirected file handle or SecureString) or explicitly
Stop-Transcript/Disable-Transcript around the sensitive write so the plaintext
password is not captured; update references to $recoveryKeyPath, $recoveryFile,
Test-Path and New-Item accordingly.
- Around line 1375-1378: The script currently computes $usedLetters from
Get-Partition which can miss network, CD-ROM, or other volume types; update both
occurrences (the block setting $usedLetters/$availableLetters/$driveLetter and
the same logic near line 1411) to gather used drive letters from Get-Volume (use
the DriveLetter property) and exclude volumes with DriveType values like CD-ROM,
Network, Removable or other non-fixed/system types before computing
$availableLetters from the pool ('D'..'H') and selecting $driveLetter; keep the
existing variable names ($usedLetters, $availableLetters, $driveLetter) so the
change is localized.
- Around line 898-904: The script uses the wrong DSU executable path; update the
$dsuPath assignment and any subsequent checks to match the installer
ValidatePath ("C:\Program Files\Dell\DELL System Update\DSU.exe") so
Test-Path($dsuPath), the Write-Host/Write-LogProgress messages, and the later
occurrence around the second check all reference the correct "C:\Program
Files\Dell\DELL System Update\DSU.exe" value (update the $dsuPath variable and
any uses of Test-Path or invocation that reference the old path).
- Around line 1011-1013: The Start-Process call that invokes RACADM with the
password in $iDRACPassword (see $setPasswordProcess, Start-Process, $racadmPath)
will be captured by Start-Transcript; to fix, temporarily suspend or stop the
transcript before invoking Start-Process and restart it afterward, or better:
write a temporary secure RACADM config file containing the password and call
RACADM with its file option (e.g., -f) instead of passing the password on the
command line, then securely remove the temp file (Remove-Item -Force)
immediately after use; update the block that constructs the RACADM invocation to
use one of these approaches and ensure no plaintext password appears in logged
arguments.
- Around line 1690-1692: The stray "continue" inside the BitLocker section is
outside any loop and must be replaced with valid control flow; locate the
BitLocker block containing the "continue" token and either (a) change it to
"return" if you intend to exit the script/function immediately, (b) introduce a
boolean flag (e.g., $skipBitLocker) that you set at that point and check later
before running the BitLocker logic, or (c) wrap the BitLocker logic in a do {
... } while ($false) so "continue" is valid — pick the approach consistent with
surrounding flow and update any subsequent checks to respect the new flag/return
or loop wrapper.
- Around line 1482-1483: The current one-liner unconditionally removes all
VMSwitches matching "SET*" which can disconnect running VMs; instead iterate
over the switches returned by Get-VMSwitch and for each switch (identify by
$_.Name) check for attached VMs/network adapters (e.g. via Get-VMNetworkAdapter
-SwitchName or equivalent); if no attachments remove it (Remove-VMSwitch
-Force), otherwise skip and emit a warning or prompt for confirmation before
removal so you don't destructively disconnect running VMs. Ensure you reference
the existing Get-VMSwitch, Where-Object, and Remove-VMSwitch calls when
implementing the loop and checks.
- Around line 267-272: The switch on $physicalDisk.MediaType currently maps
"SCM" to "nvme" which is incorrect; update the switch handling of
$physicalDisk.MediaType (the switch block that returns
"ssd"/"hdd"/"nvme"/default) so that the "SCM" case returns "scm" instead of
"nvme" (leave the "SSD" -> "ssd", "HDD" -> "hdd" and default behavior
unchanged).
🧹 Nitpick comments (2)
Setup-HyperVHost-Standalone-v3.ps1 (2)
121-122: Avoid shadowing PowerShell's automatic$inputvariable.The variable name
$inputshadows PowerShell's built-in automatic variable. While this works in most cases, it can cause unexpected behavior in certain pipeline scenarios. Consider using a more descriptive name like$userInputor$response.This same pattern appears on lines 134, 141, 146, and 157.
♻️ Suggested rename
- $input = Read-Host "Enter company name (default: DTC)" - if (![string]::IsNullOrEmpty($input)) { $CompanyName = $input } + $userInput = Read-Host "Enter company name (default: DTC)" + if (![string]::IsNullOrEmpty($userInput)) { $CompanyName = $userInput }
298-328: Consider caching PnP device lookup and using ArrayList for better performance.
Get-PnpDeviceis called inside the loop for each adapter, which is inefficient. Additionally, using+=with arrays in PowerShell creates a new array on each iteration.♻️ Suggested optimization
function Get-NICDetails { - $nicInfo = @() + $nicInfo = [System.Collections.ArrayList]::new() + + # Cache PnP devices outside the loop + $pnpDevices = Get-PnpDevice -ErrorAction SilentlyContinue Write-LogProgress "Enumerating network adapters..." "Debug" # ... adapter enumeration ... foreach ($adapter in $adapters) { - $pnpDevice = Get-PnpDevice -ErrorAction SilentlyContinue | Where-Object { $_.FriendlyName -eq $adapter.InterfaceDescription } + $pnpDevice = $pnpDevices | Where-Object { $_.FriendlyName -eq $adapter.InterfaceDescription } # ... rest of loop ... - $nicInfo += $nicDetail + [void]$nicInfo.Add($nicDetail) } return $nicInfo | Sort-Object PCIBus, PCIDevice, PCIFunction }
| switch ($physicalDisk.MediaType) { | ||
| "SSD" { return "ssd" } | ||
| "HDD" { return "hdd" } | ||
| "SCM" { return "nvme" } | ||
| default { return "hdd" } | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
PowerShell Get-PhysicalDisk MediaType values documentation
💡 Result:
Get-PhysicalDisk surfaces the MediaType from the underlying CIM/WMI class MSFT_PhysicalDisk.MediaType (a UInt16 enum). The documented values are: 0 = Unspecified, 3 = HDD, 4 = SSD, 5 = SCM (Storage Class Memory). [1]
Related PowerShell cmdlets that take a -MediaType parameter use the same enum (commonly shown as strings Unspecified/HDD/SSD/SCM in cmdlet help). For example, Set-PhysicalDisk -MediaType lists accepted values HDD, SSD, SCM [2], and Set-StoragePool -MediaTypeDefault includes Unspecified, HDD, SSD, SCM. [3]
Sources
[1] MSFT_PhysicalDisk class (MediaType values) https://learn.microsoft.com/en-us/windows-hardware/drivers/storage/msft-physicaldisk
[2] Set-PhysicalDisk (Storage) https://learn.microsoft.com/en-us/powershell/module/storage/set-physicaldisk?view=windowsserver2025-ps
[3] Set-StoragePool (Storage) https://learn.microsoft.com/en-us/powershell/module/storage/set-storagepool?view=windowsserver2025-ps
🌐 Web query:
Storage Class Memory SCM vs NVMe difference PowerShell
💡 Result:
SCM (Storage Class Memory) vs NVMe — what’s different?
- SCM / PMem (persistent memory, e.g., NVDIMM-N / Intel Optane PMem-era devices): a lower-latency storage class that can be presented to Windows as SCM/PMem and used in Windows storage stacks (including Storage Spaces Direct). It’s treated as a distinct drive type from NVMe/SSD/HDD in Microsoft guidance. [2]
- NVMe: a storage protocol/interface for SSDs on PCIe (U.2/AIC/M.2 form factors). It’s still block storage (SSD), generally higher latency than PMem/SCM but faster than SATA/SAS SSDs/HDDs. [2]
- In Storage Spaces Direct, Microsoft supports persistent memory (PMem) and NVMe as different device types. [2], [3]
PowerShell: how to tell SCM vs NVMe on Windows
1) Show BusType / MediaType
Get-PhysicalDisk |
Select FriendlyName, SerialNumber, BusType, MediaType, Size |
Sort BusType, FriendlyName2) List only SCM devices (Microsoft specifically documents BusType = "SCM")
Get-PhysicalDisk | Where-Object BusType -eq 'SCM' |
Select FriendlyName, SerialNumber, HealthStatus, OperationalStatus, OperationalDetails(From Microsoft’s SCM health management guidance.) [1]
3) List NVMe devices
Get-PhysicalDisk | Where-Object BusType -eq 'NVMe' |
Select FriendlyName, SerialNumber, MediaType, SizeImportant caveat: If your NVMe SSD is behind a RAID controller / vendor storage stack, BusType may show RAID instead of NVMe, so Get-PhysicalDisk won’t reliably identify it as NVMe in that configuration. [4]
Sources
[1] Microsoft Learn — Storage-class Memory (NVDIMM-N) Health Management in Windows (learn.microsoft.com)
[2] Microsoft Learn — Choose drives for Azure Local and Windows Server clusters (learn.microsoft.com)
[3] Microsoft Learn — Storage Spaces Direct overview (learn.microsoft.com)
[4] Stack Overflow — Windows API for identifying whether a drive is NVMe (BusType shows RAID) (stackoverflow.com)
Citations:
- 1: https://learn.microsoft.com/en-us/windows-server/storage/storage-spaces/storage-class-memory-health?utm_source=openai
- 2: https://learn.microsoft.com/windows-server/storage/storage-spaces/choose-drives?utm_source=openai
- 3: https://learn.microsoft.com/en-us/azure-stack/hci/concepts/storage-spaces-direct-overview?utm_source=openai
- 4: https://stackoverflow.com/questions/62950127/windows-api-for-identifying-whether-a-drive-is-nvme?utm_source=openai
Incorrect media type mapping: SCM should map to "scm", not "nvme".
Storage Class Memory (SCM) is a distinct technology (e.g., Intel Optane persistent memory) and should not be mapped to "nvme". According to PowerShell documentation, Get-PhysicalDisk.MediaType has four enum values: Unspecified, HDD, SSD, and SCM. There is no "NVMe" MediaType value — NVMe drives report as SSD with a separate BusType attribute. The correct fix maps SCM to its own label:
🔧 Proposed fix
switch ($physicalDisk.MediaType) {
"SSD" { return "ssd" }
"HDD" { return "hdd" }
- "SCM" { return "nvme" }
+ "SCM" { return "scm" }
default { return "hdd" }
}🤖 Prompt for AI Agents
In `@Setup-HyperVHost-Standalone-v3.ps1` around lines 267 - 272, The switch on
$physicalDisk.MediaType currently maps "SCM" to "nvme" which is incorrect;
update the switch handling of $physicalDisk.MediaType (the switch block that
returns "ssd"/"hdd"/"nvme"/default) so that the "SCM" case returns "scm" instead
of "nvme" (leave the "SSD" -> "ssd", "HDD" -> "hdd" and default behavior
unchanged).
| } catch { | ||
| Write-LogProgress "Failed to rename computer: $_" "Error" | ||
| if ($RMM -ne 1) { | ||
| $continue = Read-Host "Failed to rename computer. Continue anyway? (y/n)" | ||
| if ($continue -ne 'y') { | ||
| throw "Setup cancelled due to computer rename failure" | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
In RMM mode, computer rename failure is silently ignored.
When $RMM -eq 1, if Rename-Computer fails, the script logs the error but continues execution. This could result in the server running with an incorrect name while other configuration proceeds, leading to inconsistent state.
Consider exiting with an error in RMM mode when rename fails, or at minimum, setting a flag to warn at completion.
🐛 Proposed fix
} catch {
Write-LogProgress "Failed to rename computer: $_" "Error"
if ($RMM -ne 1) {
$continue = Read-Host "Failed to rename computer. Continue anyway? (y/n)"
if ($continue -ne 'y') {
throw "Setup cancelled due to computer rename failure"
}
+ } else {
+ Write-LogProgress "CRITICAL: Computer rename failed in RMM mode - exiting" "Error"
+ throw "Setup cancelled due to computer rename failure in RMM mode"
}
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| } catch { | |
| Write-LogProgress "Failed to rename computer: $_" "Error" | |
| if ($RMM -ne 1) { | |
| $continue = Read-Host "Failed to rename computer. Continue anyway? (y/n)" | |
| if ($continue -ne 'y') { | |
| throw "Setup cancelled due to computer rename failure" | |
| } | |
| } | |
| } | |
| } catch { | |
| Write-LogProgress "Failed to rename computer: $_" "Error" | |
| if ($RMM -ne 1) { | |
| $continue = Read-Host "Failed to rename computer. Continue anyway? (y/n)" | |
| if ($continue -ne 'y') { | |
| throw "Setup cancelled due to computer rename failure" | |
| } | |
| } else { | |
| Write-LogProgress "CRITICAL: Computer rename failed in RMM mode - exiting" "Error" | |
| throw "Setup cancelled due to computer rename failure in RMM mode" | |
| } | |
| } |
🤖 Prompt for AI Agents
In `@Setup-HyperVHost-Standalone-v3.ps1` around lines 380 - 388, The catch block
for Rename-Computer currently logs the error and only prompts when $RMM -ne 1,
which causes silent continuation in RMM mode; update the catch to handle $RMM
-eq 1 by either calling throw or setting a persistent failure flag so the script
halts or reports at completion. Specifically, inside the catch after
Write-LogProgress, if ($RMM -eq 1) then throw "Setup cancelled due to computer
rename failure: $_" (or set a global flag like $Script:RenameFailed = $true and
ensure later code checks and aborts/report based on that flag); keep the
existing interactive Read-Host/throw behavior for non-RMM ($RMM -ne 1).
| $recoveryKeyPath = "$env:SystemDrive\BitLocker-Recovery-Keys" | ||
| if (!(Test-Path $recoveryKeyPath)) { | ||
| New-Item -Path $recoveryKeyPath -ItemType Directory -Force | Out-Null | ||
| } | ||
| $recoveryFile = Join-Path $recoveryKeyPath "BitLocker-Recovery-Passwords-$(Get-Date -Format 'yyyy-MM-dd-HHmmss').txt" |
There was a problem hiding this comment.
BitLocker recovery passwords stored locally on the encrypted drive.
Recovery passwords are saved to C:\BitLocker-Recovery-Keys\, which is on the OS drive that's being encrypted. If BitLocker locks out the system, the recovery keys won't be accessible. Additionally, the recovery password is logged to the transcript at line 1757.
Consider:
- Storing keys to a network location or removable media
- Backing up to Active Directory (if domain-joined)
- Suppressing recovery password from transcript logs
🔒 Suggested improvements
+ # WARNING: Saving recovery key locally - ensure this is backed up externally!
+ Write-Host "IMPORTANT: Back up recovery keys to a secure external location!" -ForegroundColor Red
$recoveryKeyPath = "$env:SystemDrive\BitLocker-Recovery-Keys"For the transcript logging concern:
- Write-LogProgress " Recovery Password: $recoveryPassword" "Info"
+ Write-LogProgress " Recovery Password saved to file (not logged for security)" "Info"🤖 Prompt for AI Agents
In `@Setup-HyperVHost-Standalone-v3.ps1` around lines 1713 - 1717, The script
currently writes BitLocker recovery files to $recoveryKeyPath on the OS drive
and then builds $recoveryFile, which risks losing keys if the system is
encrypted and also leaks the password to the transcript; change the logic so
that when creating the recovery output you (1) prefer a configurable external
location (network share or removable media) and fall back to prompting the user
if not provided, (2) if domain-joined call the BitLocker backup routine to
Active Directory instead of writing locally, and (3) suppress the recovery
password from the PowerShell transcript/console by ensuring the code paths that
produce the password (the code that assigns/outputs the recovery password
variable used to create $recoveryFile) use secure output methods (e.g., write to
a redirected file handle or SecureString) or explicitly
Stop-Transcript/Disable-Transcript around the sensitive write so the plaintext
password is not captured; update references to $recoveryKeyPath, $recoveryFile,
Test-Path and New-Item accordingly.
Summary of changes pushed: All 10 CodeRabbit issues addressed Security hardening for firewall and credential handling Bug fixes for DSU path, BitLocker flow, and virtual switch management Code quality improvement (variable shadowing fix)
Here's an extended description for your GitHub PR:
Hyper-V Host Setup Script v3.4 - MSP RMM Template
Overview
A comprehensive, production-ready PowerShell script for automated Hyper-V host deployment in MSP environments. Designed for both RMM-driven unattended execution and interactive technician-led installations, this script transforms a bare Windows Server into a fully configured Hyper-V host with standardized naming, storage layout, network teaming, and security hardening. Key Features
Dual-Mode Operation
RMM Mode ($RMM=1): Fully non-interactive deployment with pre-configured variables, automatic reboots, and detailed logging for remote management platforms
Interactive Mode: Guided setup with prompts for technicians performing manual deployments
Intelligent Reboot Handling
Two-phase architecture separates reboot-requiring operations (Phase 1) from configuration tasks (Phase 2) Script is re-runnable and idempotent—safely re-execute after each reboot to continue setup Clear logging of pending reboot reasons with automatic or prompted restart options
Dell Hardware Integration
Auto-detects Dell servers and installs OpenManage Server Administrator, iDRAC Service Module, and Dell System Update Downloads from Backblaze B2 public repository with BITS transfer fallback Runs DSU post-install to apply firmware and driver updates Optional iDRAC root password configuration via RACADM
RAID Configuration Validation
Detects single virtual disk configurations where OS and data share the same RAID array Provides detailed remediation instructions specific to Dell PERC controllers Blocks unsafe configurations in RMM mode unless explicitly accepted ($AcceptRAIDWarning)
Storage Automation
Caps OS partition at 127GB and reclaims unallocated space for data volumes Auto-initializes and formats additional data disks with standardized naming (ers-ssd-01, rrs-hdd-02, etc.) Configures Hyper-V default paths on data drives
Supports multiple redundancy naming conventions (ers/rrs/zrs/grs)
Network Teaming (SET)
Creates Switch Embedded Teaming virtual switches with Dynamic load balancing Configurable NICs per team (2 or 4) with automatic PCIe slot grouping option Renames management vNICs for easy identification
Security & Compliance
BitLocker encryption with TPM protector and auto-generated recovery passwords Auto-unlock for data drives using TPM chain
Recovery keys saved locally with clear operator instructions LocalAccountTokenFilterPolicy enabled for admin share access in workgroup scenarios
Windows Configuration
Hyper-V role with all management tools and PowerShell modules High Performance power plan
RDP enabled with firewall rules
Configurable time zone
Server Manager auto-start disabled
Registry backup enabled
Application Deployment
WinGet-based installation of Firefox, 7-Zip, Notepad++, and Windows Terminal Graceful fallback when WinGet unavailable
Parameters
ParameterTypeDefaultDescription$RMMInt0Set to 1 for non-interactive RMM execution$ServerSequenceStringRequiredServer number 01-99 (generates HV01, HV02, etc.)$SkipWindowsUpdateBoolfalseSkip Windows Update installation$SkipBitLockerBoolfalseSkip BitLocker configuration$SkipNetworkTeamingBoolfalseSkip SET team creation$TeamsOfInt2NICs per SET team (2 or 4)$AutoNICTeamingBoolfalseAuto-group NICs by PCIe slot$StorageRedundancyString"ers"Volume label prefix (ers/rrs/zrs/grs)$TimeZoneString"Eastern Standard Time"Target time zone$iDRACPasswordString""iDRAC root password (Dell only)$AcceptRAIDWarningBoolfalseBypass single RAID disk warning Requirements
Windows Server 2019/2022/2025
PowerShell 5.1+
Administrator privileges
TPM 2.0 (for BitLocker)
Network connectivity for Dell tools and Windows Updates
Typical Deployment Flow
First Run: Renames computer, installs Hyper-V and Windows features → Reboot
Second Run: Installs Dell tools (if applicable), runs Windows Updates → Reboot
Third Run: Configures storage, networking, BitLocker, applications → Complete
Summary by CodeRabbit
New Features
Chores
✏️ Tip: You can customize this high-level summary in your review settings.