DESIRED STATE CONFIGURATION Listing 1: DSC-Überprüfung von Domänencontrollern Configuration DomainControllerConfig { Import-DscResource -ModuleName PsDesiredStateConfiguration Node "localhost" { # Die Windows-Rolle "Active Directory Domain Services" muss installiert sein WindowsFeature RoleADDS { Ensure = "Present" Name = "AD-Domain-Services" } # Die Windows-Rolle "DNS" muss installiert sein WindowsFeature RoleDNS { Ensure = "Present" Name = "DNS" } # Die Datei "NTDS.dit" muss im Verzeichnis C:\Windows\NTDS vorhanden sein File FileNTDS { Ensure = "Present" Type = "File" DestinationPath = "C:\Windows\NTDS\NTDS.dit" DependsOn = "[WindowsFeature]RoleADDS" } # Die Windows-Rolle "Web-Server" darf nicht installiert sein WindowsFeature RoleWebServer { Ensure = "Absent" Name = "Web-Server" } # Das Verzeichnis "C:\Inetpub\wwwroot" darf nicht vorhanden sein. File FileWWW { Ensure = "Absent" Type = "Directory" DestinationPath = "C:\Inetpub\wwwroot" DependsOn = "[WindowsFeature]RoleWebServer" } } } DomainControllerConfig -OutputPath "C:\scripts" Start-DscConfiguration -Wait -Verbose -Path C:\scripts Listing 2: DSC-Überprüfung von Webservern auf notwendige Rollen und Dateien Configuration WebServerConfig { param ( [string]$targetServer ) Node $targetServer { WindowsFeature RoleWebServer { Ensure = "Present" Name = "Web-Server" } WindowsFeature RoleAppDev { Ensure = "Present" Name = "Web-App-Dev" } WindowsFeature RoleASPNET { Ensure = "Present" Name = "Web-Asp-Net" } WindowsFeature RoleManagementTools { Ensure = "Present" Name = "Web-Mgmt-Tools" } WindowsFeature RoleManagementConsole { Ensure = "Present" Name = "Web-Mgmt-Console" } File FolderWWW { Ensure = "Present" Type = "Directory" DestinationPath = "C:\Inetpub\wwwroot" DependsOn = "[WindowsFeature]RoleWebServer" } File CertificateFolder { Ensure = "Present" Type = "Directory" SourcePath = "\\cert.contoso.com\Store\certificates" DestinationPath = "C:\certificates" Recurse = $true DependsOn = "[WindowsFeature]RoleWebServer" } File IntranetContents { Ensure = "Present" Type = "Directory" SourcePath = "\\cert.contoso.com\Store\wwwroot" DestinationPath = "C:\Inetpub\wwwroot\intranet" Recurse = $true DependsOn = "[File]FolderWWW" } }##end Node } WebServerConfig -targetServer "MUC-WEB-03" -OutputPath "C:\scripts" Start-DscConfiguration -Wait -Verbose -Path C:\scripts Listing 3: Systemkonfiguration mit Local Configuration Manager prüfen [DSCLocalConfigurationManager()] configuration PullClientConfig { Node localhost { Settings { RefreshMode = 'Pull' ConfigurationID = '71880e10-4815- 4009-8582-c181a43e4389' RefreshFrequencyMins = 45 ConfigurationModeFrequencyMins = 180 RebootNodeIfNeeded = $true } ConfigurationRepositoryWeb Contoso-Core-Infra-Pullserver { ServerURL = 'https://pullserver. contoso.com:8080/PSDSCPullServer.svc' } } } POWERSHELL FÜR AZURE Listing 1: Ein Lock schützt vor spezifischen Änderungen Get-AzVM -ResourceGroupName " | Start-AzVM $vm = Get-AzVM -ResourceGroupName " $vm.HardwareProfile.VmSize = "Standard_DS3_v2" Update-AzVM -VM $vm -ResourceGroupName " Get-AzVM -ResourceGroupName " | Remove-AzVM Virtual machine removal operation This cmdlet will remove the specified virtual machine. Do you want to continue? [Y] Yes [N] No [S] Suspend [?] Help (default is "Y"): Y Remove-AzVM: The scope […] cannot perform delete operation because following scope(s) are locked: […]. Please remove the lock and try again. ErrorCode: ScopeLocked ENTRA ID MIT POWERSHELL DSC KONFIGURIEREN Listing 1: Cert-Credential erstellen $today = Get-Date $endDate = $today.AddMonths(6) $notAfter = $today.AddMonths(6) $pass = "Pa$$ToProt3ctThePFX!" $thumbprint = (New-SelfSignedCertificate -CertStoreLocation cert:\Currentuser\My -DnsName powershell.contoso.com -KeyExportPolicy Exportable -Provider "Microsoft Enhanced RSA and AES Cryptographic Provider" -NotAfter $notAfter).Thumbprint $pwd = ConvertTo-SecureString -String $pass -Force -AsPlainText Export-PfxCertificate -cert "cert:\currentuser\my\$thumbprint" -FilePath c:\temp\SPCert.pfx -Password $pwd Listing 2: DSC-Konfiguration anpassen [DSCLocalConfigurationManager()] Configuration LCMConfig { Node localhost { Settings { ConfigurationMode = 'ApplyAndAutoCorrect' ConfigurationModeFrequencyMins = ‘10’ } } } LCMConfig -OutputPath C:\temp\DSCLocalConfig -Verbose HYPER-V-CLUSTER MIT DER POWERSHELL STEUERN - BEISPIELSKRIPTE Beispielskript 1: "Configure-Server.ps1" <# IT-Administrator SH I/2024 PowerShell Generisches Hyper-V-Konfigurationsskript Die "CheckOnly"-Prüfungen sind nur im ersten Teil implementiert Der Netzwerk-Teil legt nur das Management-Interface an #> [CmdletBinding()] Param( [Parameter(Mandatory=$false)] [switch]$CheckOnly ) #requires -RunAsAdministrator #region Konfigurationsdatei im gleichen Verzeichnis suchen und einlesen $cFile = Join-Path -Path $PSScriptRoot -ChildPath 'server.xml' if (!(Test-Path -Path $cFile)) { Write-Warning 'Config-Datei fehlt!' exit } try { $config = [xml](Get-Content -Path $cFile -Raw) } catch { Write-Warning $_.Exception.Message exit } #endregion #region Server anhand seiner Seriennummer identifizieren $Serial = (Get-CIMInstance -ClassName Win32_BIOS).SerialNumber $thisServerSR = $config.ServerConfiguration.Servers.Server.Where({$_.SerialNumber -eq $Serial}) if ($thisServerSR.Count -eq 0) { Write-Warning "Seriennummer nicht gefunden: $Serial" exit } $thisServer = $thisServerSR[0] #endregion #region Erster Durchlauf - Name, Features, MPIO Policy, MPIO für iSCSI $doRestart = $false $featuresToAdd = @() $iscsiVID = 'MSFT2005' $iscsiPID = 'iSCSIBusType_0x9' $configOK = $true # muss der server umbenannt werden? $currentName = [Environment]::MachineName if ($currentName -notlike $thisServer.Name) { if ($CheckOnly) { Write-Host ('Server muss umbenannt werden: aktuell {0} muss {1}' -f $currentName, $thisServer.Name) $configOK = $false } else { Rename-Computer -NewName $thisServer.Name $doRestart = $true } } # muss Hyper-V nachinstalliert werden? $testFeature = Get-WindowsFeature Hyper-V if (-not $testFeature.Installed) { if ($CheckOnly) { Write-Host 'Rolle Hyper-V muss hinzugefügt werden' $configOK = $false } else { $featuresToAdd += 'Hyper-V' } } # soll der Server iSCSI nutzen? if ($thisServer.ISCSI -eq 'true') { $svcIscsi = Get-Service MSiSCSI if ($svcIscsi.StartType -ne 'Automatic') { if ($CheckOnly) { Write-Host 'Der iSCSI-Dienst muss automatisch starten' $configOK = $false } else { try { Set-Service MSiSCSI -StartupType Automatic -EA Stop Start-Service MSiSCSI -Confirm:$false -EA Stop } catch { Write-Warning $_.Exception.Message } } } } # soll der Server MPIO nutzen? if ($thisServer.MPIO -ne 'Off') { if ($thisServer.MPIO -in @('None','FOO','RR','LQD','LB')) { $testFeature = Get-WindowsFeature Multipath-IO if (-not $testFeature.Installed) { if ($CheckOnly) { Write-Host 'Feature Multipath-IO muss hinzugefügt werden' $configOK = $false } else { $featuresToAdd += 'Multipath-IO' } } else { $currentPol = Get-MSDSMGlobalDefaultLoadBalancePolicy if ($currentPol -notlike $thisServer.MPIO) { if ($checkOnly) { Write-Host ('MPIO Policy muss von {0} zu {1} geändert werden' -f $currentPol, $thisServer.MPIO) $configOK = $false } else { try { Set-MSDSMGlobalDefaultLoadBalancePolicy -Policy $thisServer.MPIO -EA Stop } catch { Write-Warning $_.Exception.Message } } } if ($thisServer.ISCSI -eq 'true') { try { $mpioHW = Get-MSDSMSupportedHW -VendorId $iscsiVID -ProductId $iscsiPID -EA Stop } catch { $mpioHW = $null } if ($null -eq $mpioHW) { if ($CheckOnly) { Write-Host 'MPIO muss für iSCSI konfiguriert werden' $configOK = $false } else { try { New-MSDSMSupportedHW -VendorId $iscsiVID -ProductId $iscsiPID -EA Stop $doRestart = $true $autoclaim = Enable-MSDSMAutomaticClaim -BusType iSCSI -EA Stop Set-MPIOSetting -NewDiskTimeout 60 -EA Stop } catch { Write-Warning $_.Exception.Message } } } } } } else { Write-Warning 'Der Wert für MPIO ist ungültig' } } if (-not [string]::IsNullOrWhiteSpace($thisServer.Cluster)) { $testFeature = Get-WindowsFeature Failover-Clustering if (-not $testFeature.Installed) { if ($CheckOnly) { Write-Host 'Feature Failover-Clustering muss hinzugefügt werden' $configOK = $false } else { $featuresToAdd += 'Failover-Clustering' } } } if ($featuresToAdd.Count -gt 0) { Install-WindowsFeature $featuresToAdd -IncludeAllSubFeature -IncludeManagementTools $doRestart = $true } if ($doRestart) { Write-Host 'Neustart erforderlich, geben Sie "J" zum Neustarten ein' if ((Read-Host) -eq 'J') { Restart-Computer -Force } else { exit } } #endregion #region Zweiter Durchlauf - Netzwerk $pNICs = Get-NetAdapter -Physical if ($thisServer.ConvergedNetwork.Enabled -eq 'true') { $CNSwitch = Get-VMSwitch -Name $thisServer.ConvergedNetwork.SwitchName -EA SilentlyContinue if ($null -ne $CNSwitch) { Write-Host 'Netzwerk bereits konfiguriert' } else { switch ($thisServer.ConvergedNetwork.Adapter.IdBy) { 'label' { $selNICs = @($pNICs | Where-Object {$_.Name -like $thisServer.ConvergedNetwork.Adapter.'#text' }) } 'model' { $selNICs = @($pNICs | Where-Object {$_.DriverDescription -like $thisServer.ConvergedNetwork.Adapter.'#text' }) } default { Write-Warning ('IdBy-Wert ungültig: {0}' -f $thisServer.ConvergedNetwork.Adapter.IdBy) $selNICs = @() } } Write-Host $selNICs.Count if ($selNICs.Count -gt 0) { switch ($thisServer.ConvergedNetwork.Adapter.Mode) { 'single' { if ($selNICs.Count -eq 1) { $newSwitch = New-VMSwitch -Name $thisServer.ConvergedNetwork.SwitchName -NetAdapterName $selNICs[0].Name -AllowManagementOS $false } else { Write-Warning ('CN: erwartet 1 Adapter, gefunden {0} Adapter' -f $selNICs.Count) } } 'lbfo' { New-NetLbfoTeam -TeamMembers $selNICs.Name -Name 'CN-Team' -TeamNicName 'CN-Adapter' -TeamingMode SwitchIndependent -Confirm:$false $newSwitch = New-VMSwitch -Name $thisServer.ConvergedNetwork.SwitchName -NetAdapterName 'CN-Adapter' -AllowNetLbfoTeams $true -AllowManagementOS $false } 'set' { $newSwitch = New-VMSwitch -Name $thisServer.ConvergedNetwork.SwitchName -NetAdapterName $selNICs.Name -EnableEmbeddedTeaming $true -AllowManagementOS $false } default { Write-Warning ('Mode-Wert ungültig: {0}' -f $thisServer.ConvergedNetwork.Adapter.Mode) } } } $mgmtNIC = Add-VMNetworkAdapter -ManagementOS -SwitchName $thisServer.ConvergedNetwork.SwitchName -Name 'HostManagement' -Passthru $globalConfMgmtNet = @($config.ServerConfiguration.GlobalConfig.Network).Where({$_.Name -eq 'management'})[0] $iAlias = "vEthernet ($($mgmtNIC.Name))" $ipParm = @{ "InterfaceAlias" = $iAlias "IPAddress" = @($thisServer.Network).Where({$_.Name -eq 'management'})[0].IPAddress "PrefixLength" = $globalConfMgmtNet.SubnetMask -as [int] } if (-not [string]::IsNullOrWhiteSpace($globalConfMgmtNet.Gateway)) { $ipParm.Add("DefaultGateway", $globalConfMgmtNet.Gateway) } $newIP = New-NetIPAddress @ipParm Set-DnsClient -InterfaceAlias $iAlias -RegisterThisConnectionsAddress $true -EA Stop Set-DnsClientServerAddress -InterfaceAlias $iAlias -ServerAddresses $globalConfMgmtNet.DNSServer -EA Stop } } else { # Auf die gleiche Art und Weise eine Management-Schnittstelle anlegen: # -single IP-Konfiguration direkt an die NIC binden # -lbfo IP-Konfiguration an einen LBFO-Adapter binden # -set Einen SET-Switch anlegen wie oben und einen virtuellen Management-Adapter erstellen } #endregion #region Dritter Durchlauf - Domäne und Cluster $wmiCS = Get-WMIObject Win32_ComputerSystem if ((-not $wmiCS.PartOfDomain) -and ($thisServer.Domain -eq 'true')) { $domName = $config.ServerConfiguration.GlobalConfig.Domain if ([string]::IsNullOrWhiteSpace($domName)) { Write-Warning 'Keine Domäne in der globalen Konfiguration angegeben!' } else { $domCred = Get-Credential -Message ('Administrtatorkonto für Beitritt zur Domäne {0}' -f $domName) if ($null -ne $domCred) { $domParm = @{ 'DomainName' = $domName 'Credential' = $domCred } if (-not [string]::IsNullOrWhiteSpace($config.ServerConfiguration.GlobalConfig.OU)) { $domParm.Add('OUPath', $config.ServerConfiguration.GlobalConfig.OU) } try { Add-Computer @domParm -Force -EA Stop $doRestart = $true } catch { Write-Warning $_.Exception.Message $doRestart = $false } } } } if ($doRestart) { Write-Host 'Neustart erforderlich, geben Sie "J" zum Neustarten ein' if ((Read-Host) -eq 'J') { Restart-Computer -Force } else { exit } } if (-not [string]::IsNullOrWhiteSpace($thisServer.Cluster."#text")) { if ($wmiCS.PartOfDomain) { $domClusters = Get-Cluster -Domain $wmiCS.Domain if ($domClusters.Name -contains $thisServer.Cluster."#text") { $currentNodes = Get-ClusterNode -Cluster $thisServer.Cluster."#text" if ($currentNodes.Name -notcontains [Environment]::MachineName) { $testRes = Test-Cluster -Cluster $thisServer.Cluster."#text" -Node (@($currentNodes.Name) + [Environment]::MachineName) Add-ClusterNode -Cluster $thisServer.Cluster."#text" -Type Node } else { Write-Warning "Bereits Teil des Clusters!" } } else { Write-Warning ('Cluster nicht gefunden: {0}' -f $thisServer.Cluster."#text") } } } #endregion Beispielskript 1: "Server.xml" 24 10.0.102.254 10.0.102.11,10.0.102.12 102 24 10.0.105.254 105 24 103 ita22.metabpa.org OU=2024,OU=HyperV,OU=ITA,DC=ita22,DC=metabpa,DC=org ZZHV001 true HV24CL01 FOO true ita.metabpa.org. UPLINK1 HyperVNetworking 10.0.102.51 10.0.103.51 10.0.105.51 HV002 --- weitere Daten --- Beispielskript 2: "Attach-iSCSI.ps1" [CmdletBinding()] Param( [Parameter(Mandatory=$false)][switch]$CheckOnly, [Parameter(Mandatory=$false)][string]$Path ) #region function definitions function Write-Log { [CmdletBinding()] Param( [Parameter(Mandatory=$false)][string]$Message, [Parameter(Mandatory=$false)][switch]$Warning, [Parameter(Mandatory=$false)][switch]$Error ) if ($Error) { $prefix = "[ERROR] " $col = "Red" } elseif ($Warning) { $prefix = "[WARNING] " $col = "Yellow" } else { $prefix = "" $col = "Green" } $msgLine = "$(Get-Date -Format "yyyy-MM-dd HH:mm:ss") $($prefix)$Message" Write-Host $msgLine -ForegroundColor $col $msgLine | Add-Content -Path (Join-Path -Path $PSScriptRoot -ChildPath "Attach-iSCSI.log") -Encoding UTF8 -Force } #endregion #region pre-checks $currentPrincipal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent()) if (-not $currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) { Write-Warning "Please run the script elevated!" exit } if (-not $PSBoundParameters.ContainsKey('Path')) { $Path = Join-Path -Path $PSScriptRoot -ChildPath "HyperVConfig.xml" } if (Test-Path -Path $Path) { try { $config = [xml](Get-Content -Path $Path -EA Stop) } catch { Write-Warning $_.Exception.Message exit } } else { Write-Warning "File not found: $Path" exit } $hostDefFound = $false foreach ($hostdef in $config.data.hosts.host) { if ($hostdef.name -eq [Environment]::MachineName) { Write-Log "Found a host definition matching this machine's name [$([Environment]::MachineName)]" $hostDefFound = $true break } } if (-not $hostDefFound) { Write-Log "No host definition found for [$([Environment]::MachineName)]" -Warning exit } #endregion #region examine host config in XML $hostConfigOK = $true $thisHost = @($config.data.hosts.host).Where({$_.name -eq [Environment]::MachineName})[0] if ($thisHost.management.vlan -ne $null) { Write-Log "Looking up management network $($thisHost.management.vlan)" $mgmtNetwork = @($config.data.networks.network).Where({$_.vlan -eq $thisHost.management.vlan}) if ($mgmtNetwork.Count -eq 0) { Write-Log "No network definition found for management network"-Warning $hostConfigOK = $false } elseif ($mgmtNetwork.Count -gt 1) { Write-Log "Multiple network definitions found for management network" -Warning $hostConfigOK = $false } } if ($config.data.configuration.storage.useiSCSI -ne "true") { Write-Log "iSCSI not required per XML config. No need to run this script!" exit } if (-not $hostConfigOK) { Write-Log "There are errors in the XML configuration file. Please correct these and rerun the script" -Warning exit } #endregion #region checking state $ok2run = $true $iscsiVID = 'MSFT2005' $iscsiPID = 'iSCSIBusType_0x9' if ($config.data.configuration.storage.useiSCSI -eq "true") { try { $svc = Get-Service MSiSCSI -EA Stop if ($svc.StartType -ne "Automatic") { Write-Log "iSCSI Initiator not active!" -Warning $ok2run = $false } else { Write-Log "iSCSI Initiator is already active" } } catch { Write-Log $_.Exception.Message -Error $ok2run = $false } } if ($config.data.configuration.storage.useMPIO -eq "true") { try { if ((Get-WindowsFeature -Name Multipath-IO -EA Stop).Installed -eq $true) { Write-Log "MPIO is installed" } else { Write-Log "MPIO not installed" -Warning $ok2run = $false } } catch { Write-Log $_.Exception.Message -Error $ok2run = $false } if ($ok2run) { try { $mpioHW = Get-MSDSMSupportedHW -VendorId $iscsiVID -ProductId $iscsiPID -EA Stop } catch { $mpioHW = $null } if ($null -eq $mpioHW) { Write-Log "MPIO for iSCSI not active" -Warning $ok2run = $false } else { Write-Log "MPIO for iSCSI is activated" } } } else { Write-Log "Skipping MPIO activation since MPIO will not be used" } #endregion #region config $iSCSIMap = @{} foreach ($nic in $hostdef.storage) { $config.data.networks.network | Where-Object {$_.vlan -eq $nic.vlan} | ForEach-Object { if ($_.iscsitgt -ne $null) { Write-Log "Initiator $($nic.ip) will connect to targets $($_.iscsitgt)" $iSCSIMap.Add($nic.ip, @($_.iscsitgt -split "\,")) } } } if ($iSCSIMap.Count -gt 0) { $tgts = @(Get-IscsiTarget) if ($tgts.Count -eq 0) { Write-Log "Configuring iSCSI Portals" $iSCSIMap.GetEnumerator().ForEach({ foreach ($prt in $_.Value) { Write-Log "Creating portal connection from $($_.Name) to $prt" try { New-IscsiTargetPortal -TargetPortalAddress $prt -TargetPortalPortNumber 3260 -InitiatorPortalAddress $_.Name -EA Stop } catch { Write-Log $_.Exception.Message -Error } } }) Write-Host "`r`nPLEASE ENABLE THE INITIATOR IN TARGET AND RERUN THE SCRIPT`r`n" -ForegroundColor Cyan exit } Write-Log "Configuring iSCSI connections" $iSCSIMap.GetEnumerator().ForEach({ foreach ($prt in $_.Value) { Write-Log "Connecting target from $($_.Name) to $prt" try { $tgts | Connect-IscsiTarget -TargetPortalAddress $prt -InitiatorPortalAddress $_.Name -IsMultipathEnabled $true -IsPersistent $true -EA Stop } catch { Write-Log $_.Exception.Message -Error } } }) } #endregion Beispielskript 2: "HyperVConfig.xml" 255.255.255.0 10.0.100.254 10.0.100.11,10.0.100.12 24 192.168.21.2 192.168.21.15,192.168.21.14 24 10.0.102.19 24 10.0.105.19 24 24 Beispielskript 2: "Install-HVHost.ps1" <# Ein spezialisiertes Skript zur Bereitstellung von Hyper-V-Hosts. Die Konfiguration besteht aus einem konvergenten Netz für LAN-VMs, Storage und LiveMigration und einem physisch separaten DMZ-Netz nur für VMs. #> [CmdletBinding()] Param( [Parameter(Mandatory=$false)][switch]$CheckOnly, [Parameter(Mandatory=$false)][string]$Path ) #region function definitions function Write-Log { [CmdletBinding()] Param( [Parameter(Mandatory=$false)][string]$Message, [Parameter(Mandatory=$false)][switch]$Warning, [Parameter(Mandatory=$false)][switch]$Error ) if ($Error) { $prefix = "[ERROR] " $col = "Red" } elseif ($Warning) { $prefix = "[WARNING] " $col = "Yellow" } else { $prefix = "" $col = "Green" } $msgLine = "$(Get-Date -Format "yyyy-MM-dd HH:mm:ss") $($prefix)$Message" Write-Host $msgLine -ForegroundColor $col $msgLine | Add-Content -Path (Join-Path -Path $PSScriptRoot -ChildPath "Install-HyperVHost.log") -Encoding UTF8 -Force } #endregion #region pre-checks $currentPrincipal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent()) if (-not $currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) { Write-Warning "Please run the script elevated!" exit } if (-not $PSBoundParameters.ContainsKey('Path')) { $Path = Join-Path -Path $PSScriptRoot -ChildPath "HyperVConfig.xml" } if (Test-Path -Path $Path) { try { $config = [xml](Get-Content -Path $Path -EA Stop) } catch { Write-Warning $_.Exception.Message exit } } else { Write-Warning "File not found: $Path" exit } $hostDefFound = $false foreach ($hostdef in $config.data.hosts.host) { if ($hostdef.name -eq [Environment]::MachineName) { Write-Log "Found a host definition matching this machine's name [$([Environment]::MachineName)]" $hostDefFound = $true break } } if (-not $hostDefFound) { Write-Log "No host definition found for [$([Environment]::MachineName)]" -Warning exit } #endregion #region examine host config in XML $hostConfigOK = $true $thisHost = @($config.data.hosts.host).Where({$_.name -eq [Environment]::MachineName})[0] if ($thisHost.management.vlan -ne $null) { Write-Log "Looking up management network $($thisHost.management.vlan)" $mgmtNetwork = @($config.data.networks.network).Where({$_.vlan -eq $thisHost.management.vlan}) if ($mgmtNetwork.Count -eq 0) { Write-Log "No network definition found for management network"-Warning $hostConfigOK = $false } elseif ($mgmtNetwork.Count -gt 1) { Write-Log "Multiple network definitions found for management network" -Warning $hostConfigOK = $false } } if (-not $hostConfigOK) { Write-Log "There are errors in the XML configuration file. Please correct these and rerun the script" -Warning exit } #endregion #region checking state $ok2run = $true $iscsiVID = 'MSFT2005' $iscsiPID = 'iSCSIBusType_0x9' $hostConfigJob = [PSCustomObject]@{ 'InstallMPIOFeature' = $true 'ActivateiSCSIInitiator' = $true 'ActivateMPIOForiSCSI' = $true 'ActivateMPIOPolicy' = $config.data.configuration.storage.MPIOPolicy 'InstallFCRole' = $true 'InstallHyperVRole' = $true 'InstallHyperVTools' = $true 'RemoveIPConfig' = @() 'CreateSwitches' = @() 'CreateManagementNIC' = $true 'RemoveExistingSwitches' = $false 'DisableDefender' = $false } if ($config.data.configuration.defender.disable -eq "True") { $hostConfigJob.DisableDefender = $true } if ($config.data.configuration.storage.useiSCSI -eq "true") { try { $svc = Get-Service MSiSCSI -EA Stop if ($svc.StartType -ne "Automatic") { Write-Log "iSCSI Initiator will be activated" $hostConfigJob.ActivateiSCSIInitiator = $true } else { Write-Log "iSCSI Initiator is already active" $hostConfigJob.ActivateiSCSIInitiator = $false } } catch { Write-Log $_.Exception.Message -Error $ok2run = $false } } else { Write-Log "Skipping iSCSI Initiator activation since iSCSI will not be used" $hostConfigJob.ActivateiSCSIInitiator = $false } if ($config.data.configuration.storage.useMPIO -eq "true") { if ($config.data.configuration.storage.useiSCSI -eq "true") { try { $mpioHW = Get-MSDSMSupportedHW -VendorId $iscsiVID -ProductId $iscsiPID -EA Stop } catch { $mpioHW = $null } if ($null -eq $mpioHW) { Write-Log "MPIO for iSCSI will be activated" $hostConfigJob.ActivateMPIOForiSCSI = $true } else { Write-Log "MPIO for iSCSI already activated" $hostConfigJob.ActivateMPIOForiSCSI = $false } } try { if ((Get-WindowsFeature -Name Multipath-IO).Installed -eq $true) { Write-Log "MPIO already installed" $hostConfigJob.InstallMPIOFeature = $false } else { Write-Log "MPIO will be installed" $hostConfigJob.InstallMPIOFeature = $true } } catch { Write-Log $_.Exception.Message -Error $ok2run = $false } } else { Write-Log "Skipping MPIO activation since MPIO will not be used" $hostConfigJob.ActivateMPIOPolicy = $null $hostConfigJob.InstallMPIOFeature = $false } if ((Get-WindowsFeature -Name Hyper-V).Installed -eq $true) { Write-Log "Hyper-V Role is installed" $hostConfigJob.InstallHyperVRole = $false } else { Write-Log "Hyper-V Role is not installed" } if ((Get-WindowsFeature -Name Hyper-V-PowerShell).Installed -eq $true) { Write-Log "Hyper-V PowerShell Module is installed" $hostConfigJob.InstallHyperVTools = $false } else { Write-Log "Hyper-V PowerShell Module is not installed" } if ($hostdef.clusternode -eq "true") { if ((Get-WindowsFeature -Name Failover-Clustering).Installed -eq $true) { Write-Log "FailoverClustering is installed" $hostConfigJob.InstallFCRole = $false } else { Write-Log "FailoverClustering is not installed" } } else { Write-Log "Host will not be part of a cluster" } Write-Log "Enumerating target vSwitches and uplink patterns" $ulPattern = @() foreach ($sw in $config.data.configuration.switch) { if ($sw.uplinks -match "\,") { $ulPattern += (($sw.uplinks -split "\,") | ForEach-Object {$_.Trim()}) } else { $ulPattern += $sw.uplinks.Trim() } if ($sw.removeExisting -eq "true") { $hostConfigJob.RemoveExistingSwitches = $true } } Write-Log "Enumerating network adapters" try { $pNICs = Get-NetAdapter -Physical -EA Stop } catch { $pNICs = $null Write-Log $_.Exception.Message -Error $ok2run = $false } Write-Log "Physical network adapters found: $($pNics.Count)" $uplinksFound = @() foreach ($nic in $pNICs) { $useNIC = $false $nicMatches = 0 foreach ($pat in $ulPattern) { if ($nic.Name -like $pat) { Write-Log "NIC $($nic.Name) matches uplink pattern $pat" $nicMatches++ } } if ($nicMatches -eq 1) { $useNIC = $true $uplinksFound += $nic.Name } elseif ($nicMatches -eq 0) { Write-Log "NIC $($nic.Name) is not a designated uplink" } else { Write-Log "NIC $($nic.Name) matches mutliple patterns!" -Warning $ok2run = $false } if ($useNIC) { if ($config.data.configuration.uplinks.clearip -eq "true") { $fixedIP = @($nic | Get-NetIPInterface | Where-Object {$_.DHCP -eq "Disabled"}) if ($fixedIP.Count -gt 0) { Write-Log "Fixed IP configuration will be removed from NIC $($nic.Name)" $hostConfigJob.RemoveIPConfig += $nic.Name } } } } Write-Log "Checking which switches will have valid uplinks" foreach ($sw in $config.data.configuration.switch) { $ulPattern = @() $swUplinks = @() if ($sw.uplinks -match "\,") { $ulPattern += (($sw.uplinks -split "\,") | ForEach-Object {$_.Trim()}) } else { $ulPattern += $sw.uplinks.Trim() } foreach ($nic in $uplinksFound) { $isValid = $false foreach ($pat in $ulPattern) { if ($nic -like $pat) { $isValid = $true break } } if ($isValid) { $swUplinks += $nic } } if ($swUplinks.Count -gt 0) { Write-Log "Switch $($sw.Name) will have $($swUplinks.Count) uplinks and can be created" $hostConfigJob.CreateSwitches += $sw.name } else { Write-Log "Switch $($sw.Name) will have no uplinks and cannot be created" -Warning } } #endregion #region validate config and proceed if ($ok2run) { $msg = "The following configuration job will be attempted:" foreach ($prop in $hostConfigJob.PSObject.Properties) { $msg += "`r`n $($prop.Name): $($prop.Value -join ",")" } Write-Log $msg } else { Write-Log "There were errors validating configuration, exiting." exit } if ($CheckOnly) { Write-Log "The -CheckOnly switch was specified, exiting." exit } #endregion #region configuration - storage subsystem Write-Log "Starting host configuration for [$([Environment]::MachineName)]" $configOK = $true if ($hostConfigJob.DisableDefender) { Write-Log "Disabling Defender Realtime" try { Set-MpPreference -DisableRealtimeMonitoring $true -EA Stop } catch { Write-Log $_.Exception.Message -Warni $configOK = $false } } if ($hostConfigJob.RemoveIPConfig.Count -gt 0) { Write-Log "Removing fixed IP configurations from adapters $($hostConfigJob.RemoveIPConfig.Count -join ",")" foreach ($nicName in $hostConfigJob.RemoveIPConfig) { Write-Log "Enabling DHCP on $nicName" try { Get-NetIPInterface -InterfaceAlias $nicName -EA Stop | Where-Object {$_.Dhcp -eq "Disabled"} | Set-NetIPInterface -Dhcp Enabled -EA Stop } catch { Write-Log $_.Exception.Message -Warning $configOK = $false } } } if ($configOK -and $hostConfigJob.ActivateiSCSIInitiator) { Write-Log "Activating and starting iSCSI initiator" try { Set-Service MSiSCSI -StartupType Automatic -EA Stop Start-Service MSiSCSI -Confirm:$false -EA Stop } catch { Write-Log $_.Exception.Message -Error $configOK = $false } } if ($configOK -and $hostConfigJob.InstallMPIOFeature) { Write-Log "Installing MPIO..." try { Install-WindowsFeature Multipath-IO -EA Stop } catch { Write-Log $_.Exception.Message -Error $configOK = $false } } if ($configOK -and $hostConfigJob.ActivateMPIOForiSCSI) { Write-Log "Activating MPIO for iSCSI" try { New-MSDSMSupportedHW -VendorId $iscsiVID -ProductId $iscsiPID -EA Stop Write-Log "Enabled iSCSI support" $autoclaim = Enable-MSDSMAutomaticClaim -BusType iSCSI -EA Stop Write-Log "AutoClaim: $autoclaim" Set-MPIOSetting -NewDiskTimeout 60 -EA Stop Write-Log "Disk timeout set to 60 seconds" Write-Host "`r`nPLEASE RESTART THE COMPUTER AND RERUN THE SCRIPT`r`n" -ForegroundColor Cyan exit } catch { Write-Log $_.Exception.Message -Error $configOK = $false } } if ($configOK -and ($null -ne $hostConfigJob.ActivateMPIOPolicy)) { Write-Log "Activating MPIO default policy to [$($hostConfigJob.ActivateMPIOPolicy)]" try { Set-MSDSMGlobalDefaultLoadBalancePolicy -Policy $hostConfigJob.ActivateMPIOPolicy -EA Stop } catch { Write-Log $_.Exception.Message -Error $configOK = $false } } #enregion #region hyper-v and tools if ($configOK -and $hostConfigJob.InstallHyperVRole) { Write-Log "Installing Hyper-V Role..." try { Add-WindowsFeature -Name Hyper-V, Hyper-V-PowerShell, Hyper-V-Tools -IncludeAllSubFeature -EA Stop Write-Host "`r`nPLEASE RESTART THE COMPUTER AND RERUN THE SCRIPT`r`n" -ForegroundColor Cyan exit } catch { Write-Log $_.Exception.Message -Error $configOK = $false } } if ($configOK -and $hostConfigJob.InstallHyperVTools) { Write-Log "Installing Hyper-V PowerShell module..." try { Add-WindowsFeature -Name Hyper-V-PowerShell -EA Stop } catch { Write-Log $_.Exception.Message -Error $configOK = $false } } #endregion #region failover clustering if ($configOK -and $hostConfigJob.InstallFCRole) { Write-Log "Installing Failover Clustering role..." try { Add-WindowsFeature -Name Failover-Clustering -IncludeAllSubFeature -IncludeManagementTools -EA Stop } catch { Write-Log $_.Exception.Message -Error $configOK = $false } } #endregion #region switches if ($configOK -and $hostConfigJob.CreateSwitches.Count -gt 0) { Write-Log "Creating new switches" foreach ($sw in $config.data.configuration.switch) { $existingSW = $null try { $existingSW = Get-VMSwitch -Name $sw.name -EA Stop } catch { $existingSW = $null } if ($null -ne $existingSW) { if ($sw.removeExisting) { Write-Log "Removing existing switch $($sw.name)" try { $existingSW | Remove-VMSwitch -Force -Confirm:$false -EA Stop } catch { Write-Log $_.Exception.Message -Error $configOK = $false continue } } else { Write-Log "Switch $($sw.name) exists and shall not be removed as per configuration" -Warning $configOK = $false continue } } if ($sw.name -in $hostConfigJob.CreateSwitches) { $ulPattern = @() $swUplinks = @() if ($sw.uplinks -match "\,") { $ulPattern += (($sw.uplinks -split "\,") | ForEach-Object {$_.Trim()}) } else { $ulPattern += $sw.uplinks.Trim() } foreach ($nic in $uplinksFound) { $isValid = $false foreach ($pat in $ulPattern) { if ($nic -like $pat) { $isValid = $true break } } if ($isValid) { $swUplinks += $nic } } if ($swUplinks.Count -gt 0) { Write-Log "Determining uplink speed" $ulBW = 0 foreach ($nic in $swUplinks) { $sp = (Get-NetAdapter -Name $nic).Speed Write-Log "NIC $nic is running at $sp bps / $($sp / 1GB) Gbps" if ($sp -gt $ulBW) { $ulbw = $sp } } if ($sw.set -eq "true") { Write-Log "Creating SET switch $($sw.name) with uplinks $($swUplinks -join ",")" $pMTU = $sw.mtu -as [int] if (($pMTU -gt 0) -and ($pMTU -ne 1514)) { Write-Log "Setting uplinks MTU to $pMTU" foreach ($nic in $swUplinks) { try { Get-NetAdapterAdvancedProperty -Name $nic -DisplayName "Jumbo Packet" -EA Stop | Set-NetAdapterAdvancedProperty -RegistryValue "$pMTU" -EA Stop } catch { Write-Log $_.Exception.Message } } } try { $newSW = New-VMSwitch -Name $sw.name -NetAdapterName @($swUplinks) -EnableEmbeddedTeaming $true -Notes 'Created by script: SET`r`nUplinks: $($swUplinks -join ",")' -AllowManagementOS $false -MinimumBandwidthMode Absolute -EA Stop } catch { Write-Log $_.Exception.Message -Error $configOK = $false $newSW = $null } } elseif ($swUplinks.Count -eq 1) { Write-Log "Creating classic switch $($sw.name) with single uplink $($swUplinks -join ",")" try { $newSW = New-VMSwitch -Name $sw.name -NetAdapterName @($swUplinks) -EnableEmbeddedTeaming $false -Notes 'Created by script: single`r`nUplinks: $($swUplinks -join ",")' -AllowManagementOS $false -EA Stop } catch { Write-Log $_.Exception.Message -Error $configOK = $false $newSW = $null } } else { Write-Log "LBFO configuration needed for switch $($sw.name) is not implemented yet" -Warning } if ($null -ne $newSW) { if ($sw.management -eq "true") { $nicName = ('{0}-{1}' -f $config.data.configuration.management.nameprefix, $sw.name) Write-Log "Creating management adapter on switch $($sw.name)" try { $mgmtNIC = Add-VMNetworkAdapter -ManagementOS -SwitchName $sw.name -Name $nicName -Passthru -EA Stop } catch { Write-Log $_.Exception.Message -Error $configOK = $false $mgmtNIC = $null } if ($null -ne $mgmtNIC) { Write-Log "Setting management NIC VLAN to $($hostdef.management.vlan)" try { Set-VMNetworkAdapterVlan -VMNetworkAdapter $mgmtNIC -VlanId ($hostdef.management.vlan -as [int]) -Access -EA Stop } catch { Write-Log $_.Exception.Message -Error $configOK = $false } if ([string]::IsNullOrWhiteSpace($config.data.configuration.management.reserve)) { $bw = 0 } else { $bw = (Invoke-Expression $config.data.configuration.management.reserve) -as [int64] } if ($bw -gt $ulBW) { Write-Log "Bandwidth reservation is over uplink speed" -Warning } elseif ($bw -gt 0) { Write-Log "Assigning bandwidth reservation of $bw bps" try { Set-VMNetworkAdapter -VMNetworkAdapter $mgmtNIC -MinimumBandwidthAbsolute $bw -EA Stop } catch { Write-Log $_.Exception.Message -Error $configOK = $false } } $mgmtPL = 24 $mgmtDG = $null $mgmtNS = $null foreach ($net in $config.data.networks.network) { if ($net.vlan -eq $hostdef.management.vlan) { $mgmtPL = $net.subnetmask if ($null -ne $net.gateway) { $mgmtDG = $net.gateway } if ($null -ne $net.dns) { $mgmtNS = $net.dns } } } Write-Log "Setting management NIC IP config to $($hostdef.management.ip)/$($mgmtPL)/$($mgmtDG) -> $($mgmtNS)" $ipParm = @{ "InterfaceAlias" = "vEthernet ($($mgmtNIC.Name))" "IPAddress" = $hostdef.management.ip "PrefixLength" = $mgmtPL -as [int] } if ($null -ne $mgmtDG) { $ipParm.Add("DefaultGateway", $mgmtDG) } try { $newIP = New-NetIPAddress @ipParm -EA Stop } catch { $newIP = $null Write-Log $_.Exception.Message -Error $configOK = $false } if (($null -ne $mgmtNS) -and ($null -ne $newIP)) { Write-Log "Setting DNS for mgmt NIC" try { Set-DnsClient -InterfaceAlias "vEthernet ($($mgmtNIC.Name))" -RegisterThisConnectionsAddress $true -EA Stop Set-DnsClientServerAddress -InterfaceAlias "vEthernet ($($mgmtNIC.Name))" -ServerAddresses $mgmtNS -EA Stop } catch { Write-Log $_.Exception.Message -Error $configOK = $false } } else { Write-Log "Setting mgmt NIC to not register" try { Set-DnsClient -InterfaceAlias "vEthernet ($($mgmtNIC.Name))" -RegisterThisConnectionsAddress $false -EA Stop } catch { Write-Log $_.Exception.Message -Error $configOK = $false } } } } if ($sw.backup -eq "true") { $nicName = ('{0}-{1}' -f $config.data.configuration.backup.nameprefix, $sw.name) Write-Log "Creating backup adapter on switch $($sw.name)" try { $mgmtNIC = Add-VMNetworkAdapter -ManagementOS -SwitchName $sw.name -Name $nicName -Passthru -EA Stop } catch { Write-Log $_.Exception.Message -Error $configOK = $false $mgmtNIC = $null } if ($null -ne $mgmtNIC) { Write-Log "Setting backup NIC VLAN to $($hostdef.backup.vlan)" try { Set-VMNetworkAdapterVlan -VMNetworkAdapter $mgmtNIC -VlanId ($hostdef.backup.vlan -as [int]) -Access -EA Stop } catch { Write-Log $_.Exception.Message -Error $configOK = $false } if ([string]::IsNullOrWhiteSpace($config.data.configuration.backup.reserve)) { $bw = 0 } else { $bw = (Invoke-Expression $config.data.configuration.backup.reserve) -as [int64] } if ($bw -gt $ulBW) { Write-Log "Bandwidth reservation is over uplink speed" -Warning } elseif ($bw -gt 0) { Write-Log "Assigning bandwidth reservation of $bw bps" try { Set-VMNetworkAdapter -VMNetworkAdapter $mgmtNIC -MinimumBandwidthAbsolute $bw -EA Stop } catch { Write-Log $_.Exception.Message -Error $configOK = $false } } $mgmtPL = 24 $mgmtDG = $null $mgmtNS = $null foreach ($net in $config.data.networks.network) { if ($net.vlan -eq $hostdef.backup.vlan) { $mgmtPL = $net.subnetmask if ($null -ne $net.gateway) { $mgmtDG = $net.gateway } if ($null -ne $net.dns) { $mgmtNS = $net.dns } } } Write-Log "Setting backup NIC IP config to $($hostdef.backup.ip)/$($mgmtPL)/$($mgmtDG) -> $($mgmtNS)" $ipParm = @{ "InterfaceAlias" = "vEthernet ($($mgmtNIC.Name))" "IPAddress" = $hostdef.backup.ip "PrefixLength" = $mgmtPL -as [int] } if ($null -ne $mgmtDG) { $ipParm.Add("DefaultGateway", $mgmtDG) } try { $newIP = New-NetIPAddress @ipParm -EA Stop } catch { $newIP = $null Write-Log $_.Exception.Message -Error $configOK = $false } if (($null -ne $mgmtNS) -and ($null -ne $newIP)) { Write-Log "Setting DNS for backup NIC" try { Set-DnsClient -InterfaceAlias "vEthernet ($($mgmtNIC.Name))" -RegisterThisConnectionsAddress $true -EA Stop Set-DnsClientServerAddress -InterfaceAlias "vEthernet ($($mgmtNIC.Name))" -ServerAddresses $mgmtNS -EA Stop } catch { Write-Log $_.Exception.Message -Error $configOK = $false } } else { Write-Log "Setting backup NIC to not register" try { Set-DnsClient -InterfaceAlias "vEthernet ($($mgmtNIC.Name))" -RegisterThisConnectionsAddress $false -EA Stop } catch { Write-Log $_.Exception.Message -Error $configOK = $false } } } } if ($sw.livemig -eq "true") { $nicName = ('{0}-{1}' -f $config.data.configuration.livemig.nameprefix, $sw.name) Write-Log "Creating Live Migration adapter on switch $($sw.name)" try { $mgmtNIC = Add-VMNetworkAdapter -ManagementOS -SwitchName $sw.name -Name $nicName -Passthru -EA Stop } catch { Write-Log $_.Exception.Message -Error $configOK = $false $mgmtNIC = $null } if ($null -ne $mgmtNIC) { $lmMTU = $config.data.configuration.livemig.livemigMTU -as [int] if (($lmMTU -gt 0) -and ($lmMTU -ne 1514)) { Write-Log "Setting Live Migration MTU to $lmMTU" try { Get-NetAdapterAdvancedProperty -Name "vEthernet ($($mgmtNIC.Name))" -DisplayName "Jumbo Packet" -EA Stop | Set-NetAdapterAdvancedProperty -RegistryValue "$lmMTU" -EA Stop } catch { Write-Log $_.Exception.Message } } Write-Log "Setting Live Migration NIC VLAN to $($hostdef.livemig.vlan)" try { Set-VMNetworkAdapterVlan -VMNetworkAdapter $mgmtNIC -VlanId ($hostdef.livemig.vlan -as [int]) -Access -EA Stop } catch { Write-Log $_.Exception.Message -Error $configOK = $false } if ([string]::IsNullOrWhiteSpace($config.data.configuration.livemig.reserve)) { $bw = 0 } else { $bw = (Invoke-Expression $config.data.configuration.livemig.reserve) -as [int64] } if ($bw -gt $ulBW) { Write-Log "Bandwidth reservation is over uplink speed" -Warning } elseif ($bw -gt 0) { Write-Log "Assigning bandwidth reservation of $bw bps" try { Set-VMNetworkAdapter -VMNetworkAdapter $mgmtNIC -MinimumBandwidthAbsolute $bw -EA Stop } catch { Write-Log $_.Exception.Message -Error $configOK = $false } } $mgmtPL = 24 $mgmtDG = $null $mgmtNS = $null foreach ($net in $config.data.networks.network) { if ($net.vlan -eq $hostdef.livemig.vlan) { $mgmtPL = $net.subnetmask if ($null -ne $net.gateway) { $mgmtDG = $net.gateway } if ($null -ne $net.dns) { $mgmtNS = $net.dns } } } Write-Log "Setting Live Migration NIC IP config to $($hostdef.livemig.ip)/$($mgmtPL)/$($mgmtDG) -> $($mgmtNS)" $ipParm = @{ "InterfaceAlias" = "vEthernet ($($mgmtNIC.Name))" "IPAddress" = $hostdef.livemig.ip "PrefixLength" = $mgmtPL -as [int] } if ($null -ne $mgmtDG) { $ipParm.Add("DefaultGateway", $mgmtDG) } try { $newIP = New-NetIPAddress @ipParm -EA Stop } catch { $newIP = $null Write-Log $_.Exception.Message -Error $configOK = $false } if (($null -ne $mgmtNS) -and ($null -ne $newIP)) { Write-Log "Setting DNS for Live Migration NIC" try { Set-DnsClient -InterfaceAlias "vEthernet ($($mgmtNIC.Name))" -RegisterThisConnectionsAddress $true -EA Stop Set-DnsClientServerAddress -InterfaceAlias "vEthernet ($($mgmtNIC.Name))" -ServerAddresses $mgmtNS -EA Stop } catch { Write-Log $_.Exception.Message -Error $configOK = $false } } else { Write-Log "Setting Live Migration NIC to not register" try { Set-DnsClient -InterfaceAlias "vEthernet ($($mgmtNIC.Name))" -RegisterThisConnectionsAddress $false -EA Stop } catch { Write-Log $_.Exception.Message -Error $configOK = $false } } } } if ($sw.storage -eq "true") { foreach ($san in $hostdef.storage) { $nicName = ('{0}-{1}-{2}' -f $config.data.configuration.storage.nameprefix, $sw.name, $san.vlan) Write-Log "Creating storage adapter for VLAN $($san.vlan) on switch $($sw.name)" try { $mgmtNIC = Add-VMNetworkAdapter -ManagementOS -SwitchName $sw.name -Name $nicName -Passthru -EA Stop } catch { Write-Log $_.Exception.Message -Error $configOK = $false $mgmtNIC = $null } if ($null -ne $mgmtNIC) { Write-Log "Setting storage NIC VLAN to $($san.vlan)" try { Set-VMNetworkAdapterVlan -VMNetworkAdapter $mgmtNIC -VlanId ($san.vlan -as [int]) -Access -EA Stop } catch { Write-Log $_.Exception.Message -Error $configOK = $false } if ([string]::IsNullOrWhiteSpace($config.data.configuration.storage.reserve)) { $bw = 0 } else { $bw = (Invoke-Expression $config.data.configuration.storage.reserve) -as [int64] } if ($bw -gt $ulBW) { Write-Log "Bandwidth reservation is over uplink speed" -Warning } elseif ($bw -gt 0) { Write-Log "Assigning bandwidth reservation of $bw bps" try { Set-VMNetworkAdapter -VMNetworkAdapter $mgmtNIC -MinimumBandwidthAbsolute $bw -EA Stop } catch { Write-Log $_.Exception.Message -Error $configOK = $false } } $mgmtPL = 24 $mgmtDG = $null $mgmtNS = $null $iscsiT = @() foreach ($net in $config.data.networks.network) { if ($net.vlan -eq $san.vlan) { $mgmtPL = $net.subnetmask if ($null -ne $net.gateway) { $mgmtDG = $net.gateway } if ($null -ne $net.dns) { $mgmtNS = $net.dns } if ($null -ne $net.iscsitgt) { $iscsiT = $net.iscsitgt -split "\," } } } Write-Log "Setting storage NIC IP config to $($san.ip)/$($mgmtPL)/$($mgmtDG) -> $($mgmtNS)" $ipParm = @{ "InterfaceAlias" = "vEthernet ($($mgmtNIC.Name))" "IPAddress" = $san.ip "PrefixLength" = $mgmtPL -as [int] } if ($null -ne $mgmtDG) { $ipParm.Add("DefaultGateway", $mgmtDG) } try { $newIP = New-NetIPAddress @ipParm -EA Stop } catch { $newIP = $null Write-Log $_.Exception.Message -Error $configOK = $false } if (($null -ne $mgmtNS) -and ($null -ne $newIP)) { Write-Log "Setting DNS for storage NIC" try { Set-DnsClient -InterfaceAlias "vEthernet ($($mgmtNIC.Name))" -RegisterThisConnectionsAddress $true -EA Stop Set-DnsClientServerAddress -InterfaceAlias "vEthernet ($($mgmtNIC.Name))" -ServerAddresses $mgmtNS -EA Stop } catch { Write-Log $_.Exception.Message -Error $configOK = $false } } else { Write-Log "Setting storage NIC to not register" try { Set-DnsClient -InterfaceAlias "vEthernet ($($mgmtNIC.Name))" -RegisterThisConnectionsAddress $false -EA Stop } catch { Write-Log $_.Exception.Message -Error $configOK = $false } } if ($config.data.configuration.storage.useiSCSI -eq "true") { $mtuBytes = $config.data.configuration.storage.iscsiMTU -as [int] if (($mtuBytes -gt 0) -and ($mtuBytes -ne 1500)) { Write-Log "Setting MTU to $mtuBytes bytes" try { Get-NetAdapterAdvancedProperty -Name "vEthernet ($($mgmtNIC.Name))" -DisplayName "Jumbo Packet" -EA Stop | Set-NetAdapterAdvancedProperty -RegistryValue "$lmMTU" -EA Stop Write-Log "Sleeping for 10 seconds" Start-Sleep -Seconds 10 } catch { Write-Log $_.Exception.Message -Error $configOK = $false } } <# Write-Log "Configuring iSCSI Portals" foreach ($tgt in $iscsiT) { Write-Log "Crearting portal connection to $tgt" try { New-IscsiTargetPortal -TargetPortalAddress $tgt -TargetPortalPortNumber 3260 -InitiatorPortalAddress $san.ip -EA Stop } catch { Write-Log $_.Exception.Message -Error $configOK = $false } } Write-Log "Enumerating targets" $tgts = Get-IscsiTarget if ($null -ne $tgts) { Write-Log "Connecting iSCSI to $($tgts.Count) target(s)" foreach ($tgt in $iscsiT) { try { $tgts | Connect-IscsiTarget -IsMultipathEnabled ($config.data.configuration.storage.useMPIO -eq "true") -IsPersistent $true -InitiatorPortalAddress $san.ip -TargetPortalAddress $tgt -EA Stop } catch { Write-Log $_.Exception.Message -Error $configOK = $false } } }#> } } } } } } else { Write-Log "Found zero uplinks for $($sw.name) on second try - what is wrong here?" -Warning $configOK = $false } } } } #endregion #region management nic #endregion #region bailout if ($configOK) { Write-Log "Host configuration completed successfully" } else { Write-Log "There were errors during host configuration. Please review log, correct the errors and rerun." -Warning } #endregion