diff --git a/Scenarios/AzSHCI Deployment 22H2 Edition/LabConfig.ps1 b/Scenarios/AzSHCI Deployment 22H2 Edition/LabConfig.ps1 index 8b724212..a9d0abba 100644 --- a/Scenarios/AzSHCI Deployment 22H2 Edition/LabConfig.ps1 +++ b/Scenarios/AzSHCI Deployment 22H2 Edition/LabConfig.ps1 @@ -3,7 +3,7 @@ $LabConfig=@{AllowedVLANs="1-10,711-719" ; DomainAdminName='LabAdmin'; AdminPass #Azure Stack HCI 21H2 1..4 | ForEach-Object {$LABConfig.VMs += @{ VMName = "AzSHCI$_" ; Configuration = 'S2D' ; ParentVHD = 'AzSHCI22H2_G2.vhdx' ; HDDNumber = 4 ; HDDSize= 2TB ; MemoryStartupBytes= 1GB; VMProcessorCount=4 ; vTPM=$true}} #Or with nested virtualization enabled -#1..4 | ForEach-Object {$LABonfig.VMs += @{ VMName = "AzSHCI$_" ; ConfiguratioCn = 'S2D' ; ParentVHD = 'AzSHCI22H2_G2.vhdx' ; HDDNumber = 10 ; HDDSize= 10TB ; MemoryStartupBytes= 4GB; VMProcessorCount="4" ; vTPM=$true ; NestedVirt=$true}} +#1..4 | ForEach-Object {$LABonfig.VMs += @{ VMName = "AzSHCI$_" ; Configuration = 'S2D' ; ParentVHD = 'AzSHCI22H2_G2.vhdx' ; HDDNumber = 4 ; HDDSize= 2TB ; MemoryStartupBytes= 4GB; VMProcessorCount=4 ; vTPM=$true ; NestedVirt=$true}} #Optional Windows Admin Center in GW mode $LabConfig.VMs += @{ VMName = 'WACGW' ; ParentVHD = 'Win2022Core_G2.vhdx'; MGMTNICs=1} diff --git a/Scenarios/AzSHCI Deployment 22H2 Edition/Scenario.ps1 b/Scenarios/AzSHCI Deployment 22H2 Edition/Scenario.ps1 index 628b2ec2..c4d61c39 100644 --- a/Scenarios/AzSHCI Deployment 22H2 Edition/Scenario.ps1 +++ b/Scenarios/AzSHCI Deployment 22H2 Edition/Scenario.ps1 @@ -10,16 +10,19 @@ #Cluster-Aware-Updating role name $CAURoleName="AzSHCI-Cl-CAU" #if empty, CAU will not be installed + #Enable Kernel Soft Reboot? https://learn.microsoft.com/en-us/azure-stack/hci/manage/kernel-soft-reboot + $KSR=$False + #Cluster IP $ClusterIP="" #If blank (you can write just $ClusterIP="", DHCP will be used). If $DistributedManagementPoint is true, then IP is not used #Distributed Cluster ManagementPoint? (Cluster Name in DNS will have IP of every node - like SOFS). If $ClusterIP is set, then $clusterIP will be ignored). - $DistributedManagementPoint=$false + $DistributedManagementPoint=$False - #Deploy network using Network ATC? - $NetATC=$False + #Deploy network using Network ATC? https://learn.microsoft.com/en-us/azure-stack/hci/manage/manage-network-atc?tabs=22H2 + $NetATC=$True - #Variables for traditional networking (no NetATC) + #Variables for traditional networking (if NetATC is $False) $vSwitchName="vSwitch" #start IP for Storage networks $IP=1 @@ -39,7 +42,7 @@ $WindowsUpdate="Recommended" #Can be "All","Recommended" or "None" #Dell updates - $DellUpdates=$true + $DellUpdates=$False #Witness type $WitnessType="FileShare" #or Cloud @@ -52,7 +55,7 @@ #> #Delete Storage Pool (like after reinstall there might be data left from old cluster) - $DeletePool=$false + $DeletePool=$False #iDRAC settings #$iDRACCredentials=Get-Credential #grab iDRAC credentials @@ -93,6 +96,8 @@ New-PSSessionConfigurationFile -RunAsVirtualAccount -Path $env:TEMP\VirtualAccount.pssc Register-PSSessionConfiguration -Name 'VirtualAccount' -Path $env:TEMP\VirtualAccount.pssc -Force } -ErrorAction Ignore + #sleep a bit + Start-Sleep 2 # Run Windows Update via ComObject. Invoke-Command -ComputerName $servers -ConfigurationName 'VirtualAccount' { $Searcher = New-Object -ComObject Microsoft.Update.Searcher @@ -123,6 +128,8 @@ New-PSSessionConfigurationFile -RunAsVirtualAccount -Path $env:TEMP\VirtualAccount.pssc Register-PSSessionConfiguration -Name 'VirtualAccount' -Path $env:TEMP\VirtualAccount.pssc -Force } -ErrorAction Ignore + #sleep a bit + Start-Sleep 2 # Run Windows Update via ComObject. Invoke-Command -ComputerName $servers -ConfigurationName 'VirtualAccount' { $Searcher = New-Object -ComObject Microsoft.Update.Searcher @@ -164,7 +171,7 @@ } } #define and install other features - $features="Failover-Clustering","RSAT-Clustering-PowerShell","Hyper-V-PowerShell","NetworkATC","NetworkHUD","Data-Center-Bridging","Bitlocker","RSAT-Feature-Tools-BitLocker","Storage-Replica","RSAT-Storage-Replica","FS-Data-Deduplication","System-Insights","RSAT-System-Insights" + $features="Failover-Clustering","RSAT-Clustering-PowerShell","Hyper-V-PowerShell","NetworkATC","NetworkHUD","Data-Center-Bridging","RSAT-DataCenterBridging-LLDP-Tools","FS-SMBBW","Bitlocker","RSAT-Feature-Tools-BitLocker","Storage-Replica","RSAT-Storage-Replica","FS-Data-Deduplication","System-Insights","RSAT-System-Insights" Invoke-Command -ComputerName $servers -ScriptBlock {Install-WindowsFeature -Name $using:features} #endregion @@ -322,7 +329,7 @@ & "C:\Program Files\Dell\DELL System Update\DSU.exe" --catalog-location="$using:DSUPackageDownloadFolder\ASHCI-Catalog.xml" --preview | Out-Null $Result=(Get-content "C:\ProgramData\Dell\DELL System Update\dell_dup\DSU_STATUS.json" | ConvertFrom-JSon).systemupdatestatus.invokerinfo.statusmessage if ($Result -like "No Applicable Update*" ){ - $DellUpdateRequired=$false + $DellUpdateRequired=$False }else{ $DellUpdateRequired=$true } @@ -426,25 +433,22 @@ Clear-DnsClientCache #Configure the host vNIC to use a Vlan. They can be on the same or different VLans - If ($NumberOfStorageNets -eq 1){ - Set-VMNetworkAdapterVlan -VMNetworkAdapterName SMB* -VlanId $StorVLAN -Access -ManagementOS -CimSession $Servers - }else{ - #configure Odds and Evens for VLAN1 and VLAN2 - foreach ($Server in $Servers){ - $NetAdapters=Get-VMNetworkAdapter -CimSession $server -ManagementOS -Name *SMB* | Sort-Object Name - $i=1 - foreach ($NetAdapter in $NetAdapters){ - if (($i % 2) -eq 1){ - Set-VMNetworkAdapterVlan -VMNetworkAdapterName $NetAdapter.Name -VlanId $StorVLAN1 -Access -ManagementOS -CimSession $Server - $i++ - }else{ - Set-VMNetworkAdapterVlan -VMNetworkAdapterName $NetAdapter.Name -VlanId $StorVLAN2 -Access -ManagementOS -CimSession $Server - $i++ - } + #configure Odds and Evens for VLAN1 and VLAN2 + foreach ($Server in $Servers){ + $NetAdapters=Get-VMNetworkAdapter -CimSession $server -ManagementOS -Name *SMB* | Sort-Object Name + $i=1 + foreach ($NetAdapter in $NetAdapters){ + if (($i % 2) -eq 1){ + Set-VMNetworkAdapterVlan -VMNetworkAdapterName $NetAdapter.Name -VlanId $StorVLAN1 -Access -ManagementOS -CimSession $Server + $i++ + }else{ + Set-VMNetworkAdapterVlan -VMNetworkAdapterName $NetAdapter.Name -VlanId $StorVLAN2 -Access -ManagementOS -CimSession $Server + $i++ } } } + #Restart each host vNIC adapter so that the Vlan is active. Get-NetAdapter -CimSession $Servers -Name "vEthernet (SMB*)" | Restart-NetAdapter @@ -492,7 +496,7 @@ Invoke-Command -ComputerName $servers -ScriptBlock {Disable-NetQosFlowControl -Priority 0,1,2,4,5,6,7} #Disable Data Center bridging exchange (disable accept data center bridging (DCB) configurations from a remote device via the DCBX protocol, which is specified in the IEEE data center bridging (DCB) standard.) - Invoke-Command -ComputerName $servers -ScriptBlock {Set-NetQosDcbxSetting -willing $false -confirm:$false} + Invoke-Command -ComputerName $servers -ScriptBlock {Set-NetQosDcbxSetting -willing $False -confirm:$False} #Configure IeeePriorityTag #IeePriorityTag needs to be On if you want tag your nonRDMA traffic for QoS. Can be off if you use adapters that pass vSwitch (both SR-IOV and RDMA bypasses vSwitch) @@ -558,6 +562,7 @@ Invoke-Command -ComputerName $WitnessServer -ScriptBlock {new-item -Path c:\Shares -Name $using:WitnessName -ItemType Directory -ErrorAction Ignore} $accounts=@() $accounts+="$env:userdomain\$ClusterName$" + $accounts+="$env:userdomain\$env:USERNAME" #$accounts+="$env:userdomain\Domain Admins" New-SmbShare -Name $WitnessName -Path "c:\Shares\$WitnessName" -FullAccess $accounts -CimSession $WitnessServer #Set NTFS permissions @@ -598,7 +603,7 @@ } #endregion -#region configure Cluster-Aware-Updating +#region configure Cluster-Aware-Updating and Kernel Soft Reboot if ($CAURoleName){ #Install required features on nodes. Invoke-Command -ComputerName $Servers -ScriptBlock { @@ -609,76 +614,82 @@ #disable self-updating Disable-CauClusterRole -ClusterName $ClusterName -Force } + if ($KSR){ + #list cluster parameters - as you can see, CauEnableSoftReboot does not exist + Get-Cluster -Name $ClusterName | Get-ClusterParameter + #let's create the value and validate + Get-Cluster -Name $ClusterName | Set-ClusterParameter -Name CauEnableSoftReboot -Value 1 -Create + Get-Cluster -Name $ClusterName | Get-ClusterParameter -Name CauEnableSoftReboot + #to delete it again you can run following command + #Get-Cluster -Name $ClusterName | Set-ClusterParameter -Name CauEnableSoftReboot -Delete + } #endregion #region Configure networking with NetATC https://techcommunity.microsoft.com/t5/networking-blog/network-atc-what-s-coming-in-azure-stack-hci-22h2/ba-p/3598442 if ($NetATC){ - #make sure NetATC and other required features are installed on servers + #make sure NetATC,FS-SMBBW and other required features are installed on servers Invoke-Command -ComputerName $Servers -ScriptBlock { - Install-WindowsFeature -Name NetworkATC,Data-Center-Bridging,RSAT-Clustering-PowerShell,RSAT-Hyper-V-Tools + Install-WindowsFeature -Name NetworkATC,Data-Center-Bridging,RSAT-Clustering-PowerShell,RSAT-Hyper-V-Tools,FS-SMBBW } - #netatc CredSSP (hopefully CredSSP and "-ClusterName LocalHost" will go away in 11c) - # Temporarily enable CredSSP delegation to avoid double-hop issue - $CredSSPUserName="corp\LabAdmin" - $CredSSPPassword="LS1setup!" - foreach ($Server in $Servers){ - Enable-WSManCredSSP -Role "Client" -DelegateComputer $Server -Force - } - Invoke-Command -ComputerName $Servers -ScriptBlock { Enable-WSManCredSSP Server -Force } - - $SecureStringPassword = ConvertTo-SecureString $CredSSPPassword -AsPlainText -Force - $Credentials = New-Object System.Management.Automation.PSCredential ($CredSSPUserName, $SecureStringPassword) - - if ((Get-CimInstance -ClassName win32_computersystem -CimSession $servers[0]).Model -eq "Virtual Machine"){ - Invoke-Command -ComputerName $servers[0] -Credential $Credentials -Authentication Credssp -ScriptBlock { - Import-Module NetworkATC - #virtual environment (skipping RDMA config) - $AdapterOverride = New-NetIntentAdapterPropertyOverrides - $AdapterOverride.NetworkDirect = 0 - Add-NetIntent -ClusterName LocalHost -Name ConvergedIntent -Management -Compute -Storage -AdapterName "Ethernet","Ethernet 2" -AdapterPropertyOverrides $AdapterOverride -Verbose #-StorageVlans 1,2 - } - }else{ - #real hardware - #grab fastest adapters names (assuming that we are deploying converged intent with just Mellanox or Intel E810) - $FastestLinkSpeed=(get-netadapter -CimSession $Servers | Where-Object {$_.Status -eq "up" -and $_.HardwareInterface -eq $True}).Speed | Sort-Object -Descending | Select-Object -First 1 - #grab adapters - $AdapterNames=(Get-NetAdapter -CimSession $ClusterName | Where-Object {$_.Status -eq "up" -and $_.HardwareInterface -eq $True} | where-object Speed -eq $FastestLinkSpeed | Sort-Object Name).Name - #$AdapterNames="SLOT 3 Port 1","SLOT 3 Port 2" - Invoke-Command -ComputerName $servers[0] -Credential $Credentials -Authentication Credssp -ScriptBlock { - Import-Module NetworkATC - Add-NetIntent -ClusterName LocalHost -Name ConvergedIntent -Management -Compute -Storage -AdapterName $using:AdapterNames -Verbose #-StorageVlans 1,2 - } - } + #since ATC is not available on management machine, copy PowerShell module over to management machine from cluster. However global intents will not be automatically added as in C:\Windows\System32\WindowsPowerShell\v1.0\Modules\NetworkATC\NetWorkATC.psm1 is being checked if NetATC feature is installed [FabricManager.FeatureStaging]::Feature_NetworkATC_IsEnabled() + $session=New-PSSession -ComputerName $ClusterName + $items="C:\Windows\System32\WindowsPowerShell\v1.0\Modules\NetworkATC","C:\Windows\System32\NetworkAtc.Driver.dll","C:\Windows\System32\Newtonsoft.Json.dll","C:\Windows\System32\NetworkAtcFeatureStaging.dll" + foreach ($item in $items){ + Copy-Item -FromSession $session -Path $item -Destination $item -Recurse -Force + } - #check - Start-Sleep 20 #let intent propagate a bit - Write-Output "applying intent" - do { - $status=Invoke-Command -ComputerName $servers[0] -ScriptBlock {Get-NetIntentStatus -ClusterName LocalHost} - Write-Host "." -NoNewline - Start-Sleep 5 - } while ($status.ConfigurationStatus -contains "Provisioning" -or $status.ConfigurationStatus -contains "Retrying") + #if virtual environment, then skip RDMA config + if ((Get-CimInstance -ClassName win32_computersystem -CimSession $servers[0]).Model -eq "Virtual Machine"){ + Import-Module NetworkATC + #virtual environment (skipping RDMA config) + $AdapterOverride = New-NetIntentAdapterPropertyOverrides + $AdapterOverride.NetworkDirect = 0 + Add-NetIntent -ClusterName $ClusterName -Name ConvergedIntent -Management -Compute -Storage -AdapterName "Ethernet","Ethernet 2" -AdapterPropertyOverrides $AdapterOverride -Verbose #-StorageVlans 1,2 + }else{ + #on real hardware you can configure RDMA + #grab fastest adapters names (assuming that we are deploying converged intent with just Mellanox or Intel E810) + $FastestLinkSpeed=(get-netadapter -CimSession $Servers | Where-Object {$_.Status -eq "up" -and $_.HardwareInterface -eq $True}).Speed | Sort-Object -Descending | Select-Object -First 1 + #grab adapters + $AdapterNames=(Get-NetAdapter -CimSession $ClusterName | Where-Object {$_.Status -eq "up" -and $_.HardwareInterface -eq $True} | where-object Speed -eq $FastestLinkSpeed | Sort-Object Name).Name + #$AdapterNames="SLOT 3 Port 1","SLOT 3 Port 2" + Import-Module NetworkATC + Add-NetIntent -ClusterName $ClusterName -Name ConvergedIntent -Management -Compute -Storage -AdapterName $AdapterNames -Verbose #-StorageVlans 1,2 + } - #remove if necessary - <# - Invoke-Command -ComputerName $servers[0] -ScriptBlock { - $intents = Get-NetIntent -ClusterName localhost - foreach ($intent in $intents){ - Remove-NetIntent -Name $intent.IntentName -ClusterName Localhost - } + #Add default global intent + #since when configuring from Management machine there is a test [FabricManager.FeatureStaging]::Feature_NetworkATC_IsEnabled() to make global intents available, it will not be configured, so it has to be configured manually with invoke command + Invoke-Command -ComputerName $servers[0] -ScriptBlock { + Import-Module NetworkATC + $overrides=New-NetIntentGlobalClusterOverrides + #add empty intent + Add-NetIntent -GlobalClusterOverrides $overrides + } + + #check + Start-Sleep 20 #let intent propagate a bit + Write-Output "applying intent" + do { + $status=Invoke-Command -ComputerName $servers[0] -ScriptBlock {Get-NetIntentStatus} + Write-Host "." -NoNewline + Start-Sleep 5 + } while ($status.ConfigurationStatus -contains "Provisioning" -or $status.ConfigurationStatus -contains "Retrying") + + #remove if necessary + <# + Invoke-Command -ComputerName $servers[0] -ScriptBlock { + $intents = Get-NetIntent + foreach ($intent in $intents){ + Remove-NetIntent -Name $intent.IntentName } - #> + } + #> #if deploying in VMs, some nodes might fail (quarantined state) and even CNO can go to offline ... go to cluadmin and fix #Get-ClusterNode -Cluster $ClusterName | Where-Object State -eq down | Start-ClusterNode -ClearQuarantine - # Disable CredSSP - Disable-WSManCredSSP -Role Client - Invoke-Command -ComputerName $servers -ScriptBlock { Disable-WSManCredSSP Server } - <# - #since ATC is not available on managment machine, you can copy PowerShell module over. However not everything works as in C:\Windows\System32\WindowsPowerShell\v1.0\Modules\NetworkATC\NetWorkATC.psm1 is often being checked if NetATC feature is installed [FabricManager.FeatureStaging]::Feature_NetworkATC_IsEnabled() + #since ATC is not available on management machine, you can copy PowerShell module over. However not everything works as in C:\Windows\System32\WindowsPowerShell\v1.0\Modules\NetworkATC\NetWorkATC.psm1 is often being checked if NetATC feature is installed [FabricManager.FeatureStaging]::Feature_NetworkATC_IsEnabled() $session=New-PSSession -ComputerName $ClusterName $items="C:\Windows\System32\WindowsPowerShell\v1.0\Modules\NetworkATC","C:\Windows\System32\NetworkAtc.Driver.dll","C:\Windows\System32\Newtonsoft.Json.dll","C:\Windows\System32\NetworkAtcFeatureStaging.dll" foreach ($item in $items){ @@ -690,80 +701,132 @@ #region install network HUD (NetATC) if ($NetATC){ - #make sure NetworkHUD feature is installed and started on servers + #make sure NetworkHUD features are installed and network HUD is started on servers + Invoke-Command -ComputerName $Servers -ScriptBlock { + Install-WindowsFeature -Name "NetworkHUD","Hyper-V","Hyper-V-PowerShell","Data-Center-Bridging", "RSAT-DataCenterBridging-LLDP-Tools","NetworkATC","Failover-Clustering" + #make sure service is started and running (it is) + #Set-Service -Name NetworkHUD -StartupType Automatic + #Start-Service -Name NetworkHUD + } + #install Network HUD modules (Test-NetStack and az.stackhci.networkhud) on nodes + $Modules="Test-NetStack","az.stackhci.networkhud" + Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force + foreach ($Module in $Modules){ + #download module to management node + Save-Module -Name $Module -Path $env:Userprofile\downloads\ + #copy it to servers + foreach ($Server in $Servers){ + Copy-Item -Path "$env:Userprofile\downloads\$module" -Destination "\\$Server\C$\Program Files\WindowsPowerShell\Modules\" -Recurse -Force + } + } + #restart NetworkHUD service Invoke-Command -ComputerName $Servers -ScriptBlock { - Install-WindowsFeature -Name "NetworkHUD" - Set-Service -Name NetworkHUD -StartupType Automatic - Start-Service -Name NetworkHUD + Restart-Service NetworkHUD + } + #check event logs + $events=Invoke-Command -ComputerName $Servers -ScriptBlock { + Get-WinEvent -FilterHashtable @{"ProviderName"="Microsoft-Windows-Networking-NetworkHUD";Id=105} } + $events | Format-Table -AutoSize } #endregion #region configure what was/was not configured with NetATC if ($NetATC){ - #disable unused adapters - Get-Netadapter -CimSession $Servers | Where-Object Status -ne "Up" | Disable-NetAdapter -Confirm:0 + #region Configure what NetATC is not configuring + #disable unused adapters + Get-Netadapter -CimSession $Servers | Where-Object Status -ne "Up" | Disable-NetAdapter -Confirm:0 + + #Rename and Configure USB NICs (iDRAC Network) + $USBNics=get-netadapter -CimSession $Servers -InterfaceDescription "Remote NDIS Compatible Device" -ErrorAction Ignore + if ($USBNics){ + $Network=(Get-ClusterNetworkInterface -Cluster $ClusterName | Where-Object Adapter -eq "Remote NDIS Compatible Device").Network | Select-Object -Unique + $Network.Name="iDRAC" + $Network.Role="none" + } - #Rename and Configure USB NICs (iDRAC Network) - $USBNics=get-netadapter -CimSession $Servers -InterfaceDescription "Remote NDIS Compatible Device" -ErrorAction Ignore - if ($USBNics){ - $Network=(Get-ClusterNetworkInterface -Cluster $ClusterName | Where-Object Adapter -eq "Remote NDIS Compatible Device").Network | Select-Object -Unique - $Network.Name="iDRAC" - $Network.Role="none" - } + #Configure dcbxmode to be host in charge (default is firmware in charge) on mellanox adapters (Dell recommendation) + #Caution: This disconnects adapters! + if ((Get-CimInstance -ClassName win32_computersystem -CimSession $servers[0]).Manufacturer -like "*Dell Inc."){ + if (Get-NetAdapter -CimSession $Servers -InterfaceDescription Mellanox*){ + Set-NetAdapterAdvancedProperty -CimSession $Servers -InterfaceDescription Mellanox* -DisplayName 'Dcbxmode' -DisplayValue 'Host in charge' + } + } + #endregion - #Check what networks were excluded from Live Migration - $Networks=(Get-ClusterResourceType -Cluster $clustername -Name "Virtual Machine" | Get-ClusterParameter -Name MigrationExcludeNetworks).Value -split ";" - foreach ($Network in $Networks){Get-ClusterNetwork -Cluster $ClusterName | Where-Object ID -Match $Network} + #region Check settings before applying NetATC + #Check what networks were excluded from Live Migration + $Networks=(Get-ClusterResourceType -Cluster $clustername -Name "Virtual Machine" | Get-ClusterParameter -Name MigrationExcludeNetworks).Value -split ";" + foreach ($Network in $Networks){Get-ClusterNetwork -Cluster $ClusterName | Where-Object ID -Match $Network} - #check Live Migration option - Get-VMHost -CimSession $Servers | Select-Object *Migration* + #check Live Migration option (probably bug, because it should default to SMB - version tested 1366) + Get-VMHost -CimSession $Servers | Select-Object *Migration* - #Check LiveMigrationPerf option and Limit - Get-Cluster -Name $ClusterName | Select-Object *SMB* + #Check smbbandwith limit cluster settings (notice for some reason is SetSMBBandwidthLimit=1) + Get-Cluster -Name $ClusterName | Select-Object *SMB* - #check VLAN settings - Get-VMNetworkAdapterIsolation -CimSession $Servers -ManagementOS + #check SMBBandwidthLimit settings (should be pouplated already with defaults on physical cluster - it calculated 1562500000 bytes per second on 2x25Gbps NICs) + Get-SmbBandwidthLimit -CimSession $Servers - #adjust if necessary (Global cluster overrides may/may not work as there is a bug in 22h2 importing this piece of powershell module - [FabricManager.FeatureStaging]::Feature_NetworkATC_IsEnabled() sometimes work, sometimes not. Need to explore more) - Invoke-Command -ComputerName $Servers[0] -ScriptBlock { - $overrides=New-NetIntentGlobalClusterOverrides - $overrides.MaximumVirtualMachineMigrations=4 - $overrides.MaximumSMBMigrationBandwidthInGbps=20 - $overrides.VirtualMachineMigrationPerformanceOption="SMB" - Set-NetIntent -ClusterName LocalHost -GlobalClusterOverrides $overrides - } + #check VLAN settings (notice it's using Adapter Isolation, not VLAN) + Get-VMNetworkAdapterIsolation -CimSession $Servers -ManagementOS - Start-Sleep 20 #let intent propagate a bit - Write-Output "applying overrides intent" - do { - $status=Invoke-Command -ComputerName $Servers[0] -ScriptBlock {Get-NetIntentStatus -Globaloverrides -ClusterName LocalHost} - Write-Host "." -NoNewline - Start-Sleep 5 - } while ($status.ConfigurationStatus -contains "Provisioning" -or $status.ConfigurationStatus -contains "Retrying") + #check number of live migrations (default is 1) + get-vmhost -CimSession $Servers | Select-Object Name,MaximumVirtualMachineMigrations + #endregion + + #region Adjust NetATC global overrides (assuming there is one vSwitch) + $vSwitchNics=(Get-VMSwitch -CimSession $Servers[0]).NetAdapterInterfaceDescriptions + $LinkCapacityInGbps=(Get-NetAdapter -CimSession $Servers[0] -InterfaceDescription $vSwitchNics | Measure-Object Speed -Sum).sum/1000000000 + Invoke-Command -ComputerName $Servers[0] -ScriptBlock { + Import-Module NetworkATC + $overrides=New-NetIntentGlobalClusterOverrides + $overrides.MaximumVirtualMachineMigrations=4 + $overrides.MaximumSMBMigrationBandwidthInGbps=$using:LinkCapacityInGbps*0.4 #40%, if one switch is down, LM will not saturate bandwidth + $overrides.VirtualMachineMigrationPerformanceOption="SMB" + Set-NetIntent -GlobalClusterOverrides $overrides + } + + Start-Sleep 20 #let intent propagate a bit + Write-Output "applying overrides intent" + do { + $status=Invoke-Command -ComputerName $Servers[0] -ScriptBlock {Get-NetIntentStatus -Globaloverrides} + Write-Host "." -NoNewline + Start-Sleep 5 + } while ($status.ConfigurationStatus -contains "Provisioning" -or $status.ConfigurationStatus -contains "Retrying") + #endregion + + #region verify settings again + #Check Cluster Global overrides + Invoke-Command -ComputerName $ClusterName -ScriptBlock { + Import-Module NetworkATC + $GlobalOverrides=Get-Netintent -GlobalOverrides + $GlobalOverrides.ClusterOverride + } #check Live Migration option Get-VMHost -CimSession $Servers | Select-Object *Migration* - #Check LiveMigrationPerf option and Limit (Need more research on how the bandwidth works as it seems unchanged) + #Check LiveMigrationPerf option and Limit (SetSMBBandwidthLimit was 1, now is 0) Get-Cluster -Name $ClusterName | Select-Object *SMB* - #Configure dcbxmode to be host in charge (default is firmware in charge) on mellanox adapters (Dell recommendation) - #Caution: This disconnects adapters! - if ((Get-CimInstance -ClassName win32_computersystem -CimSession $servers[0]).Manufacturer -like "*Dell Inc."){ - if (Get-NetAdapter -CimSession $Servers -InterfaceDescription Mellanox*){ - Set-NetAdapterAdvancedProperty -CimSession $Servers -InterfaceDescription Mellanox* -DisplayName 'Dcbxmode' -DisplayValue 'Host in charge' - } - } + #check SMBBandwidthLimit settings + Get-SmbBandwidthLimit -CimSession $Servers - #Configure SMB Bandwidth Limits for Live Migration https://techcommunity.microsoft.com/t5/Failover-Clustering/Optimizing-Hyper-V-Live-Migrations-on-an-Hyperconverged/ba-p/396609 - #note: this should be normally configured with NetATC... docs needed https://techcommunity.microsoft.com/t5/networking-blog/network-atc-what-s-coming-in-azure-stack-hci-22h2/ba-p/3598442 - #install feature - Invoke-Command -ComputerName $servers -ScriptBlock {Install-WindowsFeature -Name "FS-SMBBW"} - #Calculate 40% of capacity of NICs in vSwitch (considering 2 NICs, if 1 fails, it will not consume all bandwith, therefore 40%) - $Adapters=(Get-VMSwitch -CimSession $Servers[0]).NetAdapterInterfaceDescriptions - $BytesPerSecond=((Get-NetAdapter -CimSession $Servers[0] -InterfaceDescription $adapters).TransmitLinkSpeed | Measure-Object -Sum).Sum/8 - Set-SmbBandwidthLimit -Category LiveMigration -BytesPerSecond ($BytesPerSecond*0.4) -CimSession $Servers + #check number of live migrations + get-vmhost -CimSession $Servers | Select-Object Name,MaximumVirtualMachineMigrations + #endregion + + #remove net intent global overrides if necessary + <# + Invoke-Command -ComputerName $servers[0] -ScriptBlock { + Import-Module NetworkATC + Remove-NetIntent -GlobalOverrides + $overrides=New-NetIntentGlobalClusterOverrides + #add empty intent + Add-NetIntent -GlobalClusterOverrides $overrides + } + #> } #endregion @@ -1051,9 +1114,9 @@ if ((Get-CimInstance -ClassName win32_computersystem -CimSession $Servers[0]).Ma $Provider = New-Object Microsoft.CSharp.CSharpCodeProvider $Compiler = $Provider.CreateCompiler() $Params = New-Object System.CodeDom.Compiler.CompilerParameters - $Params.GenerateExecutable = $false + $Params.GenerateExecutable = $False $Params.GenerateInMemory = $true - $Params.IncludeDebugInformation = $false + $Params.IncludeDebugInformation = $False $Params.ReferencedAssemblies.Add("System.DLL") > $null $TASource=@' namespace Local.ToolkitExtensions.Net.CertificatePolicy @@ -1181,7 +1244,7 @@ if ((Get-CimInstance -ClassName win32_computersystem -CimSession $Servers[0]).Ma $ComputersInfo = Invoke-Command -ComputerName $servers -ScriptBlock { Get-ItemProperty -Path $using:RegistryPath } - $ComputersInfo | Select-Object PSComputerName,CurrentBuildNumber,UBR + $ComputersInfo | Select-Object PSComputerName,ProductName,DisplayVersion,UBR #check last driver update status Invoke-Command -ComputerName $Servers -ScriptBlock { @@ -1235,6 +1298,18 @@ if ((Get-CimInstance -ClassName win32_computersystem -CimSession $Servers[0]).Ma $ScanResult #endregion + #check NetworkHUD event logs + $events=Invoke-Command -ComputerName $Servers -ScriptBlock { + Get-WinEvent -FilterHashtable @{"ProviderName"="Microsoft-Windows-Networking-NetworkHUD";StartTime=(get-date).AddMinutes(-15)} + } + $events | Format-Table -AutoSize + + #check NetworkATC event logs + $events=Invoke-Command -ComputerName $Servers -ScriptBlock { + Get-WinEvent -FilterHashtable @{"ProviderName"="Microsoft-Windows-Networking-NetworkATC";StartTime=(get-date).AddMinutes(-15)} + } + $events | Format-Table -AutoSize + #Check cluster networks Get-ClusterNetwork -Cluster $clustername @@ -1265,4 +1340,8 @@ if ((Get-CimInstance -ClassName win32_computersystem -CimSession $Servers[0]).Ma Invoke-Command -ComputerName $servers -ScriptBlock {Get-NetQosFlowControl} | Sort-Object -Property PSComputername,Priority | Select-Object PSComputerName,Priority,Enabled #validate QoS Traffic Classes Invoke-Command -ComputerName $servers -ScriptBlock {Get-NetQosTrafficClass} |Sort-Object PSComputerName,Name |Select-Object PSComputerName,Name,PriorityFriendly,Bandwidth + + #run test-netstack + Install-Module -Name Test-NetStack + test-netstack -Nodes $Servers -LogPath c:\temp\testnetstack.log -Verbose -EnableFirewallRules -ContinueOnFailure #endregion \ No newline at end of file diff --git a/Scenarios/AzSHCI Deployment 22H2 Edition/readme.md b/Scenarios/AzSHCI Deployment 22H2 Edition/readme.md index c959b476..54f45323 100644 --- a/Scenarios/AzSHCI Deployment 22H2 Edition/readme.md +++ b/Scenarios/AzSHCI Deployment 22H2 Edition/readme.md @@ -1,4 +1,4 @@ ## Notes: * Notice AllowedVLANs in labconfig (to simulate VLANs configuration in NetATC) * CreateParentDisk will create VHD with name AzSHCI**21**H2_G2.vhdx even with 22h2 media. Please rename VHDx manually -* Make sure you use latest 21H2 cumulative update (at least version 20348.1070 - september preview CU) as there are new cluster parameters (not yet used in lab), but it might be useful +* Make sure you use latest 22H2 cumulative update (at least version 20348.1070 - september preview CU) as there are new cluster parameters (not yet used in lab), but it might be useful diff --git a/Scenarios/AzSHCI and Cluster Expansion/LabConfig.ps1 b/Scenarios/AzSHCI and Cluster Expansion/LabConfig.ps1 index 972be80d..06462b47 100644 --- a/Scenarios/AzSHCI and Cluster Expansion/LabConfig.ps1 +++ b/Scenarios/AzSHCI and Cluster Expansion/LabConfig.ps1 @@ -1,4 +1,7 @@ $LabConfig=@{ DomainAdminName='LabAdmin'; AdminPassword='LS1setup!' ; Prefix = 'MSLab-' ; DCEdition='4'; Internet=$true ; TelemetryLevel='Full' ; TelemetryNickname='' ; AdditionalNetworksConfig=@(); VMs=@()} -#3 nodes for AzSHCI Cluster +#4 nodes for AzSHCI Cluster 1..4 | ForEach-Object {$VMNames="Exp" ; $LABConfig.VMs += @{ VMName = "$VMNames$_" ; Configuration = 'S2D' ; ParentVHD = 'AzSHCI21H2_G2.vhdx' ; HDDNumber = 4 ; HDDSize= 4TB ; MemoryStartupBytes= 4GB; VMProcessorCount=4 ; NestedVirt=$true ; VirtualTPM=$true}} + +#3 nodes for AzSHCI Cluster light - without nested virtualization +#1..3 | ForEach-Object {$VMNames="Exp" ; $LABConfig.VMs += @{ VMName = "$VMNames$_" ; Configuration = 'S2D' ; ParentVHD = 'AzSHCI21H2_G2.vhdx' ; HDDNumber = 4 ; HDDSize= 4TB ; VMProcessorCount=4 ; VirtualTPM=$true}} diff --git a/Scenarios/AzSHCI and Cluster Expansion/Scenario.ps1 b/Scenarios/AzSHCI and Cluster Expansion/Scenario.ps1 index 98356a55..33de4681 100644 --- a/Scenarios/AzSHCI and Cluster Expansion/Scenario.ps1 +++ b/Scenarios/AzSHCI and Cluster Expansion/Scenario.ps1 @@ -7,7 +7,7 @@ $ClusterName="Exp-Cluster" $vSwitchName="vSwitch" - # Install features for management on server + # Install features for management Install-WindowsFeature -Name RSAT-DHCP,RSAT-Clustering,RSAT-Clustering-Mgmt,RSAT-Clustering-PowerShell,RSAT-Hyper-V-Tools # Install features on server @@ -25,11 +25,11 @@ do{$Test= Test-NetConnection -ComputerName $Server -CommonTCPPort WINRM}while ($test.TcpTestSucceeded -eq $False) #} # create vSwitch from first connected NIC - $NetAdapterName=(Get-NetAdapter -Cimsession $Server | Where-Object HardwareInterface -eq $True | Where-Object Status -eq UP | Sort-Object InterfaceAlias | Select-Object -First 1).InterfaceAlias - New-VMSwitch -Cimsession $Server -Name $vSwitchName -EnableEmbeddedTeaming $TRUE -NetAdapterName $NetAdapterName -EnableIov $true + $NetAdapterName=(Get-NetAdapter -CimSession $Server | Where-Object HardwareInterface -eq $True | Where-Object Status -eq UP | Sort-Object InterfaceAlias | Select-Object -First 1).InterfaceAlias + New-VMSwitch -CimSession $Server -Name $vSwitchName -EnableEmbeddedTeaming $TRUE -NetAdapterName $NetAdapterName -EnableIov $true #rename vNIC - Rename-VMNetworkAdapter -Cimsession $Server -ManagementOS -Name $vSwitchName -NewName Management + Rename-VMNetworkAdapter -CimSession $Server -ManagementOS -Name $vSwitchName -NewName Management #create cluster with Distributed Network Name (to not consume extra IP, because why not) New-Cluster -Name $ClusterName -Node $Server -ManagementPointNetworkType "Distributed" @@ -125,17 +125,16 @@ New-Item -Path "\\$ClusterName\ClusterStorage$\$VolumeFriendlyName\$VMName\Virtual Hard Disks" -ItemType Directory Copy-Item -Path $VHDPath -Destination "\\$ClusterName\ClusterStorage$\$VolumeFriendlyName\$VMName\Virtual Hard Disks\$VMName.vhdx" $VM=New-VM -Name $VMName -MemoryStartupBytes 512MB -Generation 2 -Path "c:\ClusterStorage\$VolumeFriendlyName\" -VHDPath "c:\ClusterStorage\$VolumeFriendlyName\$VMName\Virtual Hard Disks\$VMName.vhdx" -CimSession ((Get-ClusterNode -Cluster $ClusterName).Name | Get-Random) - + #start VM + $VM | Start-VM }else{ Invoke-Command -ComputerName ((Get-ClusterNode -Cluster $ClusterName).Name | Get-Random) -ScriptBlock { #create some fake VMs - $VM=New-VM -Name $using:VMName -NewVHDPath "c:\ClusterStorage\$($using:VolumeFriendlyName)\$($using:VMName)\Virtual Hard Disks\$($using:VMName).vhdx" -NewVHDSizeBytes 32GB -SwitchName $using:vSwitchName -Generation 2 -Path "c:\ClusterStorage\$($using:VolumeFriendlyName)\" -MemoryStartupBytes 32MB + New-VM -Name $using:VMName -NewVHDPath "c:\ClusterStorage\$($using:VolumeFriendlyName)\$($using:VMName)\Virtual Hard Disks\$($using:VMName).vhdx" -NewVHDSizeBytes 32GB -SwitchName $using:vSwitchName -Generation 2 -Path "c:\ClusterStorage\$($using:VolumeFriendlyName)\" -MemoryStartupBytes 32MB } } #make it HA Add-ClusterVirtualMachineRole -VMName $VMName -Cluster $ClusterName - #start VM - $VM | Start-VM #endregion #endregion @@ -153,10 +152,8 @@ Restart-Computer -ComputerName $SecondNodeName -Protocol WSMan -Wait -For PowerShell #failsafe - sometimes it evaluates, that servers completed restart after first restart (hyper-v needs 2) Start-sleep 20 - #make sure computers are restarted - #Foreach ($Server in $Servers){ - do{$Test= Test-NetConnection -ComputerName $SecondNodeName -CommonTCPPort WINRM}while ($test.TcpTestSucceeded -eq $False) - #} + #make sure computer is restarted + do{$Test= Test-NetConnection -ComputerName $SecondNodeName -CommonTCPPort WINRM}while ($test.TcpTestSucceeded -eq $False) #endregion #region configure networking (assuming scalable, converged networking). @@ -180,9 +177,9 @@ #create vSwitch on second node #create vSwitch $NetAdapterNames=(Get-NetAdapter -CimSession $SecondNodeName | Where-Object HardwareInterface -eq $True | Where-Object Status -eq UP | Sort-Object InterfaceAlias).InterfaceAlias - New-VMSwitch -Cimsession $SecondNodeName -Name $vSwitchName -EnableEmbeddedTeaming $TRUE -NetAdapterName $NetAdapterNames -EnableIov $true + New-VMSwitch -CimSession $SecondNodeName -Name $vSwitchName -EnableEmbeddedTeaming $True -NetAdapterName $NetAdapterNames -EnableIov $true #rename vNIC - Rename-VMNetworkAdapter -Cimsession $SecondNodeName -ManagementOS -Name $vSwitchName -NewName Management + Rename-VMNetworkAdapter -CimSession $SecondNodeName -ManagementOS -Name $vSwitchName -NewName Management #add SMB vNICs and configure IP foreach ($Server in ($FirstNodeName,$SecondNodeName)){ @@ -195,7 +192,7 @@ Add-VMNetworkAdapter -ManagementOS -Name "SMB$TwoDigitNumber" -SwitchName $vSwitchName -CimSession $Server } - #assign IP Adresses + #assign IP Addresses foreach ($number in (1..$SMBvNICsCount)){ $TwoDigitNumber="{0:D2}" -f $Number if ($number % 2 -eq 1){ @@ -349,15 +346,16 @@ #endregion #region configure pool fault domain to be Storage Scale Unit and create new volume - #config + #Config $ClusterName="Exp-Cluster" $VolumeFriendlyName="TwoNodesMirror" + $VolumeSize=1TB #configure storage pool Set-StoragePool -CimSession $ClusterName -FriendlyName "S2D on $ClusterName" -FaultDomainAwarenessDefault StorageScaleUnit #create new volume - New-Volume -CimSession $ClusterName -StoragePoolFriendlyName "S2D on $ClusterName" -FriendlyName $VolumeFriendlyName -Size 1TB -ProvisioningType Thin + New-Volume -CimSession $ClusterName -StoragePoolFriendlyName "S2D on $ClusterName" -FriendlyName $VolumeFriendlyName -Size $VolumeSize -ProvisioningType Thin #validate volume fault domain awareness Get-VirtualDisk -CimSession $ClusterName | Select-Object FriendlyName,FaultDomainAwareness @@ -370,7 +368,7 @@ #delete performance history including volume (without invoking it returned error "get-srpartnership : The WS-Management service cannot process the request. The CIM namespace") Invoke-Command -ComputerName $CLusterName -ScriptBlock {Stop-ClusterPerformanceHistory -DeleteHistory} #recreate performance history - Start-ClusterPerformanceHistory -cimsession $ClusterName + Start-ClusterPerformanceHistory -CimSession $ClusterName #validate volume fault domain awareness again (takes some time to recreate volume) Get-VirtualDisk -CimSession $ClusterName | Select-Object FriendlyName,FaultDomainAwareness @@ -393,7 +391,7 @@ #region expand cluster (2node->3node, or more) #region install roles and features on third node #Config - $Servers="Exp3" + $Servers="Exp3"#,"Exp4" # Install features on server(s) Invoke-Command -computername $Servers -ScriptBlock { Enable-WindowsOptionalFeature -FeatureName Microsoft-Hyper-V -Online -NoRestart @@ -413,7 +411,7 @@ #region configure networking (assuming scalable, converged networking). #Direct connectivity would be bit different, but since we will add 3rd node and simulating direct connectivity in MSLab would add another layer of complexity, I decided to demonstrate converged #Config - $Servers="Exp3" + $Servers="Exp3"#,"Exp4" $ClusterName="Exp-Cluster" $vSwitchName="vSwitch" $IP=3 #start IP @@ -527,15 +525,16 @@ #region add cluster member(s) #Config $ClusterName="Exp-Cluster" - $ClusterNodeNames="Exp3" + $ClusterNodeNames="Exp3"#,"Exp4" #add node Add-ClusterNode -Name $ClusterNodeNames -Cluster $ClusterName #endregion - #region configure ResiliencySettingNameDefault to have 3 data copies and create 3 way mirror volume + #region configure ResiliencySettingNameDefault to have 3 data copies and create 3-way mirror volume #config $ClusterName="Exp-Cluster" $VolumeFriendlyName="Three+NodesMirror" + $VolumeSize=1TB #check configuration of mirror resiliency setting (notice 2 data copies) Get-StoragePool -CimSession $ClusterName -FriendlyName "S2D on $ClusterName" | get-resiliencysetting @@ -547,7 +546,7 @@ Get-StoragePool -CimSession $ClusterName -FriendlyName "S2D on $ClusterName" | get-resiliencysetting -Name Mirror #create new volume - New-Volume -CimSession $ClusterName -StoragePoolFriendlyName "S2D on $ClusterName" -FriendlyName $VolumeFriendlyName -Size 1TB -ProvisioningType Thin + New-Volume -CimSession $ClusterName -StoragePoolFriendlyName "S2D on $ClusterName" -FriendlyName $VolumeFriendlyName -Size $VolumeSize -ProvisioningType Thin #validate volume resiliency Get-VirtualDisk -CimSession $ClusterName | Select-Object FriendlyName,NumberOfDataCopies @@ -560,7 +559,7 @@ #delete performance history including volume (without invoking it returned error "get-srpartnership : The WS-Management service cannot process the request. The CIM namespace") Invoke-Command -ComputerName $CLusterName -ScriptBlock {Stop-ClusterPerformanceHistory -DeleteHistory} #recreate performance history - Start-ClusterPerformanceHistory -cimsession $ClusterName + Start-ClusterPerformanceHistory -CimSession $ClusterName #validate volume resiliency again (takes some time to recreate volume) Get-VirtualDisk -CimSession $ClusterName | Select-Object FriendlyName,NumberOfDataCopies diff --git a/Scenarios/AzSHCI and Deployment tool/LabConfig.ps1 b/Scenarios/AzSHCI and Deployment tool/LabConfig.ps1 new file mode 100644 index 00000000..819e912f --- /dev/null +++ b/Scenarios/AzSHCI and Deployment tool/LabConfig.ps1 @@ -0,0 +1,13 @@ +$LabConfig=@{AllowedVLANs="1-10,711-719" ; DomainAdminName='LabAdmin'; AdminPassword='LS1setup!' ; DCEdition='4'; Internet=$true; TelemetryLevel='Full' ; TelemetryNickname='' ; AdditionalNetworksConfig=@(); VMs=@(); CustomDnsForwarders="10.8.8.8","10.7.7.7"} + +#Azure Stack HCI 22H2 +#labconfig will not domain join VMs, will add "Tools disk" and will also execute powershell command to make this tools disk online. +1..4 | ForEach-Object {$LABConfig.VMs += @{ VMName = "ASNode$_" ; Configuration = 'S2D' ; ParentVHD = 'AzSHCI22H2_G2.vhdx' ; HDDNumber = 4 ; HDDSize= 2TB ; MemoryStartupBytes= 1GB; VMProcessorCount=4 ; vTPM=$true ; AddToolsVHD=$True ; Unattend="NoDjoin" }} +#labconfig for nested virtualization +#1..4 | ForEach-Object {$LABConfig.VMs += @{ VMName = "ASNode$_" ; Configuration = 'S2D' ; ParentVHD = 'AzSHCI22H2_G2.vhdx' ; HDDNumber = 4 ; HDDSize= 2TB ; MemoryStartupBytes= 6GB; VMProcessorCount=4 ; vTPM=$true ; AddToolsVHD=$True ; Unattend="NoDjoin" ; NestedVirt=$true }} + +#Windows Admin Center in GW mode +$LabConfig.VMs += @{ VMName = 'WACGW' ; ParentVHD = 'Win2022Core_G2.vhdx'; MGMTNICs=1} + +#Management machine +$LabConfig.VMs += @{ VMName = 'Management' ; ParentVHD = 'Win2022_G2.vhdx'; MGMTNICs=1 ; AddToolsVHD=$True } \ No newline at end of file diff --git a/Scenarios/AzSHCI and Deployment tool/Scenario.ps1 b/Scenarios/AzSHCI and Deployment tool/Scenario.ps1 new file mode 100644 index 00000000..156d0272 --- /dev/null +++ b/Scenarios/AzSHCI and Deployment tool/Scenario.ps1 @@ -0,0 +1,292 @@ +#region Prepare Active Directory - run from management VM! + $AsHCIOUName="OU=ASClus01,DC=Corp,DC=contoso,DC=com" + $Servers="ASNode1","ASNode2","ASNode3","ASNode4" + $DomainFQDN=$env:USERDNSDOMAIN + $ClusterName="ASClus01" + $Prefix="ASClus01" + $UserName="ASClus01-DeployUser" + $Password="LS1setup!" + $SecuredPassword = ConvertTo-SecureString $password -AsPlainText -Force + $Credentials= New-Object System.Management.Automation.PSCredential ($UserName,$SecuredPassword) + + + #install posh module for prestaging Active Directory + Install-PackageProvider -Name NuGet -Force + Install-Module AsHciADArtifactsPreCreationTool -Repository PSGallery -Force + + #add KDS Root Key + if (-not (Get-KdsRootKey)){ + Add-KdsRootKey -EffectiveTime ((Get-Date).addhours(-10)) + } + + #make sure active directory module and GPMC is installed + Install-WindowsFeature -Name RSAT-AD-PowerShell,GPMC + + #populate objects + New-HciAdObjectsPreCreation -Deploy -AsHciDeploymentUserCredential $Credentials -AsHciOUName $AsHCIOUName -AsHciPhysicalNodeList $Servers -DomainFQDN $DomainFQDN -AsHciClusterName $ClusterName -AsHciDeploymentPrefix $Prefix + + #install management features to explore cluster,settings... + Install-WindowsFeature -Name "RSAT-ADDS","RSAT-Clustering" +#endregion + +#region Deploy - run from ASNode1! + #make D drives online + $Servers="ASNode2","ASNode3","ASNode4" + #add $Servers into trustedhosts + Set-Item WSMan:\localhost\Client\TrustedHosts -Value $($Servers -join ',') -Force + #invoke command + Invoke-Command -ComputerName $Servers -ScriptBlock { + get-disk -Number 1 | Set-Disk -IsReadOnly $false + get-disk -Number 1 | Set-Disk -IsOffline $false + } + #set trusted hosts back to $Null + Set-Item WSMan:\localhost\Client\TrustedHosts -Value "" -force + + #Download files + $downloadfolder="D:" + $files=@() + $Files+=@{Uri="https://go.microsoft.com/fwlink/?linkid=2210545" ; FileName="BootstrapCloudDeploymentTool.ps1" ; Description="Bootstrap PowerShell"} + $Files+=@{Uri="https://go.microsoft.com/fwlink/?linkid=2210546" ; FileName="CloudDeployment_10.2210.0.32.zip" ; Description="Cloud Deployment Package"} + $Files+=@{Uri="https://go.microsoft.com/fwlink/?linkid=2210608" ; FileName="Verify-CloudDeployment.zip_Hash.ps1" ; Description="Verify Cloud Deployment PowerShell"} + + foreach ($file in $files){ + if (-not (Test-Path "$downloadfolder\$($file.filename)")){ + Start-BitsTransfer -Source $file.uri -Destination "$downloadfolder\$($file.filename)" -DisplayName "Downloading: $($file.filename)" + } + } + + #Start bootstrap (script is looking for file "CloudDeployment_*.zip" + & D:\BootstrapCloudDeploymentTool.ps1 + + #create deployment credentials + $UserName="ASClus01-DeployUser" + $Password="LS1setup!" + $SecuredPassword = ConvertTo-SecureString $password -AsPlainText -Force + $DeploymentUserCred = New-Object System.Management.Automation.PSCredential ($UserName,$SecuredPassword) + + $UserName="Administrator" + $Password="LS1setup!" + $SecuredPassword = ConvertTo-SecureString $password -AsPlainText -Force + $LocalAdminCred = New-Object System.Management.Automation.PSCredential ($UserName,$SecuredPassword) + $CloudName="AzureCloud" + $ServicePrincipalName="Azure-Stack-Registration" + + #login to azure + #download Azure module + if (!(Get-InstalledModule -Name az.accounts -ErrorAction Ignore)){ + Install-Module -Name Az.Accounts -Force + } + if (-not (Get-AzContext)){ + Connect-AzAccount -UseDeviceAuthentication + } + #select subscription if more available + $subscriptions=Get-AzSubscription + if (($subscriptions).count -gt 1){ + $SubscriptionID=($subscriptions | Out-GridView -OutputMode Single | Select-AzSubscription).Subscription.Id + }else{ + $SubscriptionID=$subscriptions.id + } + + if (!(Get-InstalledModule -Name az.Resources -ErrorAction Ignore)){ + Install-Module -Name Az.Resources -Force + } + + #Create Azure Stack HCI registration role https://learn.microsoft.com/en-us/azure-stack/hci/deploy/register-with-azure#assign-permissions-from-azure-portal + if (-not (Get-AzRoleDefinition -Name "Azure Stack HCI registration role")){ + $Content=@" +{ + "Name": "Azure Stack HCI registration role", + "Id": null, + "IsCustom": true, + "Description": "Custom Azure role to allow subscription-level access to register Azure Stack HCI", + "Actions": [ + "Microsoft.Resources/subscriptions/resourceGroups/read", + "Microsoft.Resources/subscriptions/resourceGroups/write", + "Microsoft.Resources/subscriptions/resourceGroups/delete", + "Microsoft.AzureStackHCI/register/action", + "Microsoft.AzureStackHCI/Unregister/Action", + "Microsoft.AzureStackHCI/clusters/*", + "Microsoft.Authorization/roleAssignments/write", + "Microsoft.Authorization/roleAssignments/read", + "Microsoft.HybridCompute/register/action", + "Microsoft.GuestConfiguration/register/action", + "Microsoft.HybridConnectivity/register/action" + ], + "NotActions": [ + ], + "AssignableScopes": [ + "/subscriptions/$SubscriptionID" + ] + } +"@ + $Content | Out-File "$env:USERPROFILE\Downloads\customHCIRole.json" + New-AzRoleDefinition -InputFile "$env:USERPROFILE\Downloads\customHCIRole.json" + } + #Create AzADServicePrincipal for Azure Stack HCI registration + $SP=Get-AZADServicePrincipal -DisplayName $ServicePrincipalName + if (-not $SP){ + $SP=New-AzADServicePrincipal -DisplayName $ServicePrincipalName -Role "Azure Stack HCI registration role" + #remove default cred + Remove-AzADAppCredential -ApplicationId $SP.AppId + } + + #Create new SPN password + $credential = New-Object -TypeName "Microsoft.Azure.PowerShell.Cmdlets.Resources.MSGraph.Models.ApiV10.MicrosoftGraphPasswordCredential" -Property @{ + "KeyID" = (new-guid).Guid ; + "EndDateTime" = [DateTime]::UtcNow.AddYears(10) + } + $Creds=New-AzADAppCredential -PasswordCredentials $credential -ApplicationID $SP.AppID + $SPNSecret=$Creds.SecretText + Write-Host "Your Password is: " -NoNewLine ; Write-Host $SPNSecret -ForegroundColor Cyan + $SPNsecStringPassword = ConvertTo-SecureString $SPNSecret -AsPlainText -Force + $SPNCred=New-Object System.Management.Automation.PSCredential ($SP.AppID, $SPNsecStringPassword) + + #create config.json + $Content=@" +{ + "Version": "3.0.0.0", + "ScaleUnits": [ + { + "DeploymentData": { + "SecuritySettings": { + "SecurityModeSealed": true, + "SecuredCoreEnforced": true, + "VBSProtection": true, + "HVCIProtection": true, + "DRTMProtection": true, + "KernelDMAProtection": true, + "DriftControlEnforced": true, + "CredentialGuardEnforced": false, + "SMBSigningEnforced": true, + "SMBClusterEncryption": false, + "SideChannelMitigationEnforced": true, + "BitlockerBootVolume": true, + "BitlockerDataVolumes": true, + "SEDProtectionEnforced": true, + "WDACEnforced": true + }, + "Observability": { + "StreamingDataClient": true, + "EULocation": true, + "EpisodicDataUpload": true + }, + "Cluster": { + "Name": "ASClus01", + "StaticAddress": [ + "" + ] + }, + "Storage": { + "ConfigurationMode": "Express" + }, + "OptionalServices": { + "VirtualSwitchName": "", + "CSVPath": "", + "ARBRegion": "westeurope" + }, + "TimeZone": "Pacific Standard Time", + "NamingPrefix": "ASClus01", + "DomainFQDN": "corp.contoso.com", + "ExternalDomainFQDN": "corp.contoso.com", + "InfrastructureNetwork": [ + { + "VlanId": "0", + "SubnetMask": "255.255.255.0", + "Gateway": "10.0.0.1", + "IPPools": [ + { + "StartingAddress": "10.0.0.100", + "EndingAddress": "10.0.0.199" + } + ], + "DNSServers": [ + "10.0.0.1" + ] + } + ], + "PhysicalNodes": [ + { + "Name": "ASNode1", + "IPv4Address": "$((Get-NetIPAddress -InterfaceAlias ethernet -AddressFamily ipv4 -CimSession ASNode1).IPAddress)" + }, + { + "Name": "ASNode2", + "IPv4Address": "$((Get-NetIPAddress -InterfaceAlias ethernet -AddressFamily ipv4 -CimSession ASNode2).IPAddress)" + }, + { + "Name": "ASNode3", + "IPv4Address": "$((Get-NetIPAddress -InterfaceAlias ethernet -AddressFamily ipv4 -CimSession ASNode3).IPAddress)" + }, + { + "Name": "ASNode4", + "IPv4Address": "$((Get-NetIPAddress -InterfaceAlias ethernet -AddressFamily ipv4 -CimSession ASNode4).IPAddress)" + } + ], + "HostNetwork": { + "Intents": [ + { + "Name": "Compute_Management_Storage", + "TrafficType": [ + "Compute", + "Management", + "Storage" + ], + "Adapter": [ + "Ethernet", + "Ethernet 2" + ], + "OverrideVirtualSwitchConfiguration": false, + "VirtualSwitchConfigurationOverrides": { + "EnableIov": "", + "LoadBalancingAlgorithm": "" + }, + "OverrideQoSPolicy": false, + "QoSPolicyOverrides": { + "PriorityValue8021Action_Cluster": "", + "PriorityValue8021Action_SMB": "", + "BandwidthPercentage_SMB": "" + }, + "OverrideAdapterProperty": false, + "AdapterPropertyOverrides": { + "JumboPacket": "", + "NetworkDirect": "", + "NetworkDirectTechnology": "" + } + } + ], + "StorageNetworks": [ + { + "Name": "Storage1Network", + "NetworkAdapterName": "Ethernet", + "VlanId": 711 + }, + { + "Name": "Storage2Network", + "NetworkAdapterName": "Ethernet 2", + "VlanId": 712 + } + ] + }, + "ADOUPath": "OU=ASClus01,DC=Corp,DC=contoso,DC=com", + "DNSForwarder": [ + "10.0.0.1" + ] + } + } + ] +} +"@ +$Content | Out-File -FilePath d:\config.json + +#start deployment +.\Invoke-CloudDeployment -JSONFilePath D:\config.json -DeploymentUserCredential $DeploymentUserCred -LocalAdminCredential $LocalAdminCred -RegistrationSPCredential $SPNCred -RegistrationCloudName $CloudName -RegistrationSubscriptionID $SubscriptionID + +#endregion + +#region Validate deployment - run from management VM! +$StagingNode="ASNode1" + +Invoke-Command -ComputerName $StagingNode -ScriptBlock { + ([xml](Get-Content C:\ecestore\efb61d70-47ed-8f44-5d63-bed6adc0fb0f\086a22e3-ef1a-7b3a-dc9d-f407953b0f84)) | Select-Xml -XPath "//Action/Steps/Step" | ForEach-Object { $_.Node } | Select-Object FullStepIndex, Status, Name, StartTimeUtc, EndTimeUtc, @{Name="Durration";Expression={new-timespan -Start $_.StartTimeUtc -End $_.EndTimeUtc } } | ft -AutoSize +} +#endregion \ No newline at end of file diff --git a/Scenarios/AzSHCI and Deployment tool/readme.md b/Scenarios/AzSHCI and Deployment tool/readme.md new file mode 100644 index 00000000..c17cbd6c --- /dev/null +++ b/Scenarios/AzSHCI and Deployment tool/readme.md @@ -0,0 +1,7 @@ +Following lab is based on new Azure Stack HCI deployment tool: https://learn.microsoft.com/en-us/azure-stack/hci/deploy/deployment-tool-powershell + +Notes: +* Deployment tool uses "D" drive, so each azure stack hci node requires it. In Labconfig it will add tools.vhdx +* ToolsVHD was 30GB, new mslab 2_CreateParentDisks.ps1 script will create 300GB ToolsVHD. If you have older vhd, just expand it (hyper-v tools, and then expand partition inside) +* You can also notice in Labconfig, that nodes are not domain joined +* if you want step-by-step doc, you can use https://geos.to/AzSLabs \ No newline at end of file diff --git a/Scripts/2_CreateParentDisks.ps1 b/Scripts/2_CreateParentDisks.ps1 index 289e7936..a6fe162d 100644 --- a/Scripts/2_CreateParentDisks.ps1 +++ b/Scripts/2_CreateParentDisks.ps1 @@ -525,7 +525,7 @@ If (-not $isAdmin) { } if (!(Test-Path "$PSScriptRoot\ParentDisks\tools.vhdx")){ WriteInfoHighlighted "Creating Tools.vhdx" - $toolsVHD=New-VHD -Path "$PSScriptRoot\ParentDisks\tools.vhdx" -SizeBytes 30GB -Dynamic + $toolsVHD=New-VHD -Path "$PSScriptRoot\ParentDisks\tools.vhdx" -SizeBytes 300GB -Dynamic #mount and format VHD $VHDMount = Mount-VHD $toolsVHD.Path -Passthru $vhddisk = $VHDMount| get-disk