AutomatedLabDefinitionNetwork.psm1
#region Virtual Network Definition Functions #region Add-LabVirtualNetworkDefinition function Add-LabVirtualNetworkDefinition { [CmdletBinding()] param ( [string]$Name = (Get-LabDefinition).Name, [AllowNull()] [AutomatedLab.IPNetwork]$AddressSpace, [AutomatedLab.VirtualizationHost]$VirtualizationEngine, [hashtable[]]$HyperVProperties, [hashtable[]]$AzureProperties, [AutomatedLab.NetworkAdapter]$ManagementAdapter, [string]$ResourceName, [switch]$PassThru ) Write-LogFunctionEntry if ((Get-LabDefinition).DefaultVirtualizationEngine -eq 'Azure' -and -not ((Get-LabDefinition).AzureSettings)) { Add-LabAzureSubscription } $azurePropertiesValidKeys = 'Subnets', 'LocationName', 'DnsServers', 'ConnectToVnets', 'DnsLabel' $hypervPropertiesValidKeys = 'SwitchType', 'AdapterName', 'ManagementAdapter' if (-not (Get-LabDefinition)) { throw 'No lab defined. Please call New-LabDefinition first before calling Add-LabVirtualNetworkDefinition.' } $script:lab = Get-LabDefinition if (-not $VirtualizationEngine) { if ((Get-LabDefinition).DefaultVirtualizationEngine) { $VirtualizationEngine = (Get-LabDefinition).DefaultVirtualizationEngine } else { Throw "Virtualization engine MUST be specified. This can be done:`n - Using parameter 'DefaultVirtualizationEngine' when calling New-LabDefinition`n - Using Set-LabDefaultVirtualizationEngine -Engine <engine>`n - Using parameter 'VirtualizationEngine' when calling Add-LabVirtualNetworkDefinition`n `nRemember to specify VirtualizationEngine parameter when adding machines if no default virtualization engine has been specified`n `n " } } if ($VirtualizationEngine -eq 'HyperV' -and (-not (Get-Module -ListAvailable -Name Hyper-V))) { throw 'The Hyper-V tools are not installed. Please install them first to use AutomatedLab with Hyper-V. Alternatively, you can use AutomatedLab with Microsoft Azure.' } if ($VirtualizationEngine -eq 'Azure' -and -not $script:lab.AzureSettings.DefaultResourceGroup) { Add-LabAzureSubscription } if ($AzureProperties) { $illegalKeys = Compare-Object -ReferenceObject $azurePropertiesValidKeys -DifferenceObject ($AzureProperties.Keys | Sort-Object -Unique) | Where-Object SideIndicator -eq '=>' | Select-Object -ExpandProperty InputObject if ($illegalKeys) { throw "The key(s) '$($illegalKeys -join ', ')' are not supported in AzureProperties. Valid keys are '$($azurePropertiesValidKeys -join ', ')'" } if (($AzureProperties.Keys -eq 'LocationName').Count -ne 1) { throw 'Location must be speficfied exactly once in AzureProperties' } } if ($HyperVProperties) { $illegalKeys = Compare-Object -ReferenceObject $hypervPropertiesValidKeys -DifferenceObject ($HyperVProperties.Keys | Select-Object -Unique) | Where-Object SideIndicator -eq '=>' | Select-Object -ExpandProperty InputObject if ($illegalKeys) { throw "The key(s) '$($illegalKeys -join ', ')' are not supported in HyperVProperties. Valid keys are '$($hypervPropertiesValidKeys -join ', ')'" } if ($HyperVProperties.SwitchType -eq 'External' -and -not $HyperVProperties.AdapterName) { throw 'You have to provide a network adapter if you want to create an external switch' return } if ($HyperVProperties.ManagementAdapter -eq $false -and $HyperVProperties.SwitchType -ne 'External') { throw 'Disabling the Management Adapter for private or internal VM Switch is not supported, as this will result in being unable to build labs' } if ($HyperVProperties.ManagementAdapter -eq $false -and $ManagementAdapter) { throw "A Management Adapter has been specified, however the Management Adapter for '$($Name)' has been disabled. Either re-enable the Management Adapter, or remove the -ManagementAdapter parameter" } if (-not $HyperVProperties.SwitchType) { $HyperVProperties.Add('SwitchType', 'Internal') } } if ($script:lab.VirtualNetworks | Where-Object Name -eq $Name) { $errorMessage = "A network with the name '$Name' is already defined" Write-Error $errorMessage Write-LogFunctionExitWithError -Message $errorMessage return } $network = New-Object -TypeName AutomatedLab.VirtualNetwork $network.AddressSpace = $AddressSpace $network.Name = $Name if ($ResourceName) {$network.FriendlyName = $ResourceName} if ($HyperVProperties.SwitchType) { $network.SwitchType = $HyperVProperties.SwitchType } if ($HyperVProperties.AdapterName) {$network.AdapterName = $HyperVProperties.AdapterName } if ($HyperVProperties.ManagementAdapter -eq $false) {$network.EnableManagementAdapter = $false } if ($ManagementAdapter) {$network.ManagementAdapter = $ManagementAdapter} #VLAN's are not supported on non-external interfaces if ($network.SwitchType -ne 'External' -and $network.ManagementAdapter.AccessVLANID -ne 0) { throw "A Management Adapter for Internal switch '$($network.Name)' has been specified with the -AccessVlanID parameter. This configuration is unsupported." } $network.HostType = $VirtualizationEngine if($AzureProperties.LocationName) { $network.LocationName = $AzureProperties.LocationName } if($AzureProperties.ConnectToVnets) { $network.ConnectToVnets = $AzureProperties.ConnectToVnets } if($AzureProperties.DnsServers) { $network.DnsServers = $AzureProperties.DnsServers } if($AzureProperties.Subnets) { foreach($subnet in $AzureProperties.Subnets.GetEnumerator()) { $temp = New-Object -TypeName AutomatedLab.AzureSubnet $temp.Name = $subnet.Key $temp.AddressSpace = $subnet.Value $network.Subnets.Add($temp) } } if ($AzureProperties.DnsLabel) { $network.AzureDnsLabel = $AzureProperties.DnsLabel } if (-not $network.LocationName) { $network.LocationName = $script:lab.AzureSettings.DefaultLocation } $script:lab.VirtualNetworks.Add($network) Write-PSFMessage "Network '$Name' added. Lab has $($Script:lab.VirtualNetworks.Count) network(s) defined" if ($PassThru) { $network } Write-LogFunctionExit } #endregion Add-LabVirtualNetworkDefinition #region Get-LabVirtualNetworkDefinition function Get-LabVirtualNetworkDefinition { [CmdletBinding()] [OutputType([AutomatedLab.VirtualNetwork])] param( [Parameter(ParameterSetName = 'ByName')] [string]$Name, [Parameter(Mandatory, ParameterSetName = 'ByAddressSpace')] [string]$AddressSpace ) $script:lab = Get-LabDefinition -ErrorAction SilentlyContinue Write-LogFunctionEntry if ($PSCmdlet.ParameterSetName -eq 'ByAddressSpace') { return $script:lab.VirtualNetworks | Where-Object AddressSpace -eq $AddressSpace } else { if ($Name) { return $script:lab.VirtualNetworks | Where-Object Name -eq $Name } else { return $script:lab.VirtualNetworks } } Write-LogFunctionExit } #endregion Get-LabVirtualNetworkDefinition #region Remove-LabVirtualNetworkDefinition function Remove-LabVirtualNetworkDefinition { [CmdletBinding()] param ( [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [string[]]$Name ) Write-LogFunctionEntry foreach ($n in $Name) { $network = $script:lab.VirtualNetworks | Where-Object Name -eq $n if (-not $network) { Write-ScreenInfo "There is no network defined with the name '$n'" -Type Warning } else { [Void]$script:lab.VirtualNetworks.Remove($network) Write-PSFMessage "Network '$n' removed. Lab has $($Script:lab.VirtualNetworks.Count) network(s) defined" } } Write-LogFunctionExit } #endregion Remove-LabVirtualNetworkDefinition #endregion #region Virtual Network Definition Functions #region New-LabNetworkAdapterDefinition function New-LabNetworkAdapterDefinition { [CmdletBinding(DefaultParameterSetName = 'manual')] param ( [Parameter(Mandatory)] [string]$VirtualSwitch, [string]$InterfaceName, [Parameter(ParameterSetName = 'dhcp')] [switch]$UseDhcp, [Parameter(ParameterSetName = 'manual')] [ValidatePattern('^(([2]([0-4][0-9]|[5][0-5])|[0-1]?[0-9]?[0-9])[.]){3}(([2]([0-4][0-9]|[5][0-5])|[0-1]?[0-9]?[0-9]))/([3][0-2]|[1-2][0-9]|[2-9])$')] [AutomatedLab.IPNetwork[]]$Ipv4Address, [Parameter(ParameterSetName = 'manual')] [ValidatePattern('^(([2]([0-4][0-9]|[5][0-5])|[0-1]?[0-9]?[0-9])[.]){3}(([2]([0-4][0-9]|[5][0-5])|[0-1]?[0-9]?[0-9]))$')] [AutomatedLab.IPAddress]$Ipv4Gateway, [ValidatePattern('^(([2]([0-4][0-9]|[5][0-5])|[0-1]?[0-9]?[0-9])[.]){3}(([2]([0-4][0-9]|[5][0-5])|[0-1]?[0-9]?[0-9]))$')] [AutomatedLab.IPAddress[]]$Ipv4DNSServers, [Parameter(ParameterSetName = 'manual')] [AutomatedLab.IPNetwork[]]$IPv6Address, [Parameter(ParameterSetName = 'manual')] [ValidateRange(1, 128)] [int]$IPv6AddressPrefix, [Parameter(ParameterSetName = 'manual')] [string]$IPv6Gateway, [string[]]$IPv6DNSServers, [string]$ConnectionSpecificDNSSuffix, [boolean]$AppendParentSuffixes, [string[]]$AppendDNSSuffixes, [boolean]$RegisterInDNS = $true, [boolean]$DnsSuffixInDnsRegistration, [ValidateSet('Default', 'Enabled', 'Disabled')] [string]$NetBIOSOptions = 'Default', [ValidateRange(0,4096)] [int]$AccessVLANID = 0, [boolean]$ManagementAdapter = $false, [string] $MacAddress ) Write-LogFunctionEntry if (-not (Get-LabDefinition)) { throw 'No lab defined. Please call New-LabDefinition first before calling Set-LabDefaultOperatingSystem.' } $adapter = New-Object -TypeName AutomatedLab.NetworkAdapter $MacAddress = $MacAddress -replace '[\.\-\:]' #If the defined interface is flagged as being a Management interface, ignore the virtual switch check as it will not exist yet if (-not $ManagementAdapter) { if ($VirtualSwitch) { $adapter.VirtualSwitch = Get-LabVirtualNetworkDefinition | Where-Object Name -eq $VirtualSwitch } else { $adapter.VirtualSwitch = Get-LabVirtualNetworkDefinition | Select-Object -First 1 } if (-not $adapter.VirtualSwitch) { throw "Could not find the virtual switch '$VirtualSwitch' nor create one automatically" } #VLAN Tagging is only currently supported on External switch interfaces. If a VLAN has been provied for an internal switch, throw an error if ($adapter.VirtualSwitch.SwitchType -ne 'External' -and $AccessVLANID -ne 0) { throw "VLAN tagging of interface '$InterfaceName' on non-external virtual switch '$VirtualSwitch' is not supported, either remove the AccessVlanID setting, or assign the interface to an external switch" } } if ($InterfaceName) { $adapter.InterfaceName = $InterfaceName } foreach ($item in $Ipv4Address) { $adapter.Ipv4Address.Add($item) } foreach ($item in $Ipv4DnsServers) { $adapter.Ipv4DnsServers.Add($item) } foreach ($item in $Ipv6Address) { $adapter.Ipv6Address.Add($item) } foreach ($item in $Ipv6DnsServers) { $adapter.Ipv6DnsServers.Add($item) } if ((Get-LabDefinition).DefaultVirtualizationEngine -eq 'HyperV' -and -not $MacAddress) { $macAddressPrefix = Get-LabConfigurationItem -Name MacAddressPrefix [string[]]$macAddressesInUse = (Get-VM | Get-VMNetworkAdapter).MacAddress $macAddressesInUse += (Get-LabMachineDefinition -All).NetworkAdapters.MacAddress if (-not $script:macIdx) { $script:macIdx = 0 } while ("$macAddressPrefix{0:X6}" -f $macIdx -in $macAddressesInUse) { $script:macIdx++ } $MacAddress = "$macAddressPrefix{0:X6}" -f $script:macIdx++ } if ($Ipv4Gateway) { $adapter.Ipv4Gateway = $Ipv4Gateway } if ($Ipv6Gateway) { $adapter.Ipv6Gateway = $Ipv6Gateway } if ($MacAddress) { $adapter.MacAddress = $MacAddress} $adapter.ConnectionSpecificDNSSuffix = $ConnectionSpecificDNSSuffix $adapter.AppendParentSuffixes = $AppendParentSuffixes $adapter.AppendDNSSuffixes = $AppendDNSSuffixes $adapter.RegisterInDNS = $RegisterInDNS $adapter.DnsSuffixInDnsRegistration = $DnsSuffixInDnsRegistration $adapter.NetBIOSOptions = $NetBIOSOptions $adapter.UseDhcp = $UseDhcp $adapter.AccessVLANID = $AccessVLANID $adapter Write-LogFunctionExit } #endregion New-LabNetworkAdapterDefinition |