|
| 1 | +function Deploy-AGInfrastructure { |
| 2 | + <# |
| 3 | + TODO: Create 'PAW' as a Custom Role that includes RSAT. |
| 4 | + TODO: Accept Roles as Parameter. |
| 5 | + #> |
| 6 | + |
| 7 | + [CmdletBinding()] |
| 8 | + param ( |
| 9 | + [PsfValidatePattern('^\w{1,11}$', ErrorMessage = 'Lab name must be no longer than 11 characters and only contain letters and numbers.')] |
| 10 | + $Name = 'Locksmith', |
| 11 | + [PsfValidatePattern('\.', ErrorMessage = 'Domain must contain at least one dot.')] |
| 12 | + $Domain = 'adcs.goat', |
| 13 | + $ExternalSwitch = 'External Switch', |
| 14 | + $Sources = (Get-LabSourcesLocation), |
| 15 | + $LabsRoot = "$((Get-PSFConfig -Module AutomatedLab -Name LabAppDataRoot).Value)\Labs", # Not currently needed, but I like it., |
| 16 | + [switch]$Confirm |
| 17 | + ) |
| 18 | + |
| 19 | + <# |
| 20 | + #requires -Modules Hyper-V, AutomatedLab -Version 7 -RunAsAdministrator |
| 21 | + #> |
| 22 | + |
| 23 | + Write-Verbose -Message @" |
| 24 | +
|
| 25 | +---------------------------------------------------- |
| 26 | +| Initial Configuration | |
| 27 | +---------------------------------------------------- |
| 28 | +
|
| 29 | +Name = $Name |
| 30 | +Domain = $Domain |
| 31 | +ExternalSwitch = $ExternalSwitch |
| 32 | +Sources = $Sources |
| 33 | +LabRoot = $LabsRoot |
| 34 | +"@ |
| 35 | + |
| 36 | + # Confirm lab name is unique on this host. |
| 37 | + while ((Get-Lab -List) -contains $Name) { |
| 38 | + Write-Host |
| 39 | + Write-Warning -Message "A lab named `"$Name`" already exists on this host." |
| 40 | + Write-Host "Please select a new lab name: " -NoNewline |
| 41 | + $Name = Read-Host |
| 42 | + } |
| 43 | + |
| 44 | + # Import existing labs and add their domains to an array. |
| 45 | + Write-Host "`nImporting existing labs to confirm the new root domain name `"$Domain`" is unique." |
| 46 | + $ExistingDomains = Get-Lab -List | ForEach-Object { |
| 47 | + Import-Lab -Name $_ |
| 48 | + Get-LabVM | Select-Object DomainName |
| 49 | + } |
| 50 | + |
| 51 | + $ExistingDomains = $ExistingDomains | Sort-Object -Property DomainName -Unique |
| 52 | + if ($ExistingDomains) { Write-Verbose "Existing Domains: $($ExistingDomains.DomainName)" } |
| 53 | + |
| 54 | + # Confirm root domain name is unique on this host. |
| 55 | + while ($ExistingDomains.DomainName -contains $Domain) { |
| 56 | + Write-Host |
| 57 | + Write-Warning -Message "A lab using the domain `"$Domain`" already exists on this host." |
| 58 | + Write-Host "Please select a new root domain name: " -NoNewline |
| 59 | + $Domain = Read-Host |
| 60 | + } |
| 61 | + |
| 62 | + # Create a Hyper-V External Switch if none exists. |
| 63 | + while (-not (Get-VMSwitch | Where-Object Name -EQ $ExternalSwitch)) { |
| 64 | + #region Select NetAdapter for Use in Lab |
| 65 | + $netIPAddressCollection = Get-NetIPAddress | Where-Object { |
| 66 | + $_.IPAddress -notmatch '^169.254|^127.0.0' -and |
| 67 | + $_.InterfaceAlias -notmatch 'VMware' -and |
| 68 | + $_.AddressFamily -eq 'IPv4' -and |
| 69 | + $_.PrefixLength -eq 24 -and |
| 70 | + $_.PrefixOrigin -eq 'Dhcp' |
| 71 | + } |
| 72 | + |
| 73 | + Write-Host @" |
| 74 | +This script is designed to use a single network adapter with the following configuration: |
| 75 | +
|
| 76 | +- has an IPv4 address |
| 77 | +- does not have an IP address in a link-local block |
| 78 | +- is configured for DHCP |
| 79 | +- has a subnet mask of /24 |
| 80 | +
|
| 81 | +Only network adapters meeting this configuration are shown below. |
| 82 | +
|
| 83 | +Select the network adapter you'd like to use in your lab. |
| 84 | +"@ |
| 85 | + |
| 86 | + # Enumerate network adapters on the host. |
| 87 | + $i = 0 |
| 88 | + $netIPAddressCollection | ForEach-Object { |
| 89 | + $i++ |
| 90 | + Write-Host " ${i}: $($_.InterfaceAlias) ($($_.IPAddress))" |
| 91 | + } |
| 92 | + [int]$adapterIndex = Read-Host -Prompt "Please enter a number `[1-$i`]" |
| 93 | + |
| 94 | + $adapterIndex = $adapterIndex - 1 |
| 95 | + |
| 96 | + $NetAdapterName = $netIPAddressCollection[$($adapterIndex)].InterfaceAlias |
| 97 | + #endregion Select NetAdapter for Use in Lab |
| 98 | + |
| 99 | + # Create a new External Switch named $ExternalSwitch aka 'vEthernet ($ExternalSwitch)' |
| 100 | + try { |
| 101 | + New-VMSwitch -Name $ExternalSwitch -NetAdapterName $NetAdapterName -ErrorAction Stop |
| 102 | + Start-Sleep -Seconds 5 |
| 103 | + } catch { |
| 104 | + throw $_ |
| 105 | + } |
| 106 | + } |
| 107 | + |
| 108 | + # Get IP Address of External Switch |
| 109 | + [string]$NetAdapterIP = (Get-NetIPConfiguration -InterfaceAlias "vEthernet ($ExternalSwitch)").IPv4Address |
| 110 | + |
| 111 | + # Create required addresses |
| 112 | + if ($NetAdapterIP -match '(?:\d{1,3}\.){3}') { |
| 113 | + $BaseAddress = $matches[0] |
| 114 | + $NetworkAddress = $BaseAddress + '0' |
| 115 | + $Gateway = $BaseAddress + '1' |
| 116 | + } |
| 117 | + |
| 118 | + # Get IP Address of other machines in subnet |
| 119 | + $ExistingIPs = Get-VM | |
| 120 | + Where-Object State -EQ Running | |
| 121 | + Select-Object -ExpandProperty NetworkAdapters | |
| 122 | + Select-Object -ExpandProperty IPAddresses | |
| 123 | + ForEach-Object { |
| 124 | + if ($_ -match '(?:\d{1,3}\.){3}') { $_ } |
| 125 | + } |
| 126 | + |
| 127 | + # Pick IP Addresses for new VMs |
| 128 | + $NewIPs = @{} |
| 129 | + $Roles = @('DC', 'CA', 'PAW') |
| 130 | + $RoleIndex = 0 |
| 131 | + |
| 132 | + for ($i = 3; $i -lt 255 -and $RoleIndex -lt $Roles.Count; $i++) { |
| 133 | + $CandidateIP = "$BaseAddress$i" |
| 134 | + if ($ExistingIPs -notcontains $CandidateIP) { |
| 135 | + $NewIPs[$Roles[$RoleIndex]] = $CandidateIP |
| 136 | + $RoleIndex++ |
| 137 | + } |
| 138 | + } |
| 139 | + |
| 140 | + # Create IPs for each role. |
| 141 | + $Roles | ForEach-Object { |
| 142 | + New-Variable -Name "${_}IP" -Value $NewIPs[$_] |
| 143 | + } |
| 144 | + |
| 145 | + if (-not $Confirm) { |
| 146 | + Write-PSFHostColor @" |
| 147 | +---------------------------------------------------- |
| 148 | +| Lab Configuration | |
| 149 | +---------------------------------------------------- |
| 150 | +Name: <c='em'>$Name</c> |
| 151 | +Root Domain: <c='em'>$Domain</c> |
| 152 | +Network Address: <c='em'>$NetworkAddress</c> |
| 153 | +Gateway: <c='em'>$Gateway</c> |
| 154 | +Domain Controller IP: <c='em'>$DCIP</c> |
| 155 | +Certification Authority IP: <c='em'>$CAIP</c> |
| 156 | +Privileged Access Workstation IP: <c='em'>$PAWIP</c> |
| 157 | +"@ |
| 158 | + |
| 159 | + $Answer = Get-PSFUserChoice -Caption 'Continue with deployment?' -Options Yes, No |
| 160 | + |
| 161 | + if ($Answer -eq 1) { exit } |
| 162 | + } |
| 163 | + |
| 164 | + # Define the lab + hypervisor |
| 165 | + New-LabDefinition -Name $Name -DefaultVirtualizationEngine HyperV |
| 166 | + |
| 167 | + # Use existing External Switch created or discovered above |
| 168 | + Add-LabVirtualNetworkDefinition -Name $ExternalSwitch -AddressSpace "$NetAdapterIP/24" |
| 169 | + |
| 170 | + # Set default parameters for all machines in the lab |
| 171 | + $PSDefaultParameterValues = @{ |
| 172 | + 'Add-LabMachineDefinition:Network' = $ExternalSwitch |
| 173 | + 'Add-LabMachineDefinition:ToolsPath' = "$Sources\Tools" |
| 174 | + 'Add-LabMachineDefinition:MinMemory' = 512MB |
| 175 | + 'Add-LabMachineDefinition:Memory' = 1GB |
| 176 | + 'Add-LabMachineDefinition:MaxMemory' = 4GB |
| 177 | + 'Add-LabMachineDefinition:Processors' = 2 |
| 178 | + 'Add-LabMachineDefinition:DomainName' = $Domain |
| 179 | + 'Add-LabMachineDefinition:Gateway' = $Gateway |
| 180 | + 'Add-LabMachineDefinition:DnsServer1' = $DCIP |
| 181 | + 'Add-LabMachineDefinition:OperatingSystem' = 'Windows Server 2022 Datacenter (Desktop Experience)' |
| 182 | + } |
| 183 | + |
| 184 | + Add-LabMachineDefinition -Name "$Name-DC" -Roles RootDC -IpAddress $DCIP |
| 185 | + Add-LabMachineDefinition -Name "$Name-CA" -Roles CaRoot -IpAddress $CAIP |
| 186 | + Add-LabMachineDefinition -Name "$Name-PAW" -IpAddress $PAWIP |
| 187 | + |
| 188 | + Install-Lab |
| 189 | + |
| 190 | + Install-LabWindowsFeature -FeatureName RSAT -ComputerName "$Name-PAW" -IncludeAllSubFeature |
| 191 | + |
| 192 | + Show-LabDeploymentSummary |
| 193 | +} |
0 commit comments