################################
# Run from DC or Management VM #
################################
#region LAB Config
# 2,3,4,8, or 16 nodes
$numberofnodes=2
$ServersNamePrefix="AzSHCI"
#generate servernames (based number of nodes and serversnameprefix)
$Servers=1..$numberofnodes | ForEach-Object {"$ServersNamePrefix$_"}
#alternatively you can just do $Servers="AzSHCI1","AzSHCI2","AzSHCI","AzSHCI4". The result is the same
# Domain Name (NetBIOS)
$corp = "AzsHCI"
# Windows Admin Center Gateway Name
$GatewayServerName="AzSHCIMGMT"
#Cluster Name
$ClusterName="AzSHCI-Cluster"
#Cluster-Aware-Updating role name
$CAURoleName="AzSHCI-Cl-CAU"
#Cluster IP
$ClusterIP="10.0.0.111" #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=$true
#Witness type
$WitnessType="Cloud" #or FileShare
#if cloud then configure following (use your own, these are just examples)
$CloudWitnessEndpoint="core.windows.net“
$ResourceGroupName="MSLabCloudWitness"
# nur Kleinbuchstaben und Ziffern, max.24 Zeichen; muss Azure weit eindeutig sein!
$StorageAccountName="mslabcloudwitness$(Get-Random -Minimum 100000 -Maximum 999999)"
#Disable CSV Balancer
$DisableCSVBalancer=$False
#Perform Windows update? (for more info visit WU Scenario https://github.com/microsoft/WSLab/tree/dev/Scenarios/Windows%20Update)
$WindowsUpdate="Recommended" #Can be "All","Recommended" or "None"
## Networking ##
$vSwitchName="vSwitch"
$NumberOfStorageNets=1 #1 or 2
#IF Stornet is 1
$StorNet="172.16.1."
$StorVLAN=1
#IF Stornets are 2 (in larger clusters it worth keep storage traffic local to each TOR switch)
$StorNet1="172.16.1."
$StorNet2="172.16.2."
$StorVLAN1=1
$StorVLAN2=2
$SRIOV=$true #Deploy SR-IOV enabled switch (best practice is to enable if possible)
#startIP of adapters that will be added to SET Switch
$AdaptersIPPrefix="10.0.0.*"
#start IP for storage network
$IP=1
#Real hardware?
$RealHW=$False #will configure VMQ not to use CPU 0 if $True, configures power plan
$DellHW=$False #include Dell recommendation to increase HW timeout to 10s becayse of their Hitachi HDDs. May be already obsolete.
#IncreaseHW Timeout for virtual environments to 30s? This is because of running in lab https://docs.microsoft.com/en-us/windows-server/storage/storage-spaces/storage-spaces-direct-in-vm
$VirtualEnvironment=$true
#Configure dcb? (more info at http://aka.ms/ConvergedRDMA)
$DCB=$False #$true for ROCE, $false for iWARP
#iWARP?
$iWARP=$False
#DisableNetBIOS on all vNICs? $True/$False It's optional. Works well with both settings default/disabled
$DisableNetBIOS=$False
#SMB Bandwith Limits for Live Migration? https://techcommunity.microsoft.com/t5/Failover-Clustering/Optimizing-Hyper-V-Live-Migrations-on-an-Hyperconverged/ba-p/396609
$SMBBandwidthLimits=$true
#Jumbo Frames? Might be necessary to increase for iWARP. If not default, make sure all switches are configured end-to-end and (for example 9216). Also if non-default is set, you might run into various issues such as https://blog.workinghardinit.work/2019/09/05/fixing-slow-roce-rdma-performance-with-winof-2-to-winof/.
#if 1514 is set, setting JumboFrames is skipped. All NICs are configured (vNICs + pNICs)
$JumboSize=1514 #9014, 4088 or 1514 (default)
#Additional Features
$Bitlocker=$true #Install "Bitlocker" and "RSAT-Feature-Tools-BitLocker" on nodes?
$StorageReplica=$true #Install "Storage-Replica" and "RSAT-Storage-Replica" on nodes?
$Deduplication=$true #install "FS-Data-Deduplication" on nodes?
$SystemInsights=$true #install "System-Insights" on nodes?
#Enable Meltdown mitigation? https://support.microsoft.com/en-us/help/4072698/windows-server-guidance-to-protect-against-the-speculative-execution
#CVE-2017-5754 cannot be used to attack across a hardware virtualized boundary. It can only be used to read memory in kernel mode from user mode. It is not a strict requirement to set this registry value on the host if no untrusted code is running and no untrusted users are able to logon to the host.
$MeltdownMitigationEnable=$false
#Enable Microarchitectural Data Sampling Mitigation? https://support.microsoft.com/en-us/help/4072698/windows-server-speculative-execution-side-channel-vulnerabilities-prot
$MicroarchitecturalDataSamplingMitigation=$false
#Enable speculative store bypass mitigation? https://support.microsoft.com/en-us/help/4073119/protect-against-speculative-execution-side-channel-vulnerabilities-in , https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/ADV180012
$SpeculativeStoreBypassMitigation=$false
#Configure PCID to expose to VMS prior version 8.0 https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/CVE-2017-5715-and-hyper-v-vms
$ConfigurePCIDMinVersion=$true
#Configure Processor Machine Check Error vulnerability mitigation https://support.microsoft.com/en-us/help/4530989/guidance-for-protecting-against-intel-processor-machine-check-error-vu
$ConfigureProcessorMachineCheckErrorMitigation=$true
#Configure Core scheduler on Windows Server 2016? https://docs.microsoft.com/en-us/windows-server/virtualization/hyper-v/manage/manage-hyper-v-scheduler-types#configuring-the-hypervisor-scheduler-type-on-windows-server-2016-hyper-v
$CoreScheduler=$True
#Memory dump type (Active or Kernel) https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/varieties-of-kernel-mode-dump-files
$MemoryDump="Active"
#real VMs? If true, script will create real VMs on mirror disks from vhd you will provide during the deployment. The most convenient is to provide NanoServer
$realVMs=$false
$NumberOfRealVMs=2 #number of VMs on each mirror disk
#ask for parent VHDx if real VMs will be created
if ($realVMs){
[reflection.assembly]::loadwithpartialname("System.Windows.Forms")
$openFile = New-Object System.Windows.Forms.OpenFileDialog -Property @{
Title="Please select parent VHDx." # You can copy it from parentdisks on the Hyper-V hosts somewhere into the lab and then browse for it"
}
$openFile.Filter = "VHDx files (*.vhdx)|*.vhdx"
If($openFile.ShowDialog() -eq "OK"){
Write-Host "File $($openfile.FileName) selected" -ForegroundColor Cyan
}
if (!$openFile.FileName){
Write-Host "No VHD was selected... Skipping VM Creation" -ForegroundColor Red
}
$VHDPath = $openFile.FileName
}
#endregion
#region install features for management (Client needs RSAT, Server/Server Core have different features)
$WindowsInstallationType=Get-ItemPropertyValue -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\' -Name InstallationType
$CurrentBuildNumber=Get-ItemPropertyValue -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\' -Name CurrentBuildNumber
if ($WindowsInstallationType -eq "Server"){
Install-WindowsFeature -Name RSAT-Clustering,RSAT-Clustering-Mgmt,RSAT-Clustering-PowerShell,RSAT-Hyper-V-Tools,RSAT-Feature-Tools-BitLocker-BdeAducExt,RSAT-Storage-Replica,RSAT-AD-PowerShell
}elseif ($WindowsInstallationType -eq "Server Core"){
Install-WindowsFeature -Name RSAT-Clustering,RSAT-Clustering-PowerShell,RSAT-Hyper-V-Tools,RSAT-Storage-Replica,RSAT-AD-PowerShell
}elseif (($WindowsInstallationType -eq "Client") -and ($CurrentBuildNumber -lt 17763)){
#Validate RSAT Installed
if (!((Get-HotFix).hotfixid -contains "KB2693643") ){
Write-Host "Please install RSAT, Exitting in 5s"
Start-Sleep 5
Exit
}
}elseif (($WindowsInstallationType -eq "Client") -and ($CurrentBuildNumber -ge 17763)){
#Install RSAT tools
$Capabilities="Rsat.ServerManager.Tools~~~~0.0.1.0","Rsat.FailoverCluster.Management.Tools~~~~0.0.1.0","Rsat.ActiveDirectory.DS-LDS.Tools~~~~0.0.1.0"
foreach ($Capability in $Capabilities){
Add-WindowsCapability -Name $Capability -Online
}
}
if ($WindowsInstallationType -eq "Client"){
#Install Hyper-V Management features
if ((Get-WindowsOptionalFeature -online -FeatureName Microsoft-Hyper-V-Management-PowerShell).state -ne "Enabled"){
#Install all features and then remove all except Management (fails when installing just management)
Enable-WindowsOptionalFeature -online -FeatureName Microsoft-Hyper-V-All -NoRestart
Disable-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V -NoRestart
$Q=Read-Host -Prompt "Restart is needed. Do you want to restart now? Y/N"
If ($Q -eq "Y"){
Write-Host "Restarting Computer"
Start-Sleep 3
Restart-Computer
}else{
Write-Host "You did not type Y, please restart Computer. Exitting"
Start-Sleep 3
Exit
}
}elseif((Get-command -Module Hyper-V) -eq $null){
$Q=Read-Host -Prompt "Restart is needed to load Hyper-V Management. Do you want to restart now? Y/N"
If ($Q -eq "Y"){
Write-Host "Restarting Computer"
Start-Sleep 3
Restart-Computer
}else{
Write-Host "You did not type Y, please restart Computer. Exitting"
Start-Sleep 3
Exit
}
}
}
#endregion
#region Install Edge and Windows Admin Center Gateway https://github.com/microsoft/WSLab/tree/master/Scenarios/Windows%20Admin%20Center%20and%20Enterprise%20CA#gw-mode-installation-with-self-signed-cert
##Install Windows Admin Center Gateway
#Download Windows Admin Center if not present
if (-not (Test-Path -Path "$env:USERPROFILE\Downloads\WindowsAdminCenter.msi")){
Start-BitsTransfer -Source https://aka.ms/WACDownload -Destination "$env:USERPROFILE\Downloads\WindowsAdminCenter.msi"
}
<#
#Create PS Session and copy install files to remote server
Invoke-Command -ComputerName $GatewayServerName -ScriptBlock {Set-Item -Path WSMan:\localhost\MaxEnvelopeSizekb -Value 4096}
$Session=New-PSSession -ComputerName $GatewayServerName
Copy-Item -Path "$env:USERPROFILE\Downloads\WindowsAdminCenter.msi" -Destination "$env:USERPROFILE\Downloads\WindowsAdminCenter.msi" -ToSession $Session
#Install Windows Admin Center
Invoke-Command -Session $session -ScriptBlock {
Start-Process msiexec.exe -Wait -ArgumentList "/i $env:USERPROFILE\Downloads\WindowsAdminCenter.msi /qn /L*v log.txt REGISTRY_REDIRECT_PORT_80=1 SME_PORT=443 SSL_CERTIFICATE_OPTION=generate"
} -ErrorAction Ignore
$Session | Remove-PSSession
#>
#install on local server
Start-Process msiexec.exe -Wait -ArgumentList "/i $env:USERPROFILE\Downloads\WindowsAdminCenter.msi /qn /L*v log.txt REGISTRY_REDIRECT_PORT_80=1 SME_PORT=443 SSL_CERTIFICATE_OPTION=generate"
#add certificate to trusted root certs (workaround to trust HTTPs cert on WACGW)
start-sleep 10
$cert = Invoke-Command -ComputerName $GatewayServerName -ScriptBlock {Get-ChildItem Cert:\LocalMachine\My\ |where subject -eq "CN=Windows Admin Center"}
$cert | Export-Certificate -FilePath $env:TEMP\WACCert.cer
Import-Certificate -FilePath $env:TEMP\WACCert.cer -CertStoreLocation Cert:\LocalMachine\Root\
#Configure Resource-Based constrained delegation
$gatewayObject = Get-ADComputer -Identity $GatewayServerName
$computers = (Get-ADComputer -Filter {OperatingSystem -eq "Azure Stack HCI"}).Name
foreach ($computer in $computers){
$computerObject = Get-ADComputer -Identity $computer
Set-ADComputer -Identity $computerObject -PrincipalsAllowedToDelegateToAccount $gatewayObject
}
##Install Edge
Start-BitsTransfer -Source "https://aka.ms/edge-msi" -Destination "$env:USERPROFILE\Downloads\MicrosoftEdgeEnterpriseX64.msi"
#start install
Start-Process -Wait -Filepath msiexec.exe -Argumentlist "/i $env:UserProfile\Downloads\MicrosoftEdgeEnterpriseX64.msi /q"
#start Edge
start-sleep 5
& "C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe"
#endregion
#region prepare for Azure sonnections
#download Azure modules
Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force
Install-Module -Name Az.Accounts -Force
Install-Module -Name Az.Resources -Force
Install-Module -Name Az.Storage -Force
Install-Module -Name Az.StackHCI -Force
#endregion
#region Update all servers (for more info visit WU Scenario https://github.com/microsoft/WSLab/tree/dev/Scenarios/Windows%20Update)
if ($WindowsUpdate -eq "Recommended"){
Invoke-Command -ComputerName $servers -ScriptBlock {
#Grab updates
$SearchCriteria = "IsInstalled=0"
#$SearchCriteria = "IsInstalled=0 and DeploymentAction='OptionalInstallation'" #does not work, not sure why
$ScanResult=Invoke-CimMethod -Namespace "root/Microsoft/Windows/WindowsUpdate" -ClassName "MSFT_WUOperations" -MethodName ScanForUpdates -Arguments @{SearchCriteria=$SearchCriteria}
#apply updates (if not empty)
if ($ScanResult.Updates){
Invoke-CimMethod -Namespace "root/Microsoft/Windows/WindowsUpdate" -ClassName "MSFT_WUOperations" -MethodName InstallUpdates -Arguments @{Updates=$ScanResult.Updates}
}
}
}elseif ($WindowsUpdate -eq "All"){
# Update servers with all updates (including preview)
Invoke-Command -ComputerName $servers -ScriptBlock {
New-PSSessionConfigurationFile -RunAsVirtualAccount -Path $env:TEMP\VirtualAccount.pssc
Register-PSSessionConfiguration -Name 'VirtualAccount' -Path $env:TEMP\VirtualAccount.pssc -Force
} -ErrorAction Ignore
# Run Windows Update via ComObject.
Invoke-Command -ComputerName $servers -ConfigurationName 'VirtualAccount' {
$Searcher = New-Object -ComObject Microsoft.Update.Searcher
$SearchCriteriaAllUpdates = "IsInstalled=0 and DeploymentAction='Installation' or
IsInstalled=0 and DeploymentAction='OptionalInstallation' or
IsPresent=1 and DeploymentAction='Uninstallation' or
IsInstalled=1 and DeploymentAction='Installation' and RebootRequired=1 or
IsInstalled=0 and DeploymentAction='Uninstallation' and RebootRequired=1"
$SearchResult = $Searcher.Search($SearchCriteriaAllUpdates).Updates
$Session = New-Object -ComObject Microsoft.Update.Session
$Downloader = $Session.CreateUpdateDownloader()
$Downloader.Updates = $SearchResult
$Downloader.Download()
$Installer = New-Object -ComObject Microsoft.Update.Installer
$Installer.Updates = $SearchResult
$Result = $Installer.Install()
$Result
}
#remove temporary PSsession config
Invoke-Command -ComputerName $servers -ScriptBlock {
Unregister-PSSessionConfiguration -Name 'VirtualAccount'
Remove-Item -Path $env:TEMP\VirtualAccount.pssc
}
}
#endregion
#region Configure basic settings on servers
#Tune HW timeout to 10 seconds (6 seconds is default) in Dell servers (may be obsolete as it applies to Dell 730xd with Hitachi HDDs)
if ($DellHW){
Invoke-Command -ComputerName $servers -ScriptBlock {Set-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Services\spaceport\Parameters -Name HwTimeout -Value 0x00002710}
}
#IncreaseHW Timeout for virtual environments to 30s
if ($VirtualEnvironment){
Invoke-Command -ComputerName $servers -ScriptBlock {Set-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Services\spaceport\Parameters -Name HwTimeout -Value 0x00007530}
}
#configure memory dump
if ($MemoryDump -eq "Kernel"){
#Configure Kernel memory dump
Invoke-Command -ComputerName $servers -ScriptBlock {
Set-ItemProperty -Path HKLM:\System\CurrentControlSet\Control\CrashControl -Name CrashDumpEnabled -value 2
}
}
if ($MemoryDump -eq "Active"){
#Configure Active memory dump
Invoke-Command -ComputerName $servers -ScriptBlock {
Set-ItemProperty -Path HKLM:\System\CurrentControlSet\Control\CrashControl -Name CrashDumpEnabled -value 1
Set-ItemProperty -Path HKLM:\System\CurrentControlSet\Control\CrashControl -Name FilterPages -value 1
}
}
#enable meltdown mitigation
if ($MeltdownMitigationEnable){
Invoke-Command -ComputerName $servers -ScriptBlock {
Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management" -Name FeatureSettingsOverride -value 0
Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management" -Name FeatureSettingsOverrideMask -value 3
}
}
#enable Speculative Store Bypass mitigation
if ($SpeculativeStoreBypassMitigation){
Invoke-Command -ComputerName $servers -ScriptBlock {
Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management" -Name FeatureSettingsOverride -value 8
Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management" -Name FeatureSettingsOverrideMask -value 3
}
}
#enable Microarchitectural Data Sampling mitigation
if ($MicroarchitecturalDataSamplingMitigation){
Invoke-Command -ComputerName $servers -ScriptBlock {
#Detect HT
$processor=Get-WmiObject win32_processor | Select-Object -First 1
if ($processor.NumberOfCores -eq $processor.NumberOfLogicalProcessors/2){
$HT=$True
}
if ($HT -eq $True){
Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management" -Name FeatureSettingsOverride -value 72
}else{
Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management" -Name FeatureSettingsOverride -value 8264
}
Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management" -Name FeatureSettingsOverrideMask -value 3
}
}
#Configure MinVmVersionForCpuBasedMitigations (only needed if you are running VM versions prior 8.0)
if ($ConfigurePCIDMinVersion){
Invoke-Command -ComputerName $servers -ScriptBlock {
if (-not (Test-Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Virtualization")){
New-Item -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion" -Name Virtualization -Force
}
Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Virtualization" -Name MinVmVersionForCpuBasedMitigations -value "1.0"
}
}
#Configure Processor Machine Check Error vulnerability mitigation https://support.microsoft.com/en-us/help/4530989/guidance-for-protecting-against-intel-processor-machine-check-error-vu
if ($ConfigureProcessorMachineCheckErrorMitigation -eq $true){
Invoke-Command -ComputerName $servers -ScriptBlock {
if (-not (Test-Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Virtualization")){
New-Item -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion" -Name Virtualization -Force
}
Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Virtualization" -Name IfuErrataMitigations -value 1
}
}
#Enable core scheduler
if ($CoreScheduler){
$RevisionNumber=Invoke-Command -ComputerName $servers[0] -ScriptBlock {
Get-ItemPropertyValue -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\' -Name UBR
}
$CurrentBuildNumber=Invoke-Command -ComputerName $servers[0] -ScriptBlock {
Get-ItemPropertyValue -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\' -Name CurrentBuildNumber
}
if ($CurrentBuildNumber -eq 14393 -and $RevisionNumber -ge 2395){
Invoke-Command -ComputerName $Servers {
bcdedit /set hypervisorschedulertype Core
}
}
}
#enable high performance power plan
if ($RealHW){
#set high performance
Invoke-Command -ComputerName $servers -ScriptBlock {powercfg /SetActive 8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c}
#check settings
Invoke-Command -ComputerName $servers -ScriptBlock {powercfg /list}
}
#install roles and features
#install Hyper-V using DISM if Install-WindowsFeature fails (if nested virtualization is not enabled install-windowsfeature fails)
Invoke-Command -ComputerName $servers -ScriptBlock {
$Result=Install-WindowsFeature -Name "Hyper-V" -ErrorAction SilentlyContinue
if ($result.ExitCode -eq "failed"){
Enable-WindowsOptionalFeature -FeatureName Microsoft-Hyper-V -Online -NoRestart
}
}
#define features
$features="Failover-Clustering","Hyper-V-PowerShell"
if ($Bitlocker){$Features+="Bitlocker","RSAT-Feature-Tools-BitLocker"}
if ($StorageReplica){$Features+="Storage-Replica","RSAT-Storage-Replica"}
if ($Deduplication){$features+="FS-Data-Deduplication"}
if ($SystemInsights){$features+="System-Insights","RSAT-System-Insights"}
#install features
Invoke-Command -ComputerName $servers -ScriptBlock {Install-WindowsFeature -Name $using:features}
#restart and wait for computers
Restart-Computer $servers -Protocol WSMan -Wait -For PowerShell
Start-Sleep 20 #Failsafe as Hyper-V needs 2 reboots and sometimes it happens, that during the first reboot the restart-computer evaluates the machine is up
#endregion
#region configure Networking (best practices are covered in this guide http://aka.ms/ConvergedRDMA ). For more information about networking you can look at this scenario: https://github.com/microsoft/WSLab/tree/master/Scenarios/S2D%20and%20Networks%20deep%20dive
#Create Virtual Switches and Virtual Adapters
if ($SRIOV){
Invoke-Command -ComputerName $servers -ScriptBlock {New-VMSwitch -Name $using:vSwitchName -EnableEmbeddedTeaming $TRUE -EnableIov $true -NetAdapterName (Get-NetIPAddress -IPAddress $using:AdaptersIPPrefix ).InterfaceAlias}
}else{
Invoke-Command -ComputerName $servers -ScriptBlock {New-VMSwitch -Name $using:vSwitchName -EnableEmbeddedTeaming $TRUE -NetAdapterName (Get-NetIPAddress -IPAddress $using:AdaptersIPPrefix).InterfaceAlias}
}
$Servers | ForEach-Object {
#Configure vNICs
Rename-VMNetworkAdapter -ManagementOS -Name $vSwitchName -NewName Management -ComputerName $_
Add-VMNetworkAdapter -ManagementOS -Name SMB01 -SwitchName $vSwitchName -CimSession $_
Add-VMNetworkAdapter -ManagementOS -Name SMB02 -SwitchName $vSwitchName -Cimsession $_
#configure IP Addresses
If ($NumberOfStorageNets -eq 1){
New-NetIPAddress -IPAddress ($StorNet+$IP.ToString()) -InterfaceAlias "vEthernet (SMB01)" -CimSession $_ -PrefixLength 24
$IP++
New-NetIPAddress -IPAddress ($StorNet+$IP.ToString()) -InterfaceAlias "vEthernet (SMB02)" -CimSession $_ -PrefixLength 24
$IP++
}
If($NumberOfStorageNets -eq 2){
New-NetIPAddress -IPAddress ($StorNet1+$IP.ToString()) -InterfaceAlias "vEthernet (SMB01)" -CimSession $_ -PrefixLength 24
New-NetIPAddress -IPAddress ($StorNet2+$IP.ToString()) -InterfaceAlias "vEthernet (SMB02)" -CimSession $_ -PrefixLength 24
$IP++
}
}
Start-Sleep 5
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 SMB01 -VlanId $StorVLAN -Access -ManagementOS -CimSession $Servers
Set-VMNetworkAdapterVlan -VMNetworkAdapterName SMB02 -VlanId $StorVLAN -Access -ManagementOS -CimSession $Servers
}else{
Set-VMNetworkAdapterVlan -VMNetworkAdapterName SMB01 -VlanId $StorVLAN1 -Access -ManagementOS -CimSession $Servers
Set-VMNetworkAdapterVlan -VMNetworkAdapterName SMB02 -VlanId $StorVLAN2 -Access -ManagementOS -CimSession $Servers
}
#Restart each host vNIC adapter so that the Vlan is active.
Restart-NetAdapter "vEthernet (SMB01)" -CimSession $Servers
Restart-NetAdapter "vEthernet (SMB02)" -CimSession $Servers
#Enable RDMA on the host vNIC adapters
Enable-NetAdapterRDMA "vEthernet (SMB01)","vEthernet (SMB02)" -CimSession $Servers
#Associate each of the vNICs configured for RDMA to a physical adapter that is up and is not virtual (to be sure that each RDMA enabled ManagementOS vNIC is mapped to separate RDMA pNIC)
Invoke-Command -ComputerName $servers -ScriptBlock {
$physicaladapters=(get-vmswitch $using:vSwitchName).NetAdapterInterfaceDescriptions | Sort-Object
Set-VMNetworkAdapterTeamMapping -VMNetworkAdapterName "SMB01" -ManagementOS -PhysicalNetAdapterName (get-netadapter -InterfaceDescription $physicaladapters[0]).name
Set-VMNetworkAdapterTeamMapping -VMNetworkAdapterName "SMB02" -ManagementOS -PhysicalNetAdapterName (get-netadapter -InterfaceDescription $physicaladapters[1]).name
}
#Configure Jumbo Frames
if ($JumboSize -ne 1514){
Set-NetAdapterAdvancedProperty -CimSession $Servers -DisplayName "Jumbo Packet" -RegistryValue $JumboSize
}
#Disable NetBIOS on all vNICs https://msdn.microsoft.com/en-us/library/aa393601(v=vs.85).aspx
if ($DisableNetBIOS){
$vNICs = Get-NetAdapter -CimSession $Servers | Where-Object Name -like vEthernet*
foreach ($vNIC in $vNICs){
Write-Host "Disabling NetBIOS on $($vNIC.Name) on computer $($vNIC.PSComputerName)"
$output=Get-WmiObject -class win32_networkadapterconfiguration -ComputerName $vNIC.PSComputerName | Where-Object Description -eq $vNIC.InterfaceDescription | Invoke-WmiMethod -Name settcpipNetBIOS -ArgumentList 2
if ($output.Returnvalue -eq 0){
Write-Host "`t Success" -ForegroundColor Green
}else{
Write-Host "`t Failure"
}
}
}
#Disable RSC (receive segment coalescing) on Physical NICs connected to vSwitch (RSC in the vSwitch (2019+ only) conflicts with NIC vendors implementation of RSC if they did it in software (miniport, not OS) rather than firmware. In Validate-DCB it's only for MLX4 drivers (Mellanox CX 3)
Invoke-Command -ComputerName $servers -ScriptBlock {
$physicaladapters=(get-vmswitch $using:vSwitchName).NetAdapterInterfaceDescriptions
foreach ($physicaladapter in $physicaladapters){
$adapter=Get-NetAdapter -InterfaceDescription $physicaladapter
if ($adapter.DriverName -like "*mlx4*"){
$adapter | Set-NetAdapterAdvancedProperty -RegistryKeyword '*RscIPv4' -RegistryValue 0
$adapter | Set-NetAdapterAdvancedProperty -RegistryKeyword '*RscIPv6' -RegistryValue 0
}
}
}
#Verify Networking
#verify mapping
Get-VMNetworkAdapterTeamMapping -CimSession $servers -ManagementOS | Format-Table ComputerName,NetAdapterName,ParentAdapter
#Verify that the VlanID is set
Get-VMNetworkAdapterVlan -ManagementOS -CimSession $servers |Sort-Object -Property Computername | Format-Table ComputerName,AccessVlanID,ParentAdapter -AutoSize -GroupBy ComputerName
#verify RDMA
Get-NetAdapterRdma -CimSession $servers | Sort-Object -Property Systemname | Format-Table systemname,interfacedescription,name,enabled -AutoSize -GroupBy Systemname
#verify ip config
Get-NetIPAddress -CimSession $servers -InterfaceAlias vEthernet* -AddressFamily IPv4 | Sort-Object -Property PSComputername | Format-Table pscomputername,interfacealias,ipaddress -AutoSize -GroupBy pscomputername
#verify JumboFrames
Get-NetAdapterAdvancedProperty -CimSession $servers -DisplayName "Jumbo Packet"
#configure DCB if requested
if ($DCB -eq $True){
#Install DCB
if (!$NanoServer){
foreach ($server in $servers) {Install-WindowsFeature -Name "Data-Center-Bridging" -ComputerName $server}
}
##Configure QoS
New-NetQosPolicy "SMB" -NetDirectPortMatchCondition 445 -PriorityValue8021Action 3 -CimSession $servers
New-NetQosPolicy "ClusterHB" -Cluster -PriorityValue8021Action 7 -CimSession $servers
New-NetQosPolicy "Default" -Default -PriorityValue8021Action 0 -CimSession $servers
#Turn on Flow Control for SMB
Invoke-Command -ComputerName $servers -ScriptBlock {Enable-NetQosFlowControl -Priority 3}
#Disable flow control for other traffic than 3 (pause frames should go only from prio 3)
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}
#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)
Invoke-Command -ComputerName $servers -ScriptBlock {Set-VMNetworkAdapter -ManagementOS -Name "SMB*" -IeeePriorityTag on}
#validate flow control setting
Invoke-Command -ComputerName $servers -ScriptBlock { Get-NetQosFlowControl} | Sort-Object -Property PSComputername | Format-Table PSComputerName,Priority,Enabled -GroupBy PSComputerName
#Validate DCBX setting
Invoke-Command -ComputerName $servers -ScriptBlock {Get-NetQosDcbxSetting} | Sort-Object PSComputerName | Format-Table Willing,PSComputerName
#Apply policy to the target adapters. The target adapters are adapters connected to vSwitch
Invoke-Command -ComputerName $servers -ScriptBlock {Enable-NetAdapterQos -InterfaceDescription (Get-VMSwitch).NetAdapterInterfaceDescriptions}
#validate policy
Invoke-Command -ComputerName $servers -ScriptBlock {Get-NetAdapterQos | Where-Object enabled -eq true} | Sort-Object PSComputerName
#Create a Traffic class and give SMB Direct 60% of the bandwidth minimum. The name of the class will be "SMB".
#This value needs to match physical switch configuration. Value might vary based on your needs.
#If connected directly (in 2 node configuration) skip this step.
Invoke-Command -ComputerName $servers -ScriptBlock {New-NetQosTrafficClass "SMB" -Priority 3 -BandwidthPercentage 60 -Algorithm ETS}
Invoke-Command -ComputerName $servers -ScriptBlock {New-NetQosTrafficClass "ClusterHB" -Priority 7 -BandwidthPercentage 1 -Algorithm ETS}
}
#enable iWARP firewall rule if requested
if ($iWARP -eq $True){
Enable-NetFirewallRule -Name "FPSSMBD-iWARP-In-TCP" -CimSession $servers
}
#endregion
#region Create cluster and configure basic settings
Test-Cluster -Node $servers -Include "Storage Spaces Direct","Inventory","Network","System Configuration","Hyper-V Configuration"
If ($DistributedManagementPoint){
New-Cluster -Name $ClusterName -Node $servers -ManagementPointNetworkType "Distributed"
}else{
if ($ClusterIP){
New-Cluster -Name $ClusterName -Node $servers -StaticAddress $ClusterIP
}else{
New-Cluster -Name $ClusterName -Node $servers
}
}
Start-Sleep 5
Clear-DnsClientCache
#Configure CSV Cache (value is in MB) - disable if SCM or VM is used. For VM it's just for labs - to save some RAM.
if (Get-PhysicalDisk -cimsession $servers[0] | Where-Object bustype -eq SCM){
#disable CSV cache if SCM storage is used
(Get-Cluster $ClusterName).BlockCacheSize = 0
}elseif ((Invoke-Command -ComputerName $servers[0] -ScriptBlock {(get-wmiobject win32_computersystem).Model}) -eq "Virtual Machine"){
#disable CSV cache for virtual environments
(Get-Cluster $ClusterName).BlockCacheSize = 0
}
#ConfigureWitness
if ($WitnessType -eq "FileShare"){
##Configure Witness on DC
#Create new directory
$WitnessName=$Clustername+"Witness"
Invoke-Command -ComputerName DC -ScriptBlock {new-item -Path c:\Shares -Name $using:WitnessName -ItemType Directory}
$accounts=@()
$accounts+="$corp\$ClusterName$"
$accounts+="$corp\Domain Admins"
New-SmbShare -Name $WitnessName -Path "c:\Shares\$WitnessName" -FullAccess $accounts -CimSession DC
#Set NTFS permissions
Invoke-Command -ComputerName DC -ScriptBlock {(Get-SmbShare $using:WitnessName).PresetPathAcl | Set-Acl}
#Set Quorum
Set-ClusterQuorum -Cluster $ClusterName -FileShareWitness "\\DC\$WitnessName"
}
elseif($WitnessType -eq $Cloud){
#login to Azure
Connect-AzAccount -UseDeviceAuthentication
#select context if more available
$context=Get-AzContext -ListAvailable
if (($context).count -gt 1){
$context | Out-GridView -OutputMode Single | Set-AzContext
}
#Create resource group
$Location=Get-AzLocation | Where-Object Providers -Contains "Microsoft.Storage" | Out-GridView -OutputMode Single
#create resource group first
if (-not(Get-AzResourceGroup -Name $ResourceGroupName -ErrorAction Ignore)){
New-AzResourceGroup -Name $ResourceGroupName -Location $location.Location
}
#create Storage Account
If (-not(Get-AzStorageAccountKey -Name $StorageAccountName -ResourceGroupName $ResourceGroupName -ErrorAction Ignore)){
New-AzStorageAccount -ResourceGroupName $ResourceGroupName -Name $StorageAccountName -SkuName Standard_LRS -Location $location.location -Kind StorageV2 -AccessTier Cool
}
$StorageAccountAccessKey=(Get-AzStorageAccountKey -Name $StorageAccountName -ResourceGroupName $ResourceGroupName | Select-Object -First 1).Value
Set-ClusterQuorum -Cluster $ClusterName -CloudWitness -AccountName $StorageAccountName -AccessKey $StorageAccountAccessKey -Endpoint $CloudWitnessEndpoint
}
#Disable CSV Balancer
if ($DisableCSVBalancer){
(Get-Cluster $ClusterName).CsvBalancer = 0
}
#endregion
#region Configure Cluster Networks
#rename networks
if ($NumberOfStorageNets -eq 1){
(Get-ClusterNetwork -Cluster $clustername | Where-Object Address -eq $StorNet"0").Name="SMB"
}else{
(Get-ClusterNetwork -Cluster $clustername | Where-Object Address -eq $StorNet1"0").Name="SMB01"
(Get-ClusterNetwork -Cluster $clustername | Where-Object Address -eq $StorNet2"0").Name="SMB02"
}
(Get-ClusterNetwork -Cluster $clustername | Where-Object Address -like $AdaptersIPPrefix).Name="Management"
#configure Live Migration
Get-ClusterResourceType -Cluster $clustername -Name "Virtual Machine" | Set-ClusterParameter -Name MigrationExcludeNetworks -Value ([String]::Join(";",(Get-ClusterNetwork -Cluster $clustername | Where-Object {$_.Name -eq "Management"}).ID))
Set-VMHost -VirtualMachineMigrationPerformanceOption SMB -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
if ($SMBBandwidthLimits){
#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
}
#endregion
#region configure Cluster-Aware-Updating
if (!$NanoServer){
#Install required features on nodes.
$ClusterNodes=(Get-ClusterNode -Cluster $ClusterName).Name
foreach ($ClusterNode in $ClusterNodes){
Install-WindowsFeature -Name RSAT-Clustering-PowerShell -ComputerName $ClusterNode
}
#add role
Add-CauClusterRole -ClusterName $ClusterName -MaxFailedNodes 0 -RequireAllNodesOnline -EnableFirewallRules -VirtualComputerObjectName $CAURoleName -Force -CauPluginName Microsoft.WindowsUpdatePlugin -MaxRetriesPerNode 3 -CauPluginArguments @{ 'IncludeRecommendedUpdates' = 'False' } -StartDate "3/2/2017 3:00:00 AM" -DaysOfWeek 4 -WeeksOfMonth @(3) -verbose
}
#endregion
#region Create Fault Domains (just an example) https://docs.microsoft.com/en-us/windows-server/failover-clustering/fault-domains
#just some examples for Rack/Chassis fault domains.
if ($numberofnodes -eq 4){
$xml = @"
"@
Set-ClusterFaultDomainXML -XML $xml -CimSession $ClusterName
}
if ($numberofnodes -eq 8){
$xml = @"
"@
Set-ClusterFaultDomainXML -XML $xml -CimSession $ClusterName
}
if ($numberofnodes -eq 16){
$xml = @"
"@
Set-ClusterFaultDomainXML -XML $xml -CimSession $ClusterName
}
#show fault domain configuration
Get-ClusterFaultDomainxml -CimSession $ClusterName
<#Alternate way
if ($numberofnodes -eq 4){
New-ClusterFaultDomain -Name "Rack01" -FaultDomainType Rack -Location "Contoso HQ, Room 4010, Aisle A, Rack 01" -CimSession $ClusterName
New-ClusterFaultDomain -Name "SEA" -FaultDomainType Site -Location "Contoso HQ, 123 Example St, Room 4010, Seattle" -CimSession $ClusterName
1..4 | ForEach-Object {Set-ClusterFaultDomain -Name "$($ServersNamePrefix)$_" -Parent "Rack01" -CimSession $ClusterName}
Set-ClusterFaultDomain -Name "Rack01" -Parent "SEA" -CimSession $ClusterName
}
if ($numberofnodes -eq 8){
New-ClusterFaultDomain -Name "Rack01" -FaultDomainType Rack -Location "Contoso HQ, Room 4010, Aisle A, Rack 01" -CimSession $ClusterName
New-ClusterFaultDomain -Name "Rack02" -FaultDomainType Rack -Location "Contoso HQ, Room 4010, Aisle A, Rack 02" -CimSession $ClusterName
New-ClusterFaultDomain -Name "Rack03" -FaultDomainType Rack -Location "Contoso HQ, Room 4010, Aisle A, Rack 03" -CimSession $ClusterName
New-ClusterFaultDomain -Name "Rack04" -FaultDomainType Rack -Location "Contoso HQ, Room 4010, Aisle A, Rack 04" -CimSession $ClusterName
New-ClusterFaultDomain -Name "SEA" -FaultDomainType Site -Location "Contoso HQ, 123 Example St, Room 4010, Seattle" -CimSession $ClusterName
1..2 |ForEach-Object {Set-ClusterFaultDomain -Name "$($ServersNamePrefix)$_" -Parent "Rack01" -CimSession $ClusterName}
3..4 |ForEach-Object {Set-ClusterFaultDomain -Name "$($ServersNamePrefix)$_" -Parent "Rack02" -CimSession $ClusterName}
5..6 |ForEach-Object {Set-ClusterFaultDomain -Name "$($ServersNamePrefix)$_" -Parent "Rack03" -CimSession $ClusterName}
7..8 |ForEach-Object {Set-ClusterFaultDomain -Name "$($ServersNamePrefix)$_" -Parent "Rack04" -CimSession $ClusterName}
1..4 |ForEach-Object {Set-ClusterFaultDomain -Name "Rack0$_" -Parent "SEA" -CimSession $ClusterName}
}
if ($numberofnodes -eq 16){
New-ClusterFaultDomain -Name "Chassis01" -FaultDomainType Chassis -Location "Rack Unit 1 (Upper)" -CimSession $ClusterName
New-ClusterFaultDomain -Name "Chassis02" -FaultDomainType Chassis -Location "Rack Unit 1 (Upper)" -CimSession $ClusterName
New-ClusterFaultDomain -Name "Chassis03" -FaultDomainType Chassis -Location "Rack Unit 1 (Lower)" -CimSession $ClusterName
New-ClusterFaultDomain -Name "Chassis04" -FaultDomainType Chassis -Location "Rack Unit 1 (Lower)" -CimSession $ClusterName
New-ClusterFaultDomain -Name "Rack01" -FaultDomainType Rack -Location "Contoso HQ, Room 4010, Aisle A, Rack 01" -CimSession $ClusterName
New-ClusterFaultDomain -Name "SEA" -FaultDomainType Site -Location "Contoso HQ, 123 Example St, Room 4010, Seattle" -CimSession $ClusterName
1..4 |ForEach-Object {Set-ClusterFaultDomain -Name "$($ServersNamePrefix)$_" -Parent "Chassis01" -CimSession $ClusterName}
5..8 |ForEach-Object {Set-ClusterFaultDomain -Name "$($ServersNamePrefix)$_" -Parent "Chassis02" -CimSession $ClusterName}
9..12 |ForEach-Object {Set-ClusterFaultDomain -Name "$($ServersNamePrefix)$_" -Parent "Chassis03" -CimSession $ClusterName}
13..16 |ForEach-Object {Set-ClusterFaultDomain -Name "$($ServersNamePrefix)$_" -Parent "Chassis04" -CimSession $ClusterName}
1..4 |ForEach-Object {Set-ClusterFaultDomain -Name "Chassis0$_" -Parent "Rack01" -CimSession $ClusterName}
1..1 |ForEach-Object {Set-ClusterFaultDomain -Name "Rack0$_" -Parent "SEA" -CimSession $ClusterName}
}
#>
#endregion
#region Enable Cluster S2D and check Pool and Tiers
#Enable-ClusterS2D
Enable-ClusterS2D -CimSession $ClusterName -confirm:0 -Verbose
#display pool
Get-StoragePool "S2D on $ClusterName" -CimSession $ClusterName
#Display disks
Get-StoragePool "S2D on $ClusterName" -CimSession $ClusterName | Get-PhysicalDisk -CimSession $ClusterName
#Get Storage Tiers
Get-StorageTier -CimSession $ClusterName
<#alternate way
#register storage provider
Get-StorageProvider | Register-StorageSubsystem -ComputerName $ClusterName
#display pool
Get-StoragePool "S2D on $ClusterName"
#Display disks
Get-StoragePool "S2D on $ClusterName" | Get-PhysicalDisk
#display tiers
Get-StorageTier
#unregister StorageSubsystem
$ss=Get-StorageSubSystem -FriendlyName *$ClusterName
Unregister-StorageSubsystem -ProviderName "Windows Storage Management Provider" -StorageSubSystemUniqueId $ss.UniqueId
#>
#endregion
#region Create Volumes to use max capacity. It also depends what mix of devices you have https://github.com/Microsoft/WSLab/tree/master/Scenarios/S2D%20and%20Volumes%20deep%20dive
#calculate reserve
$pool=Get-StoragePool -CimSession $clustername -FriendlyName s2D*
$HDDCapacity= ($pool |Get-PhysicalDisk -CimSession $clustername | where-object mediatype -eq HDD | Measure-Object -Property Size -Sum).Sum
$HDDMaxSize= ($pool |Get-PhysicalDisk -CimSession $clustername | where-object mediatype -eq HDD | Measure-Object -Property Size -Maximum).Maximum
$SSDCapacity= ($pool |Get-PhysicalDisk -CimSession $clustername | where-object mediatype -eq SSD | where-object usage -ne journal | Measure-Object -Property Size -Sum).Sum
$SSDMaxSize= ($pool |Get-PhysicalDisk -CimSession $clustername | where-object mediatype -eq SSD | where-object usage -ne journal | Measure-Object -Property Size -Maximum).Maximum
$numberofNodes=(Get-ClusterNode -Cluster $clustername).count
if ($numberofNodes -eq 2){
if ($SSDCapacity){
$SSDCapacityToUse=$SSDCapacity-($numberofNodes*$SSDMaxSize)-100GB #100GB just some reserve (16*3 = perfhistory)+some spare capacity
$sizeofvolumeonSSDs=$SSDCapacityToUse/2/$numberofNodes
}
if ($HDDCapacity){
$HDDCapacityToUse=$HDDCapacity-($numberofNodes*$HDDMaxSize)-100GB #100GB just some reserve (16*3 = perfhistory)+some spare capacity
$sizeofvolumeonHDDs=$HDDCapacityToUse/2/$numberofNodes
}
}else{
if ($SSDCapacity){
$SSDCapacityToUse=$SSDCapacity-($numberofNodes*$SSDMaxSize)-100GB #100GB just some reserve (16*3 = perfhistory)+some spare capacity
$sizeofvolumeonSSDs=$SSDCapacityToUse/3/$numberofNodes
}
if ($HDDCapacity){
$HDDCapacityToUse=$HDDCapacity-($numberofNodes*$HDDMaxSize)-100GB #100GB just some reserve (16*3 = perfhistory)+some spare capacity
$sizeofvolumeonHDDs=$HDDCapacityToUse/3/$numberofNodes
}
}
#create volumes
1..$numberofNodes | ForEach-Object {
if ($sizeofvolumeonHDDs){
New-Volume -CimSession $ClusterName -FileSystem CSVFS_ReFS -StoragePoolFriendlyName S2D* -Size $sizeofvolumeonHDDs -FriendlyName "MyVolumeonHDDs$_" -MediaType HDD
}
if ($sizeofvolumeonSSDs){
New-Volume -CimSession $ClusterName -FileSystem CSVFS_ReFS -StoragePoolFriendlyName S2D* -Size $sizeofvolumeonSSDs -FriendlyName "MyVolumeonSSDs$_" -MediaType SSD
}
}
start-sleep 10
#endregion
#region register Azure Stack HCI to Azure - must be done before creating VMs...
#login to azure
Connect-AzAccount -UseDeviceAuthentication
#select context if more available
$context=Get-AzContext -ListAvailable
if (($context).count -gt 1){
$context | Out-GridView -OutputMode Single | Set-AzContext
}
#grab subscription ID
$subscriptionID=(Get-AzContext).Subscription.id
<#
#Register AZSHCi without prompting for creds
$armTokenItemResource = "https://management.core.windows.net/"
$graphTokenItemResource = "https://graph.windows.net/"
$azContext = Get-AzContext
$authFactory = [Microsoft.Azure.Commands.Common.Authentication.AzureSession]::Instance.AuthenticationFactory
$graphToken = $authFactory.Authenticate($azContext.Account, $azContext.Environment, $azContext.Tenant.Id, $null, [Microsoft.Azure.Commands.Common.Authentication.ShowDialog]::Never, $null, $graphTokenItemResource).AccessToken
$armToken = $authFactory.Authenticate($azContext.Account, $azContext.Environment, $azContext.Tenant.Id, $null, [Microsoft.Azure.Commands.Common.Authentication.ShowDialog]::Never, $null, $armTokenItemResource).AccessToken
$id = $azContext.Account.Id
Register-AzStackHCI -SubscriptionID $subscriptionID -ComputerName $ClusterName -GraphAccessToken $graphToken -ArmAccessToken $armToken -AccountId $id
#>
<# or register Azure Stack HCI with device authentication
Register-AzStackHCI -SubscriptionID $subscriptionID -ComputerName $ClusterName -UseDeviceAuthentication
#>
<# or with standard authentication
#add some trusted sites (to be able to authenticate with Register-AzStackHCI)
reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\EscDomains\live.com\login" /v https /t REG_DWORD /d 2
reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\EscDomains\microsoftonline.com\login" /v https /t REG_DWORD /d 2
reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\EscDomains\msauth.net\aadcdn" /v https /t REG_DWORD /d 2
reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\EscDomains\msauth.net\logincdn" /v https /t REG_DWORD /d 2
reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\EscDomains\msftauth.net\aadcdn" /v https /t REG_DWORD /d 2
#and register
Register-AzStackHCI -SubscriptionID $subscriptionID -ComputerName $ClusterName
#>
#Register AZSHCI with location picker
$Location=Get-AzLocation | Where-Object Providers -Contains "Microsoft.AzureStackHCI" | Out-GridView -OutputMode Single
Register-AzStackHCI -SubscriptionID $subscriptionID -Region $location.location -ComputerName $ClusterName -UseDeviceAuthentication
#Install Azure Stack HCI RSAT Tools to all nodes
$Servers=(Get-ClusterNode -Cluster $ClusterName).Name
Invoke-Command -ComputerName $Servers -ScriptBlock {
Install-WindowsFeature -Name RSAT-Azure-Stack-HCI
}
#Validate registration (query on just one node is needed)
Invoke-Command -ComputerName $ClusterName -ScriptBlock {
Get-AzureStackHCI
}
#Cleanup if needed
Connect-AzAccount
#select context if more available
$context=Get-AzContext -ListAvailable
if (($context).count -gt 1){
$context | Out-GridView -OutputMode Single | Set-AzContext
}
#grab subscription ID
$subscriptionID=(Get-AzContext).Subscription.id
UnRegister-AzStackHCI -SubscriptionId $subscriptionID -ComputerName $ClusterName -Confirm:0 -UseDeviceAuthentication
Get-AzResourceGroup -Name $ResourceGroupName | Remove-AzResourceGroup -Force
#>
#endregion
#region Create some VMs (3 per each CSV disk) https://github.com/Microsoft/WSLab/tree/master/Scenarios/S2D%20and%20Bulk%20VM%20creation
Start-Sleep -Seconds 60 #just to a bit wait as I saw sometimes that first VMs fails to create
if ($realVMs -and $VHDPath){
$CSVs=(Get-ClusterSharedVolume -Cluster $ClusterName).Name
foreach ($CSV in $CSVs){
$CSV=($CSV -split '\((.*?)\)')[1]
1..$NumberOfRealVMs | ForEach-Object {
$VMName="TestVM$($CSV)_$_"
New-Item -Path "\\$ClusterName\ClusterStorage$\$CSV\$VMName\Virtual Hard Disks" -ItemType Directory
Copy-Item -Path $VHDPath -Destination "\\$ClusterName\ClusterStorage$\$CSV\$VMName\Virtual Hard Disks\$VMName.vhdx"
New-VM -Name $VMName -MemoryStartupBytes 512MB -Generation 2 -Path "c:\ClusterStorage\$CSV\" -VHDPath "c:\ClusterStorage\$CSV\$VMName\Virtual Hard Disks\$VMName.vhdx" -CimSession ((Get-ClusterNode -Cluster $ClusterName).Name | Get-Random)
Add-ClusterVirtualMachineRole -VMName $VMName -Cluster $ClusterName
}
}
#Start all VMs
Start-VM -VMname * -CimSession (Get-ClusterNode -Cluster $clustername).Name
}else{
$CSVs=(Get-ClusterSharedVolume -Cluster $ClusterName).Name
foreach ($CSV in $CSVs){
$CSV=($CSV -split '\((.*?)\)')[1]
1..3 | ForEach-Object {
$VMName="TestVM$($CSV)_$_"
Invoke-Command -ComputerName ((Get-ClusterNode -Cluster $ClusterName).Name | Get-Random) -ArgumentList $CSV,$VMName -ScriptBlock {
#create some fake VMs
New-VM -Name $using:VMName -NewVHDPath "c:\ClusterStorage\$($using:CSV)\$($using:VMName)\Virtual Hard Disks\$($using:VMName).vhdx" -NewVHDSizeBytes 32GB -SwitchName $using:vSwitchName -Generation 2 -Path "c:\ClusterStorage\$($using:CSV)\" -MemoryStartupBytes 32MB
}
Add-ClusterVirtualMachineRole -VMName $VMName -Cluster $ClusterName
}
}
}
#endregion