AutomatedLabRouting.psm1
#region Install-LabRouting function Install-LabRouting { [CmdletBinding()] param ( [int]$InstallationTimeout = 15, [ValidateRange(0, 300)] [int]$ProgressIndicator = (Get-LabConfigurationItem -Name DefaultProgressIndicator) ) Write-LogFunctionEntry if (-not $PSBoundParameters.ContainsKey('ProgressIndicator')) { $PSBoundParameters.Add('ProgressIndicator', $ProgressIndicator) } #enables progress indicator $roleName = [AutomatedLab.Roles]::Routing if (-not (Get-LabVM)) { Write-ScreenInfo -Message 'No machine definitions imported, so there is nothing to do. Please use Import-Lab first' -Type Warning Write-LogFunctionExit return } $machines = Get-LabVM -Role $roleName | Where-Object HostType -eq 'HyperV' if (-not $machines) { return } Write-ScreenInfo -Message 'Waiting for machines with Routing Role to startup' -NoNewline Start-LabVM -RoleName $roleName -Wait -ProgressIndicator 15 Write-ScreenInfo -Message 'Configuring Routing role...' -NoNewLine $jobs = Install-LabWindowsFeature -ComputerName $machines -FeatureName RSAT ,Routing, RSAT-RemoteAccess -IncludeAllSubFeature -NoDisplay -AsJob -PassThru Wait-LWLabJob -Job $jobs -ProgressIndicator 10 -Timeout 15 -NoDisplay -NoNewLine Restart-LabVM -ComputerName $machines -Wait -NoDisplay $jobs = @() foreach ($machine in $machines) { $externalAdapters = $machine.NetworkAdapters | Where-Object { $_.VirtualSwitch.SwitchType -eq 'External' } if ($externalAdapters.Count -gt 1) { Write-Error "Automatic configuration of routing can only be done if there is 0 or 1 network adapter connected to an external network switch. The machine '$machine' knows about $($externalAdapters.Count) externally connected adapters" continue } if ($externalAdapters) { $mac = $machine.NetworkAdapters | Where-Object { $_.VirtualSwitch.SwitchType -eq 'External' } | Select-Object -ExpandProperty MacAddress $mac = ($mac | Get-StringSection -SectionSize 2) -join ':' } $parameters = @{} $parameters.Add('ComputerName', $machine) $parameters.Add('ActivityName', 'ConfigurationRouting') $parameters.Add('Verbose', $VerbosePreference) $parameters.Add('Scriptblock', { $VerbosePreference = 'Continue' Write-Verbose 'Setting up routing...' Set-Service -Name RemoteAccess -StartupType Automatic Start-Service -Name RemoteAccess Write-Verbose '...done' if (-not $args[0]) { Write-Verbose 'No externally connected adapter available' return } Write-Verbose 'Setting up NAT...' $externalAdapter = Get-CimInstance -Class Win32_NetworkAdapter -Filter ('MACAddress = "{0}"' -f $args[0]) | Select-Object -ExpandProperty NetConnectionID netsh.exe routing ip nat install netsh.exe routing ip nat add interface $externalAdapter netsh.exe routing ip nat set interface $externalAdapter mode=full netsh.exe ras set conf confstate = enabled netsh.exe routing ip dnsproxy install Restart-Service -Name RemoteAccess Write-Verbose '...done' } ) $parameters.Add('ArgumentList', $mac) $jobs += Invoke-LabCommand @parameters -AsJob -PassThru -NoDisplay } if (Get-LabVM -Role RootDC) { Write-PSFMessage "This lab knows about an Active Directory, calling 'Set-LabADDNSServerForwarder'" Set-LabADDNSServerForwarder } Write-ScreenInfo -Message 'Waiting for configuration of routing to complete' -NoNewline Wait-LWLabJob -Job $jobs -ProgressIndicator 10 -Timeout $InstallationTimeout -NoDisplay -NoNewLine #to make sure the routing service works, restart the routers Write-PSFMessage "Restarting machines '$($machines -join ', ')'" Restart-LabVM -ComputerName $machines -Wait -NoNewLine Write-ProgressIndicatorEnd Write-LogFunctionExit } #endregion Install-LabRouting #region Set-LabADDNSServerForwarder function Set-LabADDNSServerForwarder { [CmdletBinding()] param ( ) Write-PSFMessage 'Setting DNS fowarder on all domain controllers in root domains' $rootDcs = Get-LabVM -Role RootDC $rootDomains = $rootDcs.DomainName $dcs = Get-LabVM -Role RootDC, DC | Where-Object DomainName -in $rootDomains $router = Get-LabVM -Role Routing Write-PSFMessage "Root DCs are '$dcs'" foreach ($dc in $dcs) { $gateway = if ($dc -eq $router) { Invoke-LabCommand -ActivityName 'Get default gateway' -ComputerName $dc -ScriptBlock { Get-CimInstance -Class Win32_NetworkAdapterConfiguration | Where-Object { $_.DefaultIPGateway } | Select-Object -ExpandProperty DefaultIPGateway | Select-Object -First 1 } -PassThru -NoDisplay } else { $netAdapter = $dc.NetworkAdapters | Where-Object Ipv4Gateway $netAdapter.Ipv4Gateway.AddressAsString } Write-PSFMessage "Read gateway '$gateway' from interface '$($netAdapter.InterfaceName)' on machine '$dc'" $defaultDnsForwarder1 = Get-LabConfigurationItem -Name DefaultDnsForwarder1 $defaultDnsForwarder2 = Get-LabConfigurationItem -Name DefaultDnsForwarder2 Invoke-LabCommand -ActivityName ResetDnsForwarder -ComputerName $dc -ScriptBlock { dnscmd /resetforwarders $args[0] $args[1] } -ArgumentList $defaultDnsForwarder1, $defaultDnsForwarder2 -AsJob -NoDisplay } } #endregion Set-LabADDNSServerForwarder #region Enable-LabInternalRouting function Enable-LabInternalRouting { [CmdletBinding()] param ( [Parameter(Mandatory)] [string] $RoutingNetworkName ) Write-LogFunctionEntry $routes = Get-FullMesh -List (Get-Lab).VirtualNetworks.Where( { $_.Name -ne $RoutingNetworkName }).AddressSpace.Foreach( { '{0}/{1}' -f $_.Network, $_.Cidr }) $routers = Get-LabVm -Role Routing $routingConfig = @{} foreach ($router in $routers) { $routerAdapter = (Get-LabVM $router).NetworkAdapters.Where( { $_.VirtualSwitch.Name -eq $RoutingNetworkName }) $routerInternalAdapter = (Get-LabVM $router).NetworkAdapters.Where( { $_.VirtualSwitch.Name -ne $RoutingNetworkName }) $routingConfig[$router.Name] = @{ Name = $router.Name InterfaceName = $routerAdapter.InterfaceName RouterNetwork = [string[]]$routerInternalAdapter.IPV4Address TargetRoutes = @{} } } foreach ($router in $routers) { $targetRoutes = $routes | Where-Object Source -in $routingConfig[$router.Name].RouterNetwork foreach ($route in $targetRoutes) { $nextHopVm = Get-LabVm $routingConfig.Values.Where( { $_.RouterNetwork -eq $route.Destination }).Name $nextHopIp = $nextHopVm.NetworkAdapters.Where( { $_.VirtualSwitch.Name -eq $RoutingNetworkName }).Ipv4Address.IPaddress.AddressAsString Write-ScreenInfo -Type Verbose -Message "Route on $($router.Name) to $($route.Destination) via $($nextHopVm.Name)($($nextHopIp))" $routingConfig[$router.Name].TargetRoutes[$route.Destination] = $nextHopIp } } Invoke-LabCommand -ComputerName $routers -ActivityName "Creating routes" -ScriptBlock { Install-RemoteAccess -VpnType RoutingOnly $config = $routingConfig[$env:COMPUTERNAME] foreach ($route in $config.TargetRoutes.GetEnumerator()) { New-NetRoute -InterfaceAlias $config.InterfaceName -DestinationPrefix $route.Key -AddressFamily IPv4 -NextHop $route.Value -Publish Yes } } -Variable (Get-Variable routingConfig) Write-LogFunctionExit } #endregion |