From 344a3e403312054f08710f82909291be9148ac5e Mon Sep 17 00:00:00 2001 From: saitcho Date: Fri, 19 Jan 2024 13:50:26 -0600 Subject: [PATCH 01/45] init/rebase --- .../artifacts/Deploy-AKS.ps1 | 104 - .../artifacts/Deploy-ArcResourceBridge.ps1 | 159 - .../artifacts/New-HCIBoxCluster.ps1 | 3118 ---------------- .../artifacts/{ => PowerShell}/Bootstrap.ps1 | 136 +- .../artifacts/PowerShell/Configure-AKS.ps1 | 35 + .../PowerShell/Configure-VMManagement.ps1 | 51 + .../{ => PowerShell}/Deploy-GitOps.ps1 | 14 +- .../{ => PowerShell}/Deploy-SQLMI.ps1 | 38 +- .../PowerShell/Generate-ARM-Template.ps1 | 121 + .../GetServiceAccountBearerToken.ps1 | 8 +- .../{ => PowerShell}/HCIBox-Config.psd1 | 132 +- .../{ => PowerShell}/HCIBoxLogonScript.ps1 | 100 +- .../PowerShell/New-HCIBoxCluster.ps1 | 1787 +++++++++ .../artifacts/{ => PowerShell}/PSProfile.ps1 | 0 .../artifacts/Register-AzSHCI.ps1 | 69 - .../artifacts/SDN/CertHelpers.ps1 | 167 - .../SDN/NetworkControllerRESTWrappers.ps1 | 2620 ------------- .../SDN/NetworkControllerWorkloadHelpers.psm1 | 380 -- .../artifacts/SDN/SDNExplorer.ps1 | 3269 ----------------- .../artifacts/SDN/SDNExpress.ps1 | 304 -- .../artifacts/SDN/SDNExpressModule.psm1 | 1975 ---------- .../artifacts/SDN/SDNExpressUI.psm1 | 1206 ------ .../artifacts/SDN/Single-NC.psd1 | Bin 6550 -> 0 bytes .../artifacts/Uninstall-AKS.ps1 | 47 - .../artifacts/Uninstall-ResourceBridge.ps1 | 46 - .../artifacts/dataController.json | 2 +- azure_jumpstart_hcibox/artifacts/hci.json | 613 ++++ .../artifacts/hci.parameters.json | 153 + azure_jumpstart_hcibox/bicep/host/host.bicep | 7 +- azure_jumpstart_hcibox/bicep/main.bicep | 4 + azure_jumpstart_hcibox/bicep/main.json | 1027 ------ .../bicep/main.parameters.json | 3 + 32 files changed, 3007 insertions(+), 14688 deletions(-) delete mode 100644 azure_jumpstart_hcibox/artifacts/Deploy-AKS.ps1 delete mode 100644 azure_jumpstart_hcibox/artifacts/Deploy-ArcResourceBridge.ps1 delete mode 100644 azure_jumpstart_hcibox/artifacts/New-HCIBoxCluster.ps1 rename azure_jumpstart_hcibox/artifacts/{ => PowerShell}/Bootstrap.ps1 (58%) create mode 100644 azure_jumpstart_hcibox/artifacts/PowerShell/Configure-AKS.ps1 create mode 100644 azure_jumpstart_hcibox/artifacts/PowerShell/Configure-VMManagement.ps1 rename azure_jumpstart_hcibox/artifacts/{ => PowerShell}/Deploy-GitOps.ps1 (93%) rename azure_jumpstart_hcibox/artifacts/{ => PowerShell}/Deploy-SQLMI.ps1 (93%) create mode 100644 azure_jumpstart_hcibox/artifacts/PowerShell/Generate-ARM-Template.ps1 rename azure_jumpstart_hcibox/artifacts/{ => PowerShell}/GetServiceAccountBearerToken.ps1 (78%) rename azure_jumpstart_hcibox/artifacts/{ => PowerShell}/HCIBox-Config.psd1 (66%) rename azure_jumpstart_hcibox/artifacts/{ => PowerShell}/HCIBoxLogonScript.ps1 (62%) create mode 100644 azure_jumpstart_hcibox/artifacts/PowerShell/New-HCIBoxCluster.ps1 rename azure_jumpstart_hcibox/artifacts/{ => PowerShell}/PSProfile.ps1 (100%) delete mode 100644 azure_jumpstart_hcibox/artifacts/Register-AzSHCI.ps1 delete mode 100644 azure_jumpstart_hcibox/artifacts/SDN/CertHelpers.ps1 delete mode 100644 azure_jumpstart_hcibox/artifacts/SDN/NetworkControllerRESTWrappers.ps1 delete mode 100644 azure_jumpstart_hcibox/artifacts/SDN/NetworkControllerWorkloadHelpers.psm1 delete mode 100644 azure_jumpstart_hcibox/artifacts/SDN/SDNExplorer.ps1 delete mode 100644 azure_jumpstart_hcibox/artifacts/SDN/SDNExpress.ps1 delete mode 100644 azure_jumpstart_hcibox/artifacts/SDN/SDNExpressModule.psm1 delete mode 100644 azure_jumpstart_hcibox/artifacts/SDN/SDNExpressUI.psm1 delete mode 100644 azure_jumpstart_hcibox/artifacts/SDN/Single-NC.psd1 delete mode 100644 azure_jumpstart_hcibox/artifacts/Uninstall-AKS.ps1 delete mode 100644 azure_jumpstart_hcibox/artifacts/Uninstall-ResourceBridge.ps1 create mode 100644 azure_jumpstart_hcibox/artifacts/hci.json create mode 100644 azure_jumpstart_hcibox/artifacts/hci.parameters.json delete mode 100644 azure_jumpstart_hcibox/bicep/main.json diff --git a/azure_jumpstart_hcibox/artifacts/Deploy-AKS.ps1 b/azure_jumpstart_hcibox/artifacts/Deploy-AKS.ps1 deleted file mode 100644 index 24f05f1f9a..0000000000 --- a/azure_jumpstart_hcibox/artifacts/Deploy-AKS.ps1 +++ /dev/null @@ -1,104 +0,0 @@ -# Set paths -$Env:HCIBoxDir = "C:\HCIBox" -$Env:HCIBoxLogsDir = "C:\HCIBox\Logs" -$Env:HCIBoxVMDir = "C:\HCIBox\Virtual Machines" -$Env:HCIBoxKVDir = "C:\HCIBox\KeyVault" -$Env:HCIBoxGitOpsDir = "C:\HCIBox\GitOps" -$Env:HCIBoxIconDir = "C:\HCIBox\Icons" -$Env:HCIBoxVHDDir = "C:\HCIBox\VHD" -$Env:HCIBoxSDNDir = "C:\HCIBox\SDN" -$Env:HCIBoxWACDir = "C:\HCIBox\Windows Admin Center" -$Env:agentScript = "C:\HCIBox\agentScript" -$Env:ToolsDir = "C:\Tools" -$Env:tempDir = "C:\Temp" -$Env:VMPath = "C:\VMs" - -Start-Transcript -Path $Env:HCIBoxLogsDir\Deploy-AKS.log - -# Import Configuration Module and create Azure login credentials -Write-Header 'Importing config' -$ConfigurationDataFile = 'C:\HCIBox\HCIBox-Config.psd1' -$SDNConfig = Import-PowerShellDataFile -Path $ConfigurationDataFile - -# Generate credential objects -Write-Header 'Creating credentials and connecting to Azure' -$user = "jumpstart.local\administrator" -$password = ConvertTo-SecureString -String $SDNConfig.SDNAdminPassword -AsPlainText -Force -$adcred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $user, $password # Domain credential - -$azureAppCred = (New-Object System.Management.Automation.PSCredential $env:spnClientID, (ConvertTo-SecureString -String $env:spnClientSecret -AsPlainText -Force)) -Connect-AzAccount -ServicePrincipal -Subscription $env:subscriptionId -Tenant $env:spnTenantId -Credential $azureAppCred -$context = Get-AzContext # Azure credential - -Register-AzResourceProvider -ProviderNamespace Microsoft.Kubernetes -Confirm:$false -Register-AzResourceProvider -ProviderNamespace Microsoft.KubernetesConfiguration -Confirm:$false - -# Install latest versions of Nuget and PowershellGet -Write-Header "Install latest versions of Nuget and PowershellGet" -Invoke-Command -VMName $SDNConfig.HostList -Credential $adcred -ScriptBlock { - Enable-PSRemoting -Force - $ProgressPreference = "SilentlyContinue" - Install-PackageProvider -Name NuGet -Force - Set-PSRepository -Name "PSGallery" -InstallationPolicy Trusted - Install-Module -Name PowershellGet -Force - $ProgressPreference = "Continue" -} - -# Install necessary AZ modules and initialize akshci on each node -Write-Header "Install necessary AZ modules plus AksHCI module and initialize akshci on each node" - -Invoke-Command -VMName $SDNConfig.HostList -Credential $adcred -ScriptBlock { - Write-Host "Installing Required Modules" - [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 - $ProgressPreference = "SilentlyContinue" - Install-Module -Name AksHci -Force -AcceptLicense - Import-Module Az.Accounts -DisableNameChecking - Import-Module Az.Resources -DisableNameChecking - Import-Module AzureAD -DisableNameChecking - Import-Module AksHci -DisableNameChecking - Initialize-AksHciNode - $ProgressPreference = "Continue" -} - -# Generate unique name for workload cluster -$rand = New-Object System.Random -$prefixLen = 5 -[string]$namingPrefix = '' -for($i = 0; $i -lt $prefixLen; $i++) -{ - $namingPrefix += [char]$rand.Next(97,122) -} -$clusterName = $SDNConfig.AKSworkloadClusterName + "-" + $namingPrefix -#$azureLocation = $env:azureLocation -[System.Environment]::SetEnvironmentVariable('AKSClusterName', $clusterName,[System.EnvironmentVariableTarget]::Machine) - -# Install AksHci - only need to perform the following on one of the nodes -$rg = $env:resourceGroup -Write-Header "Prepping AKS Install" -Invoke-Command -VMName $SDNConfig.HostList[0] -Credential $adcred -ScriptBlock { - $vnet = New-AksHciNetworkSetting -name $using:SDNConfig.AKSvnetname -vSwitchName $using:SDNConfig.AKSvSwitchName -k8sNodeIpPoolStart $using:SDNConfig.AKSNodeStartIP -k8sNodeIpPoolEnd $using:SDNConfig.AKSNodeEndIP -vipPoolStart $using:SDNConfig.AKSVIPStartIP -vipPoolEnd $using:SDNConfig.AKSVIPEndIP -ipAddressPrefix $using:SDNConfig.AKSIPPrefix -gateway $using:SDNConfig.AKSGWIP -dnsServers $using:SDNConfig.AKSDNSIP -vlanID $using:SDNConfig.AKSVlanID - Set-AksHciConfig -imageDir $using:SDNConfig.AKSImagedir -workingDir $using:SDNConfig.AKSWorkingdir -cloudConfigLocation $using:SDNConfig.AKSCloudConfigdir -vnet $vnet -cloudservicecidr $using:SDNConfig.AKSCloudSvcidr -controlPlaneVmSize Standard_D4s_v3 - $azurecred = Connect-AzAccount -ServicePrincipal -Subscription $using:context.Subscription.Id -Tenant $using:context.Subscription.TenantId -Credential $using:azureAppCred - Set-AksHciRegistration -subscriptionId $azurecred.Context.Subscription.Id -resourceGroupName $using:rg -Tenant $azurecred.Context.Tenant.Id -Credential $using:azureAppCred -Region "eastus" - Write-Host "Ready to Install AKS on HCI Cluster" - Install-AksHci -} - -# Create new AKS target cluster and connect it to Azure -Write-Header "Creating AKS target cluster" -Invoke-Command -VMName $SDNConfig.HostList[0] -Credential $adcred -ScriptBlock { - New-AksHciCluster -name $using:clusterName -nodePoolName linuxnodepool -nodecount 2 -osType linux -nodeVmSize Standard_D8s_v3 - Enable-AksHciArcConnection -name $using:clusterName -} - -Write-Header "Checking AKS-HCI nodes and running pods" -Invoke-Command -VMName $SDNConfig.HostList[0] -Credential $adcred -ScriptBlock { - Get-AksHciCredential -name $using:clusterName -Confirm:$false - kubectl get nodes - kubectl get pods -A -} - -# Set env variable deployAKSHCI to true (in case the script was run manually) -[System.Environment]::SetEnvironmentVariable('deployAKSHCI', 'true',[System.EnvironmentVariableTarget]::Machine) - -Stop-Transcript \ No newline at end of file diff --git a/azure_jumpstart_hcibox/artifacts/Deploy-ArcResourceBridge.ps1 b/azure_jumpstart_hcibox/artifacts/Deploy-ArcResourceBridge.ps1 deleted file mode 100644 index bc89315c73..0000000000 --- a/azure_jumpstart_hcibox/artifacts/Deploy-ArcResourceBridge.ps1 +++ /dev/null @@ -1,159 +0,0 @@ -# Set paths -$Env:HCIBoxDir = "C:\HCIBox" -$Env:HCIBoxLogsDir = "C:\HCIBox\Logs" -$Env:HCIBoxVMDir = "C:\HCIBox\Virtual Machines" -$Env:HCIBoxKVDir = "C:\HCIBox\KeyVault" -$Env:HCIBoxGitOpsDir = "C:\HCIBox\GitOps" -$Env:HCIBoxIconDir = "C:\HCIBox\Icons" -$Env:HCIBoxVHDDir = "C:\HCIBox\VHD" -$Env:HCIBoxSDNDir = "C:\HCIBox\SDN" -$Env:HCIBoxWACDir = "C:\HCIBox\Windows Admin Center" -$Env:agentScript = "C:\HCIBox\agentScript" -$Env:ToolsDir = "C:\Tools" -$Env:tempDir = "C:\Temp" -$Env:VMPath = "C:\VMs" - -Start-Transcript -Path $Env:HCIBoxLogsDir\Deploy-ArcResourceBridge.log - -# Import Configuration Module -$ConfigurationDataFile = "$Env:HCIBoxDir\HCIBox-Config.psd1" -$SDNConfig = Import-PowerShellDataFile -Path $ConfigurationDataFile -$csv_path = "C:\ClusterStorage\S2D_vDISK1" - -# Set AD Domain cred -$user = "jumpstart.local\administrator" -$password = ConvertTo-SecureString -String $SDNConfig.SDNAdminPassword -AsPlainText -Force -$adcred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $user, $password - -# Install AZ Resource Bridge and prerequisites -Write-Host "Now Preparing to Install Azure Arc Resource Bridge" - -if ($env:deployAKSHCI -eq $false) { - Write-Header "Install latest versions of Nuget and PowershellGet" - Invoke-Command -VMName $SDNConfig.HostList -Credential $adcred -ScriptBlock { - Enable-PSRemoting -Force - Install-PackageProvider -Name NuGet -Force - Set-PSRepository -Name "PSGallery" -InstallationPolicy Trusted - Install-Module -Name PowershellGet -Force - } -} - -Invoke-Command -VMName $SDNConfig.HostList -Credential $adcred -ScriptBlock { - Install-Module -Name Moc -Repository PSGallery -AcceptLicense -Force - Initialize-MocNode - Install-Module -Name ArcHci -Force -Confirm:$false -SkipPublisherCheck -AcceptLicense -} - -Invoke-Command -VMName $SDNConfig.HostList -Credential $adcred -ScriptBlock { - [System.Environment]::SetEnvironmentVariable('Path', [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";C:\Program Files\Microsoft SDKs\Azure\CLI2\wbin\",[System.EnvironmentVariableTarget]::Machine) - $Env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") - az extension add --upgrade --version 0.2.31 --name arcappliance --only-show-errors - az extension add --upgrade --name connectedk8s --only-show-errors - az extension add --upgrade --name k8s-configuration --only-show-errors - az extension add --upgrade --name k8s-extension --only-show-errors - az extension add --upgrade --name customlocation --only-show-errors - az extension add --upgrade --name azurestackhci --only-show-errors -} - -Invoke-Command -VMName $SDNConfig.HostList[0] -Credential $adcred -ScriptBlock { - New-Item -Path $using:csv_path -Name "ResourceBridge" -ItemType Directory -} - -$subId = $env:subscriptionId -$rg = $env:resourceGroup -$spnClientId = $env:spnClientId -$spnSecret = $env:spnClientSecret -$spnTenantId = $env:spnTenantId -$resource_name = "HCIBox-ResourceBridge" -$location = "eastus" -$custom_location_name = "hcibox-rb-cl" -$cloudServiceIP = $SDNConfig.AKSCloudSvcidr.Substring(0, $SDNConfig.AKSCloudSvcidr.IndexOf('/')) - -if ($env:deployAKSHCI -eq $false) { - Invoke-Command -VMName $SDNConfig.HostList[0] -Credential $adcred -ScriptBlock { - #$vnet = New-MocNetworkSetting -Name $using:SDNConfig.AKSvnetname -vswitchName $using:SDNConfig.AKSvSwitchName -vipPoolStart $using:SDNConfig.AKSVIPStartIP -vipPoolEnd $using:SDNConfig.AKSVIPEndIP -vlanID $using:SDNConfig.AKSVlanID - #Set-MocConfig -workingDir $using:csv_path\ResourceBridge -vnet $vnet -imageDir $using:csv_path\imageStore -skipHostLimitChecks -cloudConfigLocation $using:csv_path\cloudStore -catalog aks-hci-stable-catalogs-ext -ring stable -CloudServiceIP $using:cloudServiceIP -createAutoConfigContainers $false - Set-MocConfig -workingDir $using:csv_path\ResourceBridge -imageDir $using:csv_path\imageStore -skipHostLimitChecks -cloudConfigLocation $using:csv_path\cloudStore -catalog aks-hci-stable-catalogs-ext -ring stable -CloudServiceIP $using:cloudServiceIP -createAutoConfigContainers $false - Install-Moc - } -} - -Invoke-Command -VMName $SDNConfig.HostList[0] -Credential $adcred -ScriptBlock { - New-ArcHciConfigFiles -subscriptionID $using:subId -location eastus -resourceGroup $using:rg -resourceName $using:resource_name -workDirectory $using:csv_path\ResourceBridge -vnetName $using:SDNConfig.AKSvSwitchName -vswitchName $using:SDNConfig.AKSvSwitchName -ipaddressprefix $using:SDNConfig.AKSIPPrefix -gateway $using:SDNConfig.AKSGWIP -dnsservers $using:SDNConfig.AKSDNSIP -controlPlaneIP $using:SDNConfig.rbCpip -k8snodeippoolstart $using:SDNConfig.rbIp -k8snodeippoolend $using:SDNConfig.rbIp2 -vlanID $using:SDNConfig.AKSVlanID -} - -$ErrorActionPreference = "Continue" -Invoke-Command -VMName $SDNConfig.HostList[0] -Credential $adcred -ScriptBlock { - Write-Host "Deploying Arc Resource Bridge. This will take a while." - $WarningPreference = "SilentlyContinue" - [System.Environment]::SetEnvironmentVariable('Path', [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";C:\Program Files\Microsoft SDKs\Azure\CLI2\wbin\",[System.EnvironmentVariableTarget]::Machine) - $Env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") - az login --service-principal --username $using:spnClientID --password=$using:spnSecret --tenant $using:spnTenantId - az provider register -n Microsoft.ResourceConnector --wait - az arcappliance validate hci --config-file $using:csv_path\ResourceBridge\hci-appliance.yaml --only-show-errors - az arcappliance prepare hci --config-file $using:csv_path\ResourceBridge\hci-appliance.yaml --only-show-errors - az arcappliance deploy hci --config-file $using:csv_path\ResourceBridge\hci-appliance.yaml --outfile $env:USERPROFILE\.kube\config --only-show-errors - az arcappliance create hci --config-file $using:csv_path\ResourceBridge\hci-appliance.yaml --kubeconfig $env:USERPROFILE\.kube\config --only-show-errors - - $rbReady = $false - Do { - Write-Host "Waiting on Arc Resource Bridge deployment to complete..." - Start-Sleep 60 - $readiness = az arcappliance show --resource-group $using:rg --name $using:resource_name --only-show-errors | ConvertFrom-Json - if (($readiness.provisioningState -eq "Succeeded") -and ($readiness.status -eq "Connected")) { - $rbReady = $true - } - } Until ($rbReady) - Write-Host "Arc Resource Bridge deployment complete." - - # Configuring custom location - Write-Host "Creating custom location" - $hciClusterId= (Get-AzureStackHci).AzureResourceUri - az k8s-extension create --cluster-type appliances --cluster-name $using:resource_name --resource-group $using:rg --name hci-vmoperator --extension-type Microsoft.AZStackHCI.Operator --scope cluster --release-namespace helm-operator2 --configuration-settings Microsoft.CustomLocation.ServiceAccount=hci-vmoperator --configuration-protected-settings-file $using:csv_path\ResourceBridge\hci-config.json --configuration-settings HCIClusterID=$hciClusterId --auto-upgrade true --only-show-errors - Start-Sleep -Seconds 90 - - $clReady = $false - Do { - Write-Host "Waiting for custom location to provision..." - Start-Sleep 10 - $readiness = az k8s-extension show --cluster-type appliances --cluster-name $using:resource_name --resource-group $using:rg --name hci-vmoperator --only-show-errors | ConvertFrom-Json - if ($readiness.provisioningState -eq "Succeeded") { - $clReady = $true - } - } Until ($clReady) - - az customlocation create --resource-group $using:rg --name $using:custom_location_name --cluster-extension-ids "/subscriptions/$using:subId/resourceGroups/$using:rg/providers/Microsoft.ResourceConnector/appliances/$using:resource_name/providers/Microsoft.KubernetesConfiguration/extensions/hci-vmoperator" --namespace hci-vmoperator --host-resource-id "/subscriptions/$using:subId/resourceGroups/$using:rg/providers/Microsoft.ResourceConnector/appliances/$using:resource_name" --location $using:location --only-show-errors - Write-Host "Custom location created." - $WarningPreference = "Continue" -} -$ErrorActionPreference = "Continue" - -# Copy gallery VHDs to hosts -Invoke-Command -VMName $SDNConfig.HostList[0] -Credential $adcred -ScriptBlock { - New-Item -Name "VHD" -Path $using:csv_path -ItemType Directory -Force - Move-Item -Path "C:\VHD\GUI.vhdx" -Destination "$using:csv_path\VHD\GUI.vhdx" -Force - Move-Item -Path "C:\VHD\Ubuntu.vhdx" -Destination "$using:csv_path\VHD\Ubuntu.vhdx" -Force -} - -Invoke-Command -VMName $SDNConfig.HostList[0] -Credential $adcred -ScriptBlock { - $vnetName="vlan200" - # New-MocGroup -name "Default_Group" -location "MocLocation" ## No longer needed with appliance version 0.2.31 - New-MocVirtualNetwork -name "$vnetName" -group "Default_Group" -tags @{'VSwitch-Name' = "sdnSwitch"} -vlanID $using:SDNConfig.AKSVlanID - [System.Environment]::SetEnvironmentVariable('Path', [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";C:\Program Files\Microsoft SDKs\Azure\CLI2\wbin\",[System.EnvironmentVariableTarget]::Machine) - $Env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") - az azurestackhci virtualnetwork create --subscription $using:subId --resource-group $using:rg --extended-location name="/subscriptions/$using:subId/resourceGroups/$using:rg/providers/Microsoft.ExtendedLocation/customLocations/$using:custom_location_name" type="CustomLocation" --location $using:location --network-type "Transparent" --name $vnetName --vlan $using:SDNConfig.AKSVlanID --only-show-errors - - $galleryImageName = "ubuntu20" - $galleryImageSourcePath="$using:csv_path\VHD\Ubuntu.vhdx" - $osType="Linux" - az azurestackhci galleryimage create --subscription $using:subId --resource-group $using:rg --extended-location name="/subscriptions/$using:subId/resourceGroups/$using:rg/providers/Microsoft.ExtendedLocation/customLocations/$using:custom_location_name" type="CustomLocation" --location $using:location --image-path $galleryImageSourcePath --name $galleryImageName --os-type $osType --only-show-errors - - $galleryImageName = "win2k22" - $galleryImageSourcePath="$using:csv_path\VHD\GUI.vhdx" - $osType="Windows" - az azurestackhci galleryimage create --subscription $using:subId --resource-group $using:rg --extended-location name="/subscriptions/$using:subId/resourceGroups/$using:rg/providers/Microsoft.ExtendedLocation/customLocations/$using:custom_location_name" type="CustomLocation" --location $using:location --image-path $galleryImageSourcePath --name $galleryImageName --os-type $osType --only-show-errors -} - -# Set env variable deployResourceBridge to true (in case the script was run manually) -[System.Environment]::SetEnvironmentVariable('deployResourceBridge', 'true',[System.EnvironmentVariableTarget]::Machine) -Stop-Transcript diff --git a/azure_jumpstart_hcibox/artifacts/New-HCIBoxCluster.ps1 b/azure_jumpstart_hcibox/artifacts/New-HCIBoxCluster.ps1 deleted file mode 100644 index 3dde72c2eb..0000000000 --- a/azure_jumpstart_hcibox/artifacts/New-HCIBoxCluster.ps1 +++ /dev/null @@ -1,3118 +0,0 @@ -[CmdletBinding(DefaultParameterSetName = "NoParameters")] - -param( - [Parameter(Mandatory = $true, ParameterSetName = "ConfigurationFile")] - [String] $ConfigurationDataFile = 'C:\HCIBox\HCIBox-Config.psd1', - [Parameter(Mandatory = $false, ParameterSetName = "Delete")] - [Bool] $Delete = $false -) - -# Set paths -$Env:HCIBoxDir = "C:\HCIBox" -$Env:HCIBoxLogsDir = "C:\HCIBox\Logs" -$Env:HCIBoxVMDir = "C:\HCIBox\Virtual Machines" -$Env:HCIBoxKVDir = "C:\HCIBox\KeyVault" -$Env:HCIBoxGitOpsDir = "C:\HCIBox\GitOps" -$Env:HCIBoxIconDir = "C:\HCIBox\Icons" -$Env:HCIBoxVHDDir = "C:\HCIBox\VHD" -$Env:HCIBoxSDNDir = "C:\HCIBox\SDN" -$Env:HCIBoxWACDir = "C:\HCIBox\Windows Admin Center" -$Env:agentScript = "C:\HCIBox\agentScript" -$Env:ToolsDir = "C:\Tools" -$Env:tempDir = "C:\Temp" -$Env:VMPath = "C:\VMs" - -#region functions - -function BITSRequest { - Param( - [Parameter(Mandatory=$True)] - [hashtable]$Params - ) - $url = $Params['Uri'] - $filename = $Params['Filename'] - $download = Start-BitsTransfer -Source $url -Destination $filename -Asynchronous - $ProgressPreference = "Continue" - while ($download.JobState -ne "Transferred") { - if ($download.JobState -eq "TransientError"){ - Get-BitsTransfer $download.name | Resume-BitsTransfer -Asynchronous - } - [int] $dlProgress = ($download.BytesTransferred / $download.BytesTotal) * 100; - Write-Progress -Activity "Downloading File $filename..." -Status "$dlProgress% Complete:" -PercentComplete $dlProgress; - } - Complete-BitsTransfer $download.JobId - Write-Progress -Activity "Downloading File $filename..." -Status "Ready" -Completed - $ProgressPreference = "SilentlyContinue" -} - -function Set-LocalHyperVSettings { - Param ( - - [string]$HostVMPath - ) - - Write-Verbose "Configuring Hyper-V Settings on localhost" - $params = @{ - VirtualHardDiskPath = $HostVMPath - VirtualMachinePath = $HostVMPath - EnableEnhancedSessionMode = $true - } - Set-VMhost @params -} - -function New-InternalSwitch { - Param ( - $pswitchname, - $SDNConfig - ) - - $querySwitch = Get-VMSwitch -Name $pswitchname -ErrorAction Ignore - if (!$querySwitch) { - New-VMSwitch -SwitchType Internal -MinimumBandwidthMode None -Name $pswitchname | Out-Null - - #Assign IP to Internal Switch - $InternalAdapter = Get-Netadapter -Name "vEthernet ($pswitchname)" - $IP = $SDNConfig.PhysicalHostInternalIP - $Prefix = ($SDNConfig.AzSMGMTIP.Split("/"))[1] - $Gateway = $SDNConfig.SDNLABRoute - $DNS = $SDNConfig.SDNLABDNS - - $params = @{ - AddressFamily = "IPv4" - IPAddress = $IP - PrefixLength = $Prefix - DefaultGateway = $Gateway - } - - $InternalAdapter | New-NetIPAddress @params | Out-Null - $InternalAdapter | Set-DnsClientServerAddress -ServerAddresses $DNS | Out-Null - } - else { - Write-Verbose "Internal Switch $pswitchname already exists. Not creating a new internal switch." - } -} - -function Test-VHDPath { - Param ( - $guiVHDXPath, - $azSHCIVHDXPath - ) - - $Result = Get-ChildItem -Path $guiVHDXPath -ErrorAction Ignore - if (!$result) { Write-Host "Path $guiVHDXPath was not found!" -ForegroundColor Red ; break } - $Result = Get-ChildItem -Path $azSHCIVHDXPath -ErrorAction Ignore - if (!$result) { Write-Host "Path $azSHCIVHDXPath was not found!" -ForegroundColor Red ; break } -} - -function Select-SingleHost { - Param ( - $AzSHOSTs - ) - - $results = @() - foreach ($AzSHOST in $AzSHOSTs) { - $results = $results + [pscustomobject]@{AzSHOST = $AzSHOST; VMHost = $env:COMPUTERNAME } - } - - return $results -} - -function Copy-VHDXtoHost { - Param ( - $guiVHDXPath, - $HostVMPath, - $azSHCIVHDXPath - ) - - Write-Verbose "Copying $guiVHDXPath to $HostVMPath\GUI.VHDX" - Copy-Item -Path $guiVHDXPath -Destination "$HostVMPath\GUI.VHDX" -Force | Out-Null - Write-Verbose "Copying $azSHCIVHDXPath to $HostVMPath\AzSHCI.VHDX" - Copy-Item -Path $azSHCIVHDXPath -Destination "$HostVMPath\AzSHCI.VHDX" -Force | Out-Null -} - -function Get-GuiVHDXPath { - Param ( - $guiVHDXPath, - $HostVMPath - ) - $ParentVHDXPath = $HostVMPath + 'GUI.vhdx' - return $ParentVHDXPath -} - -function Get-AzSHCIVHDXPath { - Param ( - $azSHCIVHDXPath, - $HostVMPath - ) - $ParentVHDXPath = $HostVMPath + 'AzSHCI.vhdx' - return $ParentVHDXPath -} - -function Get-ConsoleVHDXPath { - Param ( - $ConsoleVHDXPath, - $HostVMPath - ) - $ParentVHDXPath = $HostVMPath + 'Console.vhdx' - return $ParentVHDXPath -} - -function New-NestedVM { - Param ( - $AzSHOST, - $VMHost, - $HostVMPath, - $VMSwitch, - $SDNConfig - ) - - $parentpath = "$HostVMPath\GUI.vhdx" - $coreparentpath = "$HostVMPath\AzSHCI.vhdx" - $vmMac = Invoke-Command -ComputerName $VMHost -ScriptBlock { - - $VerbosePreference = "SilentlyContinue" - Import-Module Hyper-V - $VerbosePreference = "Continue" - - $AzSHOST = $using:AzSHOST - $VMHost = $using:VMHost - $HostVMPath = $using:HostVMPath - $VMSwitch = $using:VMSwitch - $parentpath = $using:parentpath - $coreparentpath = $using:coreparentpath - $SDNConfig = $using:SDNConfig - $S2DDiskSize = $SDNConfig.S2D_Disk_Size - $NestedVMMemoryinGB = $SDNConfig.NestedVMMemoryinGB - $AzSMGMTMemoryinGB = $SDNConfig.AzSMGMTMemoryinGB - - # Create Differencing Disk. Note: AzSMGMT is GUI - if ($AzSHOST -eq "AzSMGMT") { - $VHDX1 = New-VHD -ParentPath $parentpath -Path "$HostVMPath\$AzSHOST.vhdx" -Differencing - $VHDX2 = New-VHD -Path "$HostVMPath\$AzSHOST-Data.vhdx" -SizeBytes 268435456000 -Dynamic - $NestedVMMemoryinGB = $AzSMGMTMemoryinGB - } - else { - $VHDX1 = New-VHD -ParentPath $coreparentpath -Path "$HostVMPath\$AzSHOST.vhdx" -Differencing - $VHDX2 = New-VHD -Path "$HostVMPath\$AzSHOST-Data.vhdx" -SizeBytes 268435456000 -Dynamic - - # Create S2D Storage - New-VHD -Path "$HostVMPath\$AzSHOST-S2D_Disk1.vhdx" -SizeBytes $S2DDiskSize -Dynamic | Out-Null - New-VHD -Path "$HostVMPath\$AzSHOST-S2D_Disk2.vhdx" -SizeBytes $S2DDiskSize -Dynamic | Out-Null - New-VHD -Path "$HostVMPath\$AzSHOST-S2D_Disk3.vhdx" -SizeBytes $S2DDiskSize -Dynamic | Out-Null - New-VHD -Path "$HostVMPath\$AzSHOST-S2D_Disk4.vhdx" -SizeBytes $S2DDiskSize -Dynamic | Out-Null - New-VHD -Path "$HostVMPath\$AzSHOST-S2D_Disk5.vhdx" -SizeBytes $S2DDiskSize -Dynamic | Out-Null - New-VHD -Path "$HostVMPath\$AzSHOST-S2D_Disk6.vhdx" -SizeBytes $S2DDiskSize -Dynamic | Out-Null - } - - # Create Nested VM - $params = @{ - Name = $AzSHOST - MemoryStartupBytes = $NestedVMMemoryinGB - VHDPath = $VHDX1.Path - SwitchName = $VMSwitch - Generation = 2 - } - New-VM @params | Out-Null - Add-VMHardDiskDrive -VMName $AzSHOST -Path $VHDX2.Path - - if ($AzSHOST -ne "AzSMGMT") { - Add-VMHardDiskDrive -Path "$HostVMPath\$AzSHOST-S2D_Disk1.vhdx" -VMName $AzSHOST | Out-Null - Add-VMHardDiskDrive -Path "$HostVMPath\$AzSHOST-S2D_Disk2.vhdx" -VMName $AzSHOST | Out-Null - Add-VMHardDiskDrive -Path "$HostVMPath\$AzSHOST-S2D_Disk3.vhdx" -VMName $AzSHOST | Out-Null - Add-VMHardDiskDrive -Path "$HostVMPath\$AzSHOST-S2D_Disk4.vhdx" -VMName $AzSHOST | Out-Null - Add-VMHardDiskDrive -Path "$HostVMPath\$AzSHOST-S2D_Disk5.vhdx" -VMName $AzSHOST | Out-Null - Add-VMHardDiskDrive -Path "$HostVMPath\$AzSHOST-S2D_Disk6.vhdx" -VMName $AzSHOST | Out-Null - } - - Set-VM -Name $AzSHOST -ProcessorCount 20 -AutomaticStartAction Start - Get-VMNetworkAdapter -VMName $AzSHOST | Rename-VMNetworkAdapter -NewName "SDN" - Get-VMNetworkAdapter -VMName $AzSHOST | Set-VMNetworkAdapter -DeviceNaming On -StaticMacAddress ("{0:D12}" -f ( Get-Random -Minimum 0 -Maximum 99999 )) - Add-VMNetworkAdapter -VMName $AzSHOST -Name SDN2 -DeviceNaming On -SwitchName $VMSwitch - $vmMac = ((Get-VMNetworkAdapter -Name SDN -VMName $AzSHOST).MacAddress) -replace '..(?!$)', '$&-' - Write-Verbose "Virtual Machine FABRIC NIC MAC is = $vmMac" - - if ($AzSHOST -ne "AzSMGMT") { - Add-VMNetworkAdapter -VMName $AzSHOST -SwitchName $VMSwitch -DeviceNaming On -Name StorageA - Add-VMNetworkAdapter -VMName $AzSHOST -SwitchName $VMSwitch -DeviceNaming On -Name StorageB - } - - Get-VM $AzSHOST | Set-VMProcessor -ExposeVirtualizationExtensions $true - Get-VM $AzSHOST | Set-VMMemory -DynamicMemoryEnabled $false - Get-VM $AzSHOST | Get-VMNetworkAdapter | Set-VMNetworkAdapter -MacAddressSpoofing On - - Set-VMNetworkAdapterVlan -VMName $AzSHOST -VMNetworkAdapterName SDN -Trunk -NativeVlanId 0 -AllowedVlanIdList 1-200 - Set-VMNetworkAdapterVlan -VMName $AzSHOST -VMNetworkAdapterName SDN2 -Trunk -NativeVlanId 0 -AllowedVlanIdList 1-200 - - if ($AzSHOST -ne "AzSMGMT") { - Set-VMNetworkAdapterVlan -VMName $AzSHOST -VMNetworkAdapterName StorageA -Access -VlanId $SDNConfig.StorageAVLAN - Set-VMNetworkAdapterVlan -VMName $AzSHOST -VMNetworkAdapterName StorageB -Access -VlanId $SDNConfig.StorageBVLAN - } - - Enable-VMIntegrationService -VMName $AzSHOST -Name "Guest Service Interface" - return $vmMac - } - - return $vmMac -} - -function Add-Files { - Param( - $VMPlacement, - $HostVMPath, - $SDNConfig, - $guiVHDXPath, - $azSHCIVHDXPath, - $vmMacs - ) - - foreach ($AzSHOST in $VMPlacement) { - # Get Drive Paths - $HypervHost = $AzSHOST.VMHost - $DriveLetter = $HostVMPath.Split(':') - $path = (("\\$HypervHost\") + ($DriveLetter[0] + "$") + ($DriveLetter[1]) + "\" + $AzSHOST.AzSHOST + ".vhdx") - - # Install Hyper-V Offline - Write-Verbose "Performing offline installation of Hyper-V to path $path" - $VerbosePreference = "SilentlyContinue" - Install-WindowsFeature -Vhd $path -Name Hyper-V, RSAT-Hyper-V-Tools, Hyper-V-Powershell -Confirm:$false | Out-Null - $VerbosePreference = "Continue" - Start-Sleep -Seconds 20 - - # Mount VHDX - bunch of kludgey logic in here to deal with different partition layouts on the GUI and HCI VHD images - Write-Verbose "Mounting VHDX file at $path" - [string]$MountedDrive = "" - if ($AzSHOST.AzSHOST -eq "AzSMGMT") { - $partition = Mount-VHD -Path $path -Passthru | Get-Disk | Get-Partition -PartitionNumber 3 - if (!$partition.DriveLetter) { - $MountedDrive = "X" - $partition | Set-Partition -NewDriveLetter $MountedDrive - } - else { - $MountedDrive = $partition.DriveLetter - } - } else { - $partition = Mount-VHD -Path $path -Passthru | Get-Disk | Get-Partition -PartitionNumber 3 - if (!$partition.DriveLetter) { - $MountedDrive = "Y" - $partition | Set-Partition -NewDriveLetter $MountedDrive - } - else { - $MountedDrive = $partition.DriveLetter - } - } - - # Get Assigned MAC Address so we know what NIC to assign a static IP to - $vmMac = ($vmMacs | Where-Object { $_.Hostname -eq $AzSHost.AzSHOST }).vmMac - - # Inject Answer File - Write-Verbose "Injecting answer file to $path" - - $AzSHOSTComputerName = $AzSHOST.AzSHOST - $AzSHOSTIP = $SDNConfig.($AzSHOSTComputerName + "IP") - $SDNAdminPassword = $SDNConfig.SDNAdminPassword - $SDNDomainFQDN = $SDNConfig.SDNDomainFQDN - $SDNLABDNS = $SDNConfig.SDNLABDNS - $SDNLabRoute = $SDNConfig.SDNLABRoute - $ProductKey = $SDNConfig.GUIProductKey - - # Only inject product key if host is AzSMGMT - $azsmgmtProdKey = $null - if ($AzSHOST.AzSHOST -eq "AzSMGMT") { $azsmgmtProdKey = "$ProductKey"} - - $UnattendXML = @" - - - - -false -false -false - - -$AzSHOSTComputerName -$azsmgmtProdKey - - -false - - -en-us -en-us -en-us -en-us - - -false -false - - - - -$vmMac - -false - - -$AzSHOSTIP - - - -1 -$SDNLabRoute -0.0.0.0/0 -100 - - - - - - - -$SDNDomainFQDN - - - - -$SDNLABDNS - -$vmMac -false -$SDNDomainFQDN -true - - - - - - - -true -true -true -true - - - -$SDNAdminPassword -true</PlainText> -</AdministratorPassword> -</UserAccounts> -</component> -</settings> -<cpi:offlineImage cpi:source="" xmlns:cpi="urn:schemas-microsoft-com:cpi" /> -</unattend> -"@ - - Write-Verbose "Mounted Disk Volume is: $MountedDrive" - $PantherDir = Get-ChildItem -Path ($MountedDrive + ":\Windows") -Filter "Panther" - if (!$PantherDir) { New-Item -Path ($MountedDrive + ":\Windows\Panther") -ItemType Directory -Force | Out-Null } - - Set-Content -Value $UnattendXML -Path ($MountedDrive + ":\Windows\Panther\Unattend.xml") -Force - - if ($AzSHOST.AzSHOST -eq "AzSMGMT") { - # Creating folder structure on AzSMGMT - Write-Verbose "Creating VMs\Base folder structure on AzSMGMT" - New-Item -Path ($MountedDrive + ":\VMs\Base") -ItemType Directory -Force | Out-Null - - # Injecting configs into VMs - Write-Verbose "Injecting VMConfigs to $path" - Copy-Item -Path "$Env:HCIBoxDir\HCIBox-Config.psd1" -Destination ($MountedDrive + ":\") -Recurse -Force - New-Item -Path ($MountedDrive + ":\") -Name VMConfigs -ItemType Directory -Force | Out-Null - Copy-Item -Path $guiVHDXPath -Destination ($MountedDrive + ":\VMs\Base\GUI.vhdx") -Force - Copy-Item -Path $azSHCIVHDXPath -Destination ($MountedDrive + ":\VMs\Base\AzSHCI.vhdx") -Force - Copy-Item -Path $Env:HCIBoxSDNDir -Destination ($MountedDrive + ":\VmConfigs") -Recurse -Force - Copy-Item -Path $Env:HCIBoxSDNDir -Destination ($MountedDrive + ":\VmConfigs") -Recurse -Force - Copy-Item -Path $Env:HCIBoxWACDir -Destination ($MountedDrive + ":\VmConfigs") -Recurse -Force - } - - if ($AzSHOST.AzSHOST -eq "AzSHOST1") { - New-Item -Path ($MountedDrive + ":\VHD") -ItemType Directory -Force | Out-Null - Copy-Item -Path "$Env:HCIBoxVHDDir\GUI.vhdx" -Destination ($MountedDrive + ":\VHD") -Recurse -Force - Copy-Item -Path "$Env:HCIBoxVHDDir\Ubuntu.vhdx" -Destination ($MountedDrive + ":\VHD") -Recurse -Force - } - - # Dismount VHDX - Write-Verbose "Dismounting VHDX File at path $path" - Dismount-VHD $path - } -} - -function Start-AzSHOSTS { - Param( - $VMPlacement - ) - - foreach ($VMHost in $VMPlacement) { - Write-Verbose "Starting VM: $VMHost" - Start-VM -ComputerName $VMHost.VMhost -Name $VMHost.AzSHOST - } -} - -function New-DataDrive { - param ( - $VMPlacement, - $SDNConfig - ) - - foreach ($SDNVM in $VMPlacement) { - - Invoke-Command -ComputerName $SDNVM.VMHost -ScriptBlock { - $VerbosePreference = "Continue" - Write-Verbose "Onlining, partitioning, and formatting Data Drive on $($Using:SDNVM.AzSHOST)" - - $localCred = new-object -typename System.Management.Automation.PSCredential -argumentlist "Administrator" ` - , (ConvertTo-SecureString $using:SDNConfig.SDNAdminPassword -AsPlainText -Force) - - Invoke-Command -VMName $using:SDNVM.AzSHOST -Credential $localCred -ScriptBlock { - - Set-Disk -Number 1 -IsOffline $false | Out-Null - Initialize-Disk -Number 1 | Out-Null - New-Partition -DiskNumber 1 -UseMaximumSize -AssignDriveLetter | Out-Null - Format-Volume -DriveLetter D | Out-Null - - } - } - } -} - -function Test-AzSHOSTVMConnection { - - param ( - - $VMPlacement, - $localCred - - ) - - foreach ($SDNVM in $VMPlacement) { - - Invoke-Command -ComputerName $SDNVM.VMHost -ScriptBlock { - $VerbosePreference = "Continue" - $localCred = $using:localCred - $testconnection = $null - While (!$testconnection) { - $testconnection = Invoke-Command -VMName $using:SDNVM.AzSHOST -ScriptBlock { - $ErrorOccurred = $false - do { - try { - $ErrorActionPreference = 'Stop' - Get-VMHost - } - catch { - $ErrorOccurred = $true - } - } while ($ErrorOccurred -eq $true) - } -Credential $localCred -ErrorAction Ignore - } - - Write-Verbose "Successfully contacted $($using:SDNVM.AzSHOST)" - } - } -} - -function Start-PowerShellScriptsOnHosts { - - Param ( - - $VMPlacement, - $ScriptPath, - $localCred - - ) - - foreach ($SDNVM in $VMPlacement) { - - Invoke-Command -ComputerName $SDNVM.VMHost -ScriptBlock { - - $VerbosePreference = "Continue" - Write-Verbose "Executing Script: $($using:ScriptPath) on host $($using:SDNVM.AzSHOST)" - Invoke-Command -VMName $using:SDNVM.AzSHOST -ArgumentList $using:Scriptpath -ScriptBlock { Invoke-Expression -Command $args[0] } -Credential $using:localCred - - } - } -} - -function New-NATSwitch { - - Param ( - - $VMPlacement, - $SwitchName, - $SDNConfig - - ) - - $natSwitchTarget = $VMPlacement | Where-Object { $_.AzSHOST -eq "AzSMGMT" } - - Add-VMNetworkAdapter -VMName $natSwitchTarget.AzSHOST -ComputerName $natSwitchTarget.VMHost -DeviceNaming On - - $params = @{ - - VMName = $natSwitchTarget.AzSHOST - ComputerName = $natSwitchTarget.VMHost - } - - Get-VMNetworkAdapter @params | Where-Object { $_.Name -match "Network" } | Connect-VMNetworkAdapter -SwitchName $SDNConfig.natHostVMSwitchName - Get-VMNetworkAdapter @params | Where-Object { $_.Name -match "Network" } | Rename-VMNetworkAdapter -NewName "NAT" - - Get-VM @params | Get-VMNetworkAdapter -Name NAT | Set-VMNetworkAdapter -MacAddressSpoofing On - - <# Should not need this anymore - - if ($SDNConfig.natVLANID) { - - Get-VM @params | Get-VMNetworkAdapter -Name NAT | Set-VMNetworkAdapterVlan -Access -VlanId $natVLANID | Out-Null - - } - - #> - - #Create PROVIDER NIC in order for NAT to work from SLB/MUX and RAS Gateways - - Add-VMNetworkAdapter @params -Name PROVIDER -DeviceNaming On -SwitchName $SwitchName - Get-VM @params | Get-VMNetworkAdapter -Name PROVIDER | Set-VMNetworkAdapter -MacAddressSpoofing On - Get-VM @params | Get-VMNetworkAdapter -Name PROVIDER | Set-VMNetworkAdapterVlan -Access -VlanId $SDNConfig.providerVLAN | Out-Null - - #Create VLAN 200 NIC in order for NAT to work from L3 Connections - - Add-VMNetworkAdapter @params -Name VLAN200 -DeviceNaming On -SwitchName $SwitchName - Get-VM @params | Get-VMNetworkAdapter -Name VLAN200 | Set-VMNetworkAdapter -MacAddressSpoofing On - Get-VM @params | Get-VMNetworkAdapter -Name VLAN200 | Set-VMNetworkAdapterVlan -Access -VlanId $SDNConfig.vlan200VLAN | Out-Null - - - #Create Simulated Internet NIC in order for NAT to work from L3 Connections - - Add-VMNetworkAdapter @params -Name simInternet -DeviceNaming On -SwitchName $SwitchName - Get-VM @params | Get-VMNetworkAdapter -Name simInternet | Set-VMNetworkAdapter -MacAddressSpoofing On - Get-VM @params | Get-VMNetworkAdapter -Name simInternet | Set-VMNetworkAdapterVlan -Access -VlanId $SDNConfig.simInternetVLAN | Out-Null - - -} - -function Resolve-Applications { - - Param ( - - $SDNConfig - ) - - # Verify Product Keys - - Write-Verbose "Performing simple validation of Product Keys" - $guiResult = $SDNConfig.GUIProductKey -match '^([A-Z0-9]{5}-){4}[A-Z0-9]{5}$' - - if (!$guiResult) { Write-Error "Cannot validate or find the product key for the Windows Server Datacenter Desktop Experience." } - - - # Verify Windows Admin Center - $isWAC = Get-ChildItem -Path $Env:HCIBoxWACDir -Filter *.MSI - if (!$isWAC) { Write-Error "Please check and ensure that you have correctly copied the Admin Center install file to C:\HCIBox\Windows Admin Center." } - - # Are we on Server Core? - $regKey = "hklm:/software/microsoft/windows nt/currentversion" - $Core = (Get-ItemProperty $regKey).InstallationType -eq "Server Core" - If ($Core) { - - Write-Warning "You might not want to run the Azure Stack HCI OS Sandbox on Server Core, getting remote access to the AdminCenter VM may require extra configuration." - Start-Sleep -Seconds 5 - - } - - -} - -function Get-PhysicalNICMTU { - - Param ( - - $SDNConfig - - ) - - foreach ($VMHost in $SDNConfig.MultipleHyperVHostNames) { - - Invoke-Command -ComputerName $VMHost -ScriptBlock { - - $SDNConfig = $using:SDNConfig - - $VswitchNICs = (Get-VMSwitch -Name ($SDNConfig.MultipleHyperVHostExternalSwitchName)).NetAdapterInterfaceDescription - - if ($VswitchNICs) { - foreach ($VswitchNIC in $VswitchNICs) { - - $MTUSetting = (Get-NetAdapterAdvancedProperty -InterfaceDescription $VswitchNIC -RegistryKeyword '*JumboPacket').RegistryValue - - if ($MTUSetting -ne $SDNConfig.SDNLABMTU) { - - Write-Error "There is a mismatch in the MTU value for the external switch and the value in the HCIBox-Config.psd1 data file." - - } - - } - - } - - else { - - Write-Error "The external switch was not found on $Env:COMPUTERNAME" - - } - - } - - } - -} - -function Set-SDNserver { - - Param ( - - $VMPlacement, - $SDNConfig, - $localCred - - ) - - - # Set base number for Storage IPs - $int = 9 - - - foreach ($SDNVM in $VMPlacement) { - - - # Increment Storage IPs - - $int++ - - - Invoke-Command -ComputerName $SDNVM.VMHost -ScriptBlock { - - Invoke-Command -VMName $using:SDNVM.AzSHOST -ArgumentList $using:SDNConfig, $using:localCred, $using:int -ScriptBlock { - - $SDNConfig = $args[0] - $localCred = $args[1] - $int = $args[2] - $VerbosePreference = "Continue" - - - # Create IP Address of Storage Adapters - - $storageAIP = $sdnconfig.storageAsubnet.Replace("0/24", $int) - $storageBIP = $sdnconfig.storageBsubnet.Replace("0/24", $int) - - - # Set Name and IP Addresses on Storage Interfaces - $storageNICs = Get-NetAdapterAdvancedProperty | Where-Object { $_.DisplayValue -match "Storage" } - - foreach ($storageNIC in $storageNICs) { - - Rename-NetAdapter -Name $storageNIC.Name -NewName $storageNIC.DisplayValue - - } - - $storageNICs = Get-Netadapter | Where-Object { $_.Name -match "Storage" } - - foreach ($storageNIC in $storageNICs) { - - If ($storageNIC.Name -eq 'StorageA') { New-NetIPAddress -InterfaceAlias $storageNIC.Name -IPAddress $storageAIP -PrefixLength 24 | Out-Null } - If ($storageNIC.Name -eq 'StorageB') { New-NetIPAddress -InterfaceAlias $storageNIC.Name -IPAddress $storageBIP -PrefixLength 24 | Out-Null } - - } - - - - - # Enable WinRM - - Write-Verbose "Enabling Windows Remoting in $env:COMPUTERNAME" - $VerbosePreference = "SilentlyContinue" - Set-Item WSMan:\localhost\Client\TrustedHosts * -Confirm:$false -Force - Enable-PSRemoting | Out-Null - $VerbosePreference = "Continue" - - Start-Sleep -Seconds 60 - - if ($env:COMPUTERNAME -ne "AzSMGMT") { - - Write-Verbose "Installing and Configuring Failover Clustering on $env:COMPUTERNAME" - $VerbosePreference = "SilentlyContinue" - Install-WindowsFeature -Name Failover-Clustering -IncludeAllSubFeature -IncludeManagementTools -ComputerName $env:COMPUTERNAME -Credential $localCred | Out-Null - $VerbosePreference = "Continue" - } - - # Enable CredSSP and MTU Settings - - Invoke-Command -ComputerName localhost -Credential $localCred -ScriptBlock { - - $fqdn = $Using:SDNConfig.SDNDomainFQDN - - Write-Verbose "Enabling CredSSP on $env:COMPUTERNAME" - Enable-WSManCredSSP -Role Server -Force - Enable-WSManCredSSP -Role Client -DelegateComputer localhost -Force - Enable-WSManCredSSP -Role Client -DelegateComputer $env:COMPUTERNAME -Force - Enable-WSManCredSSP -Role Client -DelegateComputer $fqdn -Force - Enable-WSManCredSSP -Role Client -DelegateComputer "*.$fqdn" -Force - New-Item -Path HKLM:\SOFTWARE\Policies\Microsoft\Windows\CredentialsDelegation ` - -Name AllowFreshCredentialsWhenNTLMOnly -Force - New-ItemProperty -Path HKLM:\SOFTWARE\Policies\Microsoft\Windows\CredentialsDelegation\AllowFreshCredentialsWhenNTLMOnly ` - -Name 1 -Value * -PropertyType String -Force - } -InDisconnectedSession | Out-Null - - } -Credential $using:localCred - - } - - } - -} - -function Set-AzSMGMT { - - param ( - - $SDNConfig, - $localCred, - $domainCred - - ) - - # Sleep to get around race condition on fast systems - Start-Sleep -Seconds 10 - $VerbosePreference = "Continue" - - Invoke-Command -ComputerName azsmgmt -Credential $localCred -ScriptBlock { - - # Creds - - $localCred = $using:localCred - $domainCred = $using:domainCred - $SDNConfig = $using:SDNConfig - - $ErrorActionPreference = "Stop" - $VerbosePreference = "Continue" - $WarningPreference = "SilentlyContinue" - - # Disable Fabric2 Network Adapter - $fabTwo = $null - while ($fabTwo -ne 'Disabled') { - Write-Verbose "Disabling Fabric2 Adapter" - Get-Netadapter FABRIC2 | Disable-NetAdapter -Confirm:$false | Out-Null - $fabTwo = (Get-Netadapter -Name FABRIC2).Status - - } - # Enable WinRM on AzSMGMT - $VerbosePreference = "Continue" - Write-Verbose "Enabling PSRemoting on $env:COMPUTERNAME" - $VerbosePreference = "SilentlyContinue" - Set-Item WSMan:\localhost\Client\TrustedHosts * -Confirm:$false -Force - Enable-PSRemoting | Out-Null - - - #Disable ServerManager Auto-Start - Get-ScheduledTask -TaskName ServerManager | Disable-ScheduledTask | Out-Null - - # Create Hyper-V Networking for AzSMGMT - Import-Module Hyper-V - - Try { - - $VerbosePreference = "Continue" - Write-Verbose "Creating VM Switch on $env:COMPUTERNAME" - - New-VMSwitch -AllowManagementOS $true -Name "vSwitch-Fabric" -NetAdapterName FABRIC -MinimumBandwidthMode None | Out-Null - - # Configure NAT on AzSMGMT - - if ($SDNConfig.natConfigure) { - - Write-Verbose "Configuring NAT on $env:COMPUTERNAME" - - $VerbosePreference = "SilentlyContinue" - - $natSubnet = $SDNConfig.natSubnet - $Prefix = ($natSubnet.Split("/"))[1] - $natIP = ($natSubnet.TrimEnd("0./$Prefix")) + (".1") - $provIP = $SDNConfig.BGPRouterIP_ProviderNetwork.TrimEnd("1/24") + "254" - $vlan200IP = $SDNConfig.BGPRouterIP_VLAN200.TrimEnd("1/24") + "250" - $provGW = $SDNConfig.BGPRouterIP_ProviderNetwork.TrimEnd("/24") - $provpfx = $SDNConfig.BGPRouterIP_ProviderNetwork.Split("/")[1] - $vlanpfx = $SDNConfig.BGPRouterIP_VLAN200.Split("/")[1] - $simInternetIP = $SDNConfig.BGPRouterIP_SimulatedInternet.TrimEnd("1/24") + "254" - $simInternetPFX = $SDNConfig.BGPRouterIP_SimulatedInternet.Split("/")[1] - - New-VMSwitch -SwitchName NAT -SwitchType Internal -MinimumBandwidthMode None | Out-Null - New-NetIPAddress -IPAddress $natIP -PrefixLength $Prefix -InterfaceAlias "vEthernet (NAT)" | Out-Null - New-NetNat -Name NATNet -InternalIPInterfaceAddressPrefix $natSubnet | Out-Null - - $VerbosePreference = "Continue" - Write-Verbose "Configuring Provider NIC on $env:COMPUTERNAME" - $VerbosePreference = "SilentlyContinue" - - $NIC = Get-NetAdapterAdvancedProperty -RegistryKeyWord "HyperVNetworkAdapterName" | Where-Object { $_.RegistryValue -eq "PROVIDER" } - Rename-NetAdapter -name $NIC.name -newname "PROVIDER" | Out-Null - New-NetIPAddress -InterfaceAlias "PROVIDER" -IPAddress $provIP -PrefixLength $provpfx | Out-Null - - $VerbosePreference = "Continue" - Write-Verbose "Configuring VLAN200 NIC on $env:COMPUTERNAME" - $VerbosePreference = "SilentlyContinue" - - $NIC = Get-NetAdapterAdvancedProperty -RegistryKeyWord "HyperVNetworkAdapterName" | Where-Object { $_.RegistryValue -eq "VLAN200" } - Rename-NetAdapter -name $NIC.name -newname "VLAN200" | Out-Null - New-NetIPAddress -InterfaceAlias "VLAN200" -IPAddress $vlan200IP -PrefixLength $vlanpfx | Out-Null - - $VerbosePreference = "Continue" - Write-Verbose "Configuring simulatedInternet NIC on $env:COMPUTERNAME" - $VerbosePreference = "SilentlyContinue" - - - $NIC = Get-NetAdapterAdvancedProperty -RegistryKeyWord "HyperVNetworkAdapterName" | Where-Object { $_.RegistryValue -eq "simInternet" } - Rename-NetAdapter -name $NIC.name -newname "simInternet" | Out-Null - New-NetIPAddress -InterfaceAlias "simInternet" -IPAddress $simInternetIP -PrefixLength $simInternetPFX | Out-Null - - Write-Verbose "Making NAT Work" - - $NIC = Get-NetAdapterAdvancedProperty -RegistryKeyWord "HyperVNetworkAdapterName" ` - | Where-Object { $_.RegistryValue -eq "Network Adapter" -or $_.RegistryValue -eq "NAT" } - - Rename-NetAdapter -name $NIC.name -newname "Internet" | Out-Null - - $internetIP = $SDNConfig.natHostSubnet.Replace("0/24", "5") - $internetGW = $SDNConfig.natHostSubnet.Replace("0/24", "1") - - Start-Sleep -Seconds 30 - - $internetIndex = (Get-NetAdapter | Where-Object { $_.Name -eq "Internet" }).ifIndex - - Start-Sleep -Seconds 30 - - New-NetIPAddress -IPAddress $internetIP -PrefixLength 24 -InterfaceIndex $internetIndex -DefaultGateway $internetGW -AddressFamily IPv4 | Out-Null - Set-DnsClientServerAddress -InterfaceIndex $internetIndex -ServerAddresses ($SDNConfig.natDNS) | Out-Null - - #Enable Large MTU - - $VerbosePreference = "Continue" - Write-Verbose "Configuring MTU on all Adapters" - $VerbosePreference = "SilentlyContinue" - Get-NetAdapter | Where-Object { $_.Status -eq "Up" -and $_.Name -ne "Ethernet" } | Set-NetAdapterAdvancedProperty ` - -RegistryValue $SDNConfig.SDNLABMTU -RegistryKeyword "*JumboPacket" - $VerbosePreference = "Continue" - - Start-Sleep -Seconds 30 - - #Provision Public and Private VIP Route - - New-NetRoute -DestinationPrefix $SDNConfig.PublicVIPSubnet -NextHop $provGW -InterfaceAlias PROVIDER | Out-Null - - # Remove Gateway from Fabric NIC - Write-Verbose "Removing Gateway from Fabric NIC" - $index = (Get-WmiObject Win32_NetworkAdapter | Where-Object { $_.netconnectionid -match "vSwitch-Fabric" }).InterfaceIndex - Remove-NetRoute -InterfaceIndex $index -DestinationPrefix "0.0.0.0/0" -Confirm:$false - - } - - } - - Catch { - - throw $_ - - } - - } - - # Provision BGP TOR Router - New-RouterVM -SDNConfig $SDNConfig -localCred $localCred -domainCred $domainCred | Out-Null - - # Provision Domain Controller - Write-Verbose "Provisioning Domain Controller VM" - New-DCVM -SDNConfig $SDNConfig -localCred $localCred -domainCred $domainCred | Out-Null - - # Join AzSHOSTs to Domain - Invoke-Command -VMName AzSMGMT -Credential $localCred -ScriptBlock { - - $SDNConfig = $using:SDNConfig - $VerbosePreference = "Continue" - - function AddAzSHOSTToDomain { - - Param ( - - $IP, - $localCred, - $domainCred, - $AzSHOSTName, - $SDNConfig - - ) - - Write-Verbose "Joining host $AzSHOSTName ($ip) to domain" - - Try { - - $AzSHOSTTest = Test-Connection $IP -Quiet - - While (!$AzSHOSTTest) { - Write-Host "Unable to contact computer $AzSHOSTname at $IP. Please make sure the system is contactable before continuing and the Press Enter to continue." ` - -ForegroundColor Red - pause - $AzSHOSTTest = Test-Connection $AzSHOSTName -Quiet -Count 1 - } - - While ($DomainJoined -ne $SDNConfig.SDNDomainFQDN) { - - $params = @{ - - ComputerName = $IP - Credential = $localCred - ArgumentList = ($domainCred, $SDNConfig.SDNDomainFQDN) - } - - - $job = Invoke-Command @params -ScriptBlock { add-computer -DomainName $args[1] -Credential $args[0] } -AsJob - - While ($Job.JobStateInfo.State -ne "Completed") { Start-Sleep -Seconds 10 } - $DomainJoined = (Get-WmiObject -ComputerName $ip -Class win32_computersystem).domain - } - - Restart-Computer -ComputerName $IP -Credential $localCred -Force - - } - - Catch { - - throw $_ - - } - - } - - # Set VM Path for Physical Hosts - try { - - $AzSHOST1 = $SDNConfig.AzSHOST1IP.Split("/")[0] - $AzSHOST2 = $SDNConfig.AzSHOST2IP.Split("/")[0] - - Write-Verbose "Setting VMStorage Path for all Hosts" - - Invoke-Command -ComputerName $AzSHOST1 -ArgumentList $VMStoragePathforOtherHosts ` - -ScriptBlock { Set-VMHost -VirtualHardDiskPath $args[0] -VirtualMachinePath $args[0] } ` - -Credential $using:localCred -AsJob | Out-Null - Invoke-Command -ComputerName $AzSHOST2 -ArgumentList $VMStoragePathforOtherHosts ` - -ScriptBlock { Set-VMHost -VirtualHardDiskPath $args[0] -VirtualMachinePath $args[0] } ` - -Credential $using:localCred -AsJob | Out-Null - - # 2nd pass - Invoke-Command -ComputerName $AzSHOST1 -ArgumentList $VMStoragePathforOtherHosts ` - -ScriptBlock { Set-VMHost -VirtualHardDiskPath $args[0] -VirtualMachinePath $args[0] } ` - -Credential $using:localCred -AsJob | Out-Null - Invoke-Command -ComputerName $AzSHOST2 -ArgumentList $VMStoragePathforOtherHosts ` - -ScriptBlock { Set-VMHost -VirtualHardDiskPath $args[0] -VirtualMachinePath $args[0] } ` - -Credential $using:localCred -AsJob | Out-Null - - } - - catch { - - throw $_ - - } - - # Add AzSHOSTS to domain - try { - - Write-Verbose "Adding HCIBox Hosts to the Domain" - AddAzSHOSTToDomain -IP $AzSHOST1 -localCred $using:localCred -domainCred $using:domainCred -AzSHOSTName AzSHOST1 -SDNConfig $SDNConfig - AddAzSHOSTToDomain -IP $AzSHOST2 -localCred $using:localCred -domainCred $using:domainCred -AzSHOSTName AzSHOST2 -SDNConfig $SDNConfig - } - catch { - throw $_ - } - } | Out-Null - - # Provision Admincenter - Write-Verbose "Provisioning admincenter VM" - $domainCred = new-object -typename System.Management.Automation.PSCredential -argumentlist (($SDNConfig.SDNDomainFQDN.Split(".")[0]) + "\$env:adminUsername"), (ConvertTo-SecureString $SDNConfig.SDNAdminPassword -AsPlainText -Force) - New-AdminCenterVM -SDNConfig $SDNConfig -localCred $localCred -domainCred $domainCred | Out-Null - -} - -function New-DCVM { - Param ( - $SDNConfig, - $localCred, - $domainCred - ) - - $ErrorActionPreference = "Continue" - $adminUser = $env:adminUsername - Invoke-Command -VMName AzSMGMT -Credential $localCred -ScriptBlock { - $adminUser = $using:adminUser - $SDNConfig = $using:SDNConfig - $localcred = $using:localcred - $domainCred = $using:domainCred - $ParentDiskPath = "C:\VMs\Base\" - $vmpath = "D:\VMs\" - $OSVHDX = "GUI.vhdx" - $VMName = $SDNConfig.DCName - - $ProgressPreference = "SilentlyContinue" - $ErrorActionPreference = "Stop" - $VerbosePreference = "Continue" - $WarningPreference = "SilentlyContinue" - - # Create Virtual Machine - Write-Verbose "Creating $VMName differencing disks" - $params = @{ - ParentPath = ($ParentDiskPath + $OSVHDX) - Path = ($vmpath + $VMName + '\' + $VMName + '.vhdx') - } - New-VHD @params -Differencing | Out-Null - - Write-Verbose "Creating $VMName virtual machine" - $params = @{ - Name = $VMName - VHDPath = ($vmpath + $VMName + '\' + $VMName + '.vhdx') - Path = ($vmpath + $VMName) - Generation = 2 - } - New-VM @params | Out-Null - - Write-Verbose "Setting $VMName Memory" - $params = @{ - VMName = $VMName - DynamicMemoryEnabled = $true - StartupBytes = $SDNConfig.MEM_DC - MaximumBytes = $SDNConfig.MEM_DC - MinimumBytes = 500MB - } - Set-VMMemory @params | Out-Null - - Write-Verbose "Configuring $VMName's networking" - Remove-VMNetworkAdapter -VMName $VMName -Name "Network Adapter" | Out-Null - $params = @{ - VMName = $VMName - Name = $SDNConfig.DCName - SwitchName = 'vSwitch-Fabric' - DeviceNaming = 'On' - } - Add-VMNetworkAdapter @params | Out-Null - Write-Verbose "Configuring $VMName's settings" - Set-VMProcessor -VMName $VMName -Count 2 | Out-Null - Set-VM -Name $VMName -AutomaticStartAction Start -AutomaticStopAction ShutDown | Out-Null - - # Add NIC for VLAN200 for DHCP server - Add-VMNetworkAdapter -VMName $VMName -Name "VLAN200" -SwitchName "vSwitch-Fabric" -DeviceNaming "On" - Get-VMNetworkAdapter -VMName $VMName -Name "VLAN200" | Set-VMNetworkAdapterVLAN -Access -VlanId $SDNConfig.AKSVlanID - - # Inject Answer File - Write-Verbose "Mounting and injecting answer file into the $VMName VM." - $VerbosePreference = "SilentlyContinue" - - New-Item -Path "C:\TempMount" -ItemType Directory | Out-Null - Mount-WindowsImage -Path "C:\TempMount" -Index 1 -ImagePath ($vmpath + $VMName + '\' + $VMName + '.vhdx') | Out-Null - - $VerbosePreference = "Continue" - Write-Verbose "Applying Unattend file to Disk Image..." - - $password = $SDNConfig.SDNAdminPassword - $Unattend = @" -<?xml version="1.0" encoding="utf-8"?> -<unattend xmlns="urn:schemas-microsoft-com:unattend"> - <servicing> - <package action="configure"> - <assemblyIdentity name="Microsoft-Windows-Foundation-Package" version="10.0.14393.0" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="" /> - <selection name="ADCertificateServicesRole" state="true" /> - <selection name="CertificateServices" state="true" /> - </package> - </servicing> - <settings pass="specialize"> - <component name="Networking-MPSSVC-Svc" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - <DomainProfile_EnableFirewall>false</DomainProfile_EnableFirewall> - <PrivateProfile_EnableFirewall>false</PrivateProfile_EnableFirewall> - <PublicProfile_EnableFirewall>false</PublicProfile_EnableFirewall> - </component> - <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - <ComputerName>$VMName</ComputerName> - </component> - <component name="Microsoft-Windows-TerminalServices-LocalSessionManager" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - <fDenyTSConnections>false</fDenyTSConnections> - </component> - <component name="Microsoft-Windows-International-Core" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - <UserLocale>en-us</UserLocale> - <UILanguage>en-us</UILanguage> - <SystemLocale>en-us</SystemLocale> - <InputLocale>en-us</InputLocale> - </component> - </settings> - <settings pass="oobeSystem"> - <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - <OOBE> - <HideEULAPage>true</HideEULAPage> - <SkipMachineOOBE>true</SkipMachineOOBE> - <SkipUserOOBE>true</SkipUserOOBE> - <HideOEMRegistrationScreen>true</HideOEMRegistrationScreen> - </OOBE> - <UserAccounts> - <AdministratorPassword> - <Value>$password</Value> - <PlainText>true</PlainText> - </AdministratorPassword> - </UserAccounts> - </component> - </settings> - <cpi:offlineImage cpi:source="" xmlns:cpi="urn:schemas-microsoft-com:cpi" /> -</unattend> -"@ - - New-Item -Path C:\TempMount\windows -ItemType Directory -Name Panther -Force | Out-Null - Set-Content -Value $Unattend -Path "C:\TempMount\Windows\Panther\Unattend.xml" -Force - - Write-Verbose "Dismounting Windows Image" - Dismount-WindowsImage -Path "C:\TempMount" -Save | Out-Null - Remove-Item "C:\TempMount" | Out-Null - - # Start Virtual Machine - - Write-Verbose "Starting Virtual Machine" - Start-VM -Name $VMName | Out-Null - - # Wait until the VM is restarted - while ((Invoke-Command -VMName $VMName -Credential $using:domainCred { "Test" } ` - -ea SilentlyContinue) -ne "Test") { Start-Sleep -Seconds 1 } - - Write-Verbose "Configuring Domain Controller VM and Installing Active Directory." - - $ErrorActionPreference = "SilentlyContinue" - - Invoke-Command -VMName $VMName -Credential $localCred -ArgumentList $SDNConfig -ScriptBlock { - - $SDNConfig = $args[0] - - $VerbosePreference = "Continue" - $WarningPreference = "SilentlyContinue" - $ErrorActionPreference = "Stop" - $DCName = $SDNConfig.DCName - $IP = $SDNConfig.SDNLABDNS - $PrefixLength = ($SDNConfig.AzSMGMTIP.split("/"))[1] - $SDNLabRoute = $SDNConfig.SDNLABRoute - $DomainFQDN = $SDNConfig.SDNDomainFQDN - $DomainNetBiosName = $DomainFQDN.Split(".")[0] - - Write-Verbose "Configuring NIC Settings for Domain Controller" - $VerbosePreference = "SilentlyContinue" - $NIC = Get-NetAdapterAdvancedProperty -RegistryKeyWord "HyperVNetworkAdapterName" | Where-Object { $_.RegistryValue -eq $DCName } - Rename-NetAdapter -name $NIC.name -newname $DCName | Out-Null - New-NetIPAddress -InterfaceAlias $DCName -IPAddress $ip -PrefixLength $PrefixLength -DefaultGateway $SDNLabRoute | Out-Null - Set-DnsClientServerAddress -InterfaceAlias $DCName -ServerAddresses $IP | Out-Null - Install-WindowsFeature -name AD-Domain-Services -IncludeManagementTools | Out-Null - $VerbosePreference = "Continue" - - Write-Verbose "Configuring NIC settings for DC VLAN200" - $VerbosePreference = "SilentlyContinue" - $NIC = Get-NetAdapterAdvancedProperty -RegistryKeyWord "HyperVNetworkAdapterName" | Where-Object { $_.RegistryValue -eq "VLAN200" } - Rename-NetAdapter -name $NIC.name -newname VLAN200 | Out-Null - New-NetIPAddress -InterfaceAlias VLAN200 -IPAddress $SDNConfig.dcVLAN200IP -PrefixLength ($SDNConfig.AKSIPPrefix.split("/"))[1] -DefaultGateway $SDNConfig.AKSGWIP | Out-Null - $VerbosePreference = "Continue" - - Write-Verbose "Configuring Trusted Hosts" - Set-Item WSMan:\localhost\Client\TrustedHosts * -Confirm:$false -Force - - Write-Verbose "Installing Active Directory Forest. This will take some time..." - - $SecureString = ConvertTo-SecureString $SDNConfig.SDNAdminPassword -AsPlainText -Force - Write-Verbose "Installing Active Directory..." - $params = @{ - DomainName = $DomainFQDN - DomainMode = 'WinThreshold' - DatabasePath = "C:\Domain" - DomainNetBiosName = $DomainNetBiosName - SafeModeAdministratorPassword = $SecureString - } - Write-Output $params - - $VerbosePreference = "SilentlyContinue" - Install-ADDSForest @params -InstallDns -Confirm -Force -NoRebootOnCompletion # | Out-Null - } - $ErrorActionPreference = "Stop" - - Write-Verbose "Stopping $VMName" - Get-VM $VMName | Stop-VM - Write-Verbose "Starting $VMName" - Get-VM $VMName | Start-VM - - # Wait until DC is created and rebooted - - while ((Invoke-Command -VMName $VMName -Credential $using:domainCred ` - -ArgumentList $SDNConfig.DCName { (Get-ADDomainController $args[0]).enabled } -ea SilentlyContinue) -ne $true) { Start-Sleep -Seconds 1 } - - $VerbosePreference = "Continue" - Write-Verbose "Configuring User Accounts and Groups in Active Directory" - - - $ErrorActionPreference = "Continue" - $SDNConfig.adminUser = $using:adminUser - Invoke-Command -VMName $VMName -Credential $using:domainCred -ArgumentList $SDNConfig -ScriptBlock { - - $SDNConfig = $args[0] - $SDNDomainFQDN = $SDNConfig.SDNDomainFQDN - - $VerbosePreference = "Continue" - $ErrorActionPreference = "Stop" - - $SecureString = ConvertTo-SecureString $SDNConfig.SDNAdminPassword -AsPlainText -Force - - $params = @{ - ComplexityEnabled = $false - Identity = $SDNConfig.SDNDomainFQDN - MinPasswordLength = 0 - } - - Set-ADDefaultDomainPasswordPolicy @params - - $params = @{ - Name = 'NC Admin' - GivenName = 'NC' - Surname = 'Admin' - SamAccountName = 'NCAdmin' - UserPrincipalName = "NCAdmin@$SDNDomainFQDN" - AccountPassword = $SecureString - Enabled = $true - ChangePasswordAtLogon = $false - CannotChangePassword = $true - PasswordNeverExpires = $true - } - - New-ADUser @params - $params = @{ - Name = $SDNConfig.adminUser - GivenName = 'Jumpstart' - Surname = 'Jumpstart' - SamAccountName = $SDNConfig.adminUser - UserPrincipalName = "$SDNConfig.adminUser@$SDNDomainFQDN" - AccountPassword = $SecureString - Enabled = $true - ChangePasswordAtLogon = $false - CannotChangePassword = $true - PasswordNeverExpires = $true - } - - New-ADUser @params - - $params.Name = 'NC Client' - $params.Surname = 'Client' - $params.SamAccountName = 'NCClient' - $params.UserPrincipalName = "NCClient@$SDNDomainFQDN" - - New-ADUser @params - - NEW-ADGroup -name “NCAdmins” -groupscope Global - NEW-ADGroup -name “NCClients” -groupscope Global - - add-ADGroupMember "Domain Admins" "NCAdmin" - add-ADGroupMember "NCAdmins" "NCAdmin" - add-ADGroupMember "NCClients" "NCClient" - add-ADGroupMember "NCClients" "Administrator" - add-ADGroupMember "NCAdmins" "Administrator" - add-ADGroupMember "Domain Admins" $SDNConfig.adminUser - add-ADGroupMember "NCAdmins" $SDNConfig.adminUser - add-ADGroupMember "NCClients" $SDNConfig.adminUser - - # Set Administrator Account Not to Expire - - Get-ADUser Administrator | Set-ADUser -PasswordNeverExpires $true -CannotChangePassword $true - - # Set DNS Forwarder - - Write-Verbose "Adding DNS Forwarders" - $VerbosePreference = "SilentlyContinue" - - if ($SDNConfig.natDNS) { Add-DnsServerForwarder $SDNConfig.natDNS } - else { Add-DnsServerForwarder 8.8.8.8 } - - # Create Enterprise CA - - $VerbosePreference = "Continue" - Write-Verbose "Installing and Configuring Active Directory Certificate Services and Certificate Templates" - $VerbosePreference = "SilentlyContinue" - - - - Install-WindowsFeature -Name AD-Certificate -IncludeAllSubFeature -IncludeManagementTools | Out-Null - - $params = @{ - - CAtype = 'EnterpriseRootCa' - CryptoProviderName = 'ECDSA_P256#Microsoft Software Key Storage Provider' - KeyLength = 256 - HashAlgorithmName = 'SHA256' - ValidityPeriod = 'Years' - ValidityPeriodUnits = 10 - } - - Install-AdcsCertificationAuthority @params -Confirm:$false | Out-Null - - # Give WebServer Template Enroll rights for Domain Computers - - $filter = "(CN=WebServer)" - $ConfigContext = ([ADSI]"LDAP://RootDSE").configurationNamingContext - $ConfigContext = "CN=Certificate Templates,CN=Public Key Services,CN=Services,$ConfigContext" - $ds = New-object System.DirectoryServices.DirectorySearcher([ADSI]"LDAP://$ConfigContext", $filter) - $Template = $ds.Findone().GetDirectoryEntry() - - if ($Template -ne $null) { - $objUser = New-Object System.Security.Principal.NTAccount("Domain Computers") - $objectGuid = New-Object Guid 0e10c968-78fb-11d2-90d4-00c04f79dc55 - $ADRight = [System.DirectoryServices.ActiveDirectoryRights]"ExtendedRight" - $ACEType = [System.Security.AccessControl.AccessControlType]"Allow" - $ACE = New-Object System.DirectoryServices.ActiveDirectoryAccessRule -ArgumentList $objUser, $ADRight, $ACEType, $objectGuid - $Template.ObjectSecurity.AddAccessRule($ACE) - $Template.commitchanges() - } - - CMD.exe /c "certutil -setreg ca\ValidityPeriodUnits 8" | Out-Null - Restart-Service CertSvc - Start-Sleep -Seconds 60 - - #Issue Certificate Template - - CMD.exe /c "certutil -SetCATemplates +WebServer" - - } - - # Set up DHCP scope for Arc resource bridge - Invoke-Command -VMName $SDNConfig.DCName -Credential $using:domainCred -ArgumentList $SDNConfig -ScriptBlock { - $SDNConfig = $args[0] - - # Install DHCP feature - Install-WindowsFeature DHCP -IncludeManagementTools - CMD.exe /c "netsh dhcp add securitygroups" - Restart-Service dhcpserver - - # Allow DHCP in domain - $dnsName = $SDNConfig.DCName - $fqdnsName = $SDNConfig.DCName + "." + $SDNConfig.SDNDomainFQDN - Add-DhcpServerInDC -DnsName $fqdnsName -IPAddress $SDNConfig.dcVLAN200IP - Get-DHCPServerInDC - - # Configure dynamic DNS updates for DHCP records - #Set-DhcpServerv4DnsSetting -ComputerName "jumpstartdc.jumpstart.local" -DynamicUpdates "Always" -DeleteDnsRRonLeaseExpiry $True - #$Credential = Get-Credential - #Set-DhcpServerDnsCredential -Credential $Credential -ComputerName "jumpstartdc.jumpstart.local" - - # Bind DHCP only to VLAN200 NIC - Set-DhcpServerv4Binding -ComputerName $dnsName -InterfaceAlias $dnsName -BindingState $false - Set-DhcpServerv4Binding -ComputerName $dnsName -InterfaceAlias VLAN200 -BindingState $true - - # Add DHCP scope for Resource bridge VMs - Add-DhcpServerv4Scope -name "ResourceBridge" -StartRange $SDNConfig.rbVipStart -EndRange $SDNConfig.rbVipEnd -SubnetMask 255.255.255.0 -State Active - $scope = Get-DhcpServerv4Scope - Add-DhcpServerv4ExclusionRange -ScopeID $scope.ScopeID.IPAddressToString -StartRange $SDNConfig.rbDHCPExclusionStart -EndRange $SDNConfig.rbDHCPExclusionEnd - #Set-DhcpServerv4OptionValue -OptionID 3 -Value $SDNConfig.BGPRouterIP_VLAN200.Trim("/24") -ScopeID $scope.ScopeID.IPAddressToString -ComputerName $dnsName - Set-DhcpServerv4OptionValue -ComputerName $dnsName -ScopeId $scope.ScopeID.IPAddressToString -DnsServer $SDNConfig.SDNLABDNS -Router $SDNConfig.BGPRouterIP_VLAN200.Trim("/24") - } - } - $ErrorActionPreference = "Stop" -} - -function New-RouterVM { - - Param ( - - $SDNConfig, - $localCred, - $domainCred - - ) - - Invoke-Command -VMName AzSMGMT -Credential $localCred -ScriptBlock { - - $SDNConfig = $using:SDNConfig - $localcred = $using:localcred - $domainCred = $using:domainCred - $ParentDiskPath = "C:\VMs\Base\" - $vmpath = "D:\VMs\" - $OSVHDX = "AzSHCI.vhdx" - - $ProgressPreference = "SilentlyContinue" - $ErrorActionPreference = "Stop" - $VerbosePreference = "Continue" - $WarningPreference = "SilentlyContinue" - - $VMName = "bgp-tor-router" - - # Create Host OS Disk - - Write-Verbose "Creating $VMName differencing disks" - - $params = @{ - - ParentPath = ($ParentDiskPath + $OSVHDX) - Path = ($vmpath + $VMName + '\' + $VMName + '.vhdx') - - } - - New-VHD @params -Differencing | Out-Null - - # Create VM - - $params = @{ - - Name = $VMName - VHDPath = ($vmpath + $VMName + '\' + $VMName + '.vhdx') - Path = ($vmpath + $VMName) - Generation = 2 - - } - - Write-Verbose "Creating the $VMName VM." - New-VM @params | Out-Null - - # Set VM Configuration - - Write-Verbose "Setting $VMName's VM Configuration" - - $params = @{ - - VMName = $VMName - DynamicMemoryEnabled = $true - StartupBytes = $SDNConfig.MEM_BGP - MaximumBytes = $SDNConfig.MEM_BGP - MinimumBytes = 500MB - } - - Set-VMMemory @params | Out-Null - Remove-VMNetworkAdapter -VMName $VMName -Name "Network Adapter" | Out-Null - Set-VMProcessor -VMName $VMName -Count 2 | Out-Null - set-vm -Name $VMName -AutomaticStopAction TurnOff | Out-Null - - # Configure VM Networking - - Write-Verbose "Configuring $VMName's Networking" - Add-VMNetworkAdapter -VMName $VMName -Name Mgmt -SwitchName vSwitch-Fabric -DeviceNaming On - Add-VMNetworkAdapter -VMName $VMName -Name Provider -SwitchName vSwitch-Fabric -DeviceNaming On - Add-VMNetworkAdapter -VMName $VMName -Name VLAN200 -SwitchName vSwitch-Fabric -DeviceNaming On - Add-VMNetworkAdapter -VMName $VMName -Name SIMInternet -SwitchName vSwitch-Fabric -DeviceNaming On - Set-VMNetworkAdapterVlan -VMName $VMName -VMNetworkAdapterName Provider -Access -VlanId $SDNConfig.providerVLAN - Set-VMNetworkAdapterVlan -VMName $VMName -VMNetworkAdapterName VLAN200 -Access -VlanId $SDNConfig.vlan200VLAN - Set-VMNetworkAdapterVlan -VMName $VMName -VMNetworkAdapterName SIMInternet -Access -VlanId $SDNConfig.simInternetVLAN - - - # Add NAT Adapter - - if ($SDNConfig.natConfigure) { - - Add-VMNetworkAdapter -VMName $VMName -Name NAT -SwitchName NAT -DeviceNaming On - } - - # Configure VM - Set-VMProcessor -VMName $VMName -Count 2 - Set-VM -Name $VMName -AutomaticStartAction Start -AutomaticStopAction ShutDown | Out-Null - - # Inject Answer File - - Write-Verbose "Mounting Disk Image and Injecting Answer File into the $VMName VM." - New-Item -Path "C:\TempBGPMount" -ItemType Directory | Out-Null - Mount-WindowsImage -Path "C:\TempBGPMount" -Index 1 -ImagePath ($vmpath + $VMName + '\' + $VMName + '.vhdx') | Out-Null - - New-Item -Path C:\TempBGPMount\windows -ItemType Directory -Name Panther -Force | Out-Null - - $Password = $SDNConfig.SDNAdminPassword - - $Unattend = @" -<?xml version="1.0" encoding="utf-8"?> -<unattend xmlns="urn:schemas-microsoft-com:unattend"> - <servicing> - <package action="configure"> - <assemblyIdentity name="Microsoft-Windows-Foundation-Package" version="10.0.14393.0" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="" /> - <selection name="RemoteAccessServer" state="true" /> - <selection name="RasRoutingProtocols" state="true" /> - </package> - </servicing> - <settings pass="specialize"> - <component name="Networking-MPSSVC-Svc" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - <DomainProfile_EnableFirewall>false</DomainProfile_EnableFirewall> - <PrivateProfile_EnableFirewall>false</PrivateProfile_EnableFirewall> - <PublicProfile_EnableFirewall>false</PublicProfile_EnableFirewall> - </component> - <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - <ComputerName>$VMName</ComputerName> - </component> - <component name="Microsoft-Windows-TerminalServices-LocalSessionManager" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - <fDenyTSConnections>false</fDenyTSConnections> - </component> - <component name="Microsoft-Windows-International-Core" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - <UserLocale>en-us</UserLocale> - <UILanguage>en-us</UILanguage> - <SystemLocale>en-us</SystemLocale> - <InputLocale>en-us</InputLocale> - </component> - </settings> - <settings pass="oobeSystem"> - <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - <OOBE> - <HideEULAPage>true</HideEULAPage> - <SkipMachineOOBE>true</SkipMachineOOBE> - <SkipUserOOBE>true</SkipUserOOBE> - <HideOEMRegistrationScreen>true</HideOEMRegistrationScreen> - </OOBE> - <UserAccounts> - <AdministratorPassword> - <Value>$Password</Value> - <PlainText>true</PlainText> - </AdministratorPassword> - </UserAccounts> - </component> - </settings> - <cpi:offlineImage cpi:source="" xmlns:cpi="urn:schemas-microsoft-com:cpi" /> - </unattend> -"@ - Set-Content -Value $Unattend -Path "C:\TempBGPMount\Windows\Panther\Unattend.xml" -Force - - Write-Verbose "Enabling Remote Access" - Enable-WindowsOptionalFeature -Path C:\TempBGPMount -FeatureName RasRoutingProtocols -All -LimitAccess | Out-Null - Enable-WindowsOptionalFeature -Path C:\TempBGPMount -FeatureName RemoteAccessPowerShell -All -LimitAccess | Out-Null - Write-Verbose "Dismounting Disk Image for $VMName VM." - Dismount-WindowsImage -Path "C:\TempBGPMount" -Save | Out-Null - Remove-Item "C:\TempBGPMount" - - # Start the VM - - Write-Verbose "Starting $VMName VM." - Start-VM -Name $VMName - - # Wait for VM to be started - - while ((Invoke-Command -VMName $VMName -Credential $localcred { "Test" } -ea SilentlyContinue) -ne "Test") { Start-Sleep -Seconds 1 } - - Write-Verbose "Configuring $VMName" - - Invoke-Command -VMName $VMName -Credential $localCred -ArgumentList $SDNConfig -ScriptBlock { - - $ErrorActionPreference = "Stop" - $VerbosePreference = "Continue" - $WarningPreference = "SilentlyContinue" - - $SDNConfig = $args[0] - $DNS = $SDNConfig.SDNLABDNS - $natSubnet = $SDNConfig.natSubnet - $natDNS = $SDNConfig.natSubnet - $MGMTIP = $SDNConfig.BGPRouterIP_MGMT.Split("/")[0] - $MGMTPFX = $SDNConfig.BGPRouterIP_MGMT.Split("/")[1] - $PNVIP = $SDNConfig.BGPRouterIP_ProviderNetwork.Split("/")[0] - $PNVPFX = $SDNConfig.BGPRouterIP_ProviderNetwork.Split("/")[1] - $VLANIP = $SDNConfig.BGPRouterIP_VLAN200.Split("/")[0] - $VLANPFX = $SDNConfig.BGPRouterIP_VLAN200.Split("/")[1] - $simInternetIP = $SDNConfig.BGPRouterIP_SimulatedInternet.Split("/")[0] - $simInternetPFX = $SDNConfig.BGPRouterIP_SimulatedInternet.Split("/")[1] - - # Renaming NetAdapters and setting up the IPs inside the VM using CDN parameters - - Write-Verbose "Configuring $env:COMPUTERNAME's Networking" - $VerbosePreference = "SilentlyContinue" - $NIC = Get-NetAdapterAdvancedProperty -RegistryKeyWord "HyperVNetworkAdapterName" | Where-Object { $_.RegistryValue -eq "Mgmt" } - Rename-NetAdapter -name $NIC.name -newname "Mgmt" | Out-Null - New-NetIPAddress -InterfaceAlias "Mgmt" -IPAddress $MGMTIP -PrefixLength $MGMTPFX | Out-Null - Set-DnsClientServerAddress -InterfaceAlias “Mgmt” -ServerAddresses $DNS] | Out-Null - $NIC = Get-NetAdapterAdvancedProperty -RegistryKeyWord "HyperVNetworkAdapterName" | Where-Object { $_.RegistryValue -eq "PROVIDER" } - Rename-NetAdapter -name $NIC.name -newname "PROVIDER" | Out-Null - New-NetIPAddress -InterfaceAlias "PROVIDER" -IPAddress $PNVIP -PrefixLength $PNVPFX | Out-Null - $NIC = Get-NetAdapterAdvancedProperty -RegistryKeyWord "HyperVNetworkAdapterName" | Where-Object { $_.RegistryValue -eq "VLAN200" } - Rename-NetAdapter -name $NIC.name -newname "VLAN200" | Out-Null - New-NetIPAddress -InterfaceAlias "VLAN200" -IPAddress $VLANIP -PrefixLength $VLANPFX | Out-Null - $NIC = Get-NetAdapterAdvancedProperty -RegistryKeyWord "HyperVNetworkAdapterName" | Where-Object { $_.RegistryValue -eq "SIMInternet" } - Rename-NetAdapter -name $NIC.name -newname "SIMInternet" | Out-Null - New-NetIPAddress -InterfaceAlias "SIMInternet" -IPAddress $simInternetIP -PrefixLength $simInternetPFX | Out-Null - - # if NAT is selected, configure the adapter - - if ($SDNConfig.natConfigure) { - - $NIC = Get-NetAdapterAdvancedProperty -RegistryKeyWord "HyperVNetworkAdapterName" ` - | Where-Object { $_.RegistryValue -eq "NAT" } - Rename-NetAdapter -name $NIC.name -newname "NAT" | Out-Null - $Prefix = ($natSubnet.Split("/"))[1] - $natIP = ($natSubnet.TrimEnd("0./$Prefix")) + (".10") - $natGW = ($natSubnet.TrimEnd("0./$Prefix")) + (".1") - New-NetIPAddress -InterfaceAlias "NAT" -IPAddress $natIP -PrefixLength $Prefix -DefaultGateway $natGW | Out-Null - if ($natDNS) { - Set-DnsClientServerAddress -InterfaceAlias "NAT" -ServerAddresses $natDNS | Out-Null - } - } - - # Configure Trusted Hosts - - Write-Verbose "Configuring Trusted Hosts" - Set-Item WSMan:\localhost\Client\TrustedHosts * -Confirm:$false -Force - - - # Installing Remote Access - - Write-Verbose "Installing Remote Access on $env:COMPUTERNAME" - $VerbosePreference = "SilentlyContinue" - Install-RemoteAccess -VPNType RoutingOnly | Out-Null - - # Adding a BGP Router to the VM - - $VerbosePreference = "Continue" - Write-Verbose "Installing BGP Router on $env:COMPUTERNAME" - $VerbosePreference = "SilentlyContinue" - - $params = @{ - - BGPIdentifier = $PNVIP - LocalASN = $SDNConfig.BGPRouterASN - TransitRouting = 'Enabled' - ClusterId = 1 - RouteReflector = 'Enabled' - - } - - Add-BgpRouter @params - - #Add-BgpRouter -BGPIdentifier $PNVIP -LocalASN $SDNConfig.BGPRouterASN ` - # -TransitRouting Enabled -ClusterId 1 -RouteReflector Enabled - - # Configure BGP Peers - - if ($SDNConfig.ConfigureBGPpeering -and $SDNConfig.ProvisionNC) { - - Write-Verbose "Peering future MUX/GWs" - - $Mux01IP = ($SDNConfig.BGPRouterIP_ProviderNetwork.TrimEnd("1/24")) + "4" - $GW01IP = ($SDNConfig.BGPRouterIP_ProviderNetwork.TrimEnd("1/24")) + "5" - $GW02IP = ($SDNConfig.BGPRouterIP_ProviderNetwork.TrimEnd("1/24")) + "6" - - $params = @{ - - Name = 'MUX01' - LocalIPAddress = $PNVIP - PeerIPAddress = $Mux01IP - PeerASN = $SDNConfig.SDNASN - OperationMode = 'Mixed' - PeeringMode = 'Automatic' - } - - Add-BgpPeer @params -PassThru - - $params.Name = 'GW01' - $params.PeerIPAddress = $GW01IP - - Add-BgpPeer @params -PassThru - - $params.Name = 'GW02' - $params.PeerIPAddress = $GW02IP - - Add-BgpPeer @params -PassThru - - } - - # Enable Large MTU - - Write-Verbose "Configuring MTU on all Adapters" - Get-NetAdapter | Where-Object { $_.Status -eq "Up" } | Set-NetAdapterAdvancedProperty -RegistryValue $SDNConfig.SDNLABMTU -RegistryKeyword "*JumboPacket" - -# # Enable DHCP Relay -# $routerNetAdapterName = "VLAN200" -# $netshDhcpRelay=@" -# pushd routing ip relay -# install -# set global loglevel=ERROR -# add dhcpserver $($SDNConfig.DCIP) -# add interface name="$routerNetAdapterName" -# set interface name="$routerNetAdapterName" relaymode=enable maxhop=6 minsecs=6 -# popd -# "@ - -# $netshDhcpRelayPath="$ENV:TEMP\netshDhcpRelay" - - # # Create netsh script file - # New-Item -Path $netshDhcpRelayPath -Type File -ErrorAction SilentlyContinue | Out-Null - - # # Populate contents of the script - # Set-Content -Path $netshDhcpRelayPath -Value $netshDhcpRelay.Split("`r`n") -Encoding ASCII - - # # run it - # CMD.exe /c "netsh -f $netshDhcpRelayPath" - } - - $ErrorActionPreference = "Continue" - $VerbosePreference = "SilentlyContinue" - $WarningPreference = "Continue" - - } -AsJob - -} - -function New-AdminCenterVM { - Param ( - - $SDNConfig, - $localCred, - $domainCred - - ) - - $domainAdminUsername = $env:adminUsername - - Invoke-Command -VMName AzSMGMT -Credential $localCred -ScriptBlock { - - $VMName = "admincenter" - $ParentDiskPath = "C:\VMs\Base\" - $VHDPath = "D:\VMs\" - $OSVHDX = "GUI.vhdx" - $BaseVHDPath = $ParentDiskPath + $OSVHDX - $SDNConfig = $using:SDNConfig - - $ProgressPreference = "SilentlyContinue" - $ErrorActionPreference = "Stop" - $VerbosePreference = "Continue" - $WarningPreference = "SilentlyContinue" - - # Set Credentials - $localCred = $using:localCred - $domainCred = $using:domainCred - - # Create Host OS Disk - Write-Verbose "Creating $VMName differencing disks" - - $params = @{ - - ParentPath = $BaseVHDPath - Path = (($VHDPath) + ($VMName) + (".vhdx")) - } - - New-VHD -Differencing @params | out-null - - # MountVHDXFile - $VerbosePreference = "SilentlyContinue" - Import-Module DISM - $VerbosePreference = "Continue" - - Write-Verbose "Mounting $VMName VHD." - New-Item -Path "C:\TempWACMount" -ItemType Directory | Out-Null - Mount-WindowsImage -Path "C:\TempWACMount" -Index 1 -ImagePath (($VHDPath) + ($VMName) + (".vhdx")) | Out-Null - - # Copy Source Files - Write-Verbose "Copying Application and Script Source Files to $VMName" - Copy-Item 'C:\VMConfigs\Windows Admin Center' -Destination C:\TempWACMount\ -Recurse -Force - Copy-Item C:\VMConfigs\SDN -Destination C:\TempWACMount -Recurse -Force - New-Item -Path C:\TempWACMount\VHDs -ItemType Directory -Force | Out-Null - Copy-Item C:\VMs\Base\AzSHCI.vhdx -Destination C:\TempWACMount\VHDs -Force - Copy-Item C:\VMs\Base\GUI.vhdx -Destination C:\TempWACMount\VHDs -Force - - # Create VM - Write-Verbose "Creating the $VMName VM." - - $params = @{ - - Name = $VMName - VHDPath = (($VHDPath) + ($VMName) + (".vhdx")) - Path = $VHDPath - Generation = 2 - } - - New-VM @params | Out-Null - - $params = @{ - - VMName = $VMName - DynamicMemoryEnabled = $true - StartupBytes = $SDNConfig.MEM_WAC - MaximumBytes = $SDNConfig.MEM_WAC - MinimumBytes = 500mb - } - - Set-VMMemory @params | Out-Null - Set-VM -Name $VMName -AutomaticStartAction Start -AutomaticStopAction ShutDown | Out-Null - - Write-Verbose "Configuring $VMName's Networking" - Remove-VMNetworkAdapter -VMName $VMName -Name "Network Adapter" - Add-VMNetworkAdapter -VMName $VMName -Name "Fabric" -SwitchName "vSwitch-Fabric" -DeviceNaming On - Set-VMNetworkAdapter -VMName $VMName -StaticMacAddress "10155D010B00" - - # Apply Custom Unattend.xml file - New-Item -Path C:\TempWACMount\windows -ItemType Directory -Name Panther -Force | Out-Null - $Password = $SDNConfig.SDNAdminPassword - $ProductKey = $SDNConfig.GUIProductKey - $Gateway = $SDNConfig.SDNLABRoute - $DNS = $SDNConfig.SDNLABDNS - $IPAddress = $SDNConfig.WACIP - $Domain = $SDNConfig.SDNDomainFQDN - - $Unattend = @" -<?xml version="1.0" encoding="utf-8"?> -<unattend xmlns="urn:schemas-microsoft-com:unattend"> - <settings pass="specialize"> - <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - <ProductKey>$ProductKey</ProductKey> - <ComputerName>$VMName</ComputerName> - <RegisteredOwner>$ENV:USERNAME</RegisteredOwner> - </component> - <component name="Microsoft-Windows-TCPIP" processorArchitecture="wow64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - <Interfaces> - <Interface wcm:action="add"> - <Ipv4Settings> - <DhcpEnabled>false</DhcpEnabled> - <Metric>20</Metric> - <RouterDiscoveryEnabled>true</RouterDiscoveryEnabled> - </Ipv4Settings> - <UnicastIpAddresses> - <IpAddress wcm:action="add" wcm:keyValue="1">$IPAddress</IpAddress> - </UnicastIpAddresses> - <Identifier>10-15-5D-01-0B-00</Identifier> - <Routes> - <Route wcm:action="add"> - <Identifier>1</Identifier> - <NextHopAddress>$Gateway</NextHopAddress> - </Route> - </Routes> - </Interface> - </Interfaces> - </component> - <component name="Microsoft-Windows-DNS-Client" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - <Interfaces> - <Interface wcm:action="add"> - <DNSServerSearchOrder> - <IpAddress wcm:action="add" wcm:keyValue="1">$DNS</IpAddress> - </DNSServerSearchOrder> - <Identifier>10-15-5D-01-0B-00</Identifier> - <DNSDomain>$Domain</DNSDomain> - <EnableAdapterDomainNameRegistration>true</EnableAdapterDomainNameRegistration> - </Interface> - </Interfaces> - </component> - <component name="Networking-MPSSVC-Svc" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - <DomainProfile_EnableFirewall>false</DomainProfile_EnableFirewall> - <PrivateProfile_EnableFirewall>false</PrivateProfile_EnableFirewall> - <PublicProfile_EnableFirewall>false</PublicProfile_EnableFirewall> - </component> - <component name="Microsoft-Windows-TerminalServices-LocalSessionManager" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - <fDenyTSConnections>false</fDenyTSConnections> - </component> - <component name="Microsoft-Windows-UnattendedJoin" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - <Identification> - <Credentials> - <Domain>$Domain</Domain> - <Password>$Password</Password> - <Username>Administrator</Username> - </Credentials> - <JoinDomain>$Domain</JoinDomain> - </Identification> - </component> - <component name="Microsoft-Windows-IE-ESC" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - <IEHardenAdmin>false</IEHardenAdmin> - <IEHardenUser>false</IEHardenUser> - </component> - </settings> - <settings pass="oobeSystem"> - <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - <UserAccounts> - <AdministratorPassword> - <Value>$Password</Value> - <PlainText>true</PlainText> - </AdministratorPassword> - </UserAccounts> - <TimeZone>Pacific Standard Time</TimeZone> - <OOBE> - <HideEULAPage>true</HideEULAPage> - <SkipUserOOBE>true</SkipUserOOBE> - <HideOEMRegistrationScreen>true</HideOEMRegistrationScreen> - <HideOnlineAccountScreens>true</HideOnlineAccountScreens> - <HideWirelessSetupInOOBE>true</HideWirelessSetupInOOBE> - <NetworkLocation>Work</NetworkLocation> - <ProtectYourPC>1</ProtectYourPC> - <HideLocalAccountScreen>true</HideLocalAccountScreen> - </OOBE> - </component> - <component name="Microsoft-Windows-International-Core" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - <UserLocale>en-US</UserLocale> - <SystemLocale>en-US</SystemLocale> - <InputLocale>0409:00000409</InputLocale> - <UILanguage>en-US</UILanguage> - </component> - </settings> - <cpi:offlineImage cpi:source="" xmlns:cpi="urn:schemas-microsoft-com:cpi" /> -</unattend> -"@ - - Write-Verbose "Mounting and Injecting Answer File into the $VMName VM." - Set-Content -Value $Unattend -Path "C:\TempWACMount\Windows\Panther\Unattend.xml" -Force - - # Save Customizations and then dismount. - Write-Verbose "Dismounting Disk" - Dismount-WindowsImage -Path "C:\TempWACMount" -Save | Out-Null - Remove-Item "C:\TempWACMount" - - Write-Verbose "Setting $VMName's VM Configuration" - Set-VMProcessor -VMName $VMname -Count 4 - set-vm -Name $VMName -AutomaticStopAction TurnOff - - Write-Verbose "Starting $VMName VM." - Start-VM -Name $VMName - - # Refresh Domain Cred - $domainCred = new-object -typename System.Management.Automation.PSCredential ` - -argumentlist (($SDNConfig.SDNDomainFQDN.Split(".")[0]) + "\$using:domainAdminUsername"), ` - (ConvertTo-SecureString $SDNConfig.SDNAdminPassword -AsPlainText -Force) - - # Wait until the VM is restarted - while ((Invoke-Command -VMName $VMName -Credential $domainCred { "Test" } ` - -ea SilentlyContinue) -ne "Test") { Start-Sleep -Seconds 1 } - - # Finish Configuration - Invoke-Command -VMName $VMName -Credential $domainCred -ArgumentList $SDNConfig, $VMName -ScriptBlock { - - $SDNConfig = $args[0] - $VMName = $args[1] - $Gateway = $SDNConfig.SDNLABRoute - $VerbosePreference = "Continue" - $ErrorActionPreference = "Stop" - - $VerbosePreference = "SilentlyContinue" - Import-Module NetAdapter - $VerbosePreference = "Continue" - - # Enabling Remote Access on Admincenter VM - Write-Verbose "Enabling Remote Access" - Enable-WindowsOptionalFeature -FeatureName RasRoutingProtocols -All -LimitAccess -Online | Out-Null - Enable-WindowsOptionalFeature -FeatureName RemoteAccessPowerShell -All -LimitAccess -Online | Out-Null - - Write-Verbose "Configuring WSMAN Trusted Hosts" - Set-Item WSMan:\localhost\Client\TrustedHosts * -Confirm:$false -Force - Enable-WSManCredSSP -Role Client -DelegateComputer * -Force - - Write-Verbose "Rename Network Adapter in $VMName VM" - Get-NetAdapter | Rename-NetAdapter -NewName Fabric - - # Set Gateway - $index = (Get-WmiObject Win32_NetworkAdapter | Where-Object { $_.netconnectionid -eq "Fabric" }).InterfaceIndex - $NetInterface = Get-WmiObject Win32_NetworkAdapterConfiguration | Where-Object { $_.InterfaceIndex -eq $index } - $NetInterface.SetGateways($Gateway) | Out-Null - - $fqdn = $SDNConfig.SDNDomainFQDN - - # Enable CredSSP - $VerbosePreference = "SilentlyContinue" - Enable-PSRemoting -force - Enable-WSManCredSSP -Role Server -Force - Enable-WSManCredSSP -Role Client -DelegateComputer localhost -Force - Enable-WSManCredSSP -Role Client -DelegateComputer $env:COMPUTERNAME -Force - Enable-WSManCredSSP -Role Client -DelegateComputer $fqdn -Force - Enable-WSManCredSSP -Role Client -DelegateComputer "*.$fqdn" -Force - New-Item -Path HKLM:\SOFTWARE\Policies\Microsoft\Windows\CredentialsDelegation ` - -Name AllowFreshCredentialsWhenNTLMOnly -Force - New-ItemProperty -Path HKLM:\SOFTWARE\Policies\Microsoft\Windows\CredentialsDelegation\AllowFreshCredentialsWhenNTLMOnly ` - -Name 1 -Value * -PropertyType String -Force - - $VerbosePreference = "Continue" - - # Enable Large MTU - Write-Verbose "Configuring MTU on all Adapters" - Get-NetAdapter | Where-Object { $_.Status -eq "Up" } | Set-NetAdapterAdvancedProperty -RegistryValue $SDNConfig.SDNLABMTU -RegistryKeyword "*JumboPacket" - - $WACIP = $SDNConfig.WACIP.Split("/")[0] - - # Install RSAT-NetworkController - $isAvailable = Get-WindowsFeature | Where-Object { $_.Name -eq 'RSAT-NetworkController' } - - if ($isAvailable) { - Write-Verbose "Installing RSAT-NetworkController" - - $VerbosePreference = "SilentlyContinue" - Import-Module ServerManager - Install-WindowsFeature -Name RSAT-NetworkController -IncludeAllSubFeature -IncludeManagementTools | Out-Null - $VerbosePreference = "Continue" - } - - # Install Hyper-V RSAT - Write-Verbose "Installing Hyper-V RSAT Tools" - $VerbosePreference = "SilentlyContinue" - Install-WindowsFeature -Name RSAT-Hyper-V-Tools -IncludeAllSubFeature -IncludeManagementTools | Out-Null - $VerbosePreference = "Continue" - - # Install RSAT AD Tools - Write-Verbose "Installing Active Directory RSAT Tools" - $VerbosePreference = "SilentlyContinue" - Install-WindowsFeature -Name RSAT-ADDS -IncludeAllSubFeature -IncludeManagementTools | Out-Null - $VerbosePreference = "Continue" - - # Install Failover Cluster RSAT Tools - Write-Verbose "Installing Failover Clustering RSAT Tools" - $VerbosePreference = "SilentlyContinue" - Install-WindowsFeature -Name RSAT-Clustering-Mgmt, RSAT-Clustering-PowerShell -IncludeAllSubFeature -IncludeManagementTools | Out-Null - $VerbosePreference = "Continue" - - # Install DNS RSAT Tool - Write-Verbose "Installing DNS Server RSAT Tools" - $VerbosePreference = "SilentlyContinue" - Install-WindowsFeature -Name RSAT-DNS-Server -IncludeAllSubFeature -IncludeManagementTools | Out-Null - $VerbosePreference = "Continue" - - # Install VPN Routing - $VerbosePreference = "SilentlyContinue" - Install-RemoteAccess -VPNType RoutingOnly | Out-Null - $VerbosePreference = "Continue" - - # Install Nuget - $VerbosePreference = "SilentlyContinue" - Install-PackageProvider -Name Nuget -MinimumVersion 2.8.5.201 -Force - $VerbosePreference = "Continue" - - # Stop Server Manager from starting on boot - Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\ServerManager" -Name "DoNotOpenServerManagerAtLogon" -Value 1 - - # Request SSL Certificate for Windows Admin Center - Write-Verbose "Generating SSL Certificate Request" - - # Create BGP Router - $params = @{ - BGPIdentifier = $WACIP - LocalASN = $SDNConfig.WACASN - TransitRouting = 'Enabled' - ClusterId = 1 - RouteReflector = 'Enabled' - } - - Add-BgpRouter @params - - $RequestInf = @" -[Version] -Signature="`$Windows NT$" - -[NewRequest] -Subject = "CN=AdminCenter.$fqdn" -Exportable = True -KeyLength = 2048 -KeySpec = 1 -KeyUsage = 0xA0 -MachineKeySet = True -ProviderName = "Microsoft RSA SChannel Cryptographic Provider" -ProviderType = 12 -SMIME = FALSE -RequestType = CMC -FriendlyName = "Nested SDN Windows Admin Cert" - -[Strings] -szOID_SUBJECT_ALT_NAME2 = "2.5.29.17" -szOID_ENHANCED_KEY_USAGE = "2.5.29.37" -szOID_PKIX_KP_SERVER_AUTH = "1.3.6.1.5.5.7.3.1" -szOID_PKIX_KP_CLIENT_AUTH = "1.3.6.1.5.5.7.3.2" -[Extensions] -%szOID_SUBJECT_ALT_NAME2% = "{text}dns=admincenter.$fqdn" -%szOID_ENHANCED_KEY_USAGE% = "{text}%szOID_PKIX_KP_SERVER_AUTH%,%szOID_PKIX_KP_CLIENT_AUTH%" -[RequestAttributes] -CertificateTemplate= WebServer -"@ - - New-Item C:\WACCert -ItemType Directory -Force | Out-Null - Set-Content -Value $RequestInf -Path C:\WACCert\WACCert.inf -Force | Out-Null - - $WACdomainCred = new-object -typename System.Management.Automation.PSCredential ` - -argumentlist (($SDNConfig.SDNDomainFQDN.Split(".")[0]) + "\administrator"), (ConvertTo-SecureString $SDNConfig.SDNAdminPassword -AsPlainText -Force) - $WACVMName = "admincenter" - $DCFQDN = $SDNConfig.DCName + '.' + $SDNConfig.SDNDomainFQDN - $WACport = $SDNConfig.WACport - $SDNConfig = $Using:SDNConfig - $fqdn = $SDNConfig.SDNDomainFQDN - - $params = @{ - Name = 'microsoft.SDNNested' - RunAsCredential = $Using:domainCred - MaximumReceivedDataSizePerCommandMB = 1000 - MaximumReceivedObjectSizeMB = 1000 - } - - $VerbosePreference = "SilentlyContinue" - Register-PSSessionConfiguration @params - $VerbosePreference = "Continue" - - Write-Verbose "Requesting and installing SSL Certificate" - Invoke-Command -ComputerName $WACVMName -ConfigurationName microsoft.SDNNested -ArgumentList $WACVMName, $SDNConfig, $DCFQDN -Credential $WACdomainCred -ScriptBlock { - - $DCFQDN = $args[2] - $VerbosePreference = "Continue" - $ErrorActionPreference = "Stop" - - # Get the CA Name - $CertDump = certutil -dump - $ca = ((((($CertDump.Replace('`', "")).Replace("'", "")).Replace(":", "=")).Replace('\', "")).Replace('"', "") ` - | ConvertFrom-StringData).Name - $CertAuth = $DCFQDN + '\' + $ca - - Write-Verbose "CA is: $ca" - Write-Verbose "Certificate Authority is: $CertAuth" - Write-Verbose "Certdump is $CertDump" - - # Request and Accept SSL Certificate - Set-Location C:\WACCert - certreq -q -f -new WACCert.inf WACCert.req - certreq -q -config $CertAuth -attrib "CertificateTemplate:webserver" -submit WACCert.req WACCert.cer - certreq -q -accept WACCert.cer - certutil -q -store my - - Set-Location 'C:\' - Remove-Item C:\WACCert -Recurse -Force - - } -Authentication Credssp - - $SDNConfig = Import-PowerShellDataFile -Path C:\SDN\HCIBox-Config.psd1 - - # Install Windows Admin Center - $pfxThumbPrint = (Get-ChildItem -Path Cert:\LocalMachine\my | Where-Object { $_.FriendlyName -match "Nested SDN Windows Admin Cert" }).Thumbprint - Write-Verbose "Thumbprint: $pfxThumbPrint" - Write-Verbose "WACPort: $WACPort" - $WindowsAdminCenterGateway = "https://admincenter." + $fqdn - Write-Verbose $WindowsAdminCenterGateway - Write-Verbose "Installing and Configuring Windows Admin Center" - $PathResolve = Resolve-Path -Path 'C:\Windows Admin Center\*.msi' - $arguments = "/qn /L*v C:\log.txt SME_PORT=$WACport SME_THUMBPRINT=$pfxThumbPrint SSL_CERTIFICATE_OPTION=installed SME_URL=$WindowsAdminCenterGateway" - Start-Process -FilePath $PathResolve -ArgumentList $arguments -PassThru | Wait-Process - - # Create a shortcut for Windows PowerShell ISE - Write-Verbose "Creating Shortcut for PowerShell ISE" - $TargetFile = "c:\windows\system32\WindowsPowerShell\v1.0\powershell_ise.exe" - $ShortcutFile = "C:\Users\Public\Desktop\PowerShell ISE.lnk" - $WScriptShell = New-Object -ComObject WScript.Shell - $Shortcut = $WScriptShell.CreateShortcut($ShortcutFile) - $Shortcut.TargetPath = $TargetFile - $Shortcut.Save() - - # Create a shortcut for Windows PowerShell Console - Write-Verbose "Creating Shortcut for PowerShell Console" - $TargetFile = "c:\windows\system32\WindowsPowerShell\v1.0\powershell.exe" - $ShortcutFile = "C:\Users\Public\Desktop\PowerShell.lnk" - $WScriptShell = New-Object -ComObject WScript.Shell - $Shortcut = $WScriptShell.CreateShortcut($ShortcutFile) - $Shortcut.TargetPath = $TargetFile - $Shortcut.Save() - - # Install Chocolatey - $ErrorActionPreference = "Continue" - Write-Verbose "Installing Chocolatey" - Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; Invoke-Expression ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1')) - Start-Sleep -Seconds 10 - - # Install Azure PowerShell - Write-Verbose 'Installing Az PowerShell' - $expression = "choco install az.powershell -y" - Invoke-Expression $expression - $ErrorActionPreference = "Stop" - - # Create Shortcut for Hyper-V Manager - Write-Verbose "Creating Shortcut for Hyper-V Manager" - Copy-Item -Path "C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Administrative Tools\Hyper-V Manager.lnk" ` - -Destination "C:\Users\Public\Desktop" - - # Create Shortcut for Failover-Cluster Manager - Write-Verbose "Creating Shortcut for Failover-Cluster Manager" - Copy-Item -Path "C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Administrative Tools\Failover Cluster Manager.lnk" ` - -Destination "C:\Users\Public\Desktop" - - # Create Shortcut for DNS - Write-Verbose "Creating Shortcut for DNS Manager" - Copy-Item -Path "C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Administrative Tools\DNS.lnk" ` - -Destination "C:\Users\Public\Desktop" - - # Create Shortcut for Active Directory Users and Computers - Write-Verbose "Creating Shortcut for AD Users and Computers" - Copy-Item -Path "C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Administrative Tools\Active Directory Users and Computers.lnk" ` - -Destination "C:\Users\Public\Desktop" - - # Set the SDNExplorer Script and place on desktop - Write-Verbose "Configuring SDNExplorer" - $SENCIP = "nc01." + $SDNConfig.SDNDomainFQDN - $SDNEXPLORER = "Set-Location 'C:\VMConfigs\SDN';.\SDNExplorer.ps1 -NCIP $SENCIP" - Set-Content -Value $SDNEXPLORER -Path 'C:\users\Public\Desktop\SDN Explorer.ps1' -Force - - # Set Network Profiles - Get-NetConnectionProfile | Where-Object { $_.NetworkCategory -eq "Public" } ` - | Set-NetConnectionProfile -NetworkCategory Private | Out-Null - - # Disable Automatic Updates - $WUKey = "HKLM:\software\Policies\Microsoft\Windows\WindowsUpdate" - New-Item -Path $WUKey -Force | Out-Null - New-ItemProperty -Path $WUKey -Name AUOptions -PropertyType Dword -Value 2 ` - -Force | Out-Null - - # Install Kubectl - Write-Verbose 'Installing kubectl' - $expression = "choco install kubernetes-cli -y" - Invoke-Expression $expression - $ErrorActionPreference = "Stop" - - # Create a shortcut for Windows Admin Center - Write-Verbose "Creating Shortcut for Windows Admin Center" - if ($SDNConfig.WACport -ne "443") { $TargetPath = "https://admincenter." + $SDNConfig.SDNDomainFQDN + ":" + $SDNConfig.WACport } - else { $TargetPath = "https://admincenter." + $SDNConfig.SDNDomainFQDN } - $ShortcutFile = "C:\Users\Public\Desktop\Windows Admin Center.url" - $WScriptShell = New-Object -ComObject WScript.Shell - $Shortcut = $WScriptShell.CreateShortcut($ShortcutFile) - $Shortcut.TargetPath = $TargetPath - $Shortcut.Save() - - # Disable Edge 'First Run' Setup - $edgePolicyRegistryPath = 'HKLM:SOFTWARE\Policies\Microsoft\Edge' - $desktopSettingsRegistryPath = 'HKCU:SOFTWARE\Microsoft\Windows\Shell\Bags\1\Desktop' - $firstRunRegistryName = 'HideFirstRunExperience' - $firstRunRegistryValue = '0x00000001' - $savePasswordRegistryName = 'PasswordManagerEnabled' - $savePasswordRegistryValue = '0x00000000' - $autoArrangeRegistryName = 'FFlags' - $autoArrangeRegistryValue = '1075839525' - - if (-NOT (Test-Path -Path $edgePolicyRegistryPath)) { - New-Item -Path $edgePolicyRegistryPath -Force | Out-Null - } - if (-NOT (Test-Path -Path $desktopSettingsRegistryPath)) { - New-Item -Path $desktopSettingsRegistryPath -Force | Out-Null - } - - New-ItemProperty -Path $edgePolicyRegistryPath -Name $firstRunRegistryName -Value $firstRunRegistryValue -PropertyType DWORD -Force - New-ItemProperty -Path $edgePolicyRegistryPath -Name $savePasswordRegistryName -Value $savePasswordRegistryValue -PropertyType DWORD -Force - Set-ItemProperty -Path $desktopSettingsRegistryPath -Name $autoArrangeRegistryName -Value $autoArrangeRegistryValue -Force - } - } -} - -function New-HyperConvergedEnvironment { - Param ( - $localCred, - $domainCred - ) - - Invoke-Command -ComputerName Admincenter -Credential $domainCred -ScriptBlock { - $SDNConfig = $Using:SDNConfig - - $ErrorActionPreference = "Stop" - $VerbosePreference = "Continue" - - $domainCred = new-object -typename System.Management.Automation.PSCredential ` - -argumentlist (($SDNConfig.SDNDomainFQDN.Split(".")[0]) + "\administrator"), ` - (ConvertTo-SecureString $SDNConfig.SDNAdminPassword -AsPlainText -Force) - - foreach ($AzSHOST in $SDNconfig.HostList) { - Write-Verbose "Invoking Command on $AzSHOST" - Invoke-Command -ComputerName $AzSHOST -ArgumentList $SDNConfig -Credential $using:domainCred -ScriptBlock { - function New-sdnSETSwitch { - param ( - $sdnswitchName, - $sdnswitchIP, - $sdnswitchIPpfx, - $sdnswitchVLAN, - $sdnswitchGW, - $sdnswitchDNS, - $sdnswitchteammembers - ) - - $VerbosePreference = "Continue" - Write-Verbose "Creating SET Hyper-V External Switch $sdnswitchName on host $env:COMPUTERNAME" - $params = @{ - - Name = $sdnswitchName - AllowManagementOS = $true - NetAdapterName = $sdnswitchteammembers - EnableEmbeddedTeaming = $true - MinimumBandwidthMode = "Weight" - } - New-VMSwitch @params | Out-Null - - # Set IP Config - Write-Verbose "Setting IP Configuration on $sdnswitchName" - $sdnswitchNIC = Get-Netadapter | Where-Object { $_.Name -match $sdnswitchName } - - $params = @{ - InterfaceIndex = $sdnswitchNIC.InterfaceIndex - IpAddress = $sdnswitchIP - PrefixLength = $sdnswitchIPpfx - AddressFamily = 'IPv4' - DefaultGateway = $sdnswitchGW - ErrorAction = 'SilentlyContinue' - } - - New-NetIPAddress @params | Out-Null - - # Set DNS - Set-DnsClientServerAddress -InterfaceIndex $sdnswitchNIC.InterfaceIndex -ServerAddresses ($sdnswitchDNS) - - # Set VLAN - Write-Verbose "Setting VLAN ($sdnswitchVLAN) on host vNIC" - $params = @{ - IsolationMode = 'Vlan' - DefaultIsolationID = $sdnswitchVLAN - AllowUntaggedTraffic = $true - VMNetworkAdapterName = $sdnswitchName - } - Set-VMNetworkAdapterIsolation -ManagementOS @params - - # Disable Switch Extensions - Get-VMSwitchExtension -VMSwitchName $sdnswitchName | Disable-VMSwitchExtension | Out-Null - - # Enable Large MTU - Write-Verbose "Configuring MTU on all Adapters" - Get-NetAdapter | Where-Object { $_.Status -eq "Up" } | Set-NetAdapterAdvancedProperty -RegistryValue $SDNConfig.SDNLABMTU -RegistryKeyword "*JumboPacket" - - } - - $ErrorActionPreference = "Stop" - - $SDNConfig = $args[0] - $sdnswitchteammembers = @("FABRIC", "FABRIC2") - $sdnswitchIP = $SDNConfig.($env:COMPUTERNAME + "IP").Split("/")[0] - $sdnswitchIPpfx = $SDNConfig.($env:COMPUTERNAME + "IP").Split("/")[1] - $sdnswitchGW = $SDNConfig.BGPRouterIP_MGMT.Split("/")[0] - - $sdnswitchCheck = Get-VMSwitch | Where-Object { $_.Name -eq "sdnSwitch" } - - if ($sdnswitchCheck) { Write-Warning "Switch already exists on $env:COMPUTERNAME. Skipping this host." } - else { - $params = @{ - sdnswitchName = 'sdnSwitch' - sdnswitchIP = $sdnswitchIP - sdnswitchIPpfx = $sdnswitchIPpfx - sdnswitchVLAN = $SDNConfig.mgmtVLAN - sdnswitchGW = $sdnswitchGW - sdnswitchDNS = $SDNConfig.SDNLABDNS - sdnswitchteammembers = $sdnswitchteammembers - } - New-sdnSETSwitch @params | out-null - } - } - - Start-Sleep -Seconds 60 - - } - } - # Wait until all the AzSHOSTs have been restarted - foreach ($AzSHOST in $SDNconfig.HostList) { - Write-Verbose "Rebooting HCIBox Host $AzSHOST" - Restart-Computer $AzSHOST -Force -Confirm:$false -Credential $localCred -Protocol WSMan - Write-Verbose "Checking to see if $AzSHOST is up and online" - while ((Invoke-Command -ComputerName $AzSHOST -Credential $localCred { "Test" } -ea SilentlyContinue) -ne "Test") { Start-Sleep -Seconds 60 } - } -} - -function New-SDNEnvironment { - Param ( - $domainCred, - $SDNConfig - ) - - Invoke-Command -ComputerName admincenter -Credential $domainCred -ScriptBlock { - - Register-PSSessionConfiguration -Name microsoft.SDNNestedSetup -RunAsCredential $domainCred -MaximumReceivedDataSizePerCommandMB 1000 -MaximumReceivedObjectSizeMB 1000 | Out-Null - - Invoke-Command -ComputerName localhost -Credential $Using:domainCred -ArgumentList $Using:domainCred, $Using:SDNConfig -ConfigurationName microsoft.SDNNestedSetup -ScriptBlock { - $NCConfig = @{ } - - $ErrorActionPreference = "Stop" - $VerbosePreference = "Continue" - - # Set Credential Object - $domainCred = $args[0] - $SDNConfig = $args[1] - - # Set fqdn - $fqdn = $SDNConfig.SDNDomainFQDN - - if ($SDNConfig.ProvisionNC) { - # Set NC Configuration Data - $NCConfig.RestName = ("NC01.") + $SDNConfig.SDNDomainFQDN - $NCConfig.PASubnet = $SDNConfig.ProviderSubnet - $NCConfig.JoinDomain = $SDNConfig.SDNDomainFQDN - $NCConfig.ManagementGateway = ($SDNConfig.BGPRouterIP_MGMT).Split("/")[0] - $NCConfig.PublicVIPSubnet = $SDNConfig.PublicVIPSubnet - $NCConfig.PrivateVIPSubnet = $SDNConfig.PrivateVIPSubnet - $NCConfig.GRESubnet = $SDNConfig.GRESubnet - $NCConfig.LocalAdminDomainUser = ($SDNConfig.SDNDomainFQDN.Split(".")[0]) + "\administrator" - $NCConfig.DomainJoinUsername = ($SDNConfig.SDNDomainFQDN.Split(".")[0]) + "\administrator" - $NCConfig.NCUsername = ($SDNConfig.SDNDomainFQDN.Split(".")[0]) + "\administrator" - $NCConfig.SDNMacPoolStart = "00-1D-D8-B7-1C-09" - $NCConfig.SDNMacPoolEnd = "00:1D:D8:B7:1F:FF" - $NCConfig.PAGateway = ($SDNConfig.BGPRouterIP_ProviderNetwork.TrimEnd("1/24")) + "1" - $NCConfig.PAPoolStart = ($SDNConfig.BGPRouterIP_ProviderNetwork.TrimEnd("1/24")) + "5" - $NCConfig.PAPoolEnd = ($SDNConfig.BGPRouterIP_ProviderNetwork.TrimEnd("1/24")) + "254" - $NCConfig.Capacity = "10000" - $NCConfig.ScriptVersion = "2.0" - $NCConfig.SDNASN = $SDNConfig.SDNASN - $NCConfig.ManagementVLANID = $SDNConfig.mgmtVLAN - $NCConfig.PAVLANID = $SDNConfig.providerVLAN - $NCConfig.PoolName = "DefaultAll" - $NCConfig.VMLocation = "D:\SDNVMS" - $NCConfig.VHDFile = "AzSHCI.vhdx" - $NCConfig.VHDPath = "C:\VHDS" - $NCConfig.ManagementSubnet = $SDNConfig.MGMTSubnet - $NCConfig.ProductKey = $SDNConfig.COREProductKey - $NCConfig.HyperVHosts = @("AzSHOST1.$fqdn", "AzSHOST2.$fqdn") - $NCConfig.ManagementDNS = @( - ($SDNConfig.BGPRouterIP_MGMT.Split("/")[0].TrimEnd("1")) + "254" - ) - $NCConfig.Muxes = @( - @{ - ComputerName = 'Mux01' - HostName = "AzSHOST2.$($SDNConfig.SDNDomainFQDN)" - ManagementIP = ($SDNConfig.BGPRouterIP_MGMT.TrimEnd("1/24")) + "61" - MACAddress = '00-1D-D8-B7-1C-01' - PAIPAddress = ($SDNConfig.BGPRouterIP_ProviderNetwork.TrimEnd("1/24")) + "4" - PAMACAddress = '00-1D-D8-B7-1C-02' - } - ) - - $NCConfig.Gateways = @( - @{ - ComputerName = "GW01" - ManagementIP = ($SDNConfig.BGPRouterIP_MGMT.TrimEnd("1/24")) + "62" - HostName = "AzSHOST2.$($SDNConfig.SDNDomainFQDN)" - FrontEndIP = ($SDNConfig.BGPRouterIP_ProviderNetwork.TrimEnd("1/24")) + "5" - MACAddress = "00-1D-D8-B7-1C-03" - FrontEndMac = "00-1D-D8-B7-1C-04" - BackEndMac = "00-1D-D8-B7-1C-05" - }, - @{ - ComputerName = "GW02" - ManagementIP = ($SDNConfig.BGPRouterIP_MGMT.TrimEnd("1/24")) + "63" - HostName = "AzSHOST1.$($SDNConfig.SDNDomainFQDN)" - FrontEndIP = ($SDNConfig.BGPRouterIP_ProviderNetwork.TrimEnd("1/24")) + "6" - MACAddress = "00-1D-D8-B7-1C-06" - FrontEndMac = "00-1D-D8-B7-1C-07" - BackEndMac = "00-1D-D8-B7-1C-08" - } - ) - - $NCConfig.NCs = @{ - MACAddress = "00:1D:D8:B7:1C:00" - ComputerName = "NC01" - HostName = "AzSHOST2.$($SDNConfig.SDNDomainFQDN)" - ManagementIP = ($SDNConfig.BGPRouterIP_MGMT.TrimEnd("1/24")) + "60" - } - - $NCConfig.Routers = @( - @{ - RouterASN = $SDNConfig.BGPRouterASN - RouterIPAddress = ($SDNConfig.BGPRouterIP_ProviderNetwork).Split("/")[0] - } - ) - - # Start SDNExpress (Nested Version) Install - Set-Location -Path 'C:\SDN' - $params = @{ - ConfigurationData = $NCConfig - DomainJoinCredential = $domainCred - LocalAdminCredential = $domainCred - NCCredential = $domainCred - } - - .\SDNExpress.ps1 @params - } - - } -Authentication Credssp - } -} - -function Remove-AzSHCISandbox { - param ( - $VMPlacement, - $SDNConfig, - $SingleHostDelete - ) - - $VerbosePreference = "Continue" - - Write-Verbose "Deleting Azure Stack HCI Sandbox" - foreach ($vm in $VMPlacement) { - $AzSHOSTName = $vm.vmHost - $VMName = $vm.AzSHOST - - Invoke-Command -ComputerName $AzSHOSTName -ArgumentList $VMName -ScriptBlock { - - $VerbosePreference = "SilentlyContinue" - Import-Module Hyper-V - - $VerbosePreference = "Continue" - $vmname = $args[0] - # Delete SBXAccess vNIC (if present) - $vNIC = Get-VMNetworkAdapter -ManagementOS | Where-Object { $_.Name -match "SBXAccess" } - if ($vNIC) { $vNIC | Remove-VMNetworkAdapter -Confirm:$false } - - $sdnvm = Get-VM | Where-Object { $_.Name -eq $vmname } - - If (!$sdnvm) { Write-Verbose "Could not find $vmname to delete" } - - if ($sdnvm) { - - Write-Verbose "Shutting down VM: $sdnvm)" - - Stop-VM -VM $sdnvm -TurnOff -Force -Confirm:$false - $VHDs = $sdnvm | Select-Object VMId | Get-VHD - Remove-VM -VM $sdnvm -Force -Confirm:$false - - foreach ($VHD in $VHDs) { - Write-Verbose "Removing $($VHD.Path)" - Remove-Item -Path $VHD.Path -Force -Confirm:$false - } - } - } - } - - If ($SingleHostDelete -eq $true) { - $RemoveSwitch = Get-VMSwitch | Where-Object { $_.Name -match $SDNConfig.InternalSwitch } - If ($RemoveSwitch) { - Write-Verbose "Removing Internal Switch: $($SDNConfig.InternalSwitch)" - $RemoveSwitch | Remove-VMSwitch -Force -Confirm:$false - } - } - - Write-Verbose "Deleting RDP links" - Remove-Item C:\Users\Public\Desktop\AdminCenter.lnk -Force -ErrorAction SilentlyContinue - - Write-Verbose "Deleting NetNAT" - Get-NetNAT | Remove-NetNat -Confirm:$false - - Write-Verbose "Deleting Internal Switches" - Get-VMSwitch | Where-Object { $_.SwitchType -eq "Internal" } | Remove-VMSwitch -Force -Confirm:$false -} - -function Add-WACtenants { - param ( - $SDNLabSystems, - $SDNConfig, - $domainCred - ) - - $VerbosePreference = "Continue" - Write-Verbose "Invoking Command to add Windows Admin Center Tenants" - - Invoke-Command -ComputerName Admincenter -Credential $domainCred -ScriptBlock { - $domainCred = $using:domainCred - $SDNLabSystems = $using:SDNLabSystems - $SDNConfig = $using:SDNConfig - $VerbosePreference = "Continue" - - Invoke-Command -ComputerName admincenter -Credential $domainCred -ScriptBlock { - # Set Variables - $SDNConfig = Import-PowerShellDataFile -Path C:\SDN\HCIBox-Config.psd1 - $fqdn = $SDNConfig.SDNDomainFQDN - $SDNLabSystems = @("bgp-tor-router", "$($SDNConfig.DCName).$fqdn", "NC01.$fqdn", "MUX01.$fqdn", "GW01.$fqdn", "GW02.$fqdn") - $VerbosePreference = "Continue" - $domainCred = new-object -typename System.Management.Automation.PSCredential ` - -argumentlist (($SDNConfig.SDNDomainFQDN.Split(".")[0]) + "\administrator"), ` - (ConvertTo-SecureString $SDNConfig.SDNAdminPassword -AsPlainText -Force) - - # Set Constrained Delegation for NC/MUX/GW Virtual Machines for Windows Admin Center - $SDNvms = ("NC01", "MUX01", "GW01", "GW02") - - $VerbosePreference = "Continue" - foreach ($SDNvm in $SDNvms) { - Write-Verbose "Setting Delegation for $SDNvm" - $gateway = "AdminCenter" - Write-Verbose "gateway = $gateway" - $node = $SDNvm - Write-Verbose "node = $node" - $gatewayObject = Get-ADComputer -Identity $gateway -Credential $domainCred - Write-Verbose "GatewayObject = $gatewayObject" - $nodeObject = Get-ADComputer -Identity $node -Credential $domainCred - Write-Verbose "nodeObject = $nodeObject" - Set-ADComputer -Identity $nodeObject -PrincipalsAllowedToDelegateToAccount $gatewayObject -Credential $domainCred - } - - foreach ($SDNLabSystem in $SDNLabSystems) { - $json = [pscustomobject]@{ - id = "msft.sme.connection-type.server!$SDNLabSystem" - name = $SDNLabSystem - type = "msft.sme.connection-type.server" - } | ConvertTo-Json - - $payload = @" -[ -$json -] -"@ - - if ($SDNConfig.WACport -eq "443" -or !$SDNConfig.WACport) { - $uri = "https://admincenter.$($SDNConfig.SDNDomainFQDN)/api/connections" - } - else { - $uri = "https://admincenter.$($SDNConfig.SDNDomainFQDN):$($SDNConfig.WACport)/api/connections" - } - - Write-Verbose "Adding Host: $SDNLabSystem" - $param = @{ - Uri = $uri - Method = 'Put' - Body = $payload - ContentType = $content - Credential = $domainCred - } - - Invoke-RestMethod @param -UseBasicParsing -DisableKeepAlive | Out-Null - } - } - } -} - -function New-SDNS2DCluster { - param ( - $SDNConfig, - $domainCred, - $AzStackClusterNode - ) - - $VerbosePreference = "Continue" - Invoke-Command -ComputerName $AzStackClusterNode -ArgumentList $SDNConfig, $domainCred -Credential $domainCred -ScriptBlock { - - $SDNConfig = $args[0] - $domainCred = $args[1] - $VerbosePreference = "SilentlyContinue" - $ErrorActionPreference = "Stop" - - Register-PSSessionConfiguration -Name microsoft.SDNNestedS2D -RunAsCredential $domainCred -MaximumReceivedDataSizePerCommandMB 1000 -MaximumReceivedObjectSizeMB 1000 | Out-Null - - Invoke-Command -ComputerName $Using:AzStackClusterNode -ArgumentList $SDNConfig, $domainCred -Credential $domainCred -ConfigurationName microsoft.SDNNestedS2D -ScriptBlock { - - $SDNConfig = $args[0] - - # Create S2D Cluster - $SDNConfig = $args[0] - $AzSHOSTs = @("AzSHOST1", "AzSHOST2") - - Write-Verbose "Creating Cluster: hciboxcluster" - $VerbosePreference = "SilentlyContinue" - Import-Module FailoverClusters - Import-Module Storage - $VerbosePreference = "Continue" - - - # Create Cluster - $ClusterIP = ($SDNConfig.MGMTSubnet.TrimEnd("0/24")) + "252" - $ClusterName = "hciboxcluster" - - $VerbosePreference = "SilentlyContinue" - New-Cluster -Name $ClusterName -Node $AzSHOSTs -StaticAddress $ClusterIP -NoStorage -WarningAction SilentlyContinue | Out-Null - $VerbosePreference = "Continue" - - # Invoke Command to enable S2D on hciboxcluster - Enable-ClusterS2D -Confirm:$false -Verbose - - # Wait for Cluster Performance History Volume to be Created - while (!$PerfHistory) { - - Write-Verbose "Waiting for Cluster Performance History volume to come online." - Start-Sleep -Seconds 10 - $PerfHistory = Get-ClusterResource | Where-Object {$_.Name -match 'ClusterPerformanceHistory'} - if ($PerfHistory) {Write-Verbose "Cluster Perfomance History volume online." } - - } - - Write-Verbose "Setting Physical Disk Media Type" - - Get-PhysicalDisk | Where-Object { $_.Size -lt 127GB } | Set-PhysicalDisk -MediaType HDD | Out-Null - - $params = @{ - - FriendlyName = "S2D_vDISK1" - FileSystem = 'CSVFS_ReFS' - StoragePoolFriendlyName = 'S2D on hciboxcluster' - ResiliencySettingName = 'Mirror' - PhysicalDiskRedundancy = 1 - AllocationUnitSize = 64KB - - } - - Write-Verbose "Creating Physical Disk" - Start-Sleep -Seconds 60 - New-Volume @params -UseMaximumSize | Out-Null - - # Set Virtual Environment Optimizations - Write-Verbose "Setting Virtual Environment Optimizations" - - $VerbosePreference = "SilentlyContinue" - Get-storagesubsystem clus* | set-storagehealthsetting -name “System.Storage.PhysicalDisk.AutoReplace.Enabled” -value “False” - Set-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Services\spaceport\Parameters -Name HwTimeout -Value 0x00007530 - $VerbosePreference = "Continue" - - # Rename Storage Network Adapters - - Write-Verbose "Renaming Storage Network Adapters" - - (Get-Cluster -Name hciboxcluster | Get-ClusterNetwork | Where-Object { $_.Address -eq ($sdnconfig.storageAsubnet.Replace('/24', '')) }).Name = 'StorageA' - (Get-Cluster -Name hciboxcluster | Get-ClusterNetwork | Where-Object { $_.Address -eq ($sdnconfig.storageBsubnet.Replace('/24', '')) }).Name = 'StorageB' - (Get-Cluster -Name hciboxcluster | Get-ClusterNetwork | Where-Object { $_.Address -eq ($sdnconfig.MGMTSubnet.Replace('/24', '')) }).Name = 'Public' - - - # Set Allowed Networks for Live Migration - - Write-Verbose "Setting allowed networks for Live Migration" - - Get-ClusterResourceType -Name "Virtual Machine" -Cluster hciboxcluster | Set-ClusterParameter -Cluster hciboxcluster -Name MigrationExcludeNetworks ` - -Value ([String]::Join(";", (Get-ClusterNetwork -Cluster hciboxcluster | Where-Object { $_.Name -notmatch "Storage" }).ID)) - - } | Out-Null - - } -} - -function Test-InternetConnect { - $testIP = $SDNConfig.natDNS - $ErrorActionPreference = "Stop" - $intConnect = Test-NetConnection -ComputerName $testip -Port 53 - - if (!$intConnect.TcpTestSucceeded) { - throw "Unable to connect to DNS by pinging $SDNConfig.natDNS - Network access to this IP is required." - } -} - -function Set-HostNAT { - param ( - $SDNConfig - ) - - $VerbosePreference = "Continue" - $switchExist = Get-NetAdapter | Where-Object { $_.Name -match $SDNConfig.natHostVMSwitchName } - if (!$switchExist) { - Write-Verbose "Creating Internal NAT Switch: $($SDNConfig.natHostVMSwitchName)" - # Create Internal VM Switch for NAT - New-VMSwitch -Name $SDNConfig.natHostVMSwitchName -SwitchType Internal | Out-Null - - Write-Verbose "Applying IP Address to NAT Switch: $($SDNConfig.natHostVMSwitchName)" - # Apply IP Address to new Internal VM Switch - $intIdx = (Get-NetAdapter | Where-Object { $_.Name -match $SDNConfig.natHostVMSwitchName }).ifIndex - $natIP = $SDNConfig.natHostSubnet.Replace("0/24", "1") - New-NetIPAddress -IPAddress $natIP -PrefixLength 24 -InterfaceIndex $intIdx | Out-Null - - # Create NetNAT - Write-Verbose "Creating new NETNAT" - New-NetNat -Name $SDNConfig.natHostVMSwitchName -InternalIPInterfaceAddressPrefix $SDNConfig.natHostSubnet | Out-Null - } -} - -function enable-singleSignOn { - param ( - $SDNConfig - ) - - $domainCred = new-object -typename System.Management.Automation.PSCredential -argumentlist (($SDNConfig.SDNDomainFQDN.Split(".")[0]) + "\administrator"), (ConvertTo-SecureString $SDNConfig.SDNAdminPassword -AsPlainText -Force) - - Invoke-Command -ComputerName ("$($SDNConfig.DCName).$($SDNConfig.SDNDomainFQDN)") -ScriptBlock { - Get-ADComputer -Filter * | Set-ADComputer -PrincipalsAllowedToDelegateToAccount (Get-ADComputer AdminCenter) - } -Credential $domainCred -} - -#endregion - -#region Main - -Start-Transcript -Path $Env:HCIBoxLogsDir\New-HCIBoxCluster.log - -$starttime = Get-Date - -# Import Configuration Module -$SDNConfig = Import-PowerShellDataFile -Path $ConfigurationDataFile -Copy-Item $ConfigurationDataFile -Destination $Env:HCIBoxSDNDir -Force -$NestedVMMemoryinGB = $SDNConfig.NestedVMMemoryinGB -$guiVHDXPath = $SDNConfig.guiVHDXPath -$azSHCIVHDXPath = $SDNConfig.azSHCIVHDXPath -$HostVMPath = $SDNConfig.HostVMPath -$InternalSwitch = $SDNConfig.InternalSwitch -$natDNS = $SDNConfig.natDNS -$natSubnet = $SDNConfig.natSubnet -$natConfigure = $SDNConfig.natConfigure - -Import-Module Hyper-V - -$VerbosePreference = "Continue" -$ErrorActionPreference = "Stop" -$WarningPreference = "SilentlyContinue" -$ProgressPreference = 'SilentlyContinue' - -# Download HCIBox VHDs -Write-Verbose "Downloading HCIBox VHDs. This will take a while..." -BITSRequest -Params @{'Uri'='https://aka.ms/AAijhe3'; 'Filename'="$env:HCIBoxVHDDir\AZSHCI.vhdx" } -BITSRequest -Params @{'Uri'='https://aka.ms/AAij9n9'; 'Filename'="$env:HCIBoxVHDDir\GUI.vhdx"} -BITSRequest -Params @{'Uri'='https://partner-images.canonical.com/hyper-v/desktop/focal/current/ubuntu-focal-hyperv-amd64-ubuntu-desktop-hyperv.vhdx.zip'; 'Filename'="$env:HCIBoxVHDDir\Ubuntu.vhdx.zip"} -Expand-Archive -Path $env:HCIBoxVHDDir\Ubuntu.vhdx.zip -DestinationPath $env:HCIBoxVHDDir -Move-Item -Path $env:HCIBoxVHDDir\livecd.ubuntu-desktop-hyperv.vhdx -Destination $env:HCIBoxVHDDir\Ubuntu.vhdx - -# Set VM Host Memory -# $availablePhysicalMemory = (([math]::Round(((((Get-Counter -Counter '\Hyper-V Dynamic Memory Balancer(System Balancer)\Available Memory For Balancing' -ComputerName $env:COMPUTERNAME).CounterSamples.CookedValue) / 1024) - 18) / 2))) * 1073741824 -# $SDNConfig.NestedVMMemoryinGB = $availablePhysicalMemory - -# Set-Credentials -$localCred = new-object -typename System.Management.Automation.PSCredential -argumentlist "Administrator", (ConvertTo-SecureString $SDNConfig.SDNAdminPassword -AsPlainText -Force) - -$domainCred = new-object -typename System.Management.Automation.PSCredential ` - -argumentlist (($SDNConfig.SDNDomainFQDN.Split(".")[0]) + "\Administrator"), ` - (ConvertTo-SecureString $SDNConfig.SDNAdminPassword -AsPlainText -Force) - -$NCAdminCred = new-object -typename System.Management.Automation.PSCredential ` - -argumentlist (($SDNConfig.SDNDomainFQDN.Split(".")[0]) + "\NCAdmin"), ` - (ConvertTo-SecureString $SDNConfig.SDNAdminPassword -AsPlainText -Force) - -# Define HCIBox host Names. Please do not change names as these names are hardcoded in the setup. -$AzSHOSTs = @("AzSMGMT", "AzSHOST1", "AzSHOST2") - -# Delete configuration if specified -if ($Delete) { - Write-Verbose "Deleting cluster..." - $VMPlacement = Select-SingleHost -AzSHOSTs $AzSHOSTs - $SingleHostDelete = $true - Remove-AzSHCISandbox -SDNConfig $SDNConfig -VMPlacement $VMPlacement -SingleHostDelete $SingleHostDelete - - Write-Verbose "Successfully Removed the Azure Stack HCI Sandbox" - exit -} - -# Enable PSRemoting -Write-Verbose "Enabling PS Remoting on client..." -$VerbosePreference = "SilentlyContinue" -Enable-PSRemoting -Set-Item WSMan:\localhost\Client\TrustedHosts * -Confirm:$false -Force -$VerbosePreference = "Continue" - -# Verify Applications -Resolve-Applications -SDNConfig $SDNConfig - -# Verify Internet Connectivity -Test-InternetConnect - -# Set up installation parameters -Write-Verbose "Testing VHDX Path" -$params = @{ - guiVHDXPath = $guiVHDXPath - azSHCIVHDXPath = $azSHCIVHDXPath -} -Test-VHDPath @params - -Write-Verbose "Generating Single Host Placement" -$VMPlacement = Select-SingleHost -AzSHOSTs $AzSHOSTs - -Write-Verbose "Creating Internal Switch" -$params = @{ - pswitchname = $InternalSwitch - SDNConfig = $SDNConfig -} -New-InternalSwitch @params - -Write-Verbose "Creating NAT Switch" -Set-HostNAT -SDNConfig $SDNConfig - -$VMSwitch = $InternalSwitch - -Write-Verbose "Setting local Parent VHDX Path" -$params = @{ - guiVHDXPath = $guiVHDXPath - HostVMPath = $HostVMPath -} -$ParentVHDXPath = Get-GuiVHDXPath @params -Set-LocalHyperVSettings -HostVMPath $HostVMPath - -# Copy the parent VHDX file to the specified Parent VHDX Path -Write-Verbose "Copying VHDX Files to Host" -$params = @{ - azSHCIVHDXPath = $azSHCIVHDXPath - HostVMPath = $HostVMPath - guiVHDXPath = $guiVHDXPath -} -Copy-VHDXtoHost @params - -# Create Virtual Machines -$vmMacs = @() -foreach ($VM in $VMPlacement) { - Write-Verbose "Generating the VM: $VM" - $params = @{ - VMHost = $VM.VMHost - AzSHOST = $VM.AzSHOST - HostVMPath = $HostVMPath - VMSwitch = $VMSwitch - SDNConfig = $SDNConfig - } - $vmMac = New-NestedVM @params - - Write-Verbose "Returned VMMac is $vmMac" - $vmMacs += [pscustomobject]@{ - Hostname = $VM.AzSHOST - vmMAC = $vmMac - } -} - -# Inject Answer Files and Binaries into Virtual Machines -$params = @{ - VMPlacement = $VMPlacement - HostVMPath = $HostVMPath - SDNConfig = $SDNConfig - guiVHDXPath = $guiVHDXPath - azSHCIVHDXPath = $azSHCIVHDXPath - vmMacs = $vmMacs -} -Add-Files @params - -# Start Virtual Machines -Start-AzSHOSTS -VMPlacement $VMPlacement - -# Wait for AzSHOSTs to come online -Write-Verbose "Waiting for VMs to provision and then come online" -$params = @{ - VMPlacement = $VMPlacement - localcred = $localCred -} -Test-AzSHOSTVMConnection @params - -# Online and Format Data Volumes on Virtual Machines -$params = @{ - VMPlacement = $VMPlacement - SDNConfig = $SDNConfig -} -New-DataDrive @params - -# Install HCIBox Host Software on NestedVMs -$params = @{ - SDNConfig = $SDNConfig - VMPlacement = $VMPlacement - localcred = $localCred -} -Set-SDNserver @params - -# Rename NICs from Ethernet to FABRIC -$params = @{ - scriptpath = 'Get-Netadapter ((Get-NetAdapterAdvancedProperty | Where-Object {$_.DisplayValue -eq "SDN"}).Name) | Rename-NetAdapter -NewName FABRIC' - VMPlacement = $VMPlacement - localcred = $localCred -} - -Start-PowerShellScriptsOnHosts @params - -$params.scriptpath = 'Get-Netadapter ((Get-NetAdapterAdvancedProperty | Where-Object {$_.DisplayValue -eq "SDN2"}).Name) | Rename-NetAdapter -NewName FABRIC2' - -Start-PowerShellScriptsOnHosts @params - -# Restart Machines - -$params.scriptpath = "Restart-Computer -Force" -Start-PowerShellScriptsOnHosts @params -Start-Sleep -Seconds 30 - -# Wait for AzSHOSTs to come online - -Write-Verbose "Waiting for VMs to restart..." - -$params = @{ - - VMPlacement = $VMPlacement - localcred = $localCred - -} - -Test-AzSHOSTVMConnection @params - -# This step has to be done as during the Hyper-V install as hosts reboot twice. -Start-Sleep -Seconds 15 -Write-Verbose "Ensuring that all VMs have been restarted after Hyper-V install.." -Test-AzSHOSTVMConnection @params - -# Create NAT Virtual Switch on AzSMGMT - -if ($natConfigure) { - $SwitchName = $SDNConfig.InternalSwitch - - Write-Verbose "Creating NAT Switch on switch $SwitchName" - $VerbosePreference = "SilentlyContinue" - $params = @{ - SwitchName = $SwitchName - VMPlacement = $VMPlacement - SDNConfig = $SDNConfig - } - - New-NATSwitch @params - $VerbosePreference = "Continue" -} - -# Provision AzSMGMT VMs (DC, Router, and AdminCenter) -Write-Verbose "Configuring Management VM" -$params = @{ - SDNConfig = $SDNConfig - localCred = $localCred - domainCred = $domainCred -} -Set-AzSMGMT @params - -# Provision Hyper-V Logical Switches and Create S2D Cluster on Hosts -$params = @{ - localCred = $localCred - domainCred = $domainCred -} -New-HyperConvergedEnvironment @params -Start-Sleep -Seconds 30 - -# Create S2D Cluster -$params = @{ - SDNConfig = $SDNConfig - DomainCred = $domainCred - AzStackClusterNode = 'AzSHOST2' -} -New-SDNS2DCluster @params - -# Install and Configure Network Controller if specified -If ($SDNConfig.ProvisionNC) { - $params = @{ - SDNConfig = $SDNConfig - domainCred = $domainCred - } - New-SDNEnvironment @params - - # Add Systems to Windows Admin Center - $fqdn = $SDNConfig.SDNDomainFQDN - - $SDNLabSystems = @("bgp-tor-router", "$($SDNConfig.DCName).$fqdn", "NC01.$fqdn", "MUX01.$fqdn", "GW01.$fqdn", "GW02.$fqdn") - - # Add VMs for Domain Admin - - $params = @{ - - SDNLabSystems = $SDNLabSystems - SDNConfig = $SDNConfig - domainCred = $domainCred - - } - - # Add-WACtenants @params - - - # Add VMs for NC Admin - - $params.domainCred = $NCAdminCred - - # Add-WACtenants @params - - # Enable Single Sign On - - Write-Verbose "Enabling Single Sign On in WAC" - enable-singleSignOn -SDNConfig $SDNConfig - -} - - -# Finally - Add RDP Link to Desktop - -Remove-Item C:\Users\Public\Desktop\AdminCenter.lnk -Force -ErrorAction SilentlyContinue -$wshshell = New-Object -ComObject WScript.Shell -$lnk = $wshshell.CreateShortcut("C:\Users\Public\Desktop\AdminCenter.lnk") -$lnk.TargetPath = "%windir%\system32\mstsc.exe" -$lnk.Arguments = "/v:AdminCenter" -$lnk.Description = "AdminCenter link for HCIBox." -$lnk.Save() - -$endtime = Get-Date - -$timeSpan = New-TimeSpan -Start $starttime -End $endtime - -Write-Verbose "`nSuccessfully deployed HCIBox cluster." -Write-Verbose "Now working on enabling HCIBox features." -Write-Host "Infrastructure deployment time was $($timeSpan.Hours) hour and $($timeSpan.Minutes) minutes." -ForegroundColor Green - -$ErrorActionPreference = "Continue" -$VerbosePreference = "SilentlyContinue" -$WarningPreference = "Continue" - -Stop-Transcript - -#endregion \ No newline at end of file diff --git a/azure_jumpstart_hcibox/artifacts/Bootstrap.ps1 b/azure_jumpstart_hcibox/artifacts/PowerShell/Bootstrap.ps1 similarity index 58% rename from azure_jumpstart_hcibox/artifacts/Bootstrap.ps1 rename to azure_jumpstart_hcibox/artifacts/PowerShell/Bootstrap.ps1 index 8ee1993a5a..c4b5432a05 100644 --- a/azure_jumpstart_hcibox/artifacts/Bootstrap.ps1 +++ b/azure_jumpstart_hcibox/artifacts/PowerShell/Bootstrap.ps1 @@ -3,6 +3,7 @@ param ( [string]$adminPassword, [string]$spnClientId, [string]$spnClientSecret, + [string]$spnProviderId, [string]$spnTenantId, [string]$subscriptionId, [string]$resourceGroup, @@ -21,6 +22,7 @@ param ( [System.Environment]::SetEnvironmentVariable('spnClientID', $spnClientId,[System.EnvironmentVariableTarget]::Machine) [System.Environment]::SetEnvironmentVariable('spnClientSecret', $spnClientSecret,[System.EnvironmentVariableTarget]::Machine) [System.Environment]::SetEnvironmentVariable('spnTenantId', $spnTenantId,[System.EnvironmentVariableTarget]::Machine) +[System.Environment]::SetEnvironmentVariable('spnProviderId', $spnProviderId,[System.EnvironmentVariableTarget]::Machine) [System.Environment]::SetEnvironmentVariable('SPN_CLIENT_ID', $spnClientId,[System.EnvironmentVariableTarget]::Machine) [System.Environment]::SetEnvironmentVariable('SPN_CLIENT_SECRET', $spnClientSecret,[System.EnvironmentVariableTarget]::Machine) [System.Environment]::SetEnvironmentVariable('SPN_TENANT_ID', $spnTenantId,[System.EnvironmentVariableTarget]::Machine) @@ -35,53 +37,47 @@ param ( [System.Environment]::SetEnvironmentVariable('registerCluster', $registerCluster,[System.EnvironmentVariableTarget]::Machine) [System.Environment]::SetEnvironmentVariable('natDNS', $natDNS,[System.EnvironmentVariableTarget]::Machine) -# Creating HCIBox path -Write-Output "Creating HCIBox paths" -$Env:HCIBoxDir = "C:\HCIBox" -$Env:HCIBoxLogsDir = "C:\HCIBox\Logs" -$Env:HCIBoxVMDir = "C:\HCIBox\Virtual Machines" -$Env:HCIBoxIconDir = "C:\HCIBox\Icons" -$Env:HCIBoxVHDDir = "C:\HCIBox\VHD" -$Env:HCIBoxSDNDir = "C:\HCIBox\SDN" -$Env:HCIBoxKVDir = "C:\HCIBox\KeyVault" -$Env:HCIBoxWACDir = "C:\HCIBox\Windows Admin Center" -$Env:agentScript = "C:\HCIBox\agentScript" -$Env:ToolsDir = "C:\Tools" -$Env:tempDir = "C:\Temp" -$Env:VMPath = "C:\VMs" - -New-Item -Path $Env:HCIBoxDir -ItemType directory -Force -New-Item -Path $Env:HCIBoxVHDDir -ItemType directory -Force -New-Item -Path $Env:HCIBoxSDNDir -ItemType directory -Force -New-Item -Path $Env:HCIBoxLogsDir -ItemType directory -Force -New-Item -Path $Env:HCIBoxVMDir -ItemType directory -Force -New-Item -Path $Env:HCIBoxIconDir -ItemType directory -Force -New-Item -Path $Env:HCIBoxWACDir -ItemType directory -Force -New-Item -Path $Env:HCIBoxKVDir -ItemType directory -Force -New-Item -Path $Env:ToolsDir -ItemType Directory -Force -New-Item -Path $Env:tempDir -ItemType directory -Force -New-Item -Path $Env:agentScript -ItemType directory -Force - -Start-Transcript -Path $Env:HCIBoxLogsDir\Bootstrap.log - -$ErrorActionPreference = 'SilentlyContinue' - +####################################################################### +## Setup basic environment +####################################################################### # Copy PowerShell Profile and Reload -Invoke-WebRequest ($templateBaseUrl + "artifacts/PSProfile.ps1") -OutFile $PsHome\Profile.ps1 +Invoke-WebRequest ($templateBaseUrl + "artifacts/PowerShell/PSProfile.ps1") -OutFile $PsHome\Profile.ps1 .$PsHome\Profile.ps1 +# Creating HCIBox path +$HCIPath = "C:\HCIBox" +[System.Environment]::SetEnvironmentVariable('HCIBoxDir', $HCIPath,[System.EnvironmentVariableTarget]::Machine) +New-Item -Path $HCIPath -ItemType directory -Force + +# Downloading configuration file +$ConfigurationDataFile = "$HCIPath\HCIBox-Config.psd1" +[System.Environment]::SetEnvironmentVariable('HCIBoxConfigFile', $ConfigurationDataFile,[System.EnvironmentVariableTarget]::Machine) +Invoke-WebRequest ($templateBaseUrl + "artifacts/PowerShell/HCIBox-Config.psd1") -OutFile $ConfigurationDataFile + +# Importing configuration data +$HCIBoxConfig = Import-PowerShellDataFile -Path $ConfigurationDataFile + +# Create paths +foreach ($path in $HCIBoxConfig.Paths.GetEnumerator()) { + Write-Output "Creating path $($path.Value)" + New-Item -Path $path.Value -ItemType directory -Force | Out-Null +} + +# Begin transcript +Start-Transcript -Path "$($HCIBoxConfig.Paths["LogsDir"])\Bootstrap.log" + +################################################################################# +## Setup host infrastructure and apps +################################################################################# # Extending C:\ partition to the maximum size Write-Host "Extending C:\ partition to the maximum size" Resize-Partition -DriveLetter C -Size $(Get-PartitionSupportedSize -DriveLetter C).SizeMax # Installing Posh-SSH PowerShell Module -Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force -Install-Module -Name Posh-SSH -Force +# Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force # Installing tools Write-Header "Installing Chocolatey Apps" -$chocolateyAppList = 'az.powershell,kubernetes-cli,vcredist140,microsoft-edge,azcopy10,vscode,git,7zip,kubectx,terraform,putty.install,kubernetes-helm,dotnet-sdk,setdefaultbrowser,zoomit,azure-data-studio' - try { choco config get cacheLocation } @@ -90,11 +86,7 @@ catch { Invoke-Expression ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1')) } -Write-Host "Chocolatey Apps Specified" - -$appsToInstall = $chocolateyAppList -split "," | ForEach-Object { "$($_.Trim())" } - -foreach ($app in $appsToInstall) +foreach ($app in $HCIBoxConfig.ChocolateyPackagesList) { Write-Host "Installing $app" & choco install $app /y -Force | Write-Output @@ -106,40 +98,34 @@ Invoke-WebRequest -Uri https://aka.ms/installazurecliwindowsx64 -OutFile .\Azure Start-Process msiexec.exe -Wait -ArgumentList '/I AzureCLI.msi /quiet' Remove-Item .\AzureCLI.msi -Write-Header "Downloading Azure Stack HCI configuration scripts" -Invoke-WebRequest "https://raw.githubusercontent.com/Azure/arc_jumpstart_docs/main/img/wallpaper/hcibox_wallpaper_dark.png" -OutFile $Env:HCIBoxDir\wallpaper.png -Invoke-WebRequest https://aka.ms/wacdownload -OutFile $Env:HCIBoxWACDir\WindowsAdminCenter.msi -Invoke-WebRequest ($templateBaseUrl + "artifacts/HCIBoxLogonScript.ps1") -OutFile $Env:HCIBoxDir\HCIBoxLogonScript.ps1 -Invoke-WebRequest ($templateBaseUrl + "artifacts/New-HCIBoxCluster.ps1") -OutFile $Env:HCIBoxDir\New-HCIBoxCluster.ps1 -Invoke-WebRequest ($templateBaseUrl + "artifacts/Register-AzSHCI.ps1") -OutFile $Env:HCIBoxDir\Register-AzSHCI.ps1 -Invoke-WebRequest ($templateBaseUrl + "artifacts/HCIBox-Config.psd1") -OutFile $Env:HCIBoxDir\HCIBox-Config.psd1 -Invoke-WebRequest ($templateBaseUrl + "artifacts/Deploy-AKS.ps1") -OutFile $Env:HCIBoxDir\Deploy-AKS.ps1 -Invoke-WebRequest ($templateBaseUrl + "artifacts/Deploy-SQLMI.ps1") -OutFile $Env:HCIBoxDir\Deploy-SQLMI.ps1 -Invoke-WebRequest ($templateBaseUrl + "artifacts/Uninstall-AKS.ps1") -OutFile $Env:HCIBoxDir\Uninstall-AKS.ps1 -Invoke-WebRequest ($templateBaseUrl + "artifacts/Deploy-ArcResourceBridge.ps1") -OutFile $Env:HCIBoxDir\Deploy-ArcResourceBridge.ps1 -Invoke-WebRequest ($templateBaseUrl + "artifacts/Uninstall-ResourceBridge.ps1") -OutFile $Env:HCIBoxDir\Uninstall-ResourceBridge.ps1 -Invoke-WebRequest ($templateBaseUrl + "artifacts/Deploy-GitOps.ps1") -OutFile $Env:HCIBoxDir\Deploy-GitOps.ps1 -Invoke-WebRequest ($templateBaseUrl + "artifacts/SDN/CertHelpers.ps1") -OutFile $Env:HCIBoxSDNDir\CertHelpers.ps1 -Invoke-WebRequest ($templateBaseUrl + "artifacts/SDN/NetworkControllerRESTWrappers.ps1") -OutFile $Env:HCIBoxSDNDir\NetworkControllerRESTWrappers.ps1 -Invoke-WebRequest ($templateBaseUrl + "artifacts/SDN/NetworkControllerWorkloadHelpers.psm1") -OutFile $Env:HCIBoxSDNDir\NetworkControllerWorkloadHelpers.psm1 -Invoke-WebRequest ($templateBaseUrl + "artifacts/SDN/SDNExplorer.ps1") -OutFile $Env:HCIBoxSDNDir\SDNExplorer.ps1 -Invoke-WebRequest ($templateBaseUrl + "artifacts/SDN/SDNExpress.ps1") -OutFile $Env:HCIBoxSDNDir\SDNExpress.ps1 -Invoke-WebRequest ($templateBaseUrl + "artifacts/SDN/SDNExpressModule.psm1") -OutFile $Env:HCIBoxSDNDir\SDNExpressModule.psm1 -Invoke-WebRequest ($templateBaseUrl + "artifacts/SDN/SDNExpressUI.psm1") -OutFile $Env:HCIBoxSDNDir\SDNExpressUI.psm1 -Invoke-WebRequest ($templateBaseUrl + "artifacts/SDN/Single-NC.psd1") -OutFile $Env:HCIBoxSDNDir\Single-NC.psd1 -Invoke-WebRequest ($templateBaseUrl + "artifacts/LogInstructions.txt") -OutFile $Env:HCIBoxLogsDir\LogInstructions.txt -Invoke-WebRequest ($templateBaseUrl + "artifacts/GetServiceAccountBearerToken.ps1") -OutFile $Env:HCIBoxDir\GetServiceAccountBearerToken.ps1 -Invoke-WebRequest ($templateBaseUrl + "artifacts/jumpstart-user-secret.yaml") -OutFile $Env:HCIBoxDir\jumpstart-user-secret.yaml +Write-Host "Downloading Azure Stack HCI configuration scripts" +Invoke-WebRequest "https://raw.githubusercontent.com/microsoft/azure_arc/main/img/hcibox_wallpaper.png" -OutFile $HCIPath\wallpaper.png +Invoke-WebRequest https://aka.ms/wacdownload -OutFile "$($HCIBoxConfig.Paths["WACDir"])\WindowsAdminCenter.msi" +Invoke-WebRequest ($templateBaseUrl + "artifacts/PowerShell/HCIBoxLogonScript.ps1") -OutFile $HCIPath\HCIBoxLogonScript.ps1 +Invoke-WebRequest ($templateBaseUrl + "artifacts/PowerShell/New-HCIBoxCluster.ps1") -OutFile $HCIPath\New-HCIBoxCluster.ps1 +Invoke-WebRequest ($templateBaseUrl + "artifacts/PowerShell/Configure-AKS.ps1") -OutFile $HCIPath\Deploy-AKS.ps1 +Invoke-WebRequest ($templateBaseUrl + "artifacts/PowerShell/Deploy-SQLMI.ps1") -OutFile $HCIPath\Deploy-SQLMI.ps1 +Invoke-WebRequest ($templateBaseUrl + "artifacts/PowerShell/Configure-VMManagement.ps1") -OutFile $HCIPath\Deploy-ArcResourceBridge.ps1 +Invoke-WebRequest ($templateBaseUrl + "artifacts/PowerShell/Deploy-GitOps.ps1") -OutFile $HCIPath\Deploy-GitOps.ps1 +Invoke-WebRequest ($templateBaseUrl + "artifacts/PowerShell/Cloud-Cluster-Deploy.ps1") -OutFile $HCIPath\Cloud-Cluster-Deploy.ps1 +Invoke-WebRequest ($templateBaseUrl + "artifacts/PowerShell/GetServiceAccountBearerToken.ps1") -OutFile $HCIPath\GetServiceAccountBearerToken.ps1 +Invoke-WebRequest ($templateBaseUrl + "artifacts/LogInstructions.txt") -OutFile $HCIBoxConfig.Paths["LogsDir"]\LogInstructions.txt +Invoke-WebRequest ($templateBaseUrl + "artifacts/jumpstart-user-secret.yaml") -OutFile $HCIPath\jumpstart-user-secret.yaml +Invoke-WebRequest ($templateBaseUrl + "artifacts/hci.json") -OutFile $HCIPath\hci.json +Invoke-WebRequest ($templateBaseUrl + "artifacts/hci.parameters.json") -OutFile $HCIPath\hci.parameters.json # Replace password and DNS placeholder +Write-Host "Updating config placeholders with injected values." $adminPassword = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($adminPassword)) -(Get-Content -Path $Env:HCIBoxDir\HCIBox-Config.psd1) -replace '%staging-password%',$adminPassword | Set-Content -Path $Env:HCIBoxDir\HCIBox-Config.psd1 -(Get-Content -Path $Env:HCIBoxDir\HCIBox-Config.psd1) -replace '%staging-natDNS%',$natDNS | Set-Content -Path $Env:HCIBoxDir\HCIBox-Config.psd1 +(Get-Content -Path $HCIPath\HCIBox-Config.psd1) -replace '%staging-password%',$adminPassword | Set-Content -Path $HCIPath\HCIBox-Config.psd1 +(Get-Content -Path $HCIPath\HCIBox-Config.psd1) -replace '%staging-natDNS%',$natDNS | Set-Content -Path $HCIPath\HCIBox-Config.psd1 # Disabling Windows Server Manager Scheduled Task +Write-Host "Disabling Windows Server Manager scheduled task." Get-ScheduledTask -TaskName ServerManager | Disable-ScheduledTask # Disable Server Manager WAC prompt +Write-Host "Disabling Server Manager WAC prompt." $RegistryPath = "HKLM:\SOFTWARE\Microsoft\ServerManager" $Name = "DoNotPopWACConsoleAtSMLaunch" $Value = "1" @@ -149,21 +135,25 @@ if (-not (Test-Path $RegistryPath)) { New-ItemProperty -Path $RegistryPath -Name $Name -Value $Value -PropertyType DWORD -Force # Disable Network Profile prompt +Write-Host "Disabling network profile prompt." $RegistryPath = "HKLM:\System\CurrentControlSet\Control\Network\NewNetworkWindowOff" if (-not (Test-Path $RegistryPath)) { New-Item -Path $RegistryPath -Force | Out-Null } # Configuring CredSSP and WinRM +Write-Host "Enabling CredSSP." Enable-WSManCredSSP -Role Server -Force | Out-Null Enable-WSManCredSSP -Role Client -DelegateComputer $Env:COMPUTERNAME -Force | Out-Null # Creating scheduled task for HCIBoxLogonScript.ps1 +Write-Host "Creating scheduled task for HCIBoxLogonScript.ps1" $Trigger = New-ScheduledTaskTrigger -AtLogOn -$Action = New-ScheduledTaskAction -Execute "PowerShell.exe" -Argument $Env:HCIBoxDir\HCIBoxLogonScript.ps1 +$Action = New-ScheduledTaskAction -Execute "PowerShell.exe" -Argument $HCIPath\HCIBoxLogonScript.ps1 Register-ScheduledTask -TaskName "HCIBoxLogonScript" -Trigger $Trigger -User $adminUsername -Action $Action -RunLevel "Highest" -Force # Disable Edge 'First Run' Setup +Write-Host "Configuring Microsoft Edge." $edgePolicyRegistryPath = 'HKLM:SOFTWARE\Policies\Microsoft\Edge' $desktopSettingsRegistryPath = 'HKCU:SOFTWARE\Microsoft\Windows\Shell\Bags\1\Desktop' $firstRunRegistryName = 'HideFirstRunExperience' @@ -182,7 +172,7 @@ New-ItemProperty -Path $edgePolicyRegistryPath -Name $savePasswordRegistryName - Set-ItemProperty -Path $desktopSettingsRegistryPath -Name $autoArrangeRegistryName -Value $autoArrangeRegistryValue -Force # Change RDP Port -Write-Host "RDP port number from configuration is $rdpPort" +Write-Host "Updating RDP Port - RDP port number from configuration is $rdpPort" if (($rdpPort -ne $null) -and ($rdpPort -ne "") -and ($rdpPort -ne "3389")) { Write-Host "Configuring RDP port number to $rdpPort" @@ -215,13 +205,13 @@ if (($rdpPort -ne $null) -and ($rdpPort -ne "") -and ($rdpPort -ne "3389")) } # Install Hyper-V and reboot -Write-Header "Installing Hyper-V" +Write-Header "Installing Hyper-V." Enable-WindowsOptionalFeature -Online -FeatureName Containers -All -NoRestart Enable-WindowsOptionalFeature -Online -FeatureName VirtualMachinePlatform -NoRestart Install-WindowsFeature -Name Hyper-V -IncludeAllSubFeature -IncludeManagementTools -Restart # Clean up Bootstrap.log -Write-Header "Clean up Bootstrap.log" +Write-Header "Clean up Bootstrap.log." Stop-Transcript -$logSuppress = Get-Content $Env:HCIBoxLogsDir\Bootstrap.log | Where-Object { $_ -notmatch "Host Application: powershell.exe" } -$logSuppress | Set-Content $Env:HCIBoxLogsDir\Bootstrap.log -Force +$logSuppress = Get-Content $($HCIBoxConfig.Paths["LogsDir"])\Bootstrap.log | Where-Object { $_ -notmatch "Host Application: powershell.exe" } +$logSuppress | Set-Content $($HCIBoxConfig.Paths["LogsDir"])\Bootstrap.log -Force diff --git a/azure_jumpstart_hcibox/artifacts/PowerShell/Configure-AKS.ps1 b/azure_jumpstart_hcibox/artifacts/PowerShell/Configure-AKS.ps1 new file mode 100644 index 0000000000..ce3ded1ecb --- /dev/null +++ b/azure_jumpstart_hcibox/artifacts/PowerShell/Configure-AKS.ps1 @@ -0,0 +1,35 @@ +$WarningPreference = "SilentlyContinue" +$ErrorActionPreference = "Stop" +$ProgressPreference = 'SilentlyContinue' + +# Set paths +$Env:HCIBoxDir = "C:\HCIBox" + +# Import Configuration Module +$HCIBoxConfig = Import-PowerShellDataFile -Path $Env:HCIBoxConfigFile +Start-Transcript -Path "$($HCIBoxConfig.Paths.LogsDir)\Configure-AKS.log" + +# Generate credential objects +Write-Host 'Creating credentials and connecting to Azure' +$clientId = $env:spnClientId +$tenantId = $env:spnTenantId +$subId = $env:subscriptionId +$clustervnetname = "aksvnet1" +$azureAppCred = (New-Object System.Management.Automation.PSCredential $env:spnClientID, (ConvertTo-SecureString -String $env:spnClientSecret -AsPlainText -Force)) +Invoke-Command -ComputerName $HCIBoxConfig.NodeHostConfig[0].HostName -ArgumentList $HCIBoxConfig, $azureAppCred, $tenantId, $subId, $clustervnetname -Credential $domainCred -ScriptBlock { + $HCIBoxConfig = $args[0] + $azureAppCred = $args[1] + $tenantId = $args[2] + $subId = $args[3] + $clustervnetname = $args[4] + Connect-AzAccount -ServicePrincipal -Subscription $subId -Tenant $tenantId -Credential $azureAppCred + New-ArcHciVirtualNetwork -name $clustervnetname -vswitchname "ConvergedSwitch(hci)" -ipaddressprefix "192.168.200.0/24" -gateway $HCIBoxConfig.SDNLABRoute -dnsservers $HCIBoxConfig.SDNLABDNS -vippoolstart "192.168.200.100" -vippoolend "192.168.200.200" -k8snodeippoolstart "192.168.200.201" -k8snodeippoolend "192.168.200.249" -vlanID $vlanid +} + +az login --service-principal --username $env:spnClientID --password=$env:spnClientSecret --tenant $env:spnTenantId +$customLocationID=(az customlocation show --resource-group $env:resourceGroup --name "Jumpstart" --query id -o tsv) +az akshybrid vnet create -n $HCIBoxConfig.AKSvnetname -g $env:resourceGroup --custom-location $customlocationID --moc-vnet-name $clustervnetname +$vnetId=az hybridaks vnet show --name $HCIBoxConfig.AKSvnetname -g $env:resourceGroup --query id -o tsv +$aadgroupID="97d70ef2-db1e-413c-84f5-3159fbf34693" +az akshybrid create -n $HCIBoxConfig.AKSworkloadClusterName -g $env:resourceGroup --custom-location $customlocationID --vnet-ids $vnetId --aad-admin-group-object-ids $aadgroupID --generate-ssh-keys --load-balancer-count 1 +Stop-Transcript \ No newline at end of file diff --git a/azure_jumpstart_hcibox/artifacts/PowerShell/Configure-VMManagement.ps1 b/azure_jumpstart_hcibox/artifacts/PowerShell/Configure-VMManagement.ps1 new file mode 100644 index 0000000000..9d6ef23752 --- /dev/null +++ b/azure_jumpstart_hcibox/artifacts/PowerShell/Configure-VMManagement.ps1 @@ -0,0 +1,51 @@ +$WarningPreference = "SilentlyContinue" +$ErrorActionPreference = "Stop" +$ProgressPreference = 'SilentlyContinue' + +# Set paths +$Env:HCIBoxDir = "C:\HCIBox" + +# Import Configuration Module +$HCIBoxConfig = Import-PowerShellDataFile -Path $Env:HCIBoxConfigFile +Start-Transcript -Path "$($HCIBoxConfig.Paths.LogsDir)\Configure-VMManagement.log" + +#$csv_path = $HCIBoxConfig.ClusterSharedVolumePath + +# Generate credential objects +$user = "$($HCIBoxConfig.SDNDomainFQDN)\administrator" +$password = ConvertTo-SecureString -String $HCIBoxConfig.SDNAdminPassword -AsPlainText -Force +$adcred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $user, $password + +# Install AZ Resource Bridge and prerequisites +Write-Host "Now Preparing to configure guest VM management" + +$subId = $env:subscriptionId +$rg = $env:resourceGroup +$spnClientId = $env:spnClientId +$spnSecret = $env:spnClientSecret +$spnTenantId = $env:spnTenantId +$location = "eastus" +$cloudServiceIP = $HCIBoxConfig.AKSCloudSvcidr.Substring(0, $HCIBoxConfig.AKSCloudSvcidr.IndexOf('/')) +$customLocName="Jumpstart" + +# Copy gallery VHDs to hosts +# Invoke-Command -VMName $HCIBoxConfig.NodeHostConfig[0].Hostname -Credential $adcred -ScriptBlock { +# New-Item -Name "VHD" -Path $using:csv_path -ItemType Directory -Force +# Move-Item -Path "C:\VHD\GUI.vhdx" -Destination "$using:csv_path\VHD\GUI.vhdx" -Force +# Move-Item -Path "C:\VHD\Ubuntu.vhdx" -Destination "$using:csv_path\VHD\Ubuntu.vhdx" -Force +# } + +# Create VM images +az login --service-principal --username $env:spnClientID --password=$env:spnClientSecret --tenant $env:spnTenantId +$customLocationID=(az customlocation show --resource-group $env:resourceGroup --name $customLocName --query id -o tsv) +az stack-hci-vm image create --subscription $env:subscriptionId --resource-group $env:resourceGroup --custom-location $customLocationID --location $location --name "Windows Server 2022 Datacenter: Azure Edition Core - Gen2" --os-type "windows" --offer "windowsserver" --publisher "microsoftwindowsserver" --sku "2022-datacenter-azure-edition" --version "20348.2227.240104" # --storage-path-id $storagepathid + +# Create logical networks +$switchName='"ConvergedSwitch(hci)"' +$lnetName = "myhci-lnet-static" +$addressPrefixes = "192.168.200.0/24" +$gateway = "192.168.1.1" +$dnsServers = "192.168.1.254" +$vlanid = "200" + +az stack-hci-vm network lnet create --subscription $env:subscriptionId --resource-group $env:resourceGroup --custom-location $customLocationID --location $location --name $lnetName --vm-switch-name $switchName --ip-allocation-method "Static" --address-prefixes $addressPrefixes --gateway $gateway --dns-servers $dnsServers -vlanid $vlanid \ No newline at end of file diff --git a/azure_jumpstart_hcibox/artifacts/Deploy-GitOps.ps1 b/azure_jumpstart_hcibox/artifacts/PowerShell/Deploy-GitOps.ps1 similarity index 93% rename from azure_jumpstart_hcibox/artifacts/Deploy-GitOps.ps1 rename to azure_jumpstart_hcibox/artifacts/PowerShell/Deploy-GitOps.ps1 index 2a445a9f81..02e55e83e9 100644 --- a/azure_jumpstart_hcibox/artifacts/Deploy-GitOps.ps1 +++ b/azure_jumpstart_hcibox/artifacts/PowerShell/Deploy-GitOps.ps1 @@ -34,9 +34,9 @@ catch { # Import Configuration Module $ConfigurationDataFile = "$Env:HCIBoxDir\HCIBox-Config.psd1" -$SDNConfig = Import-PowerShellDataFile -Path $ConfigurationDataFile +$HCIBoxConfig = Import-PowerShellDataFile -Path $ConfigurationDataFile $user = "jumpstart.local\administrator" -$password = ConvertTo-SecureString -String $SDNConfig.SDNAdminPassword -AsPlainText -Force +$password = ConvertTo-SecureString -String $HCIBoxConfig.SDNAdminPassword -AsPlainText -Force $adcred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $user, $password $Env:AZURE_CONFIG_DIR = $cliDir.FullName @@ -53,7 +53,7 @@ Connect-AzAccount -Credential $psCred -TenantId $Env:spnTenantId -ServicePrincip # Setting kubeconfig $clusterName = az connectedk8s list --resource-group $Env:resourceGroup --query "[].{Name:name} | [? contains(Name,'hcibox')]" --output tsv -Invoke-Command -VMName $SDNConfig.HostList[0] -Credential $adcred -ScriptBlock { +Invoke-Command -VMName $HCIBoxConfig.HostList[0] -Credential $adcred -ScriptBlock { Get-AksHciCredential -name $using:clusterName -Confirm:$false kubectl get nodes foreach ($namespace in @('hello-arc')) { @@ -124,7 +124,7 @@ $cert = New-SelfSignedCertificate -DnsName $certdns -KeyAlgorithm RSA -KeyLength $certPassword = ConvertTo-SecureString -String "arcbox" -Force -AsPlainText Export-PfxCertificate -Cert "cert:\CurrentUser\My\$($cert.Thumbprint)" -FilePath "$Env:TempDir\$certname.pfx" -Password $certPassword Copy-VMFile AzSMGMT -SourcePath "$Env:TempDir\$certname.pfx" -DestinationPath "C:\VMConfigs\$certname.pfx" -FileSource Host -$localCred = new-object -typename System.Management.Automation.PSCredential -argumentlist "Administrator", (ConvertTo-SecureString $SDNConfig.SDNAdminPassword -AsPlainText -Force) +$localCred = new-object -typename System.Management.Automation.PSCredential -argumentlist "Administrator", (ConvertTo-SecureString $HCIBoxConfig.SDNAdminPassword -AsPlainText -Force) Invoke-Command -VMName AzSMGMT -Credential $localcred -ScriptBlock { Enable-VMIntegrationService -VMName AdminCenter -Name "Guest Service Interface" } @@ -166,10 +166,10 @@ Get-ChildItem -Path $Env:HCIBoxKVDir | Write-Header "Creating Ingress Controller" # Deploy Ingress resources for Bookstore and Hello-Arc App -Copy-VMFile $SDNConfig.HostList[0] -SourcePath "$Env:HCIBoxKVDir\hello-arc.yaml" -DestinationPath "C:\VHD\hello-arc.yaml" -FileSource Host +Copy-VMFile $HCIBoxConfig.HostList[0] -SourcePath "$Env:HCIBoxKVDir\hello-arc.yaml" -DestinationPath "C:\VHD\hello-arc.yaml" -FileSource Host $clientId = $env:spnClientID $clientSecret = $env:spnClientSecret -Invoke-Command -VMName $SDNConfig.HostList[0] -Credential $adcred -ScriptBlock { +Invoke-Command -VMName $HCIBoxConfig.HostList[0] -Credential $adcred -ScriptBlock { foreach ($namespace in @('hello-arc')) { # Create the Kubernetes secret with the service principal credentials kubectl create secret generic secrets-store-creds --namespace $namespace --from-literal clientid=$using:clientId --from-literal clientsecret=$using:clientSecret @@ -179,7 +179,7 @@ Invoke-Command -VMName $SDNConfig.HostList[0] -Credential $adcred -ScriptBlock kubectl --namespace $namespace apply -f "C:\VHD\hello-arc.yaml" } } -[string]$ip = Invoke-Command -VMName $SDNConfig.HostList[0] -Credential $adcred -ScriptBlock { +[string]$ip = Invoke-Command -VMName $HCIBoxConfig.HostList[0] -Credential $adcred -ScriptBlock { $ip = kubectl get service/ingress-nginx-controller --namespace $using:ingressNamespace --output=jsonpath='{.status.loadBalancer.ingress[0].ip}' return $ip } diff --git a/azure_jumpstart_hcibox/artifacts/Deploy-SQLMI.ps1 b/azure_jumpstart_hcibox/artifacts/PowerShell/Deploy-SQLMI.ps1 similarity index 93% rename from azure_jumpstart_hcibox/artifacts/Deploy-SQLMI.ps1 rename to azure_jumpstart_hcibox/artifacts/PowerShell/Deploy-SQLMI.ps1 index d8ad10bb86..95d8ec33c4 100644 --- a/azure_jumpstart_hcibox/artifacts/Deploy-SQLMI.ps1 +++ b/azure_jumpstart_hcibox/artifacts/PowerShell/Deploy-SQLMI.ps1 @@ -27,12 +27,12 @@ until ($customLocationObjectId -ne "" -and $customLocationObjectId.Length -eq 36 # Import Configuration Module and create Azure login credentials Write-Header 'Importing config' $ConfigurationDataFile = 'C:\HCIBox\HCIBox-Config.psd1' -$SDNConfig = Import-PowerShellDataFile -Path $ConfigurationDataFile +$HCIBoxConfig = Import-PowerShellDataFile -Path $ConfigurationDataFile # Generate credential objects Write-Header 'Creating credentials and connecting to Azure' $user = "jumpstart.local\administrator" -$password = ConvertTo-SecureString -String $SDNConfig.SDNAdminPassword -AsPlainText -Force +$password = ConvertTo-SecureString -String $HCIBoxConfig.SDNAdminPassword -AsPlainText -Force $adcred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $user, $password # Domain credential $azureAppCred = (New-Object System.Management.Automation.PSCredential $env:spnClientID, (ConvertTo-SecureString -String $env:spnClientSecret -AsPlainText -Force)) @@ -44,7 +44,7 @@ Register-AzResourceProvider -ProviderNamespace Microsoft.KubernetesConfiguration # Install latest versions of Nuget and PowershellGet Write-Header "Install latest versions of Nuget and PowershellGet" -Invoke-Command -VMName $SDNConfig.HostList -Credential $adcred -ScriptBlock { +Invoke-Command -VMName $HCIBoxConfig.HostList -Credential $adcred -ScriptBlock { Enable-PSRemoting -Force $ProgressPreference = "SilentlyContinue" Install-PackageProvider -Name NuGet -Force @@ -56,7 +56,7 @@ Invoke-Command -VMName $SDNConfig.HostList -Credential $adcred -ScriptBlock { # Install necessary AZ modules and initialize akshci on each node Write-Header "Install necessary AZ modules, AZ CLI extensions, plus AksHCI module and initialize akshci on each node" -Invoke-Command -VMName $SDNConfig.HostList -Credential $adcred -ScriptBlock { +Invoke-Command -VMName $HCIBoxConfig.HostList -Credential $adcred -ScriptBlock { Write-Host "Installing Required Modules" [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 $ProgressPreference = "SilentlyContinue" @@ -82,15 +82,15 @@ Invoke-WebRequest ("https://azuredatastudio-update.azurewebsites.net/latest/win3 Invoke-WebRequest "https://aka.ms/azdata-msi" -OutFile $Env:HCIBoxDir\AZDataCLI.msi Invoke-WebRequest "https://github.com/ErikEJ/SqlQueryStress/releases/download/102/SqlQueryStressNet6.zip" -OutFile $Env:HCIBoxDir\SqlQueryStress.zip -Copy-VMFile $SDNConfig.HostList[0] -SourcePath "$Env:HCIBoxDir\dataController.json" -DestinationPath "C:\VHD\dataController.json" -FileSource Host -Force -Copy-VMFile $SDNConfig.HostList[0] -SourcePath "$Env:HCIBoxDir\dataController.parameters.json" -DestinationPath "C:\VHD\dataController.parameters.json" -FileSource Host -Force -Copy-VMFile $SDNConfig.HostList[0] -SourcePath "$Env:HCIBoxDir\adConnector.json" -DestinationPath "C:\VHD\adConnector.json" -FileSource Host -Force -Copy-VMFile $SDNConfig.HostList[0] -SourcePath "$Env:HCIBoxDir\adConnector.parameters.json" -DestinationPath "C:\VHD\adConnector.parameters.json" -FileSource Host -Force -Copy-VMFile $SDNConfig.HostList[0] -SourcePath "$Env:HCIBoxDir\sqlmiAD.json" -DestinationPath "C:\VHD\sqlmiAD.json" -FileSource Host -Force -Copy-VMFile $SDNConfig.HostList[0] -SourcePath "$Env:HCIBoxDir\sqlmiAD.parameters.json" -DestinationPath "C:\VHD\sqlmiAD.parameters.json" -FileSource Host -Force -Copy-VMFile $SDNConfig.HostList[0] -SourcePath "$Env:HCIBoxDir\settingsTemplate.json" -DestinationPath "C:\VHD\settingsTemplate.json" -FileSource Host -Force -Copy-VMFile $SDNConfig.HostList[0] -SourcePath "$Env:HCIBoxDir\azuredatastudio.zip" -DestinationPath "C:\VHD\azuredatastudio.zip" -FileSource Host -Force -Copy-VMFile $SDNConfig.HostList[0] -SourcePath "$Env:HCIBoxDir\AZDataCLI.msi" -DestinationPath "C:\VHD\AZDataCLI.msi" -FileSource Host -Force +Copy-VMFile $HCIBoxConfig.HostList[0] -SourcePath "$Env:HCIBoxDir\dataController.json" -DestinationPath "C:\VHD\dataController.json" -FileSource Host -Force +Copy-VMFile $HCIBoxConfig.HostList[0] -SourcePath "$Env:HCIBoxDir\dataController.parameters.json" -DestinationPath "C:\VHD\dataController.parameters.json" -FileSource Host -Force +Copy-VMFile $HCIBoxConfig.HostList[0] -SourcePath "$Env:HCIBoxDir\adConnector.json" -DestinationPath "C:\VHD\adConnector.json" -FileSource Host -Force +Copy-VMFile $HCIBoxConfig.HostList[0] -SourcePath "$Env:HCIBoxDir\adConnector.parameters.json" -DestinationPath "C:\VHD\adConnector.parameters.json" -FileSource Host -Force +Copy-VMFile $HCIBoxConfig.HostList[0] -SourcePath "$Env:HCIBoxDir\sqlmiAD.json" -DestinationPath "C:\VHD\sqlmiAD.json" -FileSource Host -Force +Copy-VMFile $HCIBoxConfig.HostList[0] -SourcePath "$Env:HCIBoxDir\sqlmiAD.parameters.json" -DestinationPath "C:\VHD\sqlmiAD.parameters.json" -FileSource Host -Force +Copy-VMFile $HCIBoxConfig.HostList[0] -SourcePath "$Env:HCIBoxDir\settingsTemplate.json" -DestinationPath "C:\VHD\settingsTemplate.json" -FileSource Host -Force +Copy-VMFile $HCIBoxConfig.HostList[0] -SourcePath "$Env:HCIBoxDir\azuredatastudio.zip" -DestinationPath "C:\VHD\azuredatastudio.zip" -FileSource Host -Force +Copy-VMFile $HCIBoxConfig.HostList[0] -SourcePath "$Env:HCIBoxDir\AZDataCLI.msi" -DestinationPath "C:\VHD\AZDataCLI.msi" -FileSource Host -Force $adminCenterSession = New-PSSession -ComputerName "admincenter" -Credential $adcred Copy-Item $Env:HCIBoxDir\azuredatastudio.zip -Destination "C:\VHDs\azuredatastudio.zip" -ToSession $adminCenterSession -Force Copy-Item $Env:HCIBoxDir\SqlQueryStress.zip -Destination "C:\VHDs\SqlQueryStress.zip" -ToSession $adminCenterSession -Force @@ -113,7 +113,7 @@ $spnClientId = $env:spnClientId $spnSecret = $env:spnClientSecret $spnTenantId = $env:spnTenantId $adminUsername = $env:adminUsername -$adminPassword = $SDNConfig.SDNAdminPassword +$adminPassword = $HCIBoxConfig.SDNAdminPassword $workspaceName = $env:workspaceName $dataController = "jumpstart-dc-$namingPrefix" $sqlMI = "jumpstart-sql" @@ -123,7 +123,7 @@ $defaultDomainPartition = "DC=$domainName,DC=local" # Deploying the Arc Data Controller Write-Header "Deploying the Arc Data extension" -Invoke-Command -VMName $SDNConfig.HostList[0] -Credential $adcred -ScriptBlock { +Invoke-Command -VMName $HCIBoxConfig.HostList[0] -Credential $adcred -ScriptBlock { [System.Environment]::SetEnvironmentVariable('Path', $env:Path + ";C:\Program Files (x86)\Microsoft SDKs\Azure\CLI2\wbin", [System.EnvironmentVariableTarget]::Machine) $Env:Path = [System.Environment]::GetEnvironmentVariable("Path", "Machine") az config set extension.use_dynamic_install=yes_without_prompt --only-show-errors @@ -160,7 +160,7 @@ Invoke-Command -VMName $SDNConfig.HostList[0] -Credential $adcred -ScriptBlock { # Configuring Azure Arc Custom Location on the cluster Write-Header "Deploying the Azure Arc Data Controller and Custom Location" -Invoke-Command -VMName $SDNConfig.HostList[0] -Credential $adcred -ScriptBlock { +Invoke-Command -VMName $HCIBoxConfig.HostList[0] -Credential $adcred -ScriptBlock { Get-AksHciCredential -name $using:clusterName -Confirm:$false Write-Host "Creating the Azure Arc Custom Location" Write-Host "`n" @@ -209,7 +209,7 @@ Invoke-Command -VMName $SDNConfig.HostList[0] -Credential $adcred -ScriptBlock { # Preparing AD for SQL MI AD authenticaion Write-Header "Deploying the Azure Arc-enabled SQL Managed Instance" -Invoke-Command -VMName $SDNConfig.HostList[0] -Credential $adcred -ScriptBlock { +Invoke-Command -VMName $HCIBoxConfig.HostList[0] -Credential $adcred -ScriptBlock { $ErrorActionPreference = 'SilentlyContinue' $WarningPreference = 'SilentlyContinue' Add-WindowsFeature -Name "RSAT-AD-PowerShell" -IncludeAllSubFeature @@ -222,7 +222,7 @@ Invoke-Command -VMName $SDNConfig.HostList[0] -Credential $adcred -ScriptBlock { $adminUsername = $using:adminUsername $adminPassword = $using:adminPassword $dcIPv4 = ([System.Net.IPAddress]$dcInfo.IPv4Address).GetAddressBytes() - $dcIpv4Secondary = ([System.Net.IPAddress]$using:SDNConfig.dcVLAN200IP).GetAddressBytes() + $dcIpv4Secondary = ([System.Net.IPAddress]$using:HCIBoxConfig.dcVLAN200IP).GetAddressBytes() $reverseLookupCidr = [System.String]::Concat($dcIPv4[0], '.', $dcIPv4[1], '.', $dcIPv4[2], '.0/24') $reverseLookupSecondaryCidr = [System.String]::Concat($dcIpv4Secondary[0], '.', $dcIpv4Secondary[1], '.', $dcIpv4Secondary[2], '.0/24') @@ -502,7 +502,7 @@ Invoke-Command -ComputerName admincenter -Credential $adcred -ScriptBlock { } Write-Header "Configure ADS" -Invoke-Command -VMName $SDNConfig.HostList[0] -Credential $adcred -ScriptBlock { +Invoke-Command -VMName $HCIBoxConfig.HostList[0] -Credential $adcred -ScriptBlock { $WarningPreference = 'SilentlyContinue' $ErrorActionPreference = 'silentlycontinue' $adminUsername = $using:adminUsername diff --git a/azure_jumpstart_hcibox/artifacts/PowerShell/Generate-ARM-Template.ps1 b/azure_jumpstart_hcibox/artifacts/PowerShell/Generate-ARM-Template.ps1 new file mode 100644 index 0000000000..d18ced7028 --- /dev/null +++ b/azure_jumpstart_hcibox/artifacts/PowerShell/Generate-ARM-Template.ps1 @@ -0,0 +1,121 @@ +$WarningPreference = "SilentlyContinue" +$ErrorActionPreference = "Stop" +$ProgressPreference = 'SilentlyContinue' + +# Set paths +$Env:HCIBoxDir = "C:\HCIBox" + +# Import Configuration Module +$HCIBoxConfig = Import-PowerShellDataFile -Path $Env:HCIBoxConfigFile +Start-Transcript -Path "$($HCIBoxConfig.Paths.LogsDir)\Generate-ARM-Template.log" + +# Connect to Azure +Write-Host 'Creating credentials and connecting to Azure' +$azureAppCred = (New-Object System.Management.Automation.PSCredential $env:spnClientID, (ConvertTo-SecureString -String $env:spnClientSecret -AsPlainText -Force)) +Connect-AzAccount -ServicePrincipal -Subscription $env:subscriptionId -Tenant $env:spnTenantId -Credential $azureAppCred + +# Check that extensions are finished installing on HCI nodes +# foreach ($node in $HCIBoxConfig.NodeHostConfig) { + +# } + +# Install some modules +Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force +Install-Module -Name Az.Resources -Force +Install-Module Az.ConnectedMachine -Force +Import-Module -Name Az.Resources, Az.ConnectedMachine -Force + +# Add necessary role assignments +$ErrorActionPreference = "Continue" +New-AzRoleAssignment -ApplicationId $env:spnClientId -RoleDefinitionName "Key Vault Administrator" -ResourceGroup $env:resourceGroup -ErrorAction Continue +New-AzRoleAssignment -ObjectId $env:spnProviderId -RoleDefinitionName "Azure Connected Machine Resource Manager" -ResourceGroup $env:resourceGroup -ErrorAction Continue +$ErrorActionPreference = "Stop" + +$arcNodes = Get-AzConnectedMachine -ResourceGroup $env:resourceGroup +$arcNodeResourceIds = "[" +$count = 0 +foreach ($machine in $arcNodes) { + $ErrorActionPreference = "Continue" + New-AzRoleAssignment -ObjectId $machine.IdentityPrincipalId -RoleDefinitionName "Key Vault Secrets User" -ResourceGroup $env:resourceGroup + $ErrorActionPreference = "Stop" + if ($count -gt 0) { + $arcNodeResourceIds += ", " + } + $arcNodeResourceIds += """" + $machine.id + """" + $count = $count + 1 +} +$arcNodeResourceIds += "]" + +# Get storage account key and convert to base 64 +$saKeys = Get-AzStorageAccountKey -ResourceGroupName $env:resourceGroup -Name $env:stagingStorageAccountName +$storageAccountAccessKey = [Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($saKeys[0].value)) + +# Convert user credentials to base 64 +$AzureStackLCM=[Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes("$($HCIBoxConfig.LCMDeployUsername):$($HCIBoxConfig.SDNAdminPassword)")) +$LocalUser=[Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes("Administrator:$($HCIBoxConfig.SDNAdminPassword)")) +$AzureSPN=[Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes("$($env:spnClientId):$($env:spnClientSecret)")) + +# Construct OU path +$domainName = $HCIBoxConfig.SDNDomainFQDN.Split('.') +$ouPath = "OU=$($HCIBoxConfig.LCMADOUName)" +foreach ($name in $domainName) { + $ouPath += ",DC=$name" +} + +# Build DNS value +$dns = "[""" + $HCIBoxConfig.rbDNSIP + """]" + +# Create keyvault name +$guid = ([System.Guid]::NewGuid()).ToString().subString(0,5).ToLower() +$keyVaultName = "hcibox-kv-" + $guid +$secretsLocation = "https://$keyVaultName.vault.azure.net" + +# Set physical nodes +$physicalNodesSettings = "[ " +$storageAIPs = "[ " +$storageBIPs = "[ " +$count = 0 +foreach ($node in $HCIBoxConfig.NodeHostConfig) { + if ($count -gt 0) { + $physicalNodesSettings += ", " + $storageAIPs += ", " + $storageBIPs += ", " + } + $physicalNodesSettings += "{ ""name"": ""$($node.Hostname)"", ""ipv4Address"": ""$($node.IP.Split("/")[0])"" }" + # $storageAIPs += "{ ""PhysicalNode"": ""$($node.Hostname)"", ""IPv4Address"": ""$($node.StorageAIP)"", ""SubnetMask"": ""$($HCIBoxConfig.storageAsubnet)"" }" + # $storageBIPs += "{ ""PhysicalNode"": ""$($node.Hostname)"", ""IPv4Address"": ""$($node.StorageBIP)"", ""SubnetMask"": ""$($HCIBoxConfig.storageBsubnet)"" }" + $count = $count + 1 +} +$physicalNodesSettings += " ]" +$storageAIPs += " ]" +$storageBIPs += " ]" + +# Create diagnostics storage account name +$diagnosticsStorageName = "hciboxdiagsa$guid" + +# Replace placeholder values in ARM template with real values +$hciParams = "$env:HCIBoxDir\hci.parameters.json" +(Get-Content -Path $hciParams) -replace 'clusterName-staging', $HCIBoxConfig.ClusterName | Set-Content -Path $hciParams +(Get-Content -Path $hciParams) -replace 'arcNodeResourceIds-staging', $arcNodeResourceIds | Set-Content -Path $hciParams +(Get-Content -Path $hciParams) -replace 'localAdminSecretValue-staging', $LocalUser | Set-Content -Path $hciParams +(Get-Content -Path $hciParams) -replace 'domainAdminSecretValue-staging', $AzureStackLCM | Set-Content -Path $hciParams +(Get-Content -Path $hciParams) -replace 'arbDeploymentSpnValue-staging', $AzureSPN | Set-Content -Path $hciParams +(Get-Content -Path $hciParams) -replace 'storageWitnessValue-staging', $storageAccountAccessKey | Set-Content -Path $hciParams +(Get-Content -Path $hciParams) -replace 'domainFqdn-staging', $($HCIBoxConfig.SDNDomainFQDN) | Set-Content -Path $hciParams +(Get-Content -Path $hciParams) -replace 'namingPrefix-staging', $($HCIBoxConfig.LCMDeploymentPrefix) | Set-Content -Path $hciParams +(Get-Content -Path $hciParams) -replace 'adouPath-staging', $ouPath | Set-Content -Path $hciParams +(Get-Content -Path $hciParams) -replace 'subnetMask-staging', $($HCIBoxConfig.rbSubnetMask) | Set-Content -Path $hciParams +(Get-Content -Path $hciParams) -replace 'defaultGateway-staging', $HCIBoxConfig.SDNLabRoute | Set-Content -Path $hciParams +(Get-Content -Path $hciParams) -replace 'startingIp-staging', $HCIBoxConfig.clusterIpRangeStart | Set-Content -Path $hciParams +(Get-Content -Path $hciParams) -replace 'endingIp-staging', $HCIBoxConfig.clusterIpRangeEnd | Set-Content -Path $hciParams +(Get-Content -Path $hciParams) -replace 'dnsServers-staging', $dns | Set-Content -Path $hciParams +(Get-Content -Path $hciParams) -replace 'keyVaultName-staging', $keyVaultName | Set-Content -Path $hciParams +(Get-Content -Path $hciParams) -replace 'secretsLocation-staging', $secretsLocation | Set-Content -Path $hciParams +(Get-Content -Path $hciParams) -replace 'physicalNodesSettings-staging', $physicalNodesSettings | Set-Content -Path $hciParams +(Get-Content -Path $hciParams) -replace 'ClusterWitnessStorageAccountName-staging', $env:stagingStorageAccountName | Set-Content -Path $hciParams +(Get-Content -Path $hciParams) -replace 'diagnosticStorageAccountName-staging', $diagnosticsStorageName | Set-Content -Path $hciParams +#(Get-Content -Path $hciParams) -replace 'storageNetworkA-staging', $storageAIPs | Set-Content -Path $hciParams +#(Get-Content -Path $hciParams) -replace 'storageNetworkB-staging', $storageBIPs | Set-Content -Path $hciParams +(Get-Content -Path $hciParams) -replace 'storageNicAVLAN-staging', $HCIBoxConfig.StorageAVLAN | Set-Content -Path $hciParams +(Get-Content -Path $hciParams) -replace 'storageNicBVLAN-staging', $HCIBoxConfig.StorageBVLAN | Set-Content -Path $hciParams +(Get-Content -Path $hciParams) -replace 'customLocation-staging', $HCIBoxConfig.rbCustomLocationName | Set-Content -Path $hciParams \ No newline at end of file diff --git a/azure_jumpstart_hcibox/artifacts/GetServiceAccountBearerToken.ps1 b/azure_jumpstart_hcibox/artifacts/PowerShell/GetServiceAccountBearerToken.ps1 similarity index 78% rename from azure_jumpstart_hcibox/artifacts/GetServiceAccountBearerToken.ps1 rename to azure_jumpstart_hcibox/artifacts/PowerShell/GetServiceAccountBearerToken.ps1 index 370ad334f7..cf2ffe2d8b 100644 --- a/azure_jumpstart_hcibox/artifacts/GetServiceAccountBearerToken.ps1 +++ b/azure_jumpstart_hcibox/artifacts/PowerShell/GetServiceAccountBearerToken.ps1 @@ -16,15 +16,15 @@ $Env:VMPath = "C:\VMs" # Import Configuration Module and create Azure login credentials Write-Header 'Importing config' $ConfigurationDataFile = 'C:\HCIBox\HCIBox-Config.psd1' -$SDNConfig = Import-PowerShellDataFile -Path $ConfigurationDataFile +$HCIBoxConfig = Import-PowerShellDataFile -Path $ConfigurationDataFile # Generate credential objects $user = "jumpstart.local\administrator" -$password = ConvertTo-SecureString -String $SDNConfig.SDNAdminPassword -AsPlainText -Force +$password = ConvertTo-SecureString -String $HCIBoxConfig.SDNAdminPassword -AsPlainText -Force $adcred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $user, $password # Domain credential $clusterName = $env:AKSClusterName -Copy-VMFile -Name $SDNConfig.HostList[0] -SourcePath $env:HCIBoxDir\jumpstart-user-secret.yaml -DestinationPath C:\AksHci\jumpstart-user-secret.yaml -FileSource Host -Force -$TOKEN = Invoke-Command -VMName $SDNConfig.HostList[0] -Credential $adcred -ScriptBlock { +Copy-VMFile -Name $HCIBoxConfig.HostList[0] -SourcePath $env:HCIBoxDir\jumpstart-user-secret.yaml -DestinationPath C:\AksHci\jumpstart-user-secret.yaml -FileSource Host -Force +$TOKEN = Invoke-Command -VMName $HCIBoxConfig.HostList[0] -Credential $adcred -ScriptBlock { Get-AksHciCredential -name $using:clusterName -Confirm:$false kubectl create serviceaccount jumpstart-user kubectl create clusterrolebinding jumpstart-user-binding --clusterrole cluster-admin --serviceaccount default:jumpstart-user diff --git a/azure_jumpstart_hcibox/artifacts/HCIBox-Config.psd1 b/azure_jumpstart_hcibox/artifacts/PowerShell/HCIBox-Config.psd1 similarity index 66% rename from azure_jumpstart_hcibox/artifacts/HCIBox-Config.psd1 rename to azure_jumpstart_hcibox/artifacts/PowerShell/HCIBox-Config.psd1 index 3a20a3cabc..2333e1a0df 100644 --- a/azure_jumpstart_hcibox/artifacts/HCIBox-Config.psd1 +++ b/azure_jumpstart_hcibox/artifacts/PowerShell/HCIBox-Config.psd1 @@ -2,23 +2,93 @@ # This is the PowerShell datafile used to provide configuration information for the HCIBox environment. Product keys and password are not encrypted and will be available on all hosts during installation. - # Version 1.0.0 - - # HCI host names - HostList = "AZSHOST1", "AZSHOST2" # DO NOT CHANGE these as they remain hardcoded in places - - # VHDX Paths - guiVHDXPath = "C:\HCIBox\VHD\gui.vhdx" # This value controls the location of the GUI VHDX. - azsHCIVHDXPath = "C:\HCIBox\VHD\azshci.vhdx" # This value controls the location of the Azure Stack HCI VHDX. + # HCIBox Folders + Paths = @{ + VMDir = "C:\HCIBox\Virtual Machines" + LogsDir = "C:\HCIBox\Logs" + IconDir = "C:\HCIBox\Icons" + VHDDir = "C:\HCIBox\VHD" + SDNDir = "C:\HCIBox\SDN" + KVDir = "C:\HCIBox\KeyVault" + WACDir = "C:\HCIBox\Windows Admin Center" + AgentScriptDir = "C:\HCIBox\agentScript" + ToolsDir = "C:\Tools" + TempDir = "C:\Temp" + VMPath = "C:\VMs" + } + + ChocolateyPackagesList = @( + 'az.powershell', + 'kubernetes-cli', + 'vcredist140', + 'microsoft-edge', + 'azcopy10', + 'vscode', + 'git', + '7zip', + 'kubectx', + 'terraform', + 'putty.install', + 'kubernetes-helm', + 'dotnet-sdk', + 'setdefaultbrowser', + 'zoomit', + 'azure-data-studio' + ) + + # VSCode extensions + VSCodeExtensions = @( + 'ms-vscode-remote.remote-containers', + 'ms-vscode-remote.remote-wsl', + 'ms-vscode.powershell', + 'redhat.vscode-yaml', + 'ZainChen.json', + 'esbenp.prettier-vscode', + 'ms-kubernetes-tools.vscode-kubernetes-tools' + ) + + HostVMDriveLetter = "V" + HostVMPath = "V:\VMs" # This value controls the path where the Nested VMs will be stored on all hosts. + guiVHDXPath = "C:\HCIBox\VHD\gui.vhdx" # This value controls the location of the GUI VHDX. + azsHCIVHDXPath = "C:\HCIBox\VHD\azshci.vhdx" # This value controls the location of the Azure Stack HCI VHDX. \ + + MgmtHostConfig = @{ + Hostname = "AzSMGMT" + IP = "192.168.1.11/24" + } + + NodeHostConfig = @( + @{ + Hostname = "AzSHOST1" + IP = "192.168.1.12/24" + StorageAIP = "10.71.1.10" + StorageBIP = "10.71.2.10" + }, + @{ + Hostname = "AzSHOST2" + IP = "192.168.1.13/24" + StorageAIP = "10.71.1.11" + StorageBIP = "10.71.2.11" + } + ) # SDN Lab Admin Password SDNAdminPassword = '%staging-password%' # Do not change - this value is replaced during Bootstrap with the password supplied in the ARM deployment # VM Configuration - HostVMPath = "V:\VMs" # This value controls the path where the Nested VMs will be stored on all hosts. NestedVMMemoryinGB = 105GB # This value controls the amount of RAM for each Nested Hyper-V Host (AzSHOST1-2). AzSMGMTMemoryinGB = 28GB # This value controls the amount of RAM for the AzSMGMT Nested VM which contains only the Console, Router, Admincenter, and DC VMs. - InternalSwitch = "InternalSwitch" # Name of internal switch that the HCIBox VMs will use in Single Host mode. This only applies when using a single host. + AzSMGMTProcCount = 20 + InternalSwitch = "InternalSwitch" # Name of internal switch that the HCIBox VMs will use in Single Host mode. + FabricSwitch = "vSwitch-Fabric" + FabricNIC = "FABRIC" + ClusterVSwitchName = "hciSwitch" + ClusterName = "hciboxcluster3" + WACVMName = "AdminCenter" + ClusterSharedVolumePath = "C:\ClusterStorage\S2D_vDISK1" + LCMDeployUsername = "HCIBoxDeployUser" + LCMADOUName = "hcioudocs" + LCMDeploymentPrefix = "hcibox" # ProductKeys GUIProductKey = "WX4NM-KYWYW-QJJR4-XV3QB-6VM33" # Product key for Windows Server 2019 (Desktop Experience) Datacenter Installation @@ -48,20 +118,11 @@ # AzSMGMT Management VM's Memory Settings MEM_DC = 2GB # Memory provided for the Domain Controller VM MEM_BGP = 2GB # Memory provided for the BGP-ToR-Router - MEM_Console = 3GB # Memory provided for the Windows 10 Console VM MEM_WAC = 10GB # Memory provided for the Windows Admin Center VM - MEM_GRE = 2GB # Memory provided for the gre-target VM - MEM_IPSEC = 2GB # Memory provided for the ipsec-target VM # Cluster S2D Storage Disk Size (per disk) S2D_Disk_Size = 170GB # Disk size for each of the 4 dynamic VHD disks attached to the 3 AzSHOST VMs that will be used to create the SDNCLUSTER - # SDN Host IPs - AzSMGMTIP = "192.168.1.11/24" - AzSHOST1IP = "192.168.1.12/24" - AzSHOST2IP = "192.168.1.13/24" - AzSHOST3IP = "192.168.1.14/24" - # Physical Host Internal IP PhysicalHostInternalIP = "192.168.1.20" # IP Address assigned to Internal Switch vNIC in a Single Host Configuration @@ -73,10 +134,11 @@ # Management IPs for Console and Domain Controller DCIP = "192.168.1.254/24" - CONSOLEIP = "192.168.1.10/24" WACIP = "192.168.1.9/24" + WACMAC = "10155D010B00" - # BGP Router Config + # Router Config + BGPRouterName = "bgp-router" BGPRouterIP_MGMT = "192.168.1.1/24" BGPRouterIP_ProviderNetwork = "172.16.0.1/24" BGPRouterIP_VLAN200 = "192.168.200.1/24" @@ -88,27 +150,15 @@ vlan200VLAN = 200 mgmtVLAN = 0 simInternetVLAN = 131 - StorageAVLAN = 20 - StorageBVLAN = 21 + StorageAVLAN = 711 + StorageBVLAN = 712 # Subnets MGMTSubnet = "192.168.1.0/24" - GRESubnet = "50.50.50.0/24" - ProviderSubnet = "172.16.0.0/24" - VLAN200Subnet = "192.168.200.0/24" - VLAN200VMNetworkSubnet = "192.168.44.0/24" - simInternetSubnet = "131.127.0.0/24" - storageAsubnet = "192.168.98.0/24" - storageBsubnet = "192.168.99.0/24" - - # Gateway Target IPs - GRETARGETIP_BE = "192.168.233.100/24" - GRETARGETIP_FE = "131.127.0.35/24" - IPSECTARGETIP_BE = "192.168.111.100/24" - IPSECTARGETIP_FE = "131.127.0.30/24" + storageAsubnet = "255.255.255.0" + storageBsubnet = "255.255.255.0" # VIP Subnets - PrivateVIPSubnet = "30.30.30.0/24" PublicVIPSubnet = "40.40.40.0/24" # SDN ASN @@ -118,13 +168,9 @@ # Windows Admin Center HTTPS Port WACport = 443 - # SDDCInstall - SDDCInstall = $true - # AKS and Resource bridge variables AKSworkloadClusterName = "hcibox-aks" # lowercase only AKSvnetname = "akshcivnet" - AKSvSwitchName = "sdnSwitch" AKSNodeStartIP = "192.168.200.25" AKSNodeEndIP = "192.168.200.100" AKSVIPStartIP = "192.168.200.125" @@ -148,4 +194,8 @@ rbDHCPExclusionStart = "192.168.200.200" rbDHCPExclusionEnd = "192.168.200.209" dcVLAN200IP = "192.168.200.205" + rbSubnetMask = "255.255.255.0" + rbDNSIP = "192.168.1.254" + clusterIpRangeStart = "192.168.1.100" + clusterIpRangeEnd = "192.168.1.199" } \ No newline at end of file diff --git a/azure_jumpstart_hcibox/artifacts/HCIBoxLogonScript.ps1 b/azure_jumpstart_hcibox/artifacts/PowerShell/HCIBoxLogonScript.ps1 similarity index 62% rename from azure_jumpstart_hcibox/artifacts/HCIBoxLogonScript.ps1 rename to azure_jumpstart_hcibox/artifacts/PowerShell/HCIBoxLogonScript.ps1 index ec15338553..15c873821d 100644 --- a/azure_jumpstart_hcibox/artifacts/HCIBoxLogonScript.ps1 +++ b/azure_jumpstart_hcibox/artifacts/PowerShell/HCIBoxLogonScript.ps1 @@ -1,20 +1,19 @@ -# Set paths -$Env:HCIBoxDir = "C:\HCIBox" -$Env:HCIBoxLogsDir = "C:\HCIBox\Logs" -$Env:HCIBoxVMDir = "C:\HCIBox\Virtual Machines" -$Env:HCIBoxKVDir = "C:\HCIBox\KeyVault" -$Env:HCIBoxGitOpsDir = "C:\HCIBox\GitOps" -$Env:HCIBoxIconDir = "C:\HCIBox\Icons" -$Env:HCIBoxVHDDir = "C:\HCIBox\VHD" -$Env:HCIBoxSDNDir = "C:\HCIBox\SDN" -$Env:HCIBoxWACDir = "C:\HCIBox\Windows Admin Center" -$Env:agentScript = "C:\HCIBox\agentScript" -$Env:ToolsDir = "C:\Tools" -$Env:tempDir = "C:\Temp" -$Env:VMPath = "C:\VMs" - -Start-Transcript -Path $Env:HCIBoxLogsDir\HCIBoxLogonScript.log +# Script runtime environment: Level-0 Azure virtual machine ("Client VM") +$ProgressPreference = "SilentlyContinue" +Set-PSDebug -Strict +##################################################################### +# Initialize the environment +##################################################################### + +# Load config file +$HCIBoxConfig = Import-PowerShellDataFile -Path $Env:HCIBoxConfigFile + +Start-Transcript -Path "$($HCIBoxConfig.Paths.LogsDir)\HCIBoxLogonScript.log" + +##################################################################### +# Setup Azure CLI +##################################################################### $cliDir = New-Item -Path "$Env:ArcBoxDir\.cli\" -Name ".servers" -ItemType Directory if(-not $($cliDir.Parent.Attributes.HasFlag([System.IO.FileAttributes]::Hidden))) { @@ -24,25 +23,14 @@ if(-not $($cliDir.Parent.Attributes.HasFlag([System.IO.FileAttributes]::Hidden)) $Env:AZURE_CONFIG_DIR = $cliDir.FullName -# Configure storage pools and data disks -Write-Header "Configuring storage" -New-StoragePool -FriendlyName AsHciPool -StorageSubSystemFriendlyName '*storage*' -PhysicalDisks (Get-PhysicalDisk -CanPool $true) -$disks = Get-StoragePool -FriendlyName AsHciPool -IsPrimordial $False | Get-PhysicalDisk -$diskNum = $disks.Count -New-VirtualDisk -StoragePoolFriendlyName AsHciPool -FriendlyName AsHciDisk -ResiliencySettingName Simple -NumberOfColumns $diskNum -UseMaximumSize -$vDisk = Get-VirtualDisk -FriendlyName AsHciDisk -if ($vDisk | Get-Disk | Where-Object PartitionStyle -eq 'raw') { - $vDisk | Get-Disk | Initialize-Disk -Passthru | New-Partition -DriveLetter V -UseMaximumSize | Format-Volume -NewFileSystemLabel AsHciData -AllocationUnitSize 64KB -FileSystem NTFS -} -elseif ($vDisk | Get-Disk | Where-Object PartitionStyle -eq 'GPT') { - $vDisk | Get-Disk | New-Partition -DriveLetter V -UseMaximumSize | Format-Volume -NewFileSystemLabel AsHciData -AllocationUnitSize 64KB -FileSystem NTFS -} -New-Item -Path "V:\" -Name "VMs" -ItemType "directory" - -# Required for CLI commands +# Login to Azure CLI with service principal provided by user Write-Header "Az CLI Login" az login --service-principal --username $Env:spnClientID --password=$Env:spnClientSecret --tenant $Env:spnTenantId +##################################################################### +# Register Azure providers +##################################################################### + # Register Azure providers Write-Header "Registering Providers" az provider register --namespace Microsoft.HybridCompute --wait @@ -55,30 +43,42 @@ az provider register --namespace Microsoft.OperationsManagement --wait az provider register --namespace Microsoft.AzureStackHCI --wait az provider register --namespace Microsoft.ResourceConnector --wait -Stop-Transcript - -# Build HCI cluster -Write-Header "Deploying HCI cluster" -& "$Env:HCIBoxDir\New-HCIBoxCluster.ps1" +############################################################# +# Install VSCode extensions +############################################################# -# Register HCI cluster -if ($env:registerCluster -eq $true) { - Write-Header "Registering HCI cluster" - & "$Env:HCIBoxDir\Register-AzSHCI.ps1" +Write-Host "[$(Get-Date -Format t)] INFO: Installing VSCode extensions: " + ($HCIBoxConfig.VSCodeExtensions -join ', ') -ForegroundColor Gray +foreach ($extension in $HCIBoxConfig.VSCodeExtensions) { + $WarningPreference = "SilentlyContinue" + code --install-extension $extension 2>&1 | Out-File -Append -FilePath ($HCIBoxConfig.Paths.LogsDir + "\Tools.log") + $WarningPreference = "Continue" } -# deploy AKS -if (($env:registerCluster -eq $true) -and ($env:deployAKSHCI -eq $true)) { - Write-Header "Deploying AKS" - & "$Env:HCIBoxDir\Deploy-AKS.ps1" -} +##################################################################### +# Configure virtualization infrastructure +##################################################################### -# Deploy Arc Resource Bridge -if (($env:registerCluster -eq $true) -and ($env:deployResourceBridge -eq $true)) { - Write-Header "Deploying Arc Resource Bridge" - & "$Env:HCIBoxDir\Deploy-ArcResourceBridge.ps1" +# Configure storage pools and data disks +Write-Header "Configuring storage" +New-StoragePool -FriendlyName AsHciPool -StorageSubSystemFriendlyName '*storage*' -PhysicalDisks (Get-PhysicalDisk -CanPool $true) +$disks = Get-StoragePool -FriendlyName AsHciPool -IsPrimordial $False | Get-PhysicalDisk +$diskNum = $disks.Count +New-VirtualDisk -StoragePoolFriendlyName AsHciPool -FriendlyName AsHciDisk -ResiliencySettingName Simple -NumberOfColumns $diskNum -UseMaximumSize +$vDisk = Get-VirtualDisk -FriendlyName AsHciDisk +if ($vDisk | Get-Disk | Where-Object PartitionStyle -eq 'raw') { + $vDisk | Get-Disk | Initialize-Disk -Passthru | New-Partition -DriveLetter $HCIBoxConfig.HostVMDriveLetter -UseMaximumSize | Format-Volume -NewFileSystemLabel AsHciData -AllocationUnitSize 64KB -FileSystem NTFS +} +elseif ($vDisk | Get-Disk | Where-Object PartitionStyle -eq 'GPT') { + $vDisk | Get-Disk | New-Partition -DriveLetter $HCIBoxConfig.HostVMDriveLetter -UseMaximumSize | Format-Volume -NewFileSystemLabel AsHciData -AllocationUnitSize 64KB -FileSystem NTFS } +Stop-Transcript + +# Build HCI cluster +& "$Env:HCIBoxDir\New-HCIBoxCluster.ps1" + +& "$Env:HCIBoxDir\Generate-ARM-Template.ps1" + Start-Transcript -Append -Path $Env:HCIBoxLogsDir\HCIBoxLogonScript.log # Changing to Jumpstart ArcBox wallpaper diff --git a/azure_jumpstart_hcibox/artifacts/PowerShell/New-HCIBoxCluster.ps1 b/azure_jumpstart_hcibox/artifacts/PowerShell/New-HCIBoxCluster.ps1 new file mode 100644 index 0000000000..eb5ffa49ba --- /dev/null +++ b/azure_jumpstart_hcibox/artifacts/PowerShell/New-HCIBoxCluster.ps1 @@ -0,0 +1,1787 @@ +# Set paths +$Env:HCIBoxDir = "C:\HCIBox" +$Env:HCIBoxLogsDir = "C:\HCIBox\Logs" + +Start-Transcript -Path $Env:HCIBoxLogsDir\New-HCIBoxCluster.log +$starttime = Get-Date + +# Import Configuration data file +$HCIBoxConfig = Import-PowerShellDataFile -Path $Env:HCIBoxConfigFile + +#region functions +function BITSRequest { + param ( + [Parameter(Mandatory=$True)] + [hashtable]$Params + ) + $url = $Params['Uri'] + $filename = $Params['Filename'] + $download = Start-BitsTransfer -Source $url -Destination $filename -Asynchronous + $ProgressPreference = "Continue" + while ($download.JobState -ne "Transferred") { + if ($download.JobState -eq "TransientError"){ + Get-BitsTransfer $download.name | Resume-BitsTransfer -Asynchronous + } + [int] $dlProgress = ($download.BytesTransferred / $download.BytesTotal) * 100; + Write-Progress -Activity "Downloading File $filename..." -Status "$dlProgress% Complete:" -PercentComplete $dlProgress; + } + Complete-BitsTransfer $download.JobId + Write-Progress -Activity "Downloading File $filename..." -Status "Ready" -Completed + $ProgressPreference = "SilentlyContinue" +} + +function New-InternalSwitch { + param ( + $HCIBoxConfig + ) + $pswitchname = $HCIBoxConfig.InternalSwitch + $querySwitch = Get-VMSwitch -Name $pswitchname -ErrorAction Ignore + if (!$querySwitch) { + New-VMSwitch -SwitchType Internal -MinimumBandwidthMode None -Name $pswitchname | Out-Null + + #Assign IP to Internal Switch + $InternalAdapter = Get-Netadapter -Name "vEthernet ($pswitchname)" + $IP = $HCIBoxConfig.PhysicalHostInternalIP + $Prefix = ($($HCIBoxConfig.MgmtHostConfig.IP).Split("/"))[1] + $Gateway = $HCIBoxConfig.SDNLABRoute + $DNS = $HCIBoxConfig.SDNLABDNS + + $params = @{ + AddressFamily = "IPv4" + IPAddress = $IP + PrefixLength = $Prefix + DefaultGateway = $Gateway + } + + $InternalAdapter | New-NetIPAddress @params | Out-Null + $InternalAdapter | Set-DnsClientServerAddress -ServerAddresses $DNS | Out-Null + } + else { + Write-Host "Internal Switch $pswitchname already exists. Not creating a new internal switch." + } +} + +function Get-FormattedWACMAC { + Param( + $HCIBoxConfig + ) + return $HCIBoxConfig.WACMAC -replace '..(?!$)', '$&-' +} + +function GenerateAnswerFile { + Param( + [Parameter(Mandatory=$True)] $Hostname, + [Parameter(Mandatory=$False)] $IsMgmtVM = $false, + [Parameter(Mandatory=$False)] $IsRouterVM = $false, + [Parameter(Mandatory=$False)] $IsDCVM = $false, + [Parameter(Mandatory=$False)] $IsWACVM = $false, + [Parameter(Mandatory=$False)] $IPAddress = "", + [Parameter(Mandatory=$False)] $VMMac = "", + [Parameter(Mandatory=$True)] $HCIBoxConfig + ) + + $formattedMAC = Get-FormattedWACMAC -HCIBoxConfig $HCIBoxConfig + $wacAnswerXML = @" +<?xml version="1.0" encoding="utf-8"?> +<unattend xmlns="urn:schemas-microsoft-com:unattend"> +<settings pass="specialize"> +<component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> +<ProductKey>$($HCIBoxConfig.GUIProductKey)</ProductKey> +<ComputerName>$Hostname</ComputerName> +<RegisteredOwner>$ENV:adminUsername</RegisteredOwner> +</component> +<component name="Microsoft-Windows-TCPIP" processorArchitecture="wow64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> +<Interfaces> +<Interface wcm:action="add"> +<Ipv4Settings> +<DhcpEnabled>false</DhcpEnabled> +<Metric>20</Metric> +<RouterDiscoveryEnabled>true</RouterDiscoveryEnabled> +</Ipv4Settings> +<UnicastIpAddresses> +<IpAddress wcm:action="add" wcm:keyValue="1">$IPAddress</IpAddress> +</UnicastIpAddresses> +<Identifier>$formattedMAC</Identifier> +<Routes> +<Route wcm:action="add"> +<Identifier>1</Identifier> +<NextHopAddress>$($HCIBoxConfig.SDNLABRoute)</NextHopAddress> +</Route> +</Routes> +</Interface> +</Interfaces> +</component> +<component name="Microsoft-Windows-DNS-Client" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> +<Interfaces> +<Interface wcm:action="add"> +<DNSServerSearchOrder> +<IpAddress wcm:action="add" wcm:keyValue="1">$($HCIBoxConfig.SDNLABDNS)</IpAddress> +</DNSServerSearchOrder> +<Identifier>$formattedMAC</Identifier> +<DNSDomain>$($HCIBoxConfig.SDNDomainFQDN)</DNSDomain> +<EnableAdapterDomainNameRegistration>true</EnableAdapterDomainNameRegistration> +</Interface> +</Interfaces> +</component> +<component name="Networking-MPSSVC-Svc" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> +<DomainProfile_EnableFirewall>false</DomainProfile_EnableFirewall> +<PrivateProfile_EnableFirewall>false</PrivateProfile_EnableFirewall> +<PublicProfile_EnableFirewall>false</PublicProfile_EnableFirewall> +</component> +<component name="Microsoft-Windows-TerminalServices-LocalSessionManager" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> +<fDenyTSConnections>false</fDenyTSConnections> +</component> +<component name="Microsoft-Windows-UnattendedJoin" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> +<Identification> +<Credentials> +<Domain>$($HCIBoxConfig.SDNDomainFQDN)</Domain> +<Password>$($HCIBoxConfig.SDNAdminPassword)</Password> +<Username>Administrator</Username> +</Credentials> +<JoinDomain>$($HCIBoxConfig.SDNDomainFQDN)</JoinDomain> +</Identification> +</component> +<component name="Microsoft-Windows-IE-ESC" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> +<IEHardenAdmin>false</IEHardenAdmin> +<IEHardenUser>false</IEHardenUser> +</component> +</settings> +<settings pass="oobeSystem"> +<component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> +<UserAccounts> +<AdministratorPassword> +<Value>$($HCIBoxConfig.SDNAdminPassword)</Value> +<PlainText>true</PlainText> +</AdministratorPassword> +</UserAccounts> +<TimeZone>UTC</TimeZone> +<OOBE> +<HideEULAPage>true</HideEULAPage> +<SkipUserOOBE>true</SkipUserOOBE> +<HideOEMRegistrationScreen>true</HideOEMRegistrationScreen> +<HideOnlineAccountScreens>true</HideOnlineAccountScreens> +<HideWirelessSetupInOOBE>true</HideWirelessSetupInOOBE> +<NetworkLocation>Work</NetworkLocation> +<ProtectYourPC>1</ProtectYourPC> +<HideLocalAccountScreen>true</HideLocalAccountScreen> +</OOBE> +</component> +<component name="Microsoft-Windows-International-Core" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> +<UserLocale>en-US</UserLocale> +<SystemLocale>en-US</SystemLocale> +<InputLocale>0409:00000409</InputLocale> +<UILanguage>en-US</UILanguage> +</component> +</settings> +<cpi:offlineImage cpi:source="" xmlns:cpi="urn:schemas-microsoft-com:cpi" /> +</unattend> +"@ + + $components = @" +<component name="Microsoft-Windows-IE-ESC" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> +<IEHardenAdmin>false</IEHardenAdmin> +<IEHardenUser>false</IEHardenUser> +</component> +<component name="Microsoft-Windows-TCPIP" processorArchitecture="wow64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> +<Interfaces> +<Interface wcm:action="add"> +<Identifier>$VMMac</Identifier> +<Ipv4Settings> +<DhcpEnabled>false</DhcpEnabled> +</Ipv4Settings> +<UnicastIpAddresses> +<IpAddress wcm:action="add" wcm:keyValue="1">$IPAddress</IpAddress> +</UnicastIpAddresses> +<Routes> +<Route wcm:action="add"> +<Identifier>1</Identifier> +<NextHopAddress>$($HCIBoxConfig.SDNLABRoute)</NextHopAddress> +<Prefix>0.0.0.0/0</Prefix> +<Metric>100</Metric> +</Route> +</Routes> +</Interface> +</Interfaces> +</component> +<component name="Microsoft-Windows-DNS-Client" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> +<DNSSuffixSearchOrder> +<DomainName wcm:action="add" wcm:keyValue="1">$($HCIBoxConfig.SDNDomainFQDN)</DomainName> +</DNSSuffixSearchOrder> +<Interfaces> +<Interface wcm:action="add"> +<DNSServerSearchOrder> +<IpAddress wcm:action="add" wcm:keyValue="1">$($HCIBoxConfig.SDNLABDNS)</IpAddress> +</DNSServerSearchOrder> +<Identifier>$VMMac</Identifier> +<DisableDynamicUpdate>false</DisableDynamicUpdate> +<DNSDomain>$($HCIBoxConfig.SDNDomainFQDN)</DNSDomain> +<EnableAdapterDomainNameRegistration>true</EnableAdapterDomainNameRegistration> +</Interface> +</Interfaces> +</component> +"@ + + $azsmgmtProdKey = "" + if ($IsMgmtVM) { + $azsmgmtProdKey = "<ProductKey>$($HCIBoxConfig.GUIProductKey)</ProductKey>" + } + $vmServicing = "" + + if ($IsRouterVM -or $IsDCVM) { + $components = "" + $optionXML = "" + if ($IsRouterVM) { + $optionXML = @" +<selection name="RemoteAccessServer" state="true" /> +<selection name="RasRoutingProtocols" state="true" /> +"@ + } + if ($IsDCVM) { + $optionXML = @" +<selection name="ADCertificateServicesRole" state="true" /> +<selection name="CertificateServices" state="true" /> +"@ + } + $vmServicing = @" +<servicing> +<package action="configure"> +<assemblyIdentity name="Microsoft-Windows-Foundation-Package" version="10.0.14393.0" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="" /> +$optionXML</package> +</servicing> +"@ + } + + $UnattendXML = @" +<?xml version="1.0" encoding="utf-8"?> +<unattend xmlns="urn:schemas-microsoft-com:unattend"> +$vmServicing<settings pass="specialize"> +<component name="Networking-MPSSVC-Svc" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> +<DomainProfile_EnableFirewall>false</DomainProfile_EnableFirewall> +<PrivateProfile_EnableFirewall>false</PrivateProfile_EnableFirewall> +<PublicProfile_EnableFirewall>false</PublicProfile_EnableFirewall> +</component> +<component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> +<ComputerName>$Hostname</ComputerName> +$azsmgmtProdKey</component> +<component name="Microsoft-Windows-TerminalServices-LocalSessionManager" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> +<fDenyTSConnections>false</fDenyTSConnections> +</component> +<component name="Microsoft-Windows-International-Core" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> +<UserLocale>en-us</UserLocale> +<UILanguage>en-us</UILanguage> +<SystemLocale>en-us</SystemLocale> +<InputLocale>en-us</InputLocale> +</component> +$components</settings> +<settings pass="oobeSystem"> +<component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> +<OOBE> +<HideEULAPage>true</HideEULAPage> +<SkipMachineOOBE>true</SkipMachineOOBE> +<SkipUserOOBE>true</SkipUserOOBE> +<HideOEMRegistrationScreen>true</HideOEMRegistrationScreen> +</OOBE> +<UserAccounts> +<AdministratorPassword> +<Value>$($HCIBoxConfig.SDNAdminPassword)</Value> +<PlainText>true</PlainText> +</AdministratorPassword> +</UserAccounts> +</component> +</settings> +<cpi:offlineImage cpi:source="" xmlns:cpi="urn:schemas-microsoft-com:cpi" /> +</unattend> +"@ + if ($IsWACVM) { + $UnattendXML = $wacAnswerXML + } + return $UnattendXML +} + +function Restart-VMs { + Param ( + $HCIBoxConfig, + [PSCredential]$Credential + ) + foreach ($VM in $HCIBoxConfig.NodeHostConfig) { + Write-Host "Restarting VM: $($VM.Hostname)" + Invoke-Command -VMName $VM.Hostname -Credential $Credential -ScriptBlock { + Restart-Computer -Force + } + } + Write-Host "Restarting VM: $($HCIBoxConfig.MgmtHostConfig.Hostname)" + Invoke-Command -VMName $HCIBoxConfig.MgmtHostConfig.Hostname -Credential $Credential -ScriptBlock { + Restart-Computer -Force + } + Start-Sleep -Seconds 30 +} + +function New-ManagementVM { + Param ( + $Name, + $VHDXPath, + $VMSwitch, + $HCIBoxConfig + ) + Write-Host "Creating VM $Name" + # Create disks + $VHDX1 = New-VHD -ParentPath $VHDXPath -Path "$($HCIBoxConfig.HostVMPath)\$Name.vhdx" -Differencing + $VHDX2 = New-VHD -Path "$($HCIBoxConfig.HostVMPath)\$Name-Data.vhdx" -SizeBytes 268435456000 -Dynamic + + # Create VM + # Create Nested VM + New-VM -Name $Name -MemoryStartupBytes $HCIBoxConfig.AzSMGMTMemoryinGB -VHDPath $VHDX1.Path -SwitchName $VMSwitch -Generation 2 | Out-Null + Add-VMHardDiskDrive -VMName $Name -Path $VHDX2.Path + Set-VM -Name $Name -ProcessorCount $HCIBoxConfig.AzSMGMTProcCount -AutomaticStartAction Start | Out-Null + + Get-VMNetworkAdapter -VMName $Name | Rename-VMNetworkAdapter -NewName "SDN" + Get-VMNetworkAdapter -VMName $Name | Set-VMNetworkAdapter -DeviceNaming On -StaticMacAddress ("{0:D12}" -f ( Get-Random -Minimum 0 -Maximum 99999 )) + Add-VMNetworkAdapter -VMName $Name -Name SDN2 -DeviceNaming On -SwitchName $VMSwitch + $vmMac = (((Get-VMNetworkAdapter -Name SDN -VMName $Name).MacAddress) -replace '..(?!$)', '$&-') + + Get-VM $Name | Set-VMProcessor -ExposeVirtualizationExtensions $true + Get-VM $Name | Set-VMMemory -DynamicMemoryEnabled $false + Get-VM $Name | Get-VMNetworkAdapter | Set-VMNetworkAdapter -MacAddressSpoofing On + + Set-VMNetworkAdapterVlan -VMName $Name -VMNetworkAdapterName SDN -Trunk -NativeVlanId 0 -AllowedVlanIdList 1-200 + Set-VMNetworkAdapterVlan -VMName $Name -VMNetworkAdapterName SDN2 -Trunk -NativeVlanId 0 -AllowedVlanIdList 1-200 + + Enable-VMIntegrationService -VMName $Name -Name "Guest Service Interface" + return $vmMac +} + +function New-HCINodeVM { + param ( + $Name, + $VHDXPath, + $VMSwitch, + $HCIBoxConfig + ) + Write-Host "Creating VM $Name" + # Create disks + $VHDX1 = New-VHD -ParentPath $VHDXPath -Path "$($HCIBoxConfig.HostVMPath)\$Name.vhdx" -Differencing + $VHDX2 = New-VHD -Path "$($HCIBoxConfig.HostVMPath)\$Name-Data.vhdx" -SizeBytes 268435456000 -Dynamic + + # Create S2D Storage + New-VHD -Path "$HostVMPath\$Name-S2D_Disk1.vhdx" -SizeBytes $HCIBoxConfig.S2D_Disk_Size -Dynamic | Out-Null + New-VHD -Path "$HostVMPath\$Name-S2D_Disk2.vhdx" -SizeBytes $HCIBoxConfig.S2D_Disk_Size -Dynamic | Out-Null + New-VHD -Path "$HostVMPath\$Name-S2D_Disk3.vhdx" -SizeBytes $HCIBoxConfig.S2D_Disk_Size -Dynamic | Out-Null + New-VHD -Path "$HostVMPath\$Name-S2D_Disk4.vhdx" -SizeBytes $HCIBoxConfig.S2D_Disk_Size -Dynamic | Out-Null + New-VHD -Path "$HostVMPath\$Name-S2D_Disk5.vhdx" -SizeBytes $HCIBoxConfig.S2D_Disk_Size -Dynamic | Out-Null + New-VHD -Path "$HostVMPath\$Name-S2D_Disk6.vhdx" -SizeBytes $HCIBoxConfig.S2D_Disk_Size -Dynamic | Out-Null + + # Create Nested VM + New-VM -Name $Name -MemoryStartupBytes $HCIBoxConfig.NestedVMMemoryinGB -VHDPath $VHDX1.Path -SwitchName $VMSwitch -Generation 2 | Out-Null + Add-VMHardDiskDrive -VMName $Name -Path $VHDX2.Path + Add-VMHardDiskDrive -Path "$HostVMPath\$Name-S2D_Disk1.vhdx" -VMName $Name | Out-Null + Add-VMHardDiskDrive -Path "$HostVMPath\$Name-S2D_Disk2.vhdx" -VMName $Name | Out-Null + Add-VMHardDiskDrive -Path "$HostVMPath\$Name-S2D_Disk3.vhdx" -VMName $Name | Out-Null + Add-VMHardDiskDrive -Path "$HostVMPath\$Name-S2D_Disk4.vhdx" -VMName $Name | Out-Null + Add-VMHardDiskDrive -Path "$HostVMPath\$Name-S2D_Disk5.vhdx" -VMName $Name | Out-Null + Add-VMHardDiskDrive -Path "$HostVMPath\$Name-S2D_Disk6.vhdx" -VMName $Name | Out-Null + + Set-VM -Name $Name -ProcessorCount 20 -AutomaticStartAction Start + Get-VMNetworkAdapter -VMName $Name | Rename-VMNetworkAdapter -NewName "SDN" + Get-VMNetworkAdapter -VMName $Name | Set-VMNetworkAdapter -DeviceNaming On -StaticMacAddress ("{0:D12}" -f ( Get-Random -Minimum 0 -Maximum 99999 )) + # Add-VMNetworkAdapter -VMName $Name -Name SDN2 -DeviceNaming On -SwitchName $VMSwitch + $vmMac = ((Get-VMNetworkAdapter -Name SDN -VMName $Name).MacAddress) -replace '..(?!$)', '$&-' + + Add-VMNetworkAdapter -VMName $Name -SwitchName $VMSwitch -DeviceNaming On -Name StorageA + Add-VMNetworkAdapter -VMName $Name -SwitchName $VMSwitch -DeviceNaming On -Name StorageB + + Get-VM $Name | Set-VMProcessor -ExposeVirtualizationExtensions $true + Get-VM $Name | Set-VMMemory -DynamicMemoryEnabled $false + Get-VM $Name | Get-VMNetworkAdapter | Set-VMNetworkAdapter -MacAddressSpoofing On + + Set-VMNetworkAdapterVlan -VMName $Name -VMNetworkAdapterName SDN -Trunk -NativeVlanId 0 -AllowedVlanIdList 1-200 + # Set-VMNetworkAdapterVlan -VMName $Name -VMNetworkAdapterName SDN2 -Trunk -NativeVlanId 0 -AllowedVlanIdList 1-200 + Set-VMNetworkAdapterVlan -VMName $Name -VMNetworkAdapterName StorageA -Trunk -NativeVlanId 0 -AllowedVlanIdList 1-800 + Set-VMNetworkAdapterVlan -VMName $Name -VMNetworkAdapterName StorageB -Trunk -NativeVlanId 0 -AllowedVlanIdList 1-800 + + Enable-VMIntegrationService -VMName $Name -Name "Guest Service Interface" + return $vmMac +} + +function Set-MGMTVHDX { + param ( + $VMMac, + $HCIBoxConfig + ) + $DriveLetter = $($HCIBoxConfig.HostVMPath).Split(':') + $path = (("\\localhost\") + ($DriveLetter[0] + "$") + ($DriveLetter[1]) + "\" + $($HCIBoxConfig.MgmtHostConfig.Hostname) + ".vhdx") + Write-Host "Performing offline installation of Hyper-V on $($HCIBoxConfig.MgmtHostConfig.Hostname)" + Install-WindowsFeature -Vhd $path -Name Hyper-V, RSAT-Hyper-V-Tools, Hyper-V-Powershell -Confirm:$false | Out-Null + Start-Sleep -Seconds 20 + + # Mount VHDX - bunch of kludgey logic in here to deal with different partition layouts on the GUI and HCI VHD images + Write-Host "Mounting VHDX file at $path" + [string]$MountedDrive = "" + $partition = Mount-VHD -Path $path -Passthru | Get-Disk | Get-Partition -PartitionNumber 3 + if (!$partition.DriveLetter) { + $MountedDrive = "X" + $partition | Set-Partition -NewDriveLetter $MountedDrive + } + else { + $MountedDrive = $partition.DriveLetter + } + + # Inject Answer File + Write-Host "Injecting answer file to $path" + $UnattendXML = GenerateAnswerFile -HostName $($HCIBoxConfig.MgmtHostConfig.Hostname) -IsMgmtVM $true -IPAddress $HCIBoxConfig.MgmtHostConfig.IP -VMMac $VMMac -HCIBoxConfig $HCIBoxConfig + + Write-Host "Mounted Disk Volume is: $MountedDrive" + $PantherDir = Get-ChildItem -Path ($MountedDrive + ":\Windows") -Filter "Panther" + if (!$PantherDir) { New-Item -Path ($MountedDrive + ":\Windows\Panther") -ItemType Directory -Force | Out-Null } + + Set-Content -Value $UnattendXML -Path ($MountedDrive + ":\Windows\Panther\Unattend.xml") -Force + + # Creating folder structure on AzSMGMT + Write-Host "Creating VMs\Base folder structure on $($HCIBoxConfig.MgmtHostConfig.Hostname)" + New-Item -Path ($MountedDrive + ":\VMs\Base") -ItemType Directory -Force | Out-Null + + # Injecting configs into VMs + Write-Host "Injecting files into $path" + Copy-Item -Path "$Env:HCIBoxDir\HCIBox-Config.psd1" -Destination ($MountedDrive + ":\") -Recurse -Force + Copy-Item -Path $guiVHDXPath -Destination ($MountedDrive + ":\VMs\Base\GUI.vhdx") -Force + Copy-Item -Path $azSHCIVHDXPath -Destination ($MountedDrive + ":\VMs\Base\AzSHCI.vhdx") -Force + New-Item -Path ($MountedDrive + ":\") -Name "Windows Admin Center" -ItemType Directory -Force | Out-Null + Copy-Item -Path "$($HCIBoxConfig.Paths["WACDir"])\*.msi" -Destination ($MountedDrive + ":\Windows Admin Center") -Recurse -Force + + # Dismount VHDX + Write-Host "Dismounting VHDX File at path $path" + Dismount-VHD $path +} + +function Set-HCINodeVHDX { + param ( + $Hostname, + $IPAddress, + $VMMac, + $HCIBoxConfig + ) + $DriveLetter = $($HCIBoxConfig.HostVMPath).Split(':') + $path = (("\\localhost\") + ($DriveLetter[0] + "$") + ($DriveLetter[1]) + "\" + $Hostname + ".vhdx") + Write-Host "Performing offline installation of Hyper-V on $Hostname" + Install-WindowsFeature -Vhd $path -Name Hyper-V, RSAT-Hyper-V-Tools, Hyper-V-Powershell -Confirm:$false | Out-Null + Start-Sleep -Seconds 5 + + # Install necessary tools to converge cluster + Write-Host "Installing and Configuring Failover Clustering on $Hostname" + Install-WindowsFeature -Vhd $path -Name Failover-Clustering -IncludeAllSubFeature -IncludeManagementTools | Out-Null + Start-Sleep -Seconds 15 + + Write-Host "Mounting VHDX file at $path" + $partition = Mount-VHD -Path $path -Passthru | Get-Disk | Get-Partition -PartitionNumber 3 + if (!$partition.DriveLetter) { + $MountedDrive = "Y" + $partition | Set-Partition -NewDriveLetter $MountedDrive + } + else { + $MountedDrive = $partition.DriveLetter + } + + Write-Host "Injecting answer file to $path" + $UnattendXML = GenerateAnswerFile -HostName $Hostname -IPAddress $IPAddress -VMMac $VMMac -HCIBoxConfig $HCIBoxConfig + Write-Host "Mounted Disk Volume is: $MountedDrive" + $PantherDir = Get-ChildItem -Path ($MountedDrive + ":\Windows") -Filter "Panther" + if (!$PantherDir) { New-Item -Path ($MountedDrive + ":\Windows\Panther") -ItemType Directory -Force | Out-Null } + Set-Content -Value $UnattendXML -Path ($MountedDrive + ":\Windows\Panther\Unattend.xml") -Force + + New-Item -Path ($MountedDrive + ":\VHD") -ItemType Directory -Force | Out-Null + Copy-Item -Path "$($HCIBoxConfig.Paths.VHDDir)" -Destination ($MountedDrive + ":\VHD") -Recurse -Force + Copy-Item -Path "$($HCIBoxConfig.Paths.VHDDir)\Ubuntu.vhdx" -Destination ($MountedDrive + ":\VHD") -Recurse -Force + + # Dismount VHDX + Write-Host "Dismounting VHDX File at path $path" + Dismount-VHD $path +} + +function Set-DataDrives { + param ( + $HCIBoxConfig, + [PSCredential]$Credential + ) + $VMs = @() + $VMs += $HCIBoxConfig.MgmtHostConfig.Hostname + foreach ($node in $HCIBoxConfig.NodeHostConfig) { + $VMs += $node.Hostname + } + foreach ($VM in $VMs) { + Invoke-Command -VMName $VM -Credential $Credential -ScriptBlock { + Set-Disk -Number 1 -IsOffline $false | Out-Null + Initialize-Disk -Number 1 | Out-Null + New-Partition -DiskNumber 1 -UseMaximumSize -AssignDriveLetter | Out-Null + Format-Volume -DriveLetter D | Out-Null + } + } +} + +function Test-VMAvailable { + param ( + $VMName, + [PSCredential]$Credential + ) + Invoke-Command -VMName $VMName -ScriptBlock { + $ErrorOccurred = $false + do { + try { + $ErrorActionPreference = 'Stop' + Get-VMHost | Out-Null + } + catch { + $ErrorOccurred = $true + } + } while ($ErrorOccurred -eq $true) + } -Credential $Credential -ErrorAction Ignore + Write-Host "VM $VMName is now online" +} + +function Test-AllVMsAvailable + { + param ( + $HCIBoxConfig, + [PSCredential]$Credential + ) + Write-Host "Testing whether VMs are available..." + Test-VMAvailable -VMName $HCIBoxConfig.MgmtHostConfig.Hostname -Credential $Credential + foreach ($VM in $HCIBoxConfig.NodeHostConfig) { + Test-VMAvailable -VMName $VM.Hostname -Credential $Credential + } +} + +function New-NATSwitch { + Param ( + $HCIBoxConfig + ) + Write-Host "Creating NAT Switch on switch $($HCIBoxConfig.InternalSwitch)" + Add-VMNetworkAdapter -VMName $HCIBoxConfig.MgmtHostConfig.Hostname -DeviceNaming On + Get-VMNetworkAdapter -VMName $HCIBoxConfig.MgmtHostConfig.Hostname | Where-Object { $_.Name -match "Network" } | Connect-VMNetworkAdapter -SwitchName $HCIBoxConfig.natHostVMSwitchName + Get-VMNetworkAdapter -VMName $HCIBoxConfig.MgmtHostConfig.Hostname | Where-Object { $_.Name -match "Network" } | Rename-VMNetworkAdapter -NewName "NAT" + Get-VMNetworkAdapter -VMName $HCIBoxConfig.MgmtHostConfig.Hostname -Name NAT | Set-VMNetworkAdapter -MacAddressSpoofing On + + Add-VMNetworkAdapter -VMName $HCIBoxConfig.MgmtHostConfig.Hostname -Name PROVIDER -DeviceNaming On -SwitchName $HCIBoxConfig.InternalSwitch + Get-VMNetworkAdapter -VMName $HCIBoxConfig.MgmtHostConfig.Hostname -Name PROVIDER | Set-VMNetworkAdapter -MacAddressSpoofing On + Get-VMNetworkAdapter -VMName $HCIBoxConfig.MgmtHostConfig.Hostname -Name PROVIDER | Set-VMNetworkAdapterVlan -Access -VlanId $HCIBoxConfig.providerVLAN | Out-Null + + #Create VLAN 200 NIC in order for NAT to work from L3 Connections + Add-VMNetworkAdapter -VMName $HCIBoxConfig.MgmtHostConfig.Hostname -Name VLAN200 -DeviceNaming On -SwitchName $HCIBoxConfig.InternalSwitch + Get-VMNetworkAdapter -VMName $HCIBoxConfig.MgmtHostConfig.Hostname -Name VLAN200 | Set-VMNetworkAdapter -MacAddressSpoofing On + Get-VMNetworkAdapter -VMName $HCIBoxConfig.MgmtHostConfig.Hostname -Name VLAN200 | Set-VMNetworkAdapterVlan -Access -VlanId $HCIBoxConfig.vlan200VLAN | Out-Null + + #Create Simulated Internet NIC in order for NAT to work from L3 Connections + Add-VMNetworkAdapter -VMName $HCIBoxConfig.MgmtHostConfig.Hostname -Name simInternet -DeviceNaming On -SwitchName $HCIBoxConfig.InternalSwitch + Get-VMNetworkAdapter -VMName $HCIBoxConfig.MgmtHostConfig.Hostname -Name simInternet | Set-VMNetworkAdapter -MacAddressSpoofing On + Get-VMNetworkAdapter -VMName $HCIBoxConfig.MgmtHostConfig.Hostname -Name simInternet | Set-VMNetworkAdapterVlan -Access -VlanId $HCIBoxConfig.simInternetVLAN | Out-Null +} + +function Set-NICs { + Param ( + $HCIBoxConfig, + [PSCredential]$Credential + ) + + Invoke-Command -VMName $HCIBoxConfig.MgmtHostConfig.Hostname -Credential $Credential -ScriptBlock { + Get-NetAdapter ((Get-NetAdapterAdvancedProperty | Where-Object {$_.DisplayValue -eq "SDN"}).Name) | Rename-NetAdapter -NewName FABRIC + # Get-NetAdapter ((Get-NetAdapterAdvancedProperty | Where-Object {$_.DisplayValue -eq "SDN2"}).Name) | Rename-NetAdapter -NewName FABRIC2 + } + + $int = 9 + foreach ($VM in $HCIBoxConfig.NodeHostConfig) { + $int++ + Write-Host "Setting NICs on VM $($VM.Hostname)" + Invoke-Command -VMName $VM.Hostname -Credential $Credential -ArgumentList $HCIBoxConfig, $VM -ScriptBlock { + $HCIBoxConfig = $args[0] + $VM = $args[1] + # Create IP Address of Storage Adapters + $storageAIP = $VM.StorageAIP + $storageBIP = $VM.StorageBIP + + # Set Name and IP Addresses on Storage Interfaces + $storageNICs = Get-NetAdapterAdvancedProperty | Where-Object { $_.DisplayValue -match "Storage" } + foreach ($storageNIC in $storageNICs) { + Rename-NetAdapter -Name $storageNIC.Name -NewName $storageNIC.DisplayValue + } + $storageNICs = Get-Netadapter | Where-Object { $_.Name -match "Storage" } + foreach ($storageNIC in $storageNICs) { + If ($storageNIC.Name -eq 'StorageA') { New-NetIPAddress -InterfaceAlias $storageNIC.Name -IPAddress $storageAIP -PrefixLength 24 | Out-Null } + If ($storageNIC.Name -eq 'StorageB') { New-NetIPAddress -InterfaceAlias $storageNIC.Name -IPAddress $storageBIP -PrefixLength 24 | Out-Null } + } + + # Enable WinRM + Write-Host "Enabling Windows Remoting in $env:COMPUTERNAME" + Set-Item WSMan:\localhost\Client\TrustedHosts * -Confirm:$false -Force + Enable-PSRemoting | Out-Null + + Start-Sleep -Seconds 60 + + # Rename non-storage adapters + Get-NetAdapter ((Get-NetAdapterAdvancedProperty | Where-Object {$_.DisplayValue -eq "SDN"}).Name) | Rename-NetAdapter -NewName FABRIC + # Get-Netadapter ((Get-NetAdapterAdvancedProperty | Where-Object {$_.DisplayValue -eq "SDN2"}).Name) | Rename-NetAdapter -NewName FABRIC2 + + # Enable CredSSP and MTU Settings + Invoke-Command -ComputerName localhost -Credential $using:Credential -ScriptBlock { + $fqdn = $Using:HCIBoxConfig.SDNDomainFQDN + + Write-Host "Enabling CredSSP on $env:COMPUTERNAME" + Enable-WSManCredSSP -Role Server -Force + Enable-WSManCredSSP -Role Client -DelegateComputer localhost -Force + Enable-WSManCredSSP -Role Client -DelegateComputer $env:COMPUTERNAME -Force + Enable-WSManCredSSP -Role Client -DelegateComputer $fqdn -Force + Enable-WSManCredSSP -Role Client -DelegateComputer "*.$fqdn" -Force + New-Item -Path HKLM:\SOFTWARE\Policies\Microsoft\Windows\CredentialsDelegation ` + -Name AllowFreshCredentialsWhenNTLMOnly -Force + New-ItemProperty -Path HKLM:\SOFTWARE\Policies\Microsoft\Windows\CredentialsDelegation\AllowFreshCredentialsWhenNTLMOnly ` + -Name 1 -Value * -PropertyType String -Force + } -InDisconnectedSession | Out-Null + } + } +} + +function Set-FabricNetwork { + param ( + $HCIBoxConfig, + [PSCredential]$localCred + ) + Start-Sleep -Seconds 20 + Write-Host "Configuring Fabric network on Management VM" + Invoke-Command -VMName $HCIBoxConfig.MgmtHostConfig.Hostname -Credential $localCred -ScriptBlock { + $localCred = $using:localCred + $domainCred = $using:domainCred + $HCIBoxConfig = $using:HCIBoxConfig + + $ErrorActionPreference = "Stop" + + # Disable Fabric2 Network Adapter + # Write-Host "Disabling Fabric2 Adapter" + # Get-NetAdapter FABRIC2 | Disable-NetAdapter -Confirm:$false | Out-Null + + # Enable WinRM on AzSMGMT + Write-Host "Enabling PSRemoting on $env:COMPUTERNAME" + Set-Item WSMan:\localhost\Client\TrustedHosts * -Confirm:$false -Force + Enable-PSRemoting | Out-Null + + # Disable ServerManager Auto-Start + Get-ScheduledTask -TaskName ServerManager | Disable-ScheduledTask | Out-Null + + # Create Hyper-V Networking for AzSMGMT + Import-Module Hyper-V + + Write-Host "Creating VM Switch on $env:COMPUTERNAME" + New-VMSwitch -AllowManagementOS $true -Name $HCIBoxConfig.FabricSwitch -NetAdapterName $HCIBoxConfig.FabricNIC -MinimumBandwidthMode None | Out-Null + + Write-Host "Configuring NAT on $env:COMPUTERNAME" + $Prefix = ($HCIBoxConfig.natSubnet.Split("/"))[1] + $natIP = ($HCIBoxConfig.natSubnet.TrimEnd("0./$Prefix")) + (".1") + $provIP = $HCIBoxConfig.BGPRouterIP_ProviderNetwork.TrimEnd("1/24") + "254" + $vlan200IP = $HCIBoxConfig.BGPRouterIP_VLAN200.TrimEnd("1/24") + "250" + $provGW = $HCIBoxConfig.BGPRouterIP_ProviderNetwork.TrimEnd("/24") + $provpfx = $HCIBoxConfig.BGPRouterIP_ProviderNetwork.Split("/")[1] + $vlanpfx = $HCIBoxConfig.BGPRouterIP_VLAN200.Split("/")[1] + $simInternetIP = $HCIBoxConfig.BGPRouterIP_SimulatedInternet.TrimEnd("1/24") + "254" + $simInternetPFX = $HCIBoxConfig.BGPRouterIP_SimulatedInternet.Split("/")[1] + New-VMSwitch -SwitchName NAT -SwitchType Internal -MinimumBandwidthMode None | Out-Null + New-NetIPAddress -IPAddress $natIP -PrefixLength $Prefix -InterfaceAlias "vEthernet (NAT)" | Out-Null + New-NetNat -Name NATNet -InternalIPInterfaceAddressPrefix $HCIBoxConfig.natSubnet | Out-Null + + Write-Host "Configuring Provider NIC on $env:COMPUTERNAME" + $NIC = Get-NetAdapterAdvancedProperty -RegistryKeyWord "HyperVNetworkAdapterName" | Where-Object { $_.RegistryValue -eq "PROVIDER" } + Rename-NetAdapter -name $NIC.name -newname "PROVIDER" | Out-Null + New-NetIPAddress -InterfaceAlias "PROVIDER" -IPAddress $provIP -PrefixLength $provpfx | Out-Null + + Write-Host "Configuring VLAN200 NIC on $env:COMPUTERNAME" + $NIC = Get-NetAdapterAdvancedProperty -RegistryKeyWord "HyperVNetworkAdapterName" | Where-Object { $_.RegistryValue -eq "VLAN200" } + Rename-NetAdapter -name $NIC.name -newname "VLAN200" | Out-Null + New-NetIPAddress -InterfaceAlias "VLAN200" -IPAddress $vlan200IP -PrefixLength $vlanpfx | Out-Null + + Write-Host "Configuring simulatedInternet NIC on $env:COMPUTERNAME" + $NIC = Get-NetAdapterAdvancedProperty -RegistryKeyWord "HyperVNetworkAdapterName" | Where-Object { $_.RegistryValue -eq "simInternet" } + Rename-NetAdapter -name $NIC.name -newname "simInternet" | Out-Null + New-NetIPAddress -InterfaceAlias "simInternet" -IPAddress $simInternetIP -PrefixLength $simInternetPFX | Out-Null + + Write-Host "Configuring NAT" + $NIC = Get-NetAdapterAdvancedProperty -RegistryKeyWord "HyperVNetworkAdapterName" | Where-Object { $_.RegistryValue -eq "Network Adapter" -or $_.RegistryValue -eq "NAT" } + Rename-NetAdapter -name $NIC.name -newname "Internet" | Out-Null + $internetIP = $HCIBoxConfig.natHostSubnet.Replace("0/24", "5") + $internetGW = $HCIBoxConfig.natHostSubnet.Replace("0/24", "1") + Start-Sleep -Seconds 15 + $internetIndex = (Get-NetAdapter | Where-Object { $_.Name -eq "Internet" }).ifIndex + Start-Sleep -Seconds 15 + New-NetIPAddress -IPAddress $internetIP -PrefixLength 24 -InterfaceIndex $internetIndex -DefaultGateway $internetGW -AddressFamily IPv4 | Out-Null + Set-DnsClientServerAddress -InterfaceIndex $internetIndex -ServerAddresses ($HCIBoxConfig.natDNS) | Out-Null + + # Enable Large MTU + Write-Host "Configuring MTU on all Adapters" + Get-NetAdapter | Where-Object { $_.Status -eq "Up" -and $_.Name -ne "Ethernet" } | Set-NetAdapterAdvancedProperty -RegistryValue $HCIBoxConfig.SDNLABMTU -RegistryKeyword "*JumboPacket" + Start-Sleep -Seconds 15 + + # Provision Public and Private VIP Route + New-NetRoute -DestinationPrefix $HCIBoxConfig.PublicVIPSubnet -NextHop $provGW -InterfaceAlias PROVIDER | Out-Null + + # Remove Gateway from Fabric NIC + Write-Host "Removing Gateway from Fabric NIC" + $index = (Get-WmiObject Win32_NetworkAdapter | Where-Object { $_.netconnectionid -match "vSwitch-Fabric" }).InterfaceIndex + Remove-NetRoute -InterfaceIndex $index -DestinationPrefix "0.0.0.0/0" -Confirm:$false + } +} + +function New-DCVM { + Param ( + $HCIBoxConfig, + [PSCredential]$localCred, + [PSCredential]$domainCred + ) + Write-Host "Creating domain controller VM" + $adminUser = $env:adminUsername + $Unattend = GenerateAnswerFile -Hostname $HCIBoxConfig.DCName -IsDCVM $true -HCIBoxConfig $HCIBoxConfig + Invoke-Command -VMName $HCIBoxConfig.MgmtHostConfig.Hostname -Credential $localCred -ScriptBlock { + $adminUser = $using:adminUser + $HCIBoxConfig = $using:HCIBoxConfig + $localCred = $using:localcred + $domainCred = $using:domainCred + $ParentDiskPath = "C:\VMs\Base\" + $vmpath = "D:\VMs\" + $OSVHDX = "GUI.vhdx" + $VMName = $HCIBoxConfig.DCName + + # Create Virtual Machine + Write-Host "Creating $VMName differencing disks" + New-VHD -ParentPath ($ParentDiskPath + $OSVHDX) -Path ($vmpath + $VMName + '\' + $VMName + '.vhdx') -Differencing | Out-Null + + Write-Host "Creating $VMName virtual machine" + New-VM -Name $VMName -VHDPath ($vmpath + $VMName + '\' + $VMName + '.vhdx') -Path ($vmpath + $VMName) -Generation 2 | Out-Null + + Write-Host "Setting $VMName Memory" + Set-VMMemory -VMName $VMName -DynamicMemoryEnabled $true -StartupBytes $HCIBoxConfig.MEM_DC -MaximumBytes $HCIBoxConfig.MEM_DC -MinimumBytes 500MB | Out-Null + + Write-Host "Configuring $VMName's networking" + Remove-VMNetworkAdapter -VMName $VMName -Name "Network Adapter" | Out-Null + Add-VMNetworkAdapter -VMName $VMName -Name $HCIBoxConfig.DCName -SwitchName $HCIBoxConfig.FabricSwitch -DeviceNaming 'On' | Out-Null + + Write-Host "Configuring $VMName's settings" + Set-VMProcessor -VMName $VMName -Count 2 | Out-Null + Set-VM -Name $VMName -AutomaticStartAction Start -AutomaticStopAction ShutDown | Out-Null + + # Add NIC for VLAN200 for DHCP server + Add-VMNetworkAdapter -VMName $VMName -Name "VLAN200" -SwitchName $HCIBoxConfig.FabricSwitch -DeviceNaming "On" + Get-VMNetworkAdapter -VMName $VMName -Name "VLAN200" | Set-VMNetworkAdapterVLAN -Access -VlanId $HCIBoxConfig.AKSVlanID + + # Inject Answer File + Write-Host "Mounting and injecting answer file into the $VMName VM." + New-Item -Path "C:\TempMount" -ItemType Directory | Out-Null + Mount-WindowsImage -Path "C:\TempMount" -Index 1 -ImagePath ($vmpath + $VMName + '\' + $VMName + '.vhdx') | Out-Null + Write-Host "Applying Unattend file to Disk Image..." + New-Item -Path C:\TempMount\windows -ItemType Directory -Name Panther -Force | Out-Null + Set-Content -Value $using:Unattend -Path "C:\TempMount\Windows\Panther\Unattend.xml" -Force + Write-Host "Dismounting Windows Image" + Dismount-WindowsImage -Path "C:\TempMount" -Save | Out-Null + Remove-Item "C:\TempMount" | Out-Null + + # Start Virtual Machine + Write-Host "Starting Virtual Machine $VMName" + Start-VM -Name $VMName | Out-Null + + # Wait until the VM is restarted + while ((Invoke-Command -VMName $VMName -Credential $using:localCred { "Test" } -ea SilentlyContinue) -ne "Test") { Start-Sleep -Seconds 1 } + + Write-Host "Configuring $VMName and Installing Active Directory." + Invoke-Command -VMName $VMName -Credential $localCred -ArgumentList $HCIBoxConfig -ScriptBlock { + $HCIBoxConfig = $args[0] + $DCName = $HCIBoxConfig.DCName + $IP = $HCIBoxConfig.SDNLABDNS + $PrefixLength = ($($HCIBoxConfig.MgmtHostConfig.IP).Split("/"))[1] + $SDNLabRoute = $HCIBoxConfig.SDNLABRoute + $DomainFQDN = $HCIBoxConfig.SDNDomainFQDN + $DomainNetBiosName = $DomainFQDN.Split(".")[0] + + Write-Host "Configuring NIC Settings for $DCName" + $NIC = Get-NetAdapterAdvancedProperty -RegistryKeyWord "HyperVNetworkAdapterName" | Where-Object { $_.RegistryValue -eq $DCName } + Rename-NetAdapter -name $NIC.name -newname $DCName | Out-Null + New-NetIPAddress -InterfaceAlias $DCName -IPAddress $ip -PrefixLength $PrefixLength -DefaultGateway $SDNLabRoute | Out-Null + Set-DnsClientServerAddress -InterfaceAlias $DCName -ServerAddresses $IP | Out-Null + Install-WindowsFeature -name AD-Domain-Services -IncludeManagementTools | Out-Null + + Write-Host "Configuring NIC settings for $DCName VLAN200" + $NIC = Get-NetAdapterAdvancedProperty -RegistryKeyWord "HyperVNetworkAdapterName" | Where-Object { $_.RegistryValue -eq "VLAN200" } + Rename-NetAdapter -name $NIC.name -newname VLAN200 | Out-Null + New-NetIPAddress -InterfaceAlias VLAN200 -IPAddress $HCIBoxConfig.dcVLAN200IP -PrefixLength ($HCIBoxConfig.AKSIPPrefix.split("/"))[1] -DefaultGateway $HCIBoxConfig.AKSGWIP | Out-Null + + Write-Host "Configuring Trusted Hosts on $DCName" + Set-Item WSMan:\localhost\Client\TrustedHosts * -Confirm:$false -Force + + Write-Host "Installing Active Directory forest on $DCName." + $SecureString = ConvertTo-SecureString $HCIBoxConfig.SDNAdminPassword -AsPlainText -Force + Install-ADDSForest -DomainName $DomainFQDN -DomainMode 'WinThreshold' -DatabasePath "C:\Domain" -DomainNetBiosName $DomainNetBiosName -SafeModeAdministratorPassword $SecureString -InstallDns -Confirm -Force -NoRebootOnCompletion # | Out-Null + } + + Write-Host "Stopping $VMName" + Get-VM $VMName | Stop-VM + Write-Host "Starting $VMName" + Get-VM $VMName | Start-VM + + # Wait until DC is created and rebooted + while ((Invoke-Command -VMName $VMName -Credential $domainCred -ArgumentList $HCIBoxConfig.DCName { (Get-ADDomainController $args[0]).enabled } -ea SilentlyContinue) -ne $true) { Start-Sleep -Seconds 5 } + + Write-Host "Configuring User Accounts and Groups in Active Directory" + Invoke-Command -VMName $VMName -Credential $domainCred -ArgumentList $HCIBoxConfig, $adminUser -ScriptBlock { + $HCIBoxConfig = $args[0] + $adminUser = $args[1] + $SDNDomainFQDN = $HCIBoxConfig.SDNDomainFQDN + $SecureString = ConvertTo-SecureString $HCIBoxConfig.SDNAdminPassword -AsPlainText -Force + Set-ADDefaultDomainPasswordPolicy -ComplexityEnabled $false -Identity $HCIBoxConfig.SDNDomainFQDN -MinPasswordLength 0 + + $params = @{ + Name = 'NC Admin' + GivenName = 'NC' + Surname = 'Admin' + SamAccountName = 'NCAdmin' + UserPrincipalName = "NCAdmin@$SDNDomainFQDN" + AccountPassword = $SecureString + Enabled = $true + ChangePasswordAtLogon = $false + CannotChangePassword = $true + PasswordNeverExpires = $true + } + New-ADUser @params + + $params = @{ + Name = $adminUser + GivenName = 'Jumpstart' + Surname = 'Jumpstart' + SamAccountName = $adminUser + UserPrincipalName = "$adminUser@$SDNDomainFQDN" + AccountPassword = $SecureString + Enabled = $true + ChangePasswordAtLogon = $false + CannotChangePassword = $true + PasswordNeverExpires = $true + } + New-ADUser @params + + $params.Name = 'NC Client' + $params.Surname = 'Client' + $params.SamAccountName = 'NCClient' + $params.UserPrincipalName = "NCClient@$SDNDomainFQDN" + New-ADUser @params + + New-ADGroup -name “NCAdmins” -groupscope Global + New-ADGroup -name “NCClients” -groupscope Global + + Add-ADGroupMember "Domain Admins" "NCAdmin" + Add-ADGroupMember "NCAdmins" "NCAdmin" + Add-ADGroupMember "NCClients" "NCClient" + Add-ADGroupMember "NCClients" $adminUser + Add-ADGroupMember "NCAdmins" $adminUser + Add-ADGroupMember "Domain Admins" $adminUser + Add-ADGroupMember "NCAdmins" $adminUser + Add-ADGroupMember "NCClients" $adminUser + + # Set Administrator Account Not to Expire + Get-ADUser Administrator | Set-ADUser -PasswordNeverExpires $true -CannotChangePassword $true + Get-ADUser $adminUser | Set-ADUser -PasswordNeverExpires $true -CannotChangePassword $true + + # Set DNS Forwarder + Write-Host "Adding DNS Forwarders" + Add-DnsServerForwarder $HCIBoxConfig.natDNS + + # Create Enterprise CA + Write-Host "Installing and Configuring Active Directory Certificate Services and Certificate Templates" + Install-WindowsFeature -Name AD-Certificate -IncludeAllSubFeature -IncludeManagementTools | Out-Null + Install-AdcsCertificationAuthority -CAtype 'EnterpriseRootCa' -CryptoProviderName 'ECDSA_P256#Microsoft Software Key Storage Provider' -KeyLength 256 -HashAlgorithmName 'SHA256' -ValidityPeriod 'Years' -ValidityPeriodUnits 10 -Confirm:$false | Out-Null + + # Give WebServer Template Enroll rights for Domain Computers + $filter = "(CN=WebServer)" + $ConfigContext = ([ADSI]"LDAP://RootDSE").configurationNamingContext + $ConfigContext = "CN=Certificate Templates,CN=Public Key Services,CN=Services,$ConfigContext" + $ds = New-object System.DirectoryServices.DirectorySearcher([ADSI]"LDAP://$ConfigContext", $filter) + $Template = $ds.Findone().GetDirectoryEntry() + + if ($null -ne $Template) { + $objUser = New-Object System.Security.Principal.NTAccount("Domain Computers") + $objectGuid = New-Object Guid 0e10c968-78fb-11d2-90d4-00c04f79dc55 + $ADRight = [System.DirectoryServices.ActiveDirectoryRights]"ExtendedRight" + $ACEType = [System.Security.AccessControl.AccessControlType]"Allow" + $ACE = New-Object System.DirectoryServices.ActiveDirectoryAccessRule -ArgumentList $objUser, $ADRight, $ACEType, $objectGuid + $Template.ObjectSecurity.AddAccessRule($ACE) + $Template.commitchanges() + } + + CMD.exe /c "certutil -setreg ca\ValidityPeriodUnits 8" | Out-Null + Restart-Service CertSvc + Start-Sleep -Seconds 60 + + #Issue Certificate Template + CMD.exe /c "certutil -SetCATemplates +WebServer" + } + + Write-Host "Configuring DHCP scope on DHCP server." + # Set up DHCP scope for Arc resource bridge + Invoke-Command -VMName $HCIBoxConfig.DCName -Credential $using:domainCred -ArgumentList $HCIBoxConfig -ScriptBlock { + $HCIBoxConfig = $args[0] + + # Install DHCP feature + Install-WindowsFeature DHCP -IncludeManagementTools + CMD.exe /c "netsh dhcp add securitygroups" + Restart-Service dhcpserver + + # Allow DHCP in domain + $dnsName = $HCIBoxConfig.DCName + $fqdnsName = $HCIBoxConfig.DCName + "." + $HCIBoxConfig.SDNDomainFQDN + Add-DhcpServerInDC -DnsName $fqdnsName -IPAddress $HCIBoxConfig.dcVLAN200IP + Get-DHCPServerInDC + + # Bind DHCP only to VLAN200 NIC + Set-DhcpServerv4Binding -ComputerName $dnsName -InterfaceAlias $dnsName -BindingState $false + Set-DhcpServerv4Binding -ComputerName $dnsName -InterfaceAlias VLAN200 -BindingState $true + + # Add DHCP scope for Resource bridge VMs + Add-DhcpServerv4Scope -name "ResourceBridge" -StartRange $HCIBoxConfig.rbVipStart -EndRange $HCIBoxConfig.rbVipEnd -SubnetMask 255.255.255.0 -State Active + $scope = Get-DhcpServerv4Scope + Add-DhcpServerv4ExclusionRange -ScopeID $scope.ScopeID.IPAddressToString -StartRange $HCIBoxConfig.rbDHCPExclusionStart -EndRange $HCIBoxConfig.rbDHCPExclusionEnd + Set-DhcpServerv4OptionValue -ComputerName $dnsName -ScopeId $scope.ScopeID.IPAddressToString -DnsServer $HCIBoxConfig.SDNLABDNS -Router $HCIBoxConfig.BGPRouterIP_VLAN200.Trim("/24") + } + } +} + +function New-RouterVM { + Param ( + $HCIBoxConfig, + [PSCredential]$localCred + ) + $Unattend = GenerateAnswerFile -Hostname $HCIBoxConfig.BGPRouterName -IsRouterVM $true -HCIBoxConfig $HCIBoxConfig + Invoke-Command -VMName $HCIBoxConfig.MgmtHostConfig.Hostname -Credential $localCred -ScriptBlock { + $HCIBoxConfig = $using:HCIBoxConfig + $localCred = $using:localcred + $ParentDiskPath = "C:\VMs\Base\AzSHCI.vhdx" + $vmpath = "D:\VMs\" + $VMName = $HCIBoxConfig.BGPRouterName + + # Create Host OS Disk + Write-Host "Creating $VMName differencing disks" + New-VHD -ParentPath $ParentDiskPath -Path ($vmpath + $VMName + '\' + $VMName + '.vhdx') -Differencing | Out-Null + + # Create VM + Write-Host "Creating the $VMName VM." + New-VM -Name $VMName -VHDPath ($vmpath + $VMName + '\' + $VMName + '.vhdx') -Path ($vmpath + $VMName) -Generation 2 | Out-Null + + # Set VM Configuration + Write-Host "Setting $VMName's VM Configuration" + Set-VMMemory -VMName $VMName -DynamicMemoryEnabled $true -StartupBytes $HCIBoxConfig.MEM_BGP -MinimumBytes 500MB -MaximumBytes $HCIBoxConfig.MEM_BGP | Out-Null + Remove-VMNetworkAdapter -VMName $VMName -Name "Network Adapter" | Out-Null + Set-VMProcessor -VMName $VMName -Count 2 | Out-Null + Set-VM -Name $VMName -AutomaticStopAction ShutDown | Out-Null + + # Configure VM Networking + Write-Host "Configuring $VMName's Networking" + Add-VMNetworkAdapter -VMName $VMName -Name Mgmt -SwitchName $HCIBoxConfig.FabricSwitch -DeviceNaming On + Add-VMNetworkAdapter -VMName $VMName -Name Provider -SwitchName $HCIBoxConfig.FabricSwitch -DeviceNaming On + Add-VMNetworkAdapter -VMName $VMName -Name VLAN200 -SwitchName $HCIBoxConfig.FabricSwitch -DeviceNaming On + Add-VMNetworkAdapter -VMName $VMName -Name SIMInternet -SwitchName $HCIBoxConfig.FabricSwitch -DeviceNaming On + Set-VMNetworkAdapterVlan -VMName $VMName -VMNetworkAdapterName Provider -Access -VlanId $HCIBoxConfig.providerVLAN + Set-VMNetworkAdapterVlan -VMName $VMName -VMNetworkAdapterName VLAN200 -Access -VlanId $HCIBoxConfig.vlan200VLAN + Set-VMNetworkAdapterVlan -VMName $VMName -VMNetworkAdapterName SIMInternet -Access -VlanId $HCIBoxConfig.simInternetVLAN + Add-VMNetworkAdapter -VMName $VMName -Name NAT -SwitchName NAT -DeviceNaming On + + # Mount disk and inject Answer File + Write-Host "Mounting Disk Image and Injecting Answer File into the $VMName VM." + New-Item -Path "C:\TempBGPMount" -ItemType Directory | Out-Null + Mount-WindowsImage -Path "C:\TempBGPMount" -Index 1 -ImagePath ($vmpath + $VMName + '\' + $VMName + '.vhdx') | Out-Null + New-Item -Path C:\TempBGPMount\windows -ItemType Directory -Name Panther -Force | Out-Null + Set-Content -Value $using:Unattend -Path "C:\TempBGPMount\Windows\Panther\Unattend.xml" -Force + + # Enable remote access + Write-Host "Enabling Remote Access" + Enable-WindowsOptionalFeature -Path C:\TempBGPMount -FeatureName RasRoutingProtocols -All -LimitAccess | Out-Null + Enable-WindowsOptionalFeature -Path C:\TempBGPMount -FeatureName RemoteAccessPowerShell -All -LimitAccess | Out-Null + Write-Host "Dismounting Disk Image for $VMName VM." + Dismount-WindowsImage -Path "C:\TempBGPMount" -Save | Out-Null + Remove-Item "C:\TempBGPMount" + + # Start the VM + Write-Host "Starting $VMName VM." + Start-VM -Name $VMName + + # Wait for VM to be started + while ((Invoke-Command -VMName $VMName -Credential $localcred { "Test" } -ea SilentlyContinue) -ne "Test") { Start-Sleep -Seconds 1 } + + Write-Host "Configuring $VMName" + Invoke-Command -VMName $VMName -Credential $localCred -ArgumentList $HCIBoxConfig -ScriptBlock { + $HCIBoxConfig = $args[0] + $DNS = $HCIBoxConfig.SDNLABDNS + $natSubnet = $HCIBoxConfig.natSubnet + $natDNS = $HCIBoxConfig.natSubnet + $MGMTIP = $HCIBoxConfig.BGPRouterIP_MGMT.Split("/")[0] + $MGMTPFX = $HCIBoxConfig.BGPRouterIP_MGMT.Split("/")[1] + $PNVIP = $HCIBoxConfig.BGPRouterIP_ProviderNetwork.Split("/")[0] + $PNVPFX = $HCIBoxConfig.BGPRouterIP_ProviderNetwork.Split("/")[1] + $VLANIP = $HCIBoxConfig.BGPRouterIP_VLAN200.Split("/")[0] + $VLANPFX = $HCIBoxConfig.BGPRouterIP_VLAN200.Split("/")[1] + $simInternetIP = $HCIBoxConfig.BGPRouterIP_SimulatedInternet.Split("/")[0] + $simInternetPFX = $HCIBoxConfig.BGPRouterIP_SimulatedInternet.Split("/")[1] + + # Renaming NetAdapters and setting up the IPs inside the VM using CDN parameters + Write-Host "Configuring $env:COMPUTERNAME's Networking" + $NIC = Get-NetAdapterAdvancedProperty -RegistryKeyWord "HyperVNetworkAdapterName" | Where-Object { $_.RegistryValue -eq "Mgmt" } + Rename-NetAdapter -name $NIC.name -newname "Mgmt" | Out-Null + New-NetIPAddress -InterfaceAlias "Mgmt" -IPAddress $MGMTIP -PrefixLength $MGMTPFX | Out-Null + Set-DnsClientServerAddress -InterfaceAlias “Mgmt” -ServerAddresses $DNS | Out-Null + $NIC = Get-NetAdapterAdvancedProperty -RegistryKeyWord "HyperVNetworkAdapterName" | Where-Object { $_.RegistryValue -eq "PROVIDER" } + Rename-NetAdapter -name $NIC.name -newname "PROVIDER" | Out-Null + New-NetIPAddress -InterfaceAlias "PROVIDER" -IPAddress $PNVIP -PrefixLength $PNVPFX | Out-Null + $NIC = Get-NetAdapterAdvancedProperty -RegistryKeyWord "HyperVNetworkAdapterName" | Where-Object { $_.RegistryValue -eq "VLAN200" } + Rename-NetAdapter -name $NIC.name -newname "VLAN200" | Out-Null + New-NetIPAddress -InterfaceAlias "VLAN200" -IPAddress $VLANIP -PrefixLength $VLANPFX | Out-Null + $NIC = Get-NetAdapterAdvancedProperty -RegistryKeyWord "HyperVNetworkAdapterName" | Where-Object { $_.RegistryValue -eq "SIMInternet" } + Rename-NetAdapter -name $NIC.name -newname "SIMInternet" | Out-Null + New-NetIPAddress -InterfaceAlias "SIMInternet" -IPAddress $simInternetIP -PrefixLength $simInternetPFX | Out-Null + + # Configure NAT + $NIC = Get-NetAdapterAdvancedProperty -RegistryKeyWord "HyperVNetworkAdapterName" | Where-Object { $_.RegistryValue -eq "NAT" } + Rename-NetAdapter -name $NIC.name -newname "NAT" | Out-Null + $Prefix = ($natSubnet.Split("/"))[1] + $natIP = ($natSubnet.TrimEnd("0./$Prefix")) + (".10") + $natGW = ($natSubnet.TrimEnd("0./$Prefix")) + (".1") + New-NetIPAddress -InterfaceAlias "NAT" -IPAddress $natIP -PrefixLength $Prefix -DefaultGateway $natGW | Out-Null + if ($natDNS) { + Set-DnsClientServerAddress -InterfaceAlias "NAT" -ServerAddresses $natDNS | Out-Null + } + + # Configure Trusted Hosts + Write-Host "Configuring Trusted Hosts on $env:COMPUTERNAME" + Set-Item WSMan:\localhost\Client\TrustedHosts * -Confirm:$false -Force + + # Installing Remote Access + Write-Host "Installing Remote Access on $env:COMPUTERNAME" + Install-RemoteAccess -VPNType RoutingOnly | Out-Null + + # Adding a BGP Router to the VM + # Write-Host "Creating BGP Router on $env:COMPUTERNAME" + # Add-BgpRouter -BGPIdentifier $PNVIP -LocalASN $HCIBoxConfig.BGPRouterASN -TransitRouting 'Enabled' -ClusterId 1 -RouteReflector 'Enabled' + + # Configure BGP Peers - commented during refactor for 23h2 + # if ($HCIBoxConfig.ConfigureBGPpeering -and $HCIBoxConfig.ProvisionNC) { + # Write-Verbose "Peering future MUX/GWs" + # $Mux01IP = ($HCIBoxConfig.BGPRouterIP_ProviderNetwork.TrimEnd("1/24")) + "4" + # $GW01IP = ($HCIBoxConfig.BGPRouterIP_ProviderNetwork.TrimEnd("1/24")) + "5" + # $GW02IP = ($HCIBoxConfig.BGPRouterIP_ProviderNetwork.TrimEnd("1/24")) + "6" + # $params = @{ + # Name = 'MUX01' + # LocalIPAddress = $PNVIP + # PeerIPAddress = $Mux01IP + # PeerASN = $HCIBoxConfig.SDNASN + # OperationMode = 'Mixed' + # PeeringMode = 'Automatic' + # } + # Add-BgpPeer @params -PassThru + # $params.Name = 'GW01' + # $params.PeerIPAddress = $GW01IP + # Add-BgpPeer @params -PassThru + # $params.Name = 'GW02' + # $params.PeerIPAddress = $GW02IP + # Add-BgpPeer @params -PassThru + # } + + # Enable Large MTU + Write-Host "Configuring MTU on all Adapters" + Get-NetAdapter | Where-Object { $_.Status -eq "Up" } | Set-NetAdapterAdvancedProperty -RegistryValue $HCIBoxConfig.SDNLABMTU -RegistryKeyword "*JumboPacket" + } + } +} + +function Join-HCINodesToDomain { + Param ( + $HCIBoxConfig, + [PSCredential]$localCred, + [PSCredential]$domainCred + ) + try { + foreach ($node in $HCIBoxConfig.NodeHostConfig) { + # Test connectivity to hosts + $test = Test-Connection $($node.IP).Split("/")[0] + while (!$test) { + Write-Host "Unable to contact $($node.Hostname) at $($node.IP)." -ForegroundColor Red + Start-Sleep -Seconds 2 + $test = Test-Connection $($node.IP).Split("/")[0] + } + + # Join hosts to domain + Write-Host "Joining $($node.Hostname) to domain" + $DomainJoined = "" + while ($DomainJoined -ne $HCIBoxConfig.SDNDomainFQDN) { + $job = Invoke-Command -ComputerName $node.Hostname -Credential $localCred -ArgumentList ($domainCred, $HCIBoxConfig.SDNDomainFQDN) -ScriptBlock { + Add-Computer -DomainName $args[1] -Credential $args[0] + } -AsJob + + while ($job.JobStateInfo.State -ne "Completed") { Start-Sleep -Seconds 5 } + $DomainJoined = (Get-WmiObject -ComputerName $node.Hostname -Credential $localCred -Class win32_computersystem).domain + } + Write-Host "Restarting $($node.Hostname)" + Restart-Computer -ComputerName $node.Hostname -Credential $localCred -Force + } + } + catch { + throw $_ + } +} + +function New-AdminCenterVM { + Param ( + $HCIBoxConfig, + $localCred, + $domainCred + ) + $VMName = $HCIBoxConfig.WACVMName + $UnattendXML = GenerateAnswerFile -HostName $VMName -IsWACVM $true -IPAddress $HCIBoxConfig.WACIP -VMMac $HCIBoxConfig.WACMAC -HCIBoxConfig $HCIBoxConfig + Invoke-Command -VMName AzSMGMT -Credential $localCred -ScriptBlock { + $VMName = $using:VMName + $ParentDiskPath = "C:\VMs\Base\" + $VHDPath = "D:\VMs\" + $OSVHDX = "GUI.vhdx" + $BaseVHDPath = $ParentDiskPath + $OSVHDX + $HCIBoxConfig = $using:HCIBoxConfig + $localCred = $using:localCred + $domainCred = $using:domainCred + + # Create Host OS Disk + Write-Host "Creating $VMName differencing disks" + New-VHD -ParentPath $BaseVHDPath -Path (($VHDPath) + ($VMName) + '\' + $VMName + (".vhdx")) -Differencing | Out-Null + + # Mount VHDX + Import-Module DISM + Write-Host "Mounting $VMName VHD" + New-Item -Path "C:\TempWACMount" -ItemType Directory | Out-Null + Mount-WindowsImage -Path "C:\TempWACMount" -Index 1 -ImagePath (($VHDPath) + ($VMName) + '\' + $VMName + (".vhdx")) | Out-Null + + # Copy Source Files + Write-Host "Copying Application and Script Source Files to $VMName" + Copy-Item 'C:\Windows Admin Center' -Destination C:\TempWACMount\ -Recurse -Force + New-Item -Path C:\TempWACMount\VHDs -ItemType Directory -Force | Out-Null + Copy-Item C:\VMs\Base\AzSHCI.vhdx -Destination C:\TempWACMount\VHDs -Force # I dont think this is needed + Copy-Item C:\VMs\Base\GUI.vhdx -Destination C:\TempWACMount\VHDs -Force # I dont think this is needed + + # Create VM + Write-Host "Provisioning the VM $VMName" + New-VM -Name $VMName -VHDPath (($VHDPath) + ($VMName) + '\' + $VMName + (".vhdx")) -Path $VHDPath -Generation 2 | Out-Null + Set-VMMemory -VMName $VMName -DynamicMemoryEnabled $true -StartupBytes $HCIBoxConfig.MEM_WAC -MaximumBytes $HCIBoxConfig.MEM_WAC -MinimumBytes 500MB | Out-Null + Set-VM -Name $VMName -AutomaticStartAction Start -AutomaticStopAction ShutDown | Out-Null + Write-Host "Configuring $VMName networking" + Remove-VMNetworkAdapter -VMName $VMName -Name "Network Adapter" + Add-VMNetworkAdapter -VMName $VMName -Name "Fabric" -SwitchName $HCIBoxConfig.FabricSwitch -DeviceNaming On + Set-VMNetworkAdapter -VMName $VMName -StaticMacAddress $HCIBoxConfig.WACMAC # Mac address is linked to the answer file required in next step + + # Apply custom Unattend.xml file + New-Item -Path C:\TempWACMount\windows -ItemType Directory -Name Panther -Force | Out-Null + + Write-Host "Mounting and Injecting Answer File into the $VMName VM." + Set-Content -Value $using:UnattendXML -Path "C:\TempWACMount\Windows\Panther\Unattend.xml" -Force + Write-Host "Dismounting Disk" + Dismount-WindowsImage -Path "C:\TempWACMount" -Save | Out-Null + Remove-Item "C:\TempWACMount" + + Write-Host "Setting $VMName's VM Configuration" + Set-VMProcessor -VMName $VMname -Count 4 + Set-VM -Name $VMName -AutomaticStopAction TurnOff + + Write-Host "Starting $VMName VM." + Start-VM -Name $VMName + + # Wait until the VM is restarted + while ((Invoke-Command -VMName $VMName -Credential $domainCred { "Test" } -ea SilentlyContinue) -ne "Test") { Start-Sleep -Seconds 5 } + + # Configure WAC + Invoke-Command -VMName $VMName -Credential $domainCred -ArgumentList $HCIBoxConfig, $VMName, $domainCred -ScriptBlock { + $HCIBoxConfig = $args[0] + $VMName = $args[1] + $domainCred = $args[2] + Import-Module NetAdapter + + Write-Host "Enabling Remote Access on $VMName" + Enable-WindowsOptionalFeature -FeatureName RasRoutingProtocols -All -LimitAccess -Online | Out-Null + Enable-WindowsOptionalFeature -FeatureName RemoteAccessPowerShell -All -LimitAccess -Online | Out-Null + + Write-Host "Rename Network Adapter in $VMName" + Get-NetAdapter | Rename-NetAdapter -NewName Fabric + Write-Host "Configuring MTU on all Adapters" + Get-NetAdapter | Where-Object { $_.Status -eq "Up" } | Set-NetAdapterAdvancedProperty -RegistryValue $HCIBoxConfig.SDNLABMTU -RegistryKeyword "*JumboPacket" + + # Set Gateway + $index = (Get-WmiObject Win32_NetworkAdapter | Where-Object { $_.netconnectionid -eq "Fabric" }).InterfaceIndex + $NetInterface = Get-WmiObject Win32_NetworkAdapterConfiguration | Where-Object { $_.InterfaceIndex -eq $index } + $NetInterface.SetGateways($HCIBoxConfig.SDNLABRoute) | Out-Null + + # Enable CredSSP + Write-Host "Configuring WSMAN Trusted Hosts on $VMName" + Set-Item WSMan:\localhost\Client\TrustedHosts * -Confirm:$false -Force | Out-Null + Enable-WSManCredSSP -Role Client -DelegateComputer * -Force | Out-Null + Enable-PSRemoting -force | Out-Null + Enable-WSManCredSSP -Role Server -Force | Out-Null + Enable-WSManCredSSP -Role Client -DelegateComputer localhost -Force | Out-Null + Enable-WSManCredSSP -Role Client -DelegateComputer $env:COMPUTERNAME -Force | Out-Null + Enable-WSManCredSSP -Role Client -DelegateComputer $HCIBoxConfig.SDNDomainFQDN -Force | Out-Null + Enable-WSManCredSSP -Role Client -DelegateComputer "*.$($HCIBoxConfig.SDNDomainFQDN)" -Force | Out-Null + New-Item -Path HKLM:\SOFTWARE\Policies\Microsoft\Windows\CredentialsDelegation -Name AllowFreshCredentialsWhenNTLMOnly -Force | Out-Null + New-ItemProperty -Path HKLM:\SOFTWARE\Policies\Microsoft\Windows\CredentialsDelegation\AllowFreshCredentialsWhenNTLMOnly -Name 1 -Value * -PropertyType String -Force | Out-Null + + $WACIP = $HCIBoxConfig.WACIP.Split("/")[0] + + # Install RSAT-NetworkController + $isAvailable = Get-WindowsFeature | Where-Object { $_.Name -eq 'RSAT-NetworkController' } + if ($isAvailable) { + Write-Host "Installing RSAT-NetworkController on $VMName" + Import-Module ServerManager + Install-WindowsFeature -Name RSAT-NetworkController -IncludeAllSubFeature -IncludeManagementTools | Out-Null + } + + # Install Windows features + Write-Host "Installing Hyper-V RSAT Tools on $VMName" + Install-WindowsFeature -Name RSAT-Hyper-V-Tools -IncludeAllSubFeature -IncludeManagementTools | Out-Null + Write-Host "Installing Active Directory RSAT Tools on $VMName" + Install-WindowsFeature -Name RSAT-ADDS -IncludeAllSubFeature -IncludeManagementTools | Out-Null + Write-Host "Installing Failover Clustering RSAT Tools on $VMName" + Install-WindowsFeature -Name RSAT-Clustering-Mgmt, RSAT-Clustering-PowerShell -IncludeAllSubFeature -IncludeManagementTools | Out-Null + Write-Host "Installing DNS Server RSAT Tools on $VMName" + Install-WindowsFeature -Name RSAT-DNS-Server -IncludeAllSubFeature -IncludeManagementTools | Out-Null + Install-RemoteAccess -VPNType RoutingOnly | Out-Null + # Install-PackageProvider -Name Nuget -MinimumVersion 2.8.5.201 -Force + + # Stop Server Manager from starting on boot + Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\ServerManager" -Name "DoNotOpenServerManagerAtLogon" -Value 1 + + # Create BGP Router + Add-BgpRouter -BGPIdentifier $WACIP -LocalASN $HCIBoxConfig.WACASN -TransitRouting 'Enabled' -ClusterId 1 -RouteReflector 'Enabled' + + $RequestInf = @" +[Version] +Signature="`$Windows NT$" + +[NewRequest] +Subject = "CN=$($HCIBoxConfig.WACVMName).$($HCIBoxConfig.SDNDomainFQDN)" +Exportable = True +KeyLength = 2048 +KeySpec = 1 +KeyUsage = 0xA0 +MachineKeySet = True +ProviderName = "Microsoft RSA SChannel Cryptographic Provider" +ProviderType = 12 +SMIME = FALSE +RequestType = CMC +FriendlyName = "HCIBox Windows Admin Cert" + +[Strings] +szOID_SUBJECT_ALT_NAME2 = "2.5.29.17" +szOID_ENHANCED_KEY_USAGE = "2.5.29.37" +szOID_PKIX_KP_SERVER_AUTH = "1.3.6.1.5.5.7.3.1" +szOID_PKIX_KP_CLIENT_AUTH = "1.3.6.1.5.5.7.3.2" +[Extensions] +%szOID_SUBJECT_ALT_NAME2% = "{text}dns=$($HCIBoxConfig.WACVMName).$($HCIBoxConfig.SDNDomainFQDN)" +%szOID_ENHANCED_KEY_USAGE% = "{text}%szOID_PKIX_KP_SERVER_AUTH%,%szOID_PKIX_KP_CLIENT_AUTH%" +[RequestAttributes] +CertificateTemplate= WebServer +"@ + + New-Item C:\WACCert -ItemType Directory -Force | Out-Null + Set-Content -Value $RequestInf -Path C:\WACCert\WACCert.inf -Force | Out-Null + + Register-PSSessionConfiguration -Name 'Microsoft.SDNNested' -RunAsCredential $domainCred -MaximumReceivedDataSizePerCommandMB 1000 -MaximumReceivedObjectSizeMB 1000 + Write-Host "Requesting and installing SSL Certificate on $using:VMName" + Invoke-Command -ComputerName $VMName -ConfigurationName 'Microsoft.SDNNested' -Credential $domainCred -ArgumentList $HCIBoxConfig -ScriptBlock { + $HCIBoxConfig = $args[0] + # Get the CA Name + $CertDump = certutil -dump + $ca = ((((($CertDump.Replace('`', "")).Replace("'", "")).Replace(":", "=")).Replace('\', "")).Replace('"', "") | ConvertFrom-StringData).Name + $CertAuth = $HCIBOXConfig.SDNDomainFQDN + '\' + $ca + + Write-Host "CA is: $ca" + Write-Host "Certificate Authority is: $CertAuth" + Write-Host "Certdump is $CertDump" + + # Request and Accept SSL Certificate + Set-Location C:\WACCert + certreq -q -f -new WACCert.inf WACCert.req + certreq -q -config $CertAuth -attrib "CertificateTemplate:webserver" -submit WACCert.req WACCert.cer + certreq -q -accept WACCert.cer + certutil -q -store my + + Set-Location 'C:\' + Remove-Item C:\WACCert -Recurse -Force + + } -Authentication Credssp + + # Install Windows Admin Center + $pfxThumbPrint = (Get-ChildItem -Path Cert:\LocalMachine\my | Where-Object { $_.FriendlyName -match "HCIBox Windows Admin Cert" }).Thumbprint + Write-Host "Thumbprint: $pfxThumbPrint" + Write-Host "WACPort: $($HCIBoxConfig.WACport)" + $WindowsAdminCenterGateway = "https://$($HCIBoxConfig.WACVMName)." + $HCIBOXConfig.SDNDomainFQDN + Write-Host $WindowsAdminCenterGateway + Write-Host "Installing and Configuring Windows Admin Center" + $PathResolve = Resolve-Path -Path 'C:\Windows Admin Center\*.msi' + $arguments = "/qn /L*v C:\log.txt SME_PORT=$($HCIBoxConfig.WACport) SME_THUMBPRINT=$pfxThumbPrint SSL_CERTIFICATE_OPTION=installed SME_URL=$WindowsAdminCenterGateway" + Start-Process -FilePath $PathResolve -ArgumentList $arguments -PassThru | Wait-Process + + # Install Chocolatey + Write-Host "Installing Chocolatey" + Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; Invoke-Expression ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1')) + Start-Sleep -Seconds 10 + + # Install Azure PowerShell + Write-Host 'Installing Az PowerShell' + $expression = "choco install az.powershell -y --limit-output" + Invoke-Expression $expression + + # Create Shortcut for Hyper-V Manager + Write-Host "Creating Shortcut for Hyper-V Manager" + Copy-Item -Path "C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Administrative Tools\Hyper-V Manager.lnk" -Destination "C:\Users\Public\Desktop" + + # Create Shortcut for Failover-Cluster Manager + Write-Host "Creating Shortcut for Failover-Cluster Manager" + Copy-Item -Path "C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Administrative Tools\Failover Cluster Manager.lnk" -Destination "C:\Users\Public\Desktop" + + # Create Shortcut for DNS + Write-Host "Creating Shortcut for DNS Manager" + Copy-Item -Path "C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Administrative Tools\DNS.lnk" -Destination "C:\Users\Public\Desktop" + + # Create Shortcut for Active Directory Users and Computers + Write-Host "Creating Shortcut for AD Users and Computers" + Copy-Item -Path "C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Administrative Tools\Active Directory Users and Computers.lnk" -Destination "C:\Users\Public\Desktop" + + # Set Network Profiles + Get-NetConnectionProfile | Where-Object { $_.NetworkCategory -eq "Public" } | Set-NetConnectionProfile -NetworkCategory Private | Out-Null + + # Disable Automatic Updates + $WUKey = "HKLM:\software\Policies\Microsoft\Windows\WindowsUpdate" + New-Item -Path $WUKey -Force | Out-Null + New-ItemProperty -Path $WUKey -Name AUOptions -PropertyType Dword -Value 2 -Force | Out-Null + + # Install Kubectl + Write-Host 'Installing kubectl' + $expression = "choco install kubernetes-cli -y --limit-output" + Invoke-Expression $expression + + # Create a shortcut for Windows Admin Center + Write-Host "Creating Shortcut for Windows Admin Center" + if ($HCIBoxConfig.WACport -ne "443") { $TargetPath = "https://$($HCIBoxConfig.WACVMName)." + $HCIBoxConfig.SDNDomainFQDN + ":" + $HCIBoxConfig.WACport } + else { $TargetPath = "https://$($HCIBoxConfig.WACVMName)." + $HCIBoxConfig.SDNDomainFQDN } + $ShortcutFile = "C:\Users\Public\Desktop\Windows Admin Center.url" + $WScriptShell = New-Object -ComObject WScript.Shell + $Shortcut = $WScriptShell.CreateShortcut($ShortcutFile) + $Shortcut.TargetPath = $TargetPath + $Shortcut.Save() + + # Disable Edge 'First Run' Setup + $edgePolicyRegistryPath = 'HKLM:SOFTWARE\Policies\Microsoft\Edge' + $desktopSettingsRegistryPath = 'HKCU:SOFTWARE\Microsoft\Windows\Shell\Bags\1\Desktop' + $firstRunRegistryName = 'HideFirstRunExperience' + $firstRunRegistryValue = '0x00000001' + $savePasswordRegistryName = 'PasswordManagerEnabled' + $savePasswordRegistryValue = '0x00000000' + $autoArrangeRegistryName = 'FFlags' + $autoArrangeRegistryValue = '1075839525' + + if (-NOT (Test-Path -Path $edgePolicyRegistryPath)) { + New-Item -Path $edgePolicyRegistryPath -Force | Out-Null + } + if (-NOT (Test-Path -Path $desktopSettingsRegistryPath)) { + New-Item -Path $desktopSettingsRegistryPath -Force | Out-Null + } + + New-ItemProperty -Path $edgePolicyRegistryPath -Name $firstRunRegistryName -Value $firstRunRegistryValue -PropertyType DWORD -Force + New-ItemProperty -Path $edgePolicyRegistryPath -Name $savePasswordRegistryName -Value $savePasswordRegistryValue -PropertyType DWORD -Force + Set-ItemProperty -Path $desktopSettingsRegistryPath -Name $autoArrangeRegistryName -Value $autoArrangeRegistryValue -Force + } + } +} + +function New-HyperConvergedEnvironment { + Param ( + $HCIBoxConfig, + [PSCredential]$domainCred + ) + Invoke-Command -ComputerName $HCIBoxConfig.DCName -Credential $domainCred -ScriptBlock { + $HCIBoxConfig = $using:HCIBoxConfig + $domainCred = $using:domainCred + $localCred = $using:localCred + foreach ($AzSHOST in $HCIBoxConfig.NodeHostConfig) { + Invoke-Command -ComputerName $AzSHOST.Hostname -ArgumentList $AzSHOST, $HCIBoxConfig -Credential $domainCred -ScriptBlock { + $AzSHOST = $args[0] + $HCIBoxconfig = $args[1] + # Check if switch exists already + $switchCheck = Get-VMSwitch | Where-Object { $_.Name -eq $HCIBoxConfig.ClusterVSwitchName } + if ($switchCheck) { + Write-Host "Switch already exists on $env:COMPUTERNAME. Skipping this host." + } + else { + Write-Host "Setting IP Configuration on $($HCIBoxConfig.ClusterVSwitchName) on host $($AzSHOST.Hostname)" + $switchTeamMembers = @("FABRIC", "FABRIC2") + New-VMSwitch -Name $HCIBoxConfig.ClusterVSwitchName -AllowManagementOS $true -NetAdapterName $switchTeamMembers -EnableEmbeddedTeaming $true -MinimumBandwidthMode "Weight" + + Write-Host "Setting IP Configuration on $($HCIBoxConfig.ClusterVSwitchName) on host $($AzSHOST.Hostname)" + $switchNIC = Get-Netadapter | Where-Object { $_.Name -match $HCIBoxConfig.ClusterVSwitchName } + New-NetIPAddress -InterfaceIndex $switchNIC.InterfaceIndex -IpAddress $AzSHOST.IP.Split('/')[0] -PrefixLength 24 -AddressFamily 'IpV4' -DefaultGateway $HCIBoxConfig.BGPRouterIP_MGMT -ErrorAction 'SilentlyContinue' + + Write-Host "Setting DNS configuration on $($HCIBoxConfig.ClusterVSwitchName) on host $($AzSHOST.Hostname)" + Set-DnsClientServerAddress -InterfaceIndex $switchNIC.InterfaceIndex -ServerAddresses $HCIBoxConfig.SDNLABDNS + + Write-Host "Setting vSwitch adapter VLAN $($HCIBoxConfig.mgmtVLAN) on host $($AzSHOST.Hostname)" + Set-VMNetworkAdapterIsolation -IsolationMode 'Vlan' -DefaultIsolationID $HCIBoxConfig.mgmtVLAN -AllowUntaggedTraffic $true -VMNetworkAdapterName $($HCIBoxConfig.ClusterVSwitchName) -ManagementOS + Get-VMSwitchExtension -VMSwitchName $($HCIBoxConfig.ClusterVSwitchName) | Disable-VMSwitchExtension | Out-Null + + Write-Host "Configuring MTU on all adapters on $($AzSHOST.Hostname)" + Get-NetAdapter | Where-Object { $_.Status -eq "Up" } | Set-NetAdapterAdvancedProperty -RegistryValue $HCIBoxConfig.SDNLABMTU -RegistryKeyword "*JumboPacket" + } + } + Start-Sleep -Seconds 60 + } + # Reboot all HCI nodes + foreach ($AzSHOST in $HCIBoxConfig.NodeHostConfig) { + Write-Host "Rebooting HCIBox host $($AzSHOST.Hostname)" + Restart-Computer $AzSHOST.Hostname -Force -Confirm:$false -Credential $domainCred -Protocol WSMan + Start-Sleep -Seconds 10 + Write-Host "Checking to see if $($AzSHOST.Hostname) is up and online" + while ((Invoke-Command -ComputerName $AzSHOST.Hostname -Credential $domainCred { "Test" } -ea SilentlyContinue) -ne "Test") { Start-Sleep -Seconds 10 } + Write-Host "$($AzSHOST.Hostname) is up and online" + } + } +} + +function New-S2DCluster { + param ( + $HCIBoxConfig, + [PSCredential]$domainCred + ) + Invoke-Command -ComputerName $HCIBoxConfig.NodeHostConfig[0].Hostname -Credential $domainCred -ArgumentList $HCIBoxConfig, $domainCred -ScriptBlock { + $HCIBoxConfig = $args[0] + $domainCred = $args[1] + + Import-Module FailoverClusters + Import-Module Storage + $nodes = @() + foreach ($node in $HCIBoxConfig.NodeHostConfig) { + $nodes += $node.Hostname + } + Write-Host "Creating cluster $($HCIBoxConfig.ClusterName) from nodes: $nodes" + Register-PSSessionConfiguration -Name Microsoft.HCIBoxS2D -RunAsCredential $domainCred -MaximumReceivedDataSizePerCommandMB 1000 -MaximumReceivedObjectSizeMB 1000 -WarningAction SilentlyContinue | Out-Null + + Invoke-Command -ComputerName $HCIBoxConfig.NodeHostConfig[0].Hostname -Credential $domainCred -ArgumentList $HCIBoxConfig, $nodes -ConfigurationName Microsoft.HCIBoxS2D -ScriptBlock { + $HCIBoxConfig = $args[0] + $nodes = $args[1] + $ClusterIP = ($HCIBoxConfig.MGMTSubnet.TrimEnd("0/24")) + "252" + + New-Cluster -Name $HCIBoxConfig.ClusterName -Node $nodes -StaticAddress $ClusterIP -NoStorage + Enable-ClusterS2D -Confirm:$false -Verbose + while (!$PerfHistory) { + Write-Host "Waiting for Cluster Performance History volume to come online." + Start-Sleep -Seconds 10 + $PerfHistory = Get-ClusterResource | Where-Object {$_.Name -match 'ClusterPerformanceHistory'} + if ($PerfHistory) { + Write-Host "Cluster Perfomance History volume online." + } + } + + Write-Host "Configuring S2D" + Get-PhysicalDisk | Where-Object { $_.Size -lt 127GB } | Set-PhysicalDisk -MediaType HDD | Out-Null + Start-Sleep -Seconds 10 + New-Volume -FriendlyName "S2D_vDISK1" -FileSystem 'CSVFS_ReFS' -StoragePoolFriendlyName "S2D on $($HCIBoxConfig.ClusterName)" -ResiliencySettingName 'Mirror' -PhysicalDiskRedundancy 1 -AllocationUnitSize 64KB -UseMaximumSize + Get-StorageSubsystem clus* | Set-StorageHealthSetting -name “System.Storage.PhysicalDisk.AutoReplace.Enabled” -value “False” + Set-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Services\spaceport\Parameters -Name HwTimeout -Value 0x00007530 + + Write-Host "Renaming Storage network adapters" + (Get-Cluster -Name $HCIBoxConfig.ClusterName | Get-ClusterNetwork | Where-Object { $_.Address -eq ($HCIBoxConfig.storageAsubnet.Replace('/24', '')) }).Name = 'StorageA' + (Get-Cluster -Name $HCIBoxConfig.ClusterName | Get-ClusterNetwork | Where-Object { $_.Address -eq ($HCIBoxConfig.storageBsubnet.Replace('/24', '')) }).Name = 'StorageB' + (Get-Cluster -Name $HCIBoxConfig.ClusterName | Get-ClusterNetwork | Where-Object { $_.Address -eq ($HCIBoxConfig.MGMTSubnet.Replace('/24', '')) }).Name = 'Public' + + Write-Host "Setting allowed networks for Live Migration" + Get-ClusterResourceType -Name "Virtual Machine" -Cluster $HCIBoxConfig.ClusterName | ` + Set-ClusterParameter -Cluster $HCIBoxConfig.ClusterName -Name MigrationExcludeNetworks -Value ` + ([String]::Join(";", (Get-ClusterNetwork -Cluster $HCIBoxConfig.ClusterName | ` + Where-Object { $_.Name -notmatch "Storage" }).ID)) + } + } +} + +function Test-InternetConnect { + $testIP = $HCIBoxConfig.natDNS + $ErrorActionPreference = "Stop" + $intConnect = Test-NetConnection -ComputerName $testip -Port 53 + + if (!$intConnect.TcpTestSucceeded) { + throw "Unable to connect to DNS by pinging $($HCIBoxConfig.natDNS) - Network access to this IP is required." + } +} + +function Set-HostNAT { + param ( + $HCIBoxConfig + ) + + $switchExist = Get-NetAdapter | Where-Object { $_.Name -match $HCIBoxConfig.natHostVMSwitchName } + if (!$switchExist) { + Write-Host "Creating NAT Switch: $($HCIBoxConfig.natHostVMSwitchName)" + # Create Internal VM Switch for NAT + New-VMSwitch -Name $HCIBoxConfig.natHostVMSwitchName -SwitchType Internal | Out-Null + + Write-Host "Applying IP Address to NAT Switch: $($HCIBoxConfig.natHostVMSwitchName)" + # Apply IP Address to new Internal VM Switch + $intIdx = (Get-NetAdapter | Where-Object { $_.Name -match $HCIBoxConfig.natHostVMSwitchName }).ifIndex + $natIP = $HCIBoxConfig.natHostSubnet.Replace("0/24", "1") + New-NetIPAddress -IPAddress $natIP -PrefixLength 24 -InterfaceIndex $intIdx | Out-Null + + # Create NetNAT + Write-Host "Creating new Net NAT" + New-NetNat -Name $HCIBoxConfig.natHostVMSwitchName -InternalIPInterfaceAddressPrefix $HCIBoxConfig.natHostSubnet | Out-Null + } +} + +function Set-HCIDeployPrereqs { + param ( + $HCIBoxConfig, + [PSCredential]$localCred, + [PSCredential]$domainCred + ) + Invoke-Command -VMName $HCIBoxConfig.MgmtHostConfig.Hostname -Credential $localCred -ScriptBlock { + $HCIBoxConfig = $using:HCIBoxConfig + $localCred = $using:localcred + $domainCred = $using:domainCred + Invoke-Command -VMName $HCIBoxConfig.DCName -Credential $domainCred -ArgumentList $HCIBoxConfig -ScriptBlock { + $HCIBoxConfig = $args[0] + $domainCredNoDomain = new-object -typename System.Management.Automation.PSCredential ` + -argumentlist ($HCIBoxConfig.LCMDeployUsername), (ConvertTo-SecureString $HCIBoxConfig.SDNAdminPassword -AsPlainText -Force) + + Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force -Scope CurrentUser + Install-Module AsHciADArtifactsPreCreationTool -Repository PSGallery -Force -Confirm:$false + $domainName = $HCIBoxConfig.SDNDomainFQDN.Split('.') + $ouName = "OU=$($HCIBoxConfig.LCMADOUName)" + foreach ($name in $domainName) { + $ouName += ",DC=$name" + } + $nodes = @() + foreach ($node in $HCIBoxConfig.NodeHostConfig) { + $nodes += $node.Hostname.ToString() + } + Add-KdsRootKey -EffectiveTime ((Get-Date).AddHours(-10)) + $deploymentPrefix = $HCIBoxConfig.LCMDeploymentPrefix + New-HciAdObjectsPreCreation -Deploy -AzureStackLCMUserCredential $domainCredNoDomain -AsHciOUName $ouName -AsHciPhysicalNodeList $nodes -DomainFQDN $HCIBoxConfig.SDNDomainFQDN -AsHciClusterName $HCIBoxConfig.ClusterName -AsHciDeploymentPrefix $deploymentPrefix + } + } + + foreach ($node in $HCIBoxConfig.NodeHostConfig) { + Invoke-Command -VMName $node.Hostname -Credential $localCred -ArgumentList $env:subscriptionId, $env:spnTenantId, $env:spnClientID, $env:spnClientSecret, $env:resourceGroup -ScriptBlock { + $subId = $args[0] + $tenantId = $args[1] + $clientId = $args[2] + $clientSecret = $args[3] + $resourceGroup = $args[4] + + # Prep nodes for Azure Arc onboarding + winrm quickconfig -quiet + netsh advfirewall firewall add rule name="ICMP Allow incoming V4 echo request" protocol=icmpv4:8,any dir=in action=allow + + # Register PSGallery as a trusted repo + Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force + Register-PSRepository -Default -InstallationPolicy Trusted -ErrorAction SilentlyContinue + Set-PSRepository -Name PSGallery -InstallationPolicy Trusted + + #Install Arc registration script from PSGallery + Install-Module AzsHCI.ARCinstaller -Force + + #Install required PowerShell modules in your node for registration + Install-Module Az.Accounts -Force + Install-Module Az.ConnectedMachine -Force + Install-Module Az.Resources -Force + $azureAppCred = (New-Object System.Management.Automation.PSCredential $clientId, (ConvertTo-SecureString -String $clientSecret -AsPlainText -Force)) + Connect-AzAccount -ServicePrincipal -SubscriptionId $subId -TenantId $tenantId -Credential $azureAppCred + $armtoken = Get-AzAccessToken + + #Invoke the registration script. For this preview release, only eastus region is supported. + Invoke-AzStackHciArcInitialization -SubscriptionID $subId -ResourceGroup $resourceGroup -TenantID $tenantId -Region eastus -Cloud "AzureCloud" -ArmAccessToken $armtoken.Token -AccountID $clientId + } + } + # Workaround for incomplete BITS transfer of LCM files + Start-Sleep -Seconds 60 + Invoke-Command -VMName $HCIBoxconfig.NodeHostConfig[0].Hostname { + Remove-Item -Path "C:\DeploymentPackage" -Recurse -Force + Restart-Computer -Force + } +} + +#endregion + +#region Main +$guiVHDXPath = $HCIBoxConfig.guiVHDXPath +$azSHCIVHDXPath = $HCIBoxConfig.azSHCIVHDXPath +$HostVMPath = $HCIBoxConfig.HostVMPath +$InternalSwitch = $HCIBoxConfig.InternalSwitch +$natDNS = $HCIBoxConfig.natDNS +$natSubnet = $HCIBoxConfig.natSubnet + +Import-Module Hyper-V + +$VerbosePreference = "SilentlyContinue" +$ErrorActionPreference = "Stop" +$WarningPreference = "Continue" +$ProgressPreference = "SilentlyContinue" + +# Create paths +foreach ($path in $HCIBoxConfig.Paths.GetEnumerator()) { + Write-Host "Creating $($path.Key) path at $($path.Value)" + New-Item -Path $path.Value -ItemType Directory -Force | Out-Null +} + +# Download HCIBox VHDs +Write-Host "[Build cluster - Step 1/12] Downloading HCIBox VHDs. This will take a while..." -ForegroundColor Green +BITSRequest -Params @{'Uri'='https://aka.ms/AAnn1dd'; 'Filename'="$($HCIBoxConfig.Paths.VHDDir)\AZSHCI.vhdx" } +BITSRequest -Params @{'Uri'='https://jsvhds.blob.core.windows.net/hcibox23h2/AZSHCI.sha256?sp=r&st=2024-01-16T15:09:53Z&se=2027-01-16T23:09:53Z&spr=https&sv=2022-11-02&sr=b&sig=fM6nSGOUHIB90egY95Oc02NfXxFmh8fPK0bnibjAdQU%3D'; 'Filename'="$($HCIBoxConfig.Paths.VHDDir)\AZSHCI.sha256" } +$checksum = Get-FileHash -Path "$($HCIBoxConfig.Paths.VHDDir)\AZSHCI.vhdx" +$hash = Get-Content -Path "$($HCIBoxConfig.Paths.VHDDir)\AZSHCI.sha256" +if ($checksum.Hash -eq $hash) { + Write-Host "AZSCHI.vhdx has valid checksum. Continuing..." +} +else { + Write-Error "AZSCHI.vhdx is corrupt. Abortig..." + throw +} +BITSRequest -Params @{'Uri'='https://aka.ms/AAnnebv'; 'Filename'="$($HCIBoxConfig.Paths.VHDDir)\GUI.vhdx"} +BITSRequest -Params @{'Uri'='https://jsvhds.blob.core.windows.net/hcibox23h2/gui.sha256?sp=r&st=2024-01-16T15:10:38Z&se=2027-01-16T23:10:38Z&spr=https&sv=2022-11-02&sr=b&sig=yeWvM%2FEvDcVfrJOk%2FacJublzc%2FXjYWibpzDNQl40CvA%3D'; 'Filename'="$($HCIBoxConfig.Paths.VHDDir)\GUI.sha256" } +$checksum = Get-FileHash -Path "$($HCIBoxConfig.Paths.VHDDir)\GUI.vhdx" +$hash = Get-Content -Path "$($HCIBoxConfig.Paths.VHDDir)\GUI.sha256" +if ($checksum.Hash -eq $hash) { + Write-Host "GUI.vhdx has valid checksum. Continuing..." +} +else { + Write-Error "GUI.vhdx is corrupt. Aborting..." + throw +} +BITSRequest -Params @{'Uri'='https://partner-images.canonical.com/hyper-v/desktop/focal/current/ubuntu-focal-hyperv-amd64-ubuntu-desktop-hyperv.vhdx.zip'; 'Filename'="$($HCIBoxConfig.Paths.VHDDir)\Ubuntu.vhdx.zip"} +Expand-Archive -Path "$($HCIBoxConfig.Paths.VHDDir)\Ubuntu.vhdx.zip" -DestinationPath $($HCIBoxConfig.Paths.VHDDir) +Move-Item -Path "$($HCIBoxConfig.Paths.VHDDir)\livecd.ubuntu-desktop-hyperv.vhdx" -Destination "$($HCIBoxConfig.Paths.VHDDir)\Ubuntu.vhdx" + +# Set credentials +$localCred = new-object -typename System.Management.Automation.PSCredential ` + -argumentlist "Administrator", (ConvertTo-SecureString $HCIBoxConfig.SDNAdminPassword -AsPlainText -Force) + +$domainCred = new-object -typename System.Management.Automation.PSCredential ` + -argumentlist (($HCIBoxConfig.SDNDomainFQDN.Split(".")[0]) +"\Administrator"), (ConvertTo-SecureString $HCIBoxConfig.SDNAdminPassword -AsPlainText -Force) + +# Enable PSRemoting +Write-Host "[Build cluster - Step 2/12] Preparing Azure VM virtualization host..." -ForegroundColor Green +Write-Host "Enabling PS Remoting on client..." +Enable-PSRemoting +Set-Item WSMan:\localhost\Client\TrustedHosts * -Confirm:$false -Force + +############################################################################### +# Configure Hyper-V host +############################################################################### +Write-Host "Checking internet connectivity" +Test-InternetConnect + +Write-Host "Creating Internal Switch" +New-InternalSwitch -HCIBoxConfig $HCIBoxConfig + +Write-Host "Creating NAT Switch" +Set-HostNAT -HCIBoxConfig $HCIBoxConfig + +Write-Host "Configuring HCIBox-Client Hyper-V host" +Set-VMHost -VirtualHardDiskPath $HostVMPath -VirtualMachinePath $HostVMPath -EnableEnhancedSessionMode $true + +Write-Host "Copying VHDX Files to Host virtualization drive" +$guipath = "$HostVMPath\GUI.vhdx" +$hcipath = "$HostVMPath\AzSHCI.vhdx" +Copy-Item -Path $HCIBoxConfig.guiVHDXPath -Destination $guipath -Force | Out-Null +Copy-Item -Path $HCIBoxConfig.azSHCIVHDXPath -Destination $hcipath -Force | Out-Null + +################################################################################ +# Create the three nested Virtual Machines +################################################################################ +# First create the Management VM (AzSMGMT) +Write-Host "[Build cluster - Step 3/12] Creating Management VM (AzSMGMT)..." -ForegroundColor Green +$mgmtMac = New-ManagementVM -Name $($HCIBoxConfig.MgmtHostConfig.Hostname) -VHDXPath "$HostVMPath\GUI.vhdx" -VMSwitch $InternalSwitch -HCIBoxConfig $HCIBoxConfig +Set-MGMTVHDX -VMMac $mgmtMac -HCIBoxConfig $HCIBoxConfig + +# Create the HCI host node VMs +Write-Host "[Build cluster - Step 4/12] Creating HCI node VMs (AzSHOSTx)..." -ForegroundColor Green +foreach ($VM in $HCIBoxConfig.NodeHostConfig) { + $mac = New-HCINodeVM -Name $VM.Hostname -VHDXPath $hcipath -VMSwitch $InternalSwitch -HCIBoxConfig $HCIBoxConfig + Set-HCINodeVHDX -HostName $VM.Hostname -IPAddress $VM.IP -VMMac $mac -HCIBoxConfig $HCIBoxConfig +} + +# Start Virtual Machines +Write-Host "[Build cluster - Step 5/12] Starting VMs..." -ForegroundColor Green +Write-Host "Starting VM: $($HCIBoxConfig.MgmtHostConfig.Hostname)" +Start-VM -Name $HCIBoxConfig.MgmtHostConfig.Hostname +foreach ($VM in $HCIBoxConfig.NodeHostConfig) { + Write-Host "Starting VM: $($VM.Hostname)" + Start-VM -Name $VM.Hostname +} + +####################################################################################### +# Prep the virtualization environment +####################################################################################### +Write-Host "[Build cluster - Step 6/12] Configuring host environment..." -ForegroundColor Green +# Wait for AzSHOSTs to come online +Test-AllVMsAvailable -HCIBoxConfig $HCIBoxConfig -Credential $localCred +Start-Sleep -Seconds 60 + +# Format and partition data drives +Set-DataDrives -HCIBoxConfig $HCIBoxConfig -Credential $localCred + +# Configure networking +Set-NICs -HCIBoxConfig $HCIBoxConfig -Credential $localCred + +# Restart Machines +Restart-VMs -HCIBoxConfig $HCIBoxConfig -Credential $localCred + +# Wait for AzSHOSTs to come online +Test-AllVMsAvailable -HCIBoxConfig $HCIBoxConfig -Credential $localCred + +# Create NAT Virtual Switch on AzSMGMT +New-NATSwitch -HCIBoxConfig $HCIBoxConfig + +# Configure fabric network on AzSMGMT +Set-FabricNetwork -HCIBoxConfig $HCIBoxConfig -localCred $localCred + +####################################################################################### +# Provision the router, domain controller, and WAC VMs and join the hosts to the domain +####################################################################################### +# Provision Router VM on AzSMGMT +Write-Host "[Build cluster - Step 7/12] Build BGP router VM..." -ForegroundColor Green +New-RouterVM -HCIBoxConfig $HCIBoxConfig -localCred $localCred + +# Provision Domain controller VM on AzSMGMT +Write-Host "[Build cluster - Step 8/12] Building Domain Controller VM..." -ForegroundColor Green +New-DCVM -HCIBoxConfig $HCIBoxConfig -localCred $localCred -domainCred $domainCred + +# Join hosts to domain +#Join-HCINodesToDomain -HCIBoxConfig $HCIBoxConfig -localCred $localCred -domainCred $domainCred + +# Provision Admincenter VM +Write-Host "[Build cluster - Step 9/12] Building Windows Admin Center gateway server VM... (skipping step)" -ForegroundColor Green +#New-AdminCenterVM -HCIBoxConfig $HCIBoxConfig -localCred $localCred -domainCred $domainCred + +# Provision Hyper-V Logical Switches and Create S2D Cluster on Hosts +# Write-Host "[Build cluster - Step 10/12] Configuring HCI node networking..." -ForegroundColor Green +# New-HyperConvergedEnvironment -HCIBoxConfig $HCIBoxConfig -domainCred $domainCred + +####################################################################################### +# Prepare the cluster for deployment +####################################################################################### +# New-S2DCluster -HCIBoxConfig $HCIBoxConfig -domainCred $domainCred +Write-Host "[Build cluster - Step 11/12] Preparing HCI cluster Azure deployment..." -ForegroundColor Green +Set-HCIDeployPrereqs -HCIBoxConfig $HCIBoxConfig -localCred $localCred -domainCred $domainCred + +# Cluster complete. Finish up and add RDP Link to Desktop to WAC machine. +Write-Host "[Build cluster - Step 12/12] Tidying up..." -ForegroundColor Green +Remove-Item C:\Users\Public\Desktop\AdminCenter.lnk -Force -ErrorAction SilentlyContinue +$wshshell = New-Object -ComObject WScript.Shell +$lnk = $wshshell.CreateShortcut("C:\Users\Public\Desktop\AdminCenter.lnk") +$lnk.TargetPath = "%windir%\system32\mstsc.exe" +$lnk.Arguments = "/v:$($HCIBoxConfig.WACVMName)" +$lnk.Description = "AdminCenter link for HCIBox." +$lnk.Save() + +$endtime = Get-Date +$timeSpan = New-TimeSpan -Start $starttime -End $endtime +Write-Host +Write-Host "Successfully deployed HCIBox Azure Stack HCI cluster." -ForegroundColor Green +Write-Host "Infrastructure deployment time was $($timeSpan.Hours):$($timeSpan.Minutes) (hh:mm)." -ForegroundColor Green + +Stop-Transcript + +#endregion \ No newline at end of file diff --git a/azure_jumpstart_hcibox/artifacts/PSProfile.ps1 b/azure_jumpstart_hcibox/artifacts/PowerShell/PSProfile.ps1 similarity index 100% rename from azure_jumpstart_hcibox/artifacts/PSProfile.ps1 rename to azure_jumpstart_hcibox/artifacts/PowerShell/PSProfile.ps1 diff --git a/azure_jumpstart_hcibox/artifacts/Register-AzSHCI.ps1 b/azure_jumpstart_hcibox/artifacts/Register-AzSHCI.ps1 deleted file mode 100644 index 080fbedf0c..0000000000 --- a/azure_jumpstart_hcibox/artifacts/Register-AzSHCI.ps1 +++ /dev/null @@ -1,69 +0,0 @@ -$WarningPreference = "SilentlyContinue" -$ErrorActionPreference = "Stop" -$ProgressPreference = 'SilentlyContinue' -# Set paths -$Env:HCIBoxDir = "C:\HCIBox" -$Env:HCIBoxLogsDir = "C:\HCIBox\Logs" -$Env:HCIBoxVMDir = "C:\HCIBox\Virtual Machines" -$Env:HCIBoxKVDir = "C:\HCIBox\KeyVault" -$Env:HCIBoxGitOpsDir = "C:\HCIBox\GitOps" -$Env:HCIBoxIconDir = "C:\HCIBox\Icons" -$Env:HCIBoxVHDDir = "C:\HCIBox\VHD" -$Env:HCIBoxSDNDir = "C:\HCIBox\SDN" -$Env:HCIBoxWACDir = "C:\HCIBox\Windows Admin Center" -$Env:agentScript = "C:\HCIBox\agentScript" -$Env:ToolsDir = "C:\Tools" -$Env:tempDir = "C:\Temp" -$Env:VMPath = "C:\VMs" - -Start-Transcript -Path $Env:HCIBoxLogsDir\Register-AzSHCI.log - -# Import Configuration Module -$ConfigurationDataFile = "$Env:HCIBoxDir\HCIBox-Config.psd1" -$SDNConfig = Import-PowerShellDataFile -Path $ConfigurationDataFile -$user = "jumpstart.local\administrator" -$password = ConvertTo-SecureString -String $SDNConfig.SDNAdminPassword -AsPlainText -Force -$adcred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $user, $password - -Write-Host "Installing Required Modules" -ForegroundColor Green -BackgroundColor Black -Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force -Install-WindowsFeature -name RSAT-Clustering-Powershell -$ModuleNames = "Az.Accounts", "Az.stackhci" -foreach ($ModuleName in $ModuleNames) { - Install-Module -Name $ModuleName -Force -} - -# Required for CLI commands -Write-Host "Az Login" -$azureAppCred = (New-Object System.Management.Automation.PSCredential $env:spnClientID, (ConvertTo-SecureString -String $env:spnClientSecret -AsPlainText -Force)) -Connect-AzAccount -ServicePrincipal -Subscription $env:subscriptionId -Tenant $env:spnTenantId -Credential $azureAppCred - -#Register the Cluster -Write-Host "Registering the Cluster" -ForegroundColor Green -BackgroundColor Black -$armtoken = Get-AzAccessToken -$clustername = 'HCIBox-Cluster' -$azureLocation = 'eastus' -Register-AzStackHCI -SubscriptionId $env:subscriptionId -ComputerName $SDNConfig.HostList[0] -AccountId $env:spnClientID -ArmAccessToken $armtoken.Token -Credential $adcred -Region $azureLocation -ResourceName $clustername -ResourceGroupName $env:resourceGroup -Move-Item -Path RegisterHCI_* -Destination $Env:HCIBoxLogsDir\RegisterHCI_PS_Output.log - -Write-Host "$clustername successfully registered as Az Stack HCI cluster resource in Azure" - -# Set up cluster cloud witness -Connect-AzAccount -ServicePrincipal -Subscription $env:subscriptionId -Tenant $env:spnTenantId -Credential $azureAppCred -$storageKey = Get-AzStorageAccountKey -Name $env:stagingStorageAccountName -ResourceGroup $env:resourceGroup -$saName = $env:stagingStorageAccountName -Invoke-Command -VMName $SDNConfig.HostList[0] -Credential $adcred -ScriptBlock { - Set-ClusterQuorum -Cluster "hciboxcluster" -CloudWitness -AccountName $using:saName -AccessKey $using:storageKey[0].value -} - -# Install Az CLI and extensions on each node -Invoke-Command -VMName $SDNConfig.HostList -Credential $adcred -ScriptBlock { - Write-Verbose "Installing Az CLI" - $ProgressPreference = "SilentlyContinue" - Invoke-WebRequest -Uri https://aka.ms/installazurecliwindowsx64 -OutFile .\AzureCLI.msi; - Start-Process msiexec.exe -Wait -ArgumentList '/I AzureCLI.msi /quiet'; - Start-Sleep -Seconds 30 - $ProgressPreference = "Continue" -} - -Stop-Transcript \ No newline at end of file diff --git a/azure_jumpstart_hcibox/artifacts/SDN/CertHelpers.ps1 b/azure_jumpstart_hcibox/artifacts/SDN/CertHelpers.ps1 deleted file mode 100644 index 94e0acb7cb..0000000000 --- a/azure_jumpstart_hcibox/artifacts/SDN/CertHelpers.ps1 +++ /dev/null @@ -1,167 +0,0 @@ -# -------------------------------------------------------------- -# Copyright � Microsoft Corporation. All Rights Reserved. -# Microsoft Corporation (or based on where you live, one of its affiliates) licenses this sample code for your internal testing purposes only. -# Microsoft provides the following sample code AS IS without warranty of any kind. The sample code arenot supported under any Microsoft standard support program or services. -# Microsoft further disclaims all implied warranties including, without limitation, any implied warranties of merchantability or of fitness for a particular purpose. -# The entire risk arising out of the use or performance of the sample code remains with you. -# In no event shall Microsoft, its authors, or anyone else involved in the creation, production, or delivery of the code be liable for any damages whatsoever -# (including, without limitation, damages for loss of business profits, business interruption, loss of business information, or other pecuniary loss) -# arising out of the use of or inability to use the sample code, even if Microsoft has been advised of the possibility of such damages. -# --------------------------------------------------------------- - - -Function PrettyTime() { - return "[" + (Get-Date -Format o) + "]" -} -Function Log($msg) { - Write-Verbose $( $(PrettyTime) + " " + $msg) -Verbose -} - -function GetSubjectName([bool] $UseManagementAddress) { - if ($UseManagementAddress -eq $true) - { - # When IP Address is specified, we are currently looking just for IPv4 corpnet ip address - # In the final design, only computer names will be used for subject names - $corpIPAddresses = get-netIpAddress -AddressFamily IPv4 -PrefixOrigin Dhcp -ErrorAction Ignore - if ($corpIPAddresses -ne $null -and $corpIPAddresses[0] -ne $null) - { - $mesg = [System.String]::Format("Using IP Address {0} for certificate subject name", $corpIPAddresses[0].IPAddress); - Log $mesg - return $corpIPAddresses[0].IPAddress - } - else - { - Log "Unable to find management IP address "; - } - } - - $hostFqdn = [System.Net.Dns]::GetHostByName(($env:computerName)).HostName; - $mesg = [System.String]::Format("Using computer name {0} for certificate subject name", $hostFqdn); - Log $mesg - return $hostFqdn ; -} -function GenerateSelfSignedCertificate([string] $subjectName) { - $cryptographicProviderName = "Microsoft Base Cryptographic Provider v1.0"; - [int] $privateKeyLength = 1024; - $sslServerOidString = "1.3.6.1.5.5.7.3.1"; - $sslClientOidString = "1.3.6.1.5.5.7.3.2"; - [int] $validityPeriodInYear = 5; - - $name = new-object -com "X509Enrollment.CX500DistinguishedName.1" - $name.Encode("CN=" + $SubjectName, 0) - - $mesg = [System.String]::Format("Generating certificate with subject Name {0}", $subjectName); - Log $mesg - - - #Generate Key - $key = new-object -com "X509Enrollment.CX509PrivateKey.1" - $key.ProviderName = $cryptographicProviderName - $key.KeySpec = 1 #X509KeySpec.XCN_AT_KEYEXCHANGE - $key.Length = $privateKeyLength - $key.MachineContext = 1 - $key.ExportPolicy = 0x2 #X509PrivateKeyExportFlags.XCN_NCRYPT_ALLOW_EXPORT_FLAG - $key.Create() - - #Configure Eku - $serverauthoid = new-object -com "X509Enrollment.CObjectId.1" - $serverauthoid.InitializeFromValue($sslServerOidString) - $clientauthoid = new-object -com "X509Enrollment.CObjectId.1" - $clientauthoid.InitializeFromValue($sslClientOidString) - $ekuoids = new-object -com "X509Enrollment.CObjectIds.1" - $ekuoids.add($serverauthoid) - $ekuoids.add($clientauthoid) - $ekuext = new-object -com "X509Enrollment.CX509ExtensionEnhancedKeyUsage.1" - $ekuext.InitializeEncode($ekuoids) - - # Set the hash algorithm to sha512 instead of the default sha1 - $hashAlgorithmObject = New-Object -ComObject X509Enrollment.CObjectId - $hashAlgorithmObject.InitializeFromAlgorithmName( $ObjectIdGroupId.XCN_CRYPT_HASH_ALG_OID_GROUP_ID, $ObjectIdPublicKeyFlags.XCN_CRYPT_OID_INFO_PUBKEY_ANY, $AlgorithmFlags.AlgorithmFlagsNone, "SHA512") - - - #Request Cert - $cert = new-object -com "X509Enrollment.CX509CertificateRequestCertificate.1" - - $cert.InitializeFromPrivateKey(2, $key, "") - $cert.Subject = $name - $cert.Issuer = $cert.Subject - $cert.NotBefore = (get-date).ToUniversalTime() - $cert.NotAfter = $cert.NotBefore.AddYears($validityPeriodInYear); - $cert.X509Extensions.Add($ekuext) - $cert.HashAlgorithm = $hashAlgorithmObject - $cert.Encode() - - $enrollment = new-object -com "X509Enrollment.CX509Enrollment.1" - $enrollment.InitializeFromRequest($cert) - $certdata = $enrollment.CreateRequest(0) - $enrollment.InstallResponse(2, $certdata, 0, "") - - Log "Successfully added cert to local machine store"; -} -function GivePermissionToNetworkService($targetCert) { - $targetCertPrivKey = $targetCert.PrivateKey - $privKeyCertFile = Get-Item -path "$ENV:ProgramData\Microsoft\Crypto\RSA\MachineKeys\*" | where {$_.Name -eq $targetCertPrivKey.CspKeyContainerInfo.UniqueKeyContainerName} - $privKeyAcl = Get-Acl $privKeyCertFile - $permission = "NT AUTHORITY\NETWORK SERVICE","Read","Allow" - $accessRule = new-object System.Security.AccessControl.FileSystemAccessRule $permission - $privKeyAcl.AddAccessRule($accessRule) - Set-Acl $privKeyCertFile.FullName $privKeyAcl -} -Function AddCertToLocalMachineStore($certFullPath, $storeName, $securePassword) { - $rootName = "LocalMachine" - - # create a representation of the certificate file - $certificate = new-object System.Security.Cryptography.X509Certificates.X509Certificate2 - if($securePassword -eq $null) - { - $certificate.import($certFullPath) - } - else - { - # https://msdn.microsoft.com/library/system.security.cryptography.x509certificates.x509keystorageflags(v=vs.110).aspx - $certificate.import($certFullPath, $securePassword, "MachineKeySet,PersistKeySet") - } - - # import into the store - $store = new-object System.Security.Cryptography.X509Certificates.X509Store($storeName, $rootName) - $store.open("MaxAllowed") - $store.add($certificate) - $store.close() -} -Function GetSubjectFqdnFromCertificatePath($certFullPath) { - # create a representation of the certificate file - $certificate = new-object System.Security.Cryptography.X509Certificates.X509Certificate2 - $certificate.import($certFullPath) - return GetSubjectFqdnFromCertificate $certificate ; -} -Function GetSubjectFqdnFromCertificate([System.Security.Cryptography.X509Certificates.X509Certificate2] $certificate) { - $mesg = [System.String]::Format("Parsing Subject Name {0} to get Subject Fqdn ", $certificate.Subject) - Log $mesg - $subjectFqdn = $certificate.Subject.Split('=')[1] ; - return $subjectFqdn; -} -Function GetCertificate($cn, [bool]$generateCert=$false) { - $cert = get-childitem "Cert:\localmachine\my" | where {$_.Subject.ToUpper().StartsWith("CN=$cn")} - - if (($generateCert -eq $true) -and ($cert -eq $null)) { - $mesg = [System.String]::Format("Generating Certificate..."); - Log $mesg - GenerateSelfSignedCertificate $cn - $cert = Get-ChildItem -Path Cert:\LocalMachine\My | Where {$_.Subject.ToUpper().StartsWith("CN=$cn")} - } - - # adding check for cert - if ($cert -eq $null) { - $mesg = [System.String]::Format("Certificate was null, waiting 30 secs and retrying, CN= {0}", $cn); - Log $mesg - Sleep 30 - $cert = get-childitem "Cert:\localmachine\my" | where {$_.Subject.ToUpper().StartsWith("CN=$cn")} - - #last chance - if ($cert -eq $null) { - throw "Certificate not available..." - } - } - return $cert; -} - diff --git a/azure_jumpstart_hcibox/artifacts/SDN/NetworkControllerRESTWrappers.ps1 b/azure_jumpstart_hcibox/artifacts/SDN/NetworkControllerRESTWrappers.ps1 deleted file mode 100644 index 7dc2053674..0000000000 --- a/azure_jumpstart_hcibox/artifacts/SDN/NetworkControllerRESTWrappers.ps1 +++ /dev/null @@ -1,2620 +0,0 @@ -# -------------------------------------------------------------- -# Copyright © Microsoft Corporation. All Rights Reserved. -# Microsoft Corporation (or based on where you live, one of its affiliates) licenses this sample code for your internal testing purposes only. -# Microsoft provides the following sample code AS IS without warranty of any kind. The sample code arenot supported under any Microsoft standard support program or services. -# Microsoft further disclaims all implied warranties including, without limitation, any implied warranties of merchantability or of fitness for a particular purpose. -# The entire risk arising out of the use or performance of the sample code remains with you. -# In no event shall Microsoft, its authors, or anyone else involved in the creation, production, or delivery of the code be liable for any damages whatsoever -# (including, without limitation, damages for loss of business profits, business interruption, loss of business information, or other pecuniary loss) -# arising out of the use of or inability to use the sample code, even if Microsoft has been advised of the possibility of such damages. -# --------------------------------------------------------------- -[cmdletbinding()] -Param( - [Parameter(mandatory=$false)] - [String] $ComputerName=$null, - [Parameter(mandatory=$false)] - [String] $Username=$null, - [Parameter(mandatory=$false)] - [String] $Password=$null, - [Parameter(mandatory=$false)] - [PSCredential] $Credential=[System.Management.Automation.PSCredential]::Empty - ) - -$script:urlroot = "https://" -#region Private script variables -$script:NetworkControllerRestIP = $ComputerName -if (![String]::isnullorempty($Username)) { - $securepass = convertto-securestring $Password -asplaintext -force - $script:NetworkControllerCred = new-object -typename System.Management.Automation.PSCredential -argumentlist $Username,$securepass -} else { - $script:NetworkControllerCred = $Credential -} -#endregion - -#region some IPv4 address related helper functions - -function Convert-IPv4StringToInt { - param([string] $addr) - - $ip = $null - $valid = [System.Net.IPAddress]::TryParse($addr, [ref]$ip) - if (!$valid -or $ip.AddressFamily -ne [System.Net.Sockets.AddressFamily]::InterNetwork) { - throw "$addr is not a valid IPv4 address." - } - - $sp = $addr.Split(".", 4) - $bits = [System.Convert]::ToInt64($sp[0]) - $bits = $bits -shl 8 - $bits += [System.Convert]::ToInt64($sp[1]) - $bits = $bits -shl 8 - $bits += [System.Convert]::ToInt64($sp[2]) - $bits = $bits -shl 8 - $bits += [System.Convert]::ToInt64($sp[3]) - - $bits -} - -function Convert-IPv4IntToString { - param([Int64] $addr) - - "{0}.{1}.{2}.{3}" -f (($addr -shr 24) -band 0xff), (($addr -shr 16) -band 0xff), (($addr -shr 8) -band 0xff), ($addr -band 0xff ) - -} - -function IsIpPoolRangeValid { - param( - [Parameter(Mandatory=$true)][string]$startIp, - [Parameter(Mandatory=$true)][string]$endIp - ) - - $startIpInt = Convert-IPv4StringToInt -addr $startIp - $endIpInt = Convert-IPv4StringToInt -addr $endIp - - if( $startIpInt -gt $endIpInt) { - return $false - } - - return $true -} - -function IsIpWithinPoolRange { - param( - [Parameter(Mandatory=$true)][string]$targetIp, - [Parameter(Mandatory=$true)][string]$startIp, - [Parameter(Mandatory=$true)][string]$endIp - ) - - $startIpInt = Convert-IPv4StringToInt -addr $startIp - $endIpInt = Convert-IPv4StringToInt -addr $endIp - $targetIpInt = Convert-IPv4StringToInt -addr $targetIp - - if (($targetIpInt -ge $startIpInt) -and ($targetIpInt -le $endIpInt)) { - return $true - } - - return $false -} - -#endregion - -#region Invoke command wrapper -function Invoke-CommandVerify -{ - param ( - [Parameter(mandatory=$true)] - [ValidateNotNullOrEmpty()][string[]]$ComputerName, - [Parameter(mandatory=$true)] - [ValidateNotNullOrEmpty()][PSCredential]$Credential, - [Parameter(mandatory=$true)] - [ValidateNotNullOrEmpty()][ScriptBlock]$ScriptBlock, - [Parameter(mandatory=$false)] - [Object[]]$ArgumentList = $null, - [Parameter(mandatory=$false)] - [int]$RetryCount = 3 - ) - - # find number of targets - $numberTargets = $ComputerName.Count - - if ($numberTargets -eq 0) - { - throw "Please specify >= 1 target" - } - - do - { - # create sessions - $sessions = New-PSSession -ComputerName $ComputerName -Credential $Credential -ErrorAction Ignore - - # ensure number of sessions match target number - if ($sessions.Count -eq $numberTargets) - { - $readyActive = 0 - # ensure that all the sessions are active - foreach ($session in $sessions) - { - if ( ($session.State -eq "Opened") -and ($session.Availability -eq "Available") ) - { - $readyActive ++ - } - else - { - Write-Verbose "Session: $($session.Name) is $($session.State) and $($session.Availability)" - } - } - - if ($readyActive -eq $numberTargets) - { - Write-Verbose "All sessions are active and ready for $($ComputerName)" - break - } - } - else - { - Write-Verbose "Different number of Session: $($sessions.Count) and $($numberTargets)" - } - - # close any active sessions - Write-Verbose "Not all sessions are active and ready for $($ComputerName), retrying $($RetryCount)" - if ($sessions) - { - $sessions | Remove-PSSession -ErrorAction Ignore - } - $RetryCount -- - $session = $null - Sleep 10 - } while ($RetryCount -gt 0) - - if ($sessions -eq $null) - { - Write-Verbose "Cannot establish all PS sessions for $($ComputerName)" - throw "Cannot establish all PS sessions for $($ComputerName)" - } - - Write-Verbose "Invoking command" - if ($ArgumentList) - { - $returnObject = Invoke-Command -Session $sessions -Argumentlist $ArgumentList -ScriptBlock $ScriptBlock - } - else { - $returnObject = Invoke-Command -Session $sessions -ScriptBlock $ScriptBlock - } - - Write-Verbose "Closing all sessions" - $sessions | Remove-PSSession -ErrorAction Ignore - - return $returnObject -} - -#endregion - -#region Private JSON helper functions - -function Invoke-WebRequestWithRetries { - param( - [System.Collections.IDictionary] $Headers, - [string] $ContentType, - [Microsoft.PowerShell.Commands.WebRequestMethod] $Method, - [System.Uri] $Uri, - [object] $Body, - [Switch] $DisableKeepAlive, - [Switch] $UseBasicParsing, - [System.Management.Automation.PSCredential] $Credential, - [System.Management.Automation.Runspaces.PSSession] $RemoteSession, - [Parameter(mandatory=$false)] - [bool] $shouldRetry = $true - ) - - $params = @{ - 'Headers'=$headers; - 'ContentType'=$content; - 'Method'=$method; - 'uri'=$uri - } - - if($Body -ne $null) { - $params.Add('Body', $Body) - } - if($DisableKeepAlive.IsPresent) { - $params.Add('DisableKeepAlive', $true) - } - if($UseBasicParsing.IsPresent) { - $params.Add('UseBasicParsing', $true) - } - if($Credential -ne [System.Management.Automation.PSCredential]::Empty -and $Credential -ne $null) { - $params.Add('Credential', $Credential) - } - - $retryIntervalInSeconds = 30 - $maxRetry = 6 - $retryCounter = 0 - - do { - try { - if($RemoteSession -eq $null) { - $result = Invoke-WebRequest @params - } - else { - $result = Invoke-Command -Session $RemoteSession -ScriptBlock { - Invoke-WebRequest @using:params - } - } - break - } - catch { - Write-Verbose "Invoke-WebRequestWithRetries: $($Method) Exception: $_" - Write-Verbose "Invoke-WebRequestWithRetries: $($Method) Exception: $($_.Exception.Response)" - - if ($_.Exception.Response.statuscode -eq "NotFound") { - return $null - } - - $retryCounter++ - if($retryCounter -le $maxRetry) { - - Write-verbose "Invoke-WebRequestWithRetries: retry this operation in $($retryIntervalInSeconds) seconds. Retry count: $($retryCounter)." - sleep -Seconds $retryIntervalInSeconds - } - else { - # last retry still fails, so throw the exception - throw $_ - } - } - } while ($shouldRetry -and ($retryCounter -le $maxRetry)) - - return $result -} - -function JSONPost { - param( - [Parameter(position=0,mandatory=$true,ParameterSetName="WithCreds")] - [String] $NetworkControllerRestIP=$script:NetworkControllerRestIP, - [Parameter(position=1,mandatory=$true,ParameterSetName="WithCreds")] - [Parameter(position=0,mandatory=$true,ParameterSetName="CachedCreds")] - [String] $path, #starts with object, does not include server, i.e. "/Credentials" - [Parameter(position=2,mandatory=$true,ParameterSetName="WithCreds")] - [Parameter(position=1,mandatory=$true,ParameterSetName="CachedCreds")] - [Object] $bodyObject, - [Parameter(position=3,mandatory=$true,ParameterSetName="WithCreds")] - [Object] $credential=$script:NetworkControllerCred, - [Parameter(position=4,mandatory=$false,ParameterSetName="WithCreds")] - [String] $computerName=$null - ) - - if ($NetworkControllerRestIP -eq "") - { - write-error "Network controller REST IP not specified. You must first call Set-NCConnection." - return - } - - $headers = @{"Accept"="application/json"} - $content = "application/json; charset=UTF-8" - $uriRoot = "$($script:urlroot)$NetworkControllerRestIP/Networking/v1" - $timeout = 10 - - $method = "Put" - $uri = "$uriRoot$path/$($bodyObject.resourceId)" - $body = convertto-json $bodyObject -Depth 100 - $pssession = $null - - Write-Verbose "JSON Put [$path]" - if ($path -notlike '/Credentials*') { - Write-Verbose "Payload follows:" - Write-Verbose $body - } - - try { - # $computerName is here to workaround product limitation for PUT of LoadBalancer, which is > 35KB and must be done from the REST hosting NC Vm. - if (-not $computerName) { - if ($credential -eq [System.Management.Automation.PSCredential]::Empty -or $credential -eq $null) { - Invoke-WebRequestWithRetries -Headers $headers -ContentType $content -Method $method -Uri $uri -Body $body -DisableKeepAlive -UseBasicParsing | out-null - } else { - Invoke-WebRequestWithRetries -Headers $headers -ContentType $content -Method $method -Uri $uri -Body $body -DisableKeepAlive -UseBasicParsing -Credential $credential | out-null - } - } - else { - $pssession = new-pssession -ComputerName $computerName -Credential $credential - Invoke-WebRequestWithRetries -Headers $headers -ContentType $content -Method $method -Uri $uri -Body $body -DisableKeepAlive -UseBasicParsing -Credential $credential -RemoteSession $pssession | out-null - } - } - catch { - Write-Verbose "PUT Exception: $_" - Write-Verbose "PUT Exception: $($_.Exception.Response)" - } - finally { - if($pssession -ne $null) - { - Remove-PSSession $pssession - } - } -} - -function JSONGet { - param( - [Parameter(mandatory=$true)] - [String] $NetworkControllerRestIP, - [Parameter(mandatory=$true)] - [String] $path, #starts with object and may include resourceid, does not include server, i.e. "/Credentials" or "/Credentials/{1234- - [Parameter(mandatory=$false)] - [Switch] $WaitForUpdate, - [Switch] $Silent, - [PSCredential] $credential - ) - - if ($NetworkControllerRestIP -eq "") - { - write-error "Network controller REST IP not specified. You must first call Set-NCConnection." - return - } - - $headers = @{"Accept"="application/json"} - $content = "application/json; charset=UTF-8" - $uriRoot = "$($script:urlroot)$NetworkControllerRestIP/Networking/v1" - - $method = "Get" - $uri = "$uriRoot$path" - - if (!$Silent) { - Write-Verbose "JSON Get [$path]" - } - - try { - $NotFinished = $true - do { - if ($credential -eq [System.Management.Automation.PSCredential]::Empty -or $credential -eq $null) { - $result = Invoke-WebRequestWithRetries -Headers $headers -ContentType $content -Method $method -Uri $uri -DisableKeepAlive -UseBasicParsing - } else { - $result = Invoke-WebRequestWithRetries -Headers $headers -ContentType $content -Method $method -Uri $uri -DisableKeepAlive -UseBasicParsing -Credential $credential - } - - if($result -eq $null) { - return $null - } - - #Write-Verbose "JSON Result: $result" - $toplevel = convertfrom-json $result.Content - if ($toplevel.value -eq $null) - { - $obj = $toplevel - } else { - $obj = $toplevel.value - } - - if ($WaitForUpdate.IsPresent) { - if ($obj.properties.provisioningState -eq "Updating") - { - Write-Verbose "JSONGet: the object's provisioningState is Updating. Wait 1 second and check again." - sleep 1 #then retry - } - else - { - $NotFinished = $false - } - } - else - { - $notFinished = $false - } - } while ($NotFinished) - - if ($obj.properties.provisioningState -eq "Failed") { - write-error ("Provisioning failed: {0}`nReturned Object: {1}`nObject properties: {2}" -f $uri, $obj, $obj.properties) - } - return $obj - } - catch - { - if (!$Silent) - { - Write-Verbose "GET Exception: $_" - Write-Verbose "GET Exception: $($_.Exception.Response)" - } - return $null - } -} - -function JSONDelete { - param( - [String] $NetworkControllerRestIP, - [String] $path, - [Parameter(mandatory=$false)] - [Switch] $WaitForUpdate, - [PSCredential] $credential - ) - if ($NetworkControllerRestIP -eq "") - { - write-error "Network controller REST IP not specified. You must first call Set-NCConnection." - return - } - - $headers = @{"Accept"="application/json"} - $content = "application/json; charset=UTF-8" - $uriRoot = "$($script:urlroot)$NetworkControllerRestIP/Networking/v1" - - $method = "Delete" - $uri = "$uriRoot$path" - - Write-Verbose "JSON Delete [$path]" - try { - if ($credential -eq [System.Management.Automation.PSCredential]::Empty -or $credential -eq $null) { - Invoke-WebRequestWithRetries -Headers $headers -ContentType $content -Method $method -Uri $uri -DisableKeepAlive -UseBasicParsing - } else { - Invoke-WebRequestWithRetries -Headers $headers -ContentType $content -Method $method -Uri $uri -DisableKeepAlive -UseBasicParsing -Credential $credential - } - } - catch { - Write-Verbose "PUT Exception: $_" - Write-Verbose "PUT Exception: $($_.Exception.Response)" - } - - $maxRecheck = 100 - $currentCheck = 0 - if ($WaitForUpdate.IsPresent) { - try { - $NotFinished = $true - do { - if ($credential -eq [System.Management.Automation.PSCredential]::Empty -or $credential -eq $null) { - $result = Invoke-WebRequestWithRetries -Headers $headers -ContentType $content -Method "GET" -Uri $uri -DisableKeepAlive -UseBasicParsing - } - else { - $result = Invoke-WebRequestWithRetries -Headers $headers -ContentType $content -Method "GET" -Uri $uri -DisableKeepAlive -UseBasicParsing -Credential $credential - } - - if($result -ne $null) { - Write-Verbose "Object still exists, check again in 1 second" - sleep 1 #then retry - $currentCheck++ - } - else { - break - } - } while ($currentCheck -lt $maxRecheck) - } - catch { - if ($_.Exception.Response.statuscode -eq "NotFound") { - return - } - Write-Verbose "GET Exception: $_" - Write-Verbose "GET Exception: $($_.Exception.Response)" - } - } -} - -#endregion - -function Get-NCNetworkInterfaceResourceId -{ - param( - [Parameter(mandatory=$true)] - [String] $InstanceId - ) - if (([String]::IsNullOrEmpty($InstanceId)) -or ($InstanceId -eq "") -or ($InstanceId -eq [System.Guid]::Empty)) { - write-verbose ("Instance id ($InstanceId) either null or empty string or empty guid") - return $InstanceId - } - - write-verbose ("Searching resourceId for instance id [$InstanceId]." ) - - try - { - $interfaces = JSONGet $script:NetworkControllerRestIP "/networkinterfaces" -Credential $script:NetworkControllerCred - - if ($interfaces -ne $null) - { - foreach ($interface in $interfaces) - { - if ($interface.instanceId -eq $InstanceId) - { - return $interface.resourceId - } - } - } - } - catch - { - Write-Error "Failed with error: $_" - } - - return $null -} - -function Get-NCNetworkInterfaceInstanceId -{ - param( - [Parameter(mandatory=$true)] - [String] $ResourceId - ) - if (([String]::IsNullOrEmpty($ResourceId)) -or ($ResourceId -eq "") -or ($ResourceId -eq [System.Guid]::Empty)) { - write-verbose ("Resource id ($ResourceId) either null or empty string or empty guid") - return $ResourceId - } - - write-verbose ("Searching Instance Id for Resource Id [$ResourceId]." ) - - try - { - $interfaces = JSONGet $script:NetworkControllerRestIP "/networkinterfaces" -Credential $script:NetworkControllerCred - - if ($interfaces -ne $null) - { - foreach ($interface in $interfaces) - { - if ($interface.resourceId -eq $ResourceId) - { - return $interface.instanceId - } - } - } - } - catch - { - Write-Error "Failed with error: $_" - } - - return $null -} - -function Set-NCConnection -{ - param( - [Parameter(position=0,mandatory=$true,ParameterSetName="Credential")] - [Parameter(position=0,mandatory=$true,ParameterSetName="NoCreds")] - [string] $RestIP, - [Parameter(mandatory=$true,ParameterSetName="Credential")] - [PSCredential] $Credential=[System.Management.Automation.PSCredential]::Empty - ) - - $script:NetworkControllerRestIP = $RestIP - $script:NetworkControllerCred = $Credential -} - -function New-NCLogicalNetwork { - param( - [Parameter(mandatory=$false)] - [string] $ResourceID=[system.guid]::NewGuid(), - [Parameter(mandatory=$false)] - [object[]] $LogicalNetworkSubnets=$null, - [Switch] $EnableNetworkVirtualization - ) - - $LogicalNetwork = @{} - $LogicalNetwork.resourceId = $resourceId - $logicalNetwork.properties = @{} - - if ($LogicalNetworkSubnets -eq $null) - { - $logicalNetwork.properties.subnets = @() - } - else - { - $logicalNetwork.properties.subnets = $LogicalNetworkSubnets - } - - if ($EnableNetworkVirtualization.ispresent) { - $logicalNetwork.properties.networkVirtualizationEnabled = "True" - } else { - $logicalNetwork.properties.networkVirtualizationEnabled = "False" - } - JSONPost $script:NetworkControllerRestIP "/logicalnetworks" $logicalnetwork -Credential $script:NetworkControllerCred | out-null - return JSONGet $script:NetworkControllerRestIP "/logicalnetworks/$resourceID" -WaitForUpdate -Credential $script:NetworkControllerCred - - -} -function Get-NCLogicalNetwork { - param( - [Parameter(mandatory=$false)] - [string] $ResourceID="" - ) - - return JSONGet $script:NetworkControllerRestIP "/logicalnetworks/$ResourceId" -Credential $script:NetworkControllerCred -} -function Remove-NCLogicalNetwork { - param( - [Parameter(mandatory=$true)] - [string[]] $ResourceIDs - ) - foreach ($resourceId in $ResourceIDs) { - JSONDelete $script:NetworkControllerRestIP "/logicalnetworks/$ResourceId" -Waitforupdate -Credential $script:NetworkControllerCred| out-null - } -} - -function Get-NCLogicalNetworkSubnet { - param( - [Parameter(mandatory=$true)] - [object] $LogicalNetwork, - [Parameter(mandatory=$false)] - [string] $ResourceID="" - ) - - if ($resourceId -eq "") { - $uri = "/logicalnetworks/$($LogicalNetwork.ResourceId)/subnets" - } else { - $uri = "/logicalnetworks/$($LogicalNetwork.ResourceId)/subnets/$ResourceId" - } - - return JSONGet $script:NetworkControllerRestIP $uri -Credential $script:NetworkControllerCred -} - -function New-NCLogicalNetworkSubnet { -#Creates an in-memory object only. Must pass it into New-NCLogicalNetwork to persist it. - param( - [Parameter(mandatory=$false)] - [string] $ResourceID=[system.guid]::NewGuid(), - [Parameter(mandatory=$true)] - [string] $AddressPrefix, - [Parameter(mandatory=$false)] - [string[]] $DNSServers = @(), - [Parameter(mandatory=$false)] - [int] $VLANid = 0, - [Parameter(mandatory=$true)] - [string[]] $defaultGateway, - [Switch] $IsPublic - ) - $subnet = @{} - $subnet.resourceId = $ResourceID - $subnet.properties = @{} - $subnet.properties.addressPrefix = $AddressPrefix - $subnet.properties.vlanid = "$vlanid" - if ($dnsservers -ne $null -and $dnsservers.count -gt 0) { - $subnet.properties.dnsServers = $dnsServers - } - $subnet.properties.defaultGateways = $defaultGateway - $subnet.properties.IsPublic = $IsPublic.IsPresent - - return $subnet -} - -function New-NCCredential { - param( - [Parameter(mandatory=$false,parametersetname='username')] - [Parameter(mandatory=$false,parametersetname='cert')] - [Parameter(mandatory=$false,parametersetname='snmp')] - [string] $resourceID=[system.guid]::NewGuid(), - [Parameter(mandatory=$true,parametersetname='username')] - [string] $Username=$null, - [Parameter(mandatory=$true,parametersetname='username')] - [String] $password=$null, - [Parameter(mandatory=$true,parametersetname='snmp')] - [String] $communitystring=$null, - [Parameter(mandatory=$true,parametersetname='cert')] - [string] $Thumbprint - ) - - # create credentials that will be used to talk to host - - $creds = @{} - $creds.resourceID = $resourceID - $creds.properties = @{} - if ($pscmdlet.ParameterSetName -eq 'cert') { - $creds.properties.Type = "X509Certificate" - $creds.properties.Value = $thumbprint - } - elseif ($pscmdlet.ParameterSetName -eq 'username') { - $creds.properties.Type = "UsernamePassword" - $creds.properties.Username = $Username - $creds.properties.Value = $password - } - else { - $creds.properties.Type = "SnmpCommunityString" - $creds.properties.Value = $communitystring - } - - JSONPost $script:NetworkControllerRestIP "/Credentials" $creds -Credential $script:NetworkControllerCred| out-null - return JSONGet $script:NetworkControllerRestIP "/Credentials/$resourceID" -WaitForUpdate -Credential $script:NetworkControllerCred -} - -function Get-NCCredential { - param( - [Parameter(mandatory=$false)] - [string] $resourceID = "" - ) - return JSONGet $script:NetworkControllerRestIP "/Credentials/$resourceID" -Credential $script:NetworkControllerCred -} -function Remove-NCCredential { - param( - [Parameter(mandatory=$true)] - [string[]] $ResourceIDs - ) - foreach ($resourceId in $ResourceIDs) { - JSONDelete $script:NetworkControllerRestIP "/Credentials/$ResourceId" -Waitforupdate -Credential $script:NetworkControllerCred| out-null - } -} - -function New-NCServerConnection { - #Creates an in-memory object only. Must pass it into New-NCServer to persist it. - param( - [Parameter(mandatory=$true)] - [string[]] $ComputerNames, - [Parameter(mandatory=$true)] - [object] $Credential - ) - - $connection = @{} - $connection.managementAddresses = $ComputerNames - $connection.credential = @{} - $connection.credential.resourceRef = "/credentials/$($credential.ResourceID)" - $connection.credentialType = $credential.properties.Type - - return $connection -} - -function New-NCServerNetworkInterface { - param( - [Parameter(mandatory=$false)] - [string] $ResourceID=[system.guid]::NewGuid(), - [Parameter(mandatory=$false)] - [boolean] $IsBMC=$false, - [Parameter(mandatory=$true,ParameterSetName="LogicalSubnet")] - [object[]] $LogicalNetworkSubnets - ) - - $networkInterface = @{} - $networkInterface.resourceId = $ResourceID - $networkInterface.instanceId = $ResourceID - $networkInterface.properties = @{} - $networkInterface.properties.isBMC = $IsBMC - - $networkInterface.properties.logicalSubnets = @() - foreach ($logicalnetworksubnet in $logicalNetworkSubnets) { - $logicalSubnetref = @{} - $logicalSubnetref.resourceRef = $logicalnetworksubnet.resourceRef - $networkInterface.properties.logicalSubnets += $logicalSubnetref - } - - return $networkInterface -} -function New-NCServer { -#Must pass in ResourceID since it must match id of virtual switch - param( - [Parameter(mandatory=$true)] - [string] $ResourceID, - [Parameter(mandatory=$true)] - [object[]] $Connections, - [Parameter(mandatory=$false)] - [string] $Certificate = $null, - [Parameter(mandatory=$true)] - [object[]] $PhysicalNetworkInterfaces - - ) - - $server = @{} - $server.resourceId = $ResourceID - $server.instanceId = $ResourceID - $server.properties = @{} - - $server.properties.connections = $Connections - $server.properties.networkInterfaces = $PhysicalNetworkInterfaces - if ($certificate -ne $null) { - $server.properties.certificate = $certificate - } - - JSONPost $script:NetworkControllerRestIP "/Servers" $server -Credential $script:NetworkControllerCred | out-null - return JSONGet $script:NetworkControllerRestIP "/Servers/$resourceID" -WaitForUpdate -Credential $script:NetworkControllerCred -} -function Get-NCServer { - param( - [Parameter(mandatory=$false)] - [string] $resourceID = "" - ) - return JSONGet $script:NetworkControllerRestIP "/Servers/$resourceID" -Credential $script:NetworkControllerCred -} -function Remove-NCServer { - param( - [Parameter(mandatory=$true)] - [string[]] $ResourceIDs - ) - foreach ($resourceId in $ResourceIDs) { - JSONDelete $script:NetworkControllerRestIP "/Servers/$ResourceId" -Waitforupdate -Credential $script:NetworkControllerCred| out-null - } -} - -function New-NCMACPool { - param( - [Parameter(mandatory=$false)] - [string] $ResourceID=[system.guid]::NewGuid(), - [Parameter(mandatory=$true)] - [string] $StartMACAddress, - [Parameter(mandatory=$true)] - [string] $EndMACAddress - ) - - $macpool = @{} - $macpool.resourceId = $ResourceId - $macpool.properties = @{} - $macpool.properties.startMacAddress = $StartMACAddress - $macpool.properties.endMacAddress = $EndMACAddress - - JSONPost $script:NetworkControllerRestIP "/MacPools" $macPool -Credential $script:NetworkControllerCred | out-null - return JSONGet $script:NetworkControllerRestIP "/MacPools/$resourceID" -WaitForUpdate -Credential $script:NetworkControllerCred -} - -function Get-NCMACPool { - param( - [Parameter(mandatory=$false)] - [string] $resourceID = "" - ) - return JSONGet $script:NetworkControllerRestIP "/MacPools/$resourceID" -Credential $script:NetworkControllerCred -} -function Remove-NCMACPool { - param( - [Parameter(mandatory=$true)] - [string[]] $ResourceIDs - ) - foreach ($resourceId in $ResourceIDs) { - JSONDelete $script:NetworkControllerRestIP "/MacPools/$ResourceId" -Waitforupdate -Credential $script:NetworkControllerCred | out-null - } -} - -function New-NCIPPool { - param( - [Parameter(mandatory=$false)] - [string] $ResourceID=[system.guid]::NewGuid(), - [Parameter(mandatory=$true)] - [object] $LogicalNetworkSubnet, - [Parameter(mandatory=$true)] - [string] $StartIPAddress, - [Parameter(mandatory=$true)] - [string] $EndIPAddress, - [Parameter(mandatory=$false)] - [string[]] $DNSServers, - [Parameter(mandatory=$false)] - [string[]] $DefaultGateways - ) - - #todo: prevalidate that ip addresses and default gateway are within subnet - - $ippool = @{} - $ippool.resourceId = $ResourceId - $ippool.properties = @{} - $ippool.properties.startIpAddress = $StartIPAddress - $ippool.properties.endIpAddress = $EndIPAddress - - $refpath = "$($logicalnetworksubnet.resourceRef)/ippools" - JSONPost $script:NetworkControllerRestIP $refpath $ippool -Credential $script:NetworkControllerCred| out-null - return JSONGet $script:NetworkControllerRestIP "$refpath/$resourceID" -WaitForUpdate -Credential $script:NetworkControllerCred -} -function Get-NCIPPool { - param( - [Parameter(mandatory=$false)] - [string] $resourceID = "", - [Parameter(mandatory=$true)] - [object] $LogicalNetworkSubnet - ) - $refpath = "$($logicalnetworksubnet.resourceRef)/ippools" - return JSONGet $script:NetworkControllerRestIP "$refpath/$resourceID" -Credential $script:NetworkControllerCred -} -function Remove-NCIPPool { - param( - [Parameter(mandatory=$true)] - [string[]] $ResourceIDs, - [Parameter(mandatory=$true)] - [object] $LogicalNetworkSubnet - ) - $refpath = "$($logicalnetworksubnet.resourceRef)/ippools" - foreach ($resourceId in $ResourceIDs) { - JSONDelete $script:NetworkControllerRestIP "$refpath/$ResourceId" -Waitforupdate -Credential $script:NetworkControllerCred | out-null - } -} -function New-NCAccessControlListRule { - param( - [Parameter(mandatory=$false)] - [string] $ResourceID=[system.guid]::NewGuid(), - [Parameter(mandatory=$true)] - [string] $Protocol, - [Parameter(mandatory=$true)] - [string] $SourcePortRange, - [Parameter(mandatory=$true)] - [string] $DestinationPortRange, - [Parameter(mandatory=$true)] - [string] $SourceAddressPrefix, - [Parameter(mandatory=$true)] - [string] $DestinationAddressPrefix, - [Parameter(mandatory=$true)] - [string] $Action, - [Parameter(mandatory=$true)] - [string] $ACLType, - [Parameter(mandatory=$true)] - [boolean] $Logging, - [Parameter(mandatory=$true)] - [int] $Priority - ) - - $aclRule = @{} - $aclRule.resourceId = $resourceId - - $aclRule.properties = @{} - $aclRule.properties.protocol = $protocol - $aclRule.properties.sourcePortRange = $SourcePortRange - $aclRule.properties.destinationPortRange = $Destinationportrange - $aclRule.properties.sourceAddressPrefix = $SourceAddressPrefix - $aclRule.properties.destinationAddressPrefix = $destinationAddressprefix - $aclRule.properties.action = $action - $aclRule.properties.type = $ACLType - if ($logging) { - $aclRule.properties.logging = "Enabled" - } else { - $aclRule.properties.logging = "Disabled" - } - $aclRule.properties.priority = "$priority" - - return $aclRule -} -function New-NCAccessControlList { - param( - [Parameter(mandatory=$false)] - [string] $ResourceID=[system.guid]::NewGuid(), - [Parameter(mandatory=$true)] - [object[]] $AccessControlListRules - ) - - $acls = @{} - $acls.resourceID = $resourceId - $acls.properties = @{} - $acls.properties.aclRules = $AccessControlListRules - - $acls.properties.ipConfigurations = @() - $acls.properties.subnet = @() - - $refpath = "/accessControlLists" - JSONPost $script:NetworkControllerRestIP $refpath $acls -Credential $script:NetworkControllerCred| out-null - return JSONGet $script:NetworkControllerRestIP "$refpath/$resourceID" -WaitForUpdate -Credential $script:NetworkControllerCred -} -function Get-NCAccessControlList { - param( - [Parameter(mandatory=$false)] - [string] $resourceID = "" - ) - return JSONGet $script:NetworkControllerRestIP "/accessControlLists/$resourceID" -Credential $script:NetworkControllerCred -} -function Remove-NCAccessControlList { - param( - [Parameter(mandatory=$true)] - [string[]] $ResourceIDs - ) - foreach ($resourceId in $ResourceIDs) { - JSONDelete $script:NetworkControllerRestIP "/accessControlLists/$ResourceId" -Waitforupdate -Credential $script:NetworkControllerCred | out-null - } -} - -function New-NCVirtualSubnet { - param( - [Parameter(mandatory=$false)] - [string] $ResourceID=[system.guid]::NewGuid(), - [Parameter(mandatory=$true)] - [string] $addressPrefix, - [Parameter(mandatory=$true)] - [object] $AccessControlList - ) - - $subnet = @{} - $subnet.resourceId = $ResourceId - $subnet.properties = @{} - $subnet.properties.addressPrefix = $AddressPrefix - - $subnet.properties.accessControlList = @{} - $subnet.properties.accessControlList.resourceRef = $AccessControlList.resourceRef - - $subnet.properties.ipConfigurations = @() - - return $subnet -} - -function Get-NCVirtualSubnet { - param( - [Parameter(mandatory=$true)] - [object] $VirtualNetwork, - [Parameter(mandatory=$false)] - [string] $ResourceID="" - ) - - if ($resourceId -eq "") { - $uri = "/VirtualNetworks/$($VirtualNetwork.ResourceId)/subnets" - } else { - $uri = "/VirtualNetworks/$($VirtualNetwork.ResourceId)/subnets/$ResourceId" - } - - return JSONGet $script:NetworkControllerRestIP $uri -Credential $script:NetworkControllerCred -} - -function New-NCVirtualNetwork { - param( - [Parameter(mandatory=$false)] - [string] $ResourceID=[system.guid]::NewGuid(), - [Parameter(mandatory=$true)] - [string[]] $addressPrefixes, - [Parameter(mandatory=$true)] - [object] $LogicalNetwork, - [Parameter(mandatory=$true)] - [object[]] $VirtualSubnets - ) - - $vnet = @{} - $vnet.resourceId = $resourceId - $vnet.properties = @{} - $vnet.properties.addressSpace = @{} - $vnet.properties.addressSpace.addressPrefixes = $AddressPrefixes - $vnet.properties.logicalnetwork = @{} - $vnet.properties.logicalnetwork.resourceRef = "/logicalnetworks/$($LogicalNetwork.resourceId)" - $vnet.properties.subnets = $VirtualSubnets - - $refpath = "/virtualnetworks" - JSONPost $script:NetworkControllerRestIP $refpath $vnet -Credential $script:NetworkControllerCred| out-null - return JSONGet $script:NetworkControllerRestIP "$refpath/$resourceID" -WaitForUpdate -Credential $script:NetworkControllerCred - -} -function Get-NCVirtualNetwork { - param( - [Parameter(mandatory=$false)] - [string] $resourceID = "" - ) - return JSONGet $script:NetworkControllerRestIP "/VirtualNetworks/$resourceID" -Credential $script:NetworkControllerCred -} -function Remove-NCVirtualNetwork { - param( - [Parameter(mandatory=$true)] - [string[]] $ResourceIDs - ) - foreach ($resourceId in $ResourceIDs) { - JSONDelete $script:NetworkControllerRestIP "/VirtualNetworks/$ResourceId" -Waitforupdate -Credential $script:NetworkControllerCred | out-null - } -} - -function Set-NCLoadBalancerManager { - param( - [Parameter(mandatory=$false)] - [Object[]] $VIPIPPools=$null, - [Parameter(mandatory=$false)] - [String[]] $OutboundNatIPExemptions=$null, - [Parameter(mandatory=$true)] - [String] $IPAddress - -) - - $LBM = @{} - $lbm.resourceId = "config" - $lbm.properties = @{} - $lbm.properties.loadbalancermanageripaddress = $IPAddress - - if ($VIPIPPools -ne $NULL) { - $lbm.properties.vipIpPools = @() - - foreach ($ippool in $VIPIPPools) { - $poolRef = @{} - $poolRef.resourceRef = $ippool.resourceRef - $lbm.properties.vipIpPools += $poolRef - } - } - - if ($OutboundNatIPExemptions -ne $null) { - $lbm.properties.OutboundNatIPExemptions = $OutboundNatIPExemptions - } - - JSONPost $script:NetworkControllerRestIP "/loadbalancermanager" $lbm -Credential $script:NetworkControllerCred| out-null - return JSONGet $script:NetworkControllerRestIP "/loadbalancermanager/config" -WaitForUpdate -Credential $script:NetworkControllerCred - - -} -function Get-NCLoadbalancerManager { - - return JSONGet $script:NetworkControllerRestIP "/LoadBalancerManager/Config" -Credential $script:NetworkControllerCred -} - -function New-NCVirtualServer { - param( - [Parameter(mandatory=$false)] - [string] $resourceID=[system.guid]::NewGuid(), - [Parameter(mandatory=$true)] - [object[]] $Connections, - [Parameter(mandatory=$false)] - [string] $Certificate, - [Parameter(mandatory=$true)] - [string] $vmGuid - ) - - $server = @{} - $server.resourceId = $ResourceID - if ($ResourceID.Length -lt 36) - { $server.instanceId = [system.guid]::NewGuid() } - else - { $server.instanceId = $ResourceID } - $server.properties = @{} - - $server.properties.connections = $Connections - if (![string]::IsNullOrEmpty($Certificate)) - { - $server.properties.certificate = $certificate - } - $server.properties.vmGuid = $vmGuid - - JSONPost $script:NetworkControllerRestIP "/VirtualServers" $server -Credential $script:NetworkControllerCred | out-null - return JSONGet $script:NetworkControllerRestIP "/VirtualServers/$resourceID" -WaitForUpdate -Credential $script:NetworkControllerCred - -} -function Get-NCVirtualServer { - param( - [Parameter(mandatory=$false)] - [string] $resourceID = "" - ) - return JSONGet $script:NetworkControllerRestIP "/VirtualServers/$resourceID" -Credential $script:NetworkControllerCred -} -function Remove-NCVirtualServer { - param( - [Parameter(mandatory=$true)] - [string[]] $ResourceIDs - ) - foreach ($resourceId in $ResourceIDs) { - JSONDelete $script:NetworkControllerRestIP "/VirtualServers/$ResourceId" -Waitforupdate -Credential $script:NetworkControllerCred| out-null - } -} - -function New-NCLoadBalancerMuxPeerRouterConfiguration { - param( - [Parameter(mandatory=$true)] - [string] $RouterName, - [Parameter(mandatory=$true)] - [string] $RouterIPAddress, - [Parameter(mandatory=$true)] - [int] $PeerASN, - [Parameter(mandatory=$false)] - [string] $LocalIPAddress - ) - - $peer = @{} - $peer.routerName = $RouterName - $peer.routerIPAddress = $RouterIPAddress - $peer.PeerASN = "$PeerASN" - $peer.localIPAddress = $LocalIPAddress - - return $peer -} -function New-NCLoadBalancerMux { - param( - [Parameter(mandatory=$false)] - [string] $resourceID=[system.guid]::NewGuid(), - [Parameter(mandatory=$true)] - [int] $LocalASN, - [Parameter(mandatory=$false)] - [object[]] $peerRouterConfigurations, - [Parameter(mandatory=$true)] - [object] $VirtualServer, - [Parameter(mandatory=$false)] - [object[]] $connections - - ) - - # create credentials that will be used to talk to host - - $mux = @{} - $mux.resourceID = $resourceID - $mux.properties = @{} - $mux.properties.routerConfiguration = @{} - $mux.properties.routerConfiguration.localASN = "$LocalASN" - $mux.properties.routerConfiguration.peerRouterConfigurations = @() - foreach ($peerRouterConfiguration in $peerRouterConfigurations) - { - $mux.properties.routerConfiguration.peerRouterConfigurations += $peerRouterConfiguration - } - $mux.properties.virtualServer = @{} - $mux.properties.virtualServer.resourceRef = $VirtualServer.resourceRef - - JSONPost $script:NetworkControllerRestIP "/LoadBalancerMuxes" $mux -Credential $script:NetworkControllerCred| out-null - return JSONGet $script:NetworkControllerRestIP "/LoadBalancerMuxes/$resourceID" -WaitForUpdate -Credential $script:NetworkControllerCred -} -function Get-NCLoadBalancerMux { - param( - [Parameter(mandatory=$false)] - [string] $resourceID = "" - ) - return JSONGet $script:NetworkControllerRestIP "/LoadBalancerMuxes/$resourceID" -Credential $script:NetworkControllerCred -} -function Remove-NCLoadBalancerMux { - param( - [Parameter(mandatory=$true)] - [string[]] $ResourceIDs - ) - foreach ($resourceId in $ResourceIDs) { - JSONDelete $script:NetworkControllerRestIP "/LoadBalancerMuxes/$ResourceId" -Waitforupdate -Credential $script:NetworkControllerCred| out-null - } -} - -function New-NCLoadBalancerFrontEndIPConfiguration { - param( - [Parameter(mandatory=$false)] - [string] $resourceID=[system.guid]::NewGuid(), - #[Parameter(mandatory=$true)] - #[object] $LoadBalancer, - [Parameter(mandatory=$true)] - [string] $PrivateIPAddress, - #[Parameter(mandatory=$true)] - #[object[]] $LoadBalancingRules, - [Parameter(mandatory=$true)] - [object] $Subnet - ) - - $frontend= @{} - $frontend.resourceID = $resourceID - $frontend.properties = @{} - $frontend.properties.privateIPAddress = $PrivateIPAddress - $frontend.properties.privateIPAllocationMethod = "Static" - $frontend.properties.Subnet = @{} - $frontend.properties.Subnet.resourceRef = $subnet.resourceRef - - return $frontend -} - -function New-NCLoadBalancerBackendAddressPool { - param( - [Parameter(mandatory=$false)] - [string] $resourceID=[system.guid]::NewGuid() - ) - - $be= @{} - $be.resourceID = $resourceID - $be.properties = @{} - - $be.properties.backendIPConfigurations = @() - return $be -} -function New-NCLoadBalancerLoadBalancingRule { - param( - [Parameter(mandatory=$false)] - [string] $resourceID=[system.guid]::NewGuid(), - [Parameter(mandatory=$true)] - [string] $protocol, - [Parameter(mandatory=$true)] - [int] $frontendPort, - [Parameter(mandatory=$true)] - [int] $backendPort, - [Parameter(mandatory=$true)] - [boolean] $enableFloatingIP, - [Parameter(mandatory=$false)] - [int] $IdleTimeoutInMinutes = 4, - [Parameter(mandatory=$false)] - [String] $LoadDistribution = "Default", - [Parameter(mandatory=$true)] - [object[]] $frontEndIPConfigurations = $null, - [Parameter(mandatory=$true)] - [object] $backendAddressPool - ) - - $rule= @{} - $rule.resourceID = $resourceID - $rule.properties = @{} - $rule.properties.protocol = $protocol - $rule.properties.frontEndPort = "$frontendPort" - $rule.properties.backendPort = "$backendPort" - - if ($enableFloatingIP) { - $rule.properties.enableFloatingIP = "true" - } else { - $rule.properties.enableFloatingIP = "false" - } - $rule.properties.idleTimeoutInMinutes = "$idleTImeoutInMinutes" - $rule.properties.loadDistribution = $LoadDistribution - - $rule.properties.frontendIPConfigurations = @() - - foreach ($vip in $frontendipconfigurations) { - $newvip = @{} - $newvip.resourceRef = "/loadbalancers/`{0`}/frontendipconfigurations/$($vip.resourceId)" - $rule.properties.frontendIPConfigurations += $newvip - } - $rule.properties.backendAddressPool = @{} - $rule.properties.backendAddressPool.resourceRef = "/loadbalancers/`{0`}/backendaddresspools/$($backendAddressPool.resourceID)" - - return $rule -} - -function New-NCLoadBalancerProbe { - param( - [Parameter(mandatory=$false)] - [string] $resourceID=[system.guid]::NewGuid(), - [Parameter(mandatory=$true)] - [object] $LoadBalancer, - [Parameter(mandatory=$true)] - [string] $protocol, - [Parameter(mandatory=$true)] - [int] $port, - [Parameter(mandatory=$true)] - [int] $intervalInSeconds, - [Parameter(mandatory=$true)] - [int] $numberOfProbes, - [Parameter(mandatory=$false)] - [object[]] $loadBalancingRules = $null - ) - - $probe= @{} - $probe.resourceID = $resourceID - $probe.properties = @{} - $probe.properties.protocol = $protocol - $probe.properties.port = "$port" - $probe.properties.intervalInSeconds= "$intervalInSeconds" - $probe.properties.numberOfProbes = "$numberOfProbes" - - #TODO: what to do with loadbalancingrules - - $refpath = "$($loadbalancer.resourceRef)/probes" - JSONPost $script:NetworkControllerRestIP $refpath $probe -Credential $script:NetworkControllerCred| out-null - return JSONGet $script:NetworkControllerRestIP "$refpath/$resourceID" -WaitForUpdate -Credential $script:NetworkControllerCred -} -function New-NCLoadBalancerOutboundNatRule { - param( - [Parameter(mandatory=$false)] - [string] $resourceID=[system.guid]::NewGuid(), - [Parameter(mandatory=$false)] - [string] $protocol="All", - [Parameter(mandatory=$true)] - [object[]] $frontEndIpConfigurations, - [Parameter(mandatory=$true)] - [object] $backendAddressPool - ) - - $natrule= @{} - $natrule.resourceID = $resourceID - $natrule.properties = @{} - $natrule.properties.protocol = $protocol - $natrule.properties.frontendIPConfigurations = @() - - foreach ($frontendIP in $frontEndIpConfigurations) { - $NewFEIP = @{} - $NewFEIP.resourceRef = "/loadbalancers/`{0`}/frontendipconfigurations/$($frontendIP.resourceId)" - $natrule.properties.frontendIPConfigurations += $NewFEIP - } - - $natrule.properties.backendAddressPool = @{} - $natrule.properties.backendAddressPool.resourceRef = "/loadbalancers/`{0`}/backendaddresspools/$($backendAddressPool.resourceID)" - - return $natrule -} - -function New-NCLoadBalancer -{ - param( - [Parameter(mandatory=$false)] - [string] $resourceID=[system.guid]::NewGuid(), - [parameter(mandatory=$true)] - [object[]] $FrontEndIPConfigurations, - [parameter(mandatory=$true)] - [object[]] $backendAddressPools, - [parameter(mandatory=$false)] - [object[]] $loadBalancingRules = $NULL, - [parameter(mandatory=$false)] - [object[]] $probes = $NULL, - [parameter(mandatory=$false)] - [object[]] $outboundnatrules= $NULL, - [Parameter(mandatory=$false)] - [string] $ComputerName=$script:NetworkControllerRestIP - ) - - $lb = JSONGet $script:NetworkControllerRestIP "/LoadBalancers/$resourceID" -WaitForUpdate -Credential $script:NetworkControllerCred -Silent:$true - # Note this handles Add updates ONLY for LOAD Balancing RULES (common case in MAS / PoC) - if ($null -ne $lb) - { - # add the obNat, LB Rule, Inbound Rule - - $FrontEndIPConfigurations = @($FrontEndIPConfigurations) - - $lbfeIp = $lb.properties.frontendipconfigurations[0] - - if($null -ne $lbfeIp) - { - $newFeIP = @(New-NCLoadBalancerFrontEndIPConfiguration -resourceID $lbfeIp.resourceid -PrivateIPAddress $lbfeIp.properties.privateIpaddress -Subnet $lbfeIp.properties.subnet) - $FrontEndIPConfigurations = $newFeIp - } - - $lbbepool = $lb.properties.backendaddresspools[0] - - if($null -ne $lbbepool) - { - $newBePool = @(New-NCLoadBalancerBackendAddressPool -resourceID $lbbepool.resourceId) - $backendAddressPools = $newBePool - } - - if ( ($null -ne $lb.properties.OutboundNatRules) -and ($lb.properties.OutboundNatRules.count -ne 0)) - { - $obNatRules =$lb.properties.OutboundNatRules[0] - - $newObNatRule = @(New-NCLoadBalancerOutboundNatRule -resourceID $obNatRules.resourceId -protocol $obNatRules.properties.protocol -frontEndIpConfigurations $FrontEndIPConfigurations -backendAddressPool $backendAddressPools) - $outboundnatrules = $newObNatRule - } - - $loadBalancingRules = @($loadBalancingRules) - $newloadBalancingRules = @() - - foreach ($lbrule in $lb.properties.loadBalancingRules) - { - $newLbRule = @(New-NCLoadBalancerLoadBalancingRule -resourceId $lbrule.resourceId -protocol $lbrule.properties.protocol -frontendPort $lbrule.properties.frontendPort -backendport $lbrule.properties.backendPort -enableFloatingIP $lbrule.properties.enableFloatingIp -frontEndIPConfigurations $FrontEndIPConfigurations -backendAddressPool $backendAddressPools) - $newloadBalancingRules += $newLbRule - } - - $lbRuleCount = $newloadBalancingRules.Count - - #find new unique lb rules - foreach ($lbrule in $loadBalancingRules) - { - $found = $false - foreach ($oldrule in $lb.properties.loadBalancingRules) - { - if(($lbrule.properties.frontendPort -eq $oldrule.properties.frontendPort) -and ($lbrule.properties.backendPort -eq $oldrule.properties.backendPort)) - { - $found = $true - } - } - - if(-not $found) - { - $enableFloat = [Boolean]::Parse("$($lbrule.properties.enableFloatingIp)") - $newLbRule = @(New-NCLoadBalancerLoadBalancingRule -resourceId $lbrule.resourceId -protocol $lbrule.properties.protocol -frontendPort $lbrule.properties.frontendPort -backendport $lbrule.properties.backendPort -enableFloatingIP $enableFloat -frontEndIPConfigurations $FrontEndIPConfigurations -backendAddressPool $backendAddressPools) - $newloadBalancingRules += $newLbRule - } - } - - if($lbRuleCount -eq $newloadBalancingRules.Count) - { - #No change in LB required, skip the update - return $lb - } - - $loadBalancingRules = $newloadBalancingRules - } - else - { - $lb = @{} - $lb.resourceID = $resourceID - $lb.properties = @{} - } - - #Need to populate existing refs with LB resourceID - if ($loadbalancingrules -ne $null) - { - foreach ($rule in $loadbalancingrules) - { - foreach ($frontend in $rule.properties.frontendipconfigurations) - { - $frontend.resourceRef = ($frontend.resourceRef -f $resourceID) - } - $rule.properties.backendaddresspool.resourceRef = ($rule.properties.backendaddresspool.resourceRef -f $resourceID) - } - $lb.properties.loadBalancingRules = $loadbalancingrules - } - - if ($outboundnatrules -ne $null) - { - foreach ($rule in $outboundnatrules) - { - foreach ($frontend in $rule.properties.frontendipconfigurations) - { - $frontend.resourceRef = ($frontend.resourceRef -f $resourceID) - } - $rule.properties.backendaddresspool.resourceRef = ($rule.properties.backendaddresspool.resourceRef -f $resourceID) - } - $lb.properties.outboundnatrules = $outboundnatrules - } - - foreach ($frontend in $frontendipconfigurations) - { - $frontendref = "/loadbalancers/$resourceID/frontendipconfigurations/$($frontend.resourceId)" - - $frontend.properties.loadbalancingrules = @() - if ($loadbalancingrules -ne $null) - { - foreach ($rule in $loadbalancingrules) - { - foreach ($rulefe in $rule.properties.frontendipconfigurations) - { - if ($rulefe.resourceRef -eq $frontendref) - { - $newref = @{} - $newref.resourceRef = "/loadbalancers/$resourceID/loadbalancingrules/$($rule.resourceId)" - - $frontend.properties.loadbalancingrules += $newref - } - } - - } - } - - $frontend.properties.outboundNatRules = @() - if ($oubboundNatRules -ne $null) - { - foreach ($rule in $outboundnatrules) - { - foreach ($rulefe in $rule.properties.frontendipconfigurations) - { - if ($rulefe.resourceRef -eq $frontendref) - { - $newref = @{} - $newref.resourceRef = "/loadbalancers/$resourceID/outboundnatrules/$($rule.resourceId)" - - $frontend.properties.outboundNatRules += $newref - } - } - - } - } - } - $lb.properties.frontendipconfigurations = $frontendipconfigurations - - foreach ($be in $backendaddresspools) - { - $beref = "/loadbalancers/$resourceID/backendaddresspools/$($be.resourceId)" - - $be.properties.loadbalancingrules = @() - if ($loadbalancingrules -ne $null) - { - foreach ($rule in $loadbalancingrules) - { - if ($rule.properties.backendaddresspool.resourceRef -eq $beref) - { - $newref = @{} - $newref.resourceRef = "/loadbalancers/$resourceID/loadbalancingrules/$($rule.resourceId)" - $be.properties.loadbalancingrules += $newref - } - - } - } - $be.properties.outboundnatrules = @() - if ($outboundnatrules -ne $null) - { - foreach ($rule in $outboundnatrules) - { - if ($rule.properties.backendaddresspool.resourceRef -eq $beref) - { - $newref = @{} - $newref.resourceRef = "/loadbalancers/$resourceID/outboundnatrules/$($rule.resourceId)" - $be.properties.outboundnatrules += $newref - } - - } - } - } - $lb.properties.backendaddresspools = $backendaddresspools - - # $computerName is here to workaround product limitation for PUT of LoadBalancer, which is > 35KB and must be done from the REST hosting NC Vm. - JSONPost $script:NetworkControllerRestIP "/LoadBalancers" $lb -Credential $script:NetworkControllerCred -computerName $ComputerName| out-null - return JSONGet $script:NetworkControllerRestIP "/LoadBalancers/$resourceID" -WaitForUpdate -Credential $script:NetworkControllerCred -} - -function Get-NCLoadBalancer { - param( - [Parameter(mandatory=$false)] - [string] $resourceID = "" - ) - return JSONGet $script:NetworkControllerRestIP "/LoadBalancers/$resourceID" -Credential $script:NetworkControllerCred -} -function Remove-NCLoadBalancer { - param( - [Parameter(mandatory=$true)] - [string[]] $ResourceIDs - ) - foreach ($resourceId in $ResourceIDs) { - JSONDelete $script:NetworkControllerRestIP "/LoadBalancers/$ResourceId" -Waitforupdate -Credential $script:NetworkControllerCred| out-null - } -} - -function New-NCNetworkInterface { - param( - [Parameter(mandatory=$true,ParameterSetName="ByVirtualNetwork")] - [Parameter(mandatory=$true,ParameterSetName="ByLogicalNetwork")] - [Parameter(mandatory=$true,ParameterSetName="ByNoNetwork")] - [string] $resourceID, - [Parameter(mandatory=$true,ParameterSetName="ByVirtualNetwork")] - [object] $VirtualSubnet = $null, - [Parameter(mandatory=$true,ParameterSetName="ByLogicalNetwork")] - [object] $Subnet = $null, - [Parameter(mandatory=$false,ParameterSetName="ByVirtualNetwork")] - [Parameter(mandatory=$false,ParameterSetName="ByLogicalNetwork")] - [Parameter(mandatory=$false,ParameterSetName="ByNoNetwork")] - [string] $IPAddress = $null, - [Parameter(mandatory=$true,ParameterSetName="ByVirtualNetwork")] - [Parameter(mandatory=$true,ParameterSetName="ByLogicalNetwork")] - [Parameter(mandatory=$true,ParameterSetName="ByNoNetwork")] - [string] $MACAddress, - [Parameter(mandatory=$false,ParameterSetName="ByVirtualNetwork")] - [Parameter(mandatory=$false,ParameterSetName="ByLogicalNetwork")] - [Parameter(mandatory=$false,ParameterSetName="ByNoNetwork")] - [string[]] $DNSServers = @(), - [Parameter(mandatory=$false,ParameterSetName="ByVirtualNetwork")] - [Parameter(mandatory=$false,ParameterSetName="ByLogicalNetwork")] - [Parameter(mandatory=$false,ParameterSetName="ByNoNetwork")] - [object] $acl=$null - ) - - if ($pscmdlet.ParameterSetName -eq 'ByVirtualNetwork') { - $subnet = $virtualsubnet - } - - $interface = @{} - # resource Id - $interface.resourceID = $resourceID - $interface.properties = @{} - - # Mac Address - $interface.properties.privateMacAddress = $macaddress - $interface.properties.privateMacAllocationMethod = "Static" - - # IPConfigurations - if ($Subnet -ne $null -or ![string]::IsNullOrEmpty($IPAddress) -or $acl -ne $null) - { - $interface.properties.ipConfigurations = @() - - $ipconfig = @{} - $ipconfig.resourceId = [System.Guid]::NewGuid().toString() - $ipconfig.properties = @{} - - if ($Subnet -ne $null) - { - $ipconfig.properties.subnet = @{} - $ipconfig.properties.subnet.resourceRef = $Subnet.resourceRef - } - if (![string]::IsNullOrEmpty($IPAddress)) - { - $ipconfig.properties.privateIPAddress = $IPAddress - $ipconfig.properties.privateIPAllocationMethod = "Static" - } - if ($acl -ne $null) { - $ipconfig.properties.accessControlList = @{} - $ipconfig.properties.accessControlList.resourceRef = $acl.resourceRef - } - - $interface.properties.ipConfigurations += $ipconfig - } - - # DNS Servers - if ($DNSServers -ne $null -and $DNSServers.count -gt 0) - { - $interface.properties.dnsSettings = @{} - $interface.properties.dnsSettings.dnsServers = $DNSServers - } - - JSONPost $script:NetworkControllerRestIP "/NetworkInterfaces" $interface -Credential $script:NetworkControllerCred| out-null - return JSONGet $script:NetworkControllerRestIP "/NetworkInterfaces/$resourceID" -WaitForUpdate -Credential $script:NetworkControllerCred -} -function Get-NCNetworkInterface { - param( - [Parameter(mandatory=$false)] - [string] $resourceID = "" - ) - return JSONGet $script:NetworkControllerRestIP "/NetworkInterfaces/$resourceID" -Credential $script:NetworkControllerCred -} -function Remove-NCNetworkInterface { - param( - [Parameter(mandatory=$true)] - [string[]] $ResourceIDs - ) - foreach ($resourceId in $ResourceIDs) { - JSONDelete $script:NetworkControllerRestIP "/NetworkInterfaces/$ResourceId" -Waitforupdate -Credential $script:NetworkControllerCred| out-null - } -} - -function Get-ServerResourceId { - param ( - [Parameter(mandatory=$false)] - [string] $ComputerName="localhost", - [Parameter(mandatory=$false)] - [Object] $Credential=$script:NetworkControllerCred - ) - - $resourceId = "" - - write-verbose ("Retrieving server resource id on [$ComputerName]") - - try - { - $pssession = new-pssession -ComputerName $ComputerName -Credential $Credential - - $resourceId = invoke-command -session $pssession -ScriptBlock { - $VerbosePreference = 'Continue' - write-verbose "Retrieving first VMSwitch on [$using:ComputerName]" - - $switches = Get-VMSwitch -ErrorAction Ignore - if ($switches.Count -eq 0) - { - throw "No VMSwitch was found on [$using:ComputerName]" - } - - return $switches[0].Id - } - } - catch - { - Write-Error "Failed with error: $_" - } - finally - { - Remove-PSSession $pssession - } - - write-verbose "Server resource id is [$resourceId] on [$ComputerName]" - return $resourceId -} - -function Set-PortProfileId { - param ( - [Parameter(mandatory=$true)] - [string] $resourceID, - [Parameter(mandatory=$true)] - [string] $VMName, - [Parameter(mandatory=$false)] - [string] $VMNetworkAdapterName, - [Parameter(mandatory=$false)] - [string] $ComputerName="localhost", - [Parameter(mandatory=$false)] - [Object] $credential=$script:NetworkControllerCred, - [Parameter(mandatory=$false)] - [int] $ProfileData = 1, - [Switch] $force - ) - - #do not change these values - write-verbose ("Setting port profile for [$vmname] on [$computername]" ) - - try - { - $pssession = new-pssession -ComputerName $computername -Credential $credential - $isforce = $force.ispresent - - invoke-command -session $pssession -ScriptBlock { - $VerbosePreference = 'Continue' - write-verbose ("Running port profile set script block on host" ) - - $PortProfileFeatureId = "9940cd46-8b06-43bb-b9d5-93d50381fd56" - $NcVendorId = "{1FA41B39-B444-4E43-B35A-E1F7985FD548}" - - $portProfileDefaultSetting = Get-VMSystemSwitchExtensionPortFeature -FeatureId $PortProfileFeatureId - - $portProfileDefaultSetting.SettingData.ProfileId = "{$using:resourceId}" - $portProfileDefaultSetting.SettingData.NetCfgInstanceId = "{56785678-a0e5-4a26-bc9b-c0cba27311a3}" - $portProfileDefaultSetting.SettingData.CdnLabelString = "TestCdn" - $portProfileDefaultSetting.SettingData.CdnLabelId = 1111 - $portProfileDefaultSetting.SettingData.ProfileName = "Testprofile" - $portProfileDefaultSetting.SettingData.VendorId = $NcVendorId - $portProfileDefaultSetting.SettingData.VendorName = "NetworkController" - $portProfileDefaultSetting.SettingData.ProfileData = $using:ProfileData - #$portprofiledefaultsetting.settingdata - - write-verbose ("Retrieving VM network adapter $using:VMNetworkAdapterName" ) - if ([String]::IsNullOrEmpty($using:VMNetworkAdapterName)) - { - write-verbose ("Retrieving all VM network adapters for VM $using:VMName") - $vmNics = Get-VMNetworkAdapter -VMName $using:VMName - } - else - { - write-verbose ("Retrieving VM network adapter $using:VMNetworkAdapterName for VM $using:VMName" ) - $vmNics = @(Get-VMNetworkAdapter -VMName $using:VMName -Name $using:VMNetworkAdapterName) - } - - foreach ($vmNic in $vmNics) { - write-verbose ("Setting port profile on vm network adapter $($vmNic.Name)" ) - $currentProfile = Get-VMSwitchExtensionPortFeature -FeatureId $PortProfileFeatureId -VMNetworkAdapter $vmNic - - if ( $currentProfile -eq $null) - { - write-verbose ("Adding port feature for [{0}] to [{1}]" -f $using:VMName, "{$using:resourceId}") - Add-VMSwitchExtensionPortFeature -VMSwitchExtensionFeature $portProfileDefaultSetting -VMNetworkAdapter $vmNic | out-null - write-verbose "Adding port feature complete" - - } - else - { - if ($using:isforce) { - write-verbose ("Setting port feature for [{0}] to [{1}]" -f $using:VMName, "{$using:resourceId}") - - $currentProfile.SettingData.ProfileId = "{$using:resourceId}" - $currentProfile.SettingData.ProfileData = $using:ProfileData - Set-VMSwitchExtensionPortFeature -VMSwitchExtensionFeature $currentProfile -VMNetworkAdapter $vmNic | out-null - } else { - write-verbose ("Port profile already set for [{0}] use -Force to override." -f $using:VMName) - } - } - } - } - } - catch - { - Write-Error "Failed with error: $_" - } - finally - { - Remove-PSSession $pssession - } -} - -function Remove-PortProfileId -{ - param ( - [Parameter(mandatory=$true)] - [string] $VMName, - [Parameter(mandatory=$false)] - [string] $VMNetworkAdapterName="Network Adapter", - [Parameter(mandatory=$false)] - [string] $ComputerName="localhost" - ) - - write-verbose ("Removing port profile for Network Adapter [$VMNetworkAdapterName] on VM [$vmname] on [$computername]" ) - - try - { - $pssession = new-pssession -ComputerName $computername - - invoke-command -session $pssession -ScriptBlock { - param($VMName, $VMNetworkAdapterName) - $VerbosePreference = 'Continue' - write-verbose ("Running port profile remove script block on host" ) - - #do not change these values - $PortProfileFeatureId = "9940cd46-8b06-43bb-b9d5-93d50381fd56" - $NcVendorId = "{1FA41B39-B444-4E43-B35A-E1F7985FD548}" - - $portProfileCurrentSetting = Get-VMSwitchExtensionPortFeature -FeatureId $PortProfileFeatureId -VMName $VMName -VMNetworkAdapterName $VMNetworkAdapterName - - write-verbose ("Removing port profile from vm network adapter $VMNetworkAdapterName" ) - Remove-VMSwitchExtensionPortFeature -VMSwitchExtensionFeature $portProfileCurrentSetting -VMName $VMName -VMNetworkAdapterName $VMNetworkAdapterName -Confirm:$false - } -ArgumentList @($VMName, $VMNetworkAdapterName) - } - catch - { - Write-Error "Failed with error: $_" - } - finally - { - Remove-PSSession $pssession - } -} - -function New-NCSwitchPort { - param( - [Parameter(mandatory=$false)] - [string] $resourceID=[system.guid]::NewGuid() - ) - - $server = @{} - $server.resourceId = $ResourceID - $server.instanceId = $ResourceID - $server.properties = @{} - - if ($managed.ispresent) { - $server.properties.managementState = "Managed" - } else - { - $server.properties.managementState = "unManaged" - } - $server.properties.roleType = "multiLayerSwitch" - $server.properties.switchType = $switchtype - - $server.properties.connections = $Connections - - JSONPost $script:NetworkControllerRestIP "/Switches" $server -Credential $script:NetworkControllerCred | out-null - return JSONGet $script:NetworkControllerRestIP "/Switches/$resourceID" -WaitForUpdate -Credential $script:NetworkControllerCred - -} - -function New-NCSwitch { - param( - [Parameter(mandatory=$false)] - [string] $resourceID=[system.guid]::NewGuid(), - [Parameter(mandatory=$true)] - [object[]] $Connections, - [Parameter(mandatory=$true)] - [string] $switchType, - [Switch] $Managed - ) - - $server = @{} - $server.resourceId = $ResourceID - $server.instanceId = $ResourceID - $server.properties = @{} - - if ($managed.ispresent) { - $server.properties.managementState = "Managed" - } else - { - $server.properties.managementState = "Unmanaged" - } - $server.properties.roleType = "multiLayerSwitch" - $server.properties.switchType = $switchtype - $server.properties.switchPorts = @() - - $newport = @{} - $newport.ResourceRef = "Port1" - $newport.properties = @{} - $server.properties.switchPorts += $newport - - $newport = @{} - $newport.ResourceRef = "Port2" - $newport.properties = @{} - $server.properties.switchPorts += $newport - - $server.properties.connections = $Connections - - JSONPost $script:NetworkControllerRestIP "/Switches" $server -Credential $script:NetworkControllerCred| out-null - return JSONGet $script:NetworkControllerRestIP "/Switches/$resourceID" -WaitForUpdate -Credential $script:NetworkControllerCred - -} - -function Get-NCSwitch { - param( - [Parameter(mandatory=$false)] - [string] $resourceID = "" - ) - return JSONGet $script:NetworkControllerRestIP "/Switches/$resourceID" -Credential $script:NetworkControllerCred -} - -function Remove-NCSwitch { - param( - [Parameter(mandatory=$true)] - [string[]] $ResourceIDs - ) - foreach ($resourceId in $ResourceIDs) { - JSONDelete $script:NetworkControllerRestIP "/Switches/$ResourceId" -Waitforupdate -Credential $script:NetworkControllerCred| out-null - } -} - -# -# iDNS Specific Wrappers -# -function Add-iDnsConfiguration -{ - param( - [Parameter(mandatory=$true)] - [object[]] $connections, - [Parameter(mandatory=$true)] - [string] $zoneName - ) - - $iDnsObj = @{} - # resource Id configuration is fixed - $iDnsObj.resourceID = "configuration" - $iDnsObj.properties = @{} - - $iDnsObj.properties.connections=$connections - $iDnsObj.properties.zone=$zoneName - - - JSONPost $script:NetworkControllerRestIP "/iDnsServer" $iDnsObj -Credential $script:NetworkControllerCred| out-null - return JSONGet $script:NetworkControllerRestIP "/iDnsServer/Configuration" -WaitForUpdate -Credential $script:NetworkControllerCred -} - -function Get-iDnsConfiguration -{ - return JSONGet $script:NetworkControllerRestIP "/iDnsServer/configuration" -Credential $script:NetworkControllerCred -} - - -# -# Gateway Specific Wrappers -# - -function New-NCPublicIPAddress -{ - param( - [Parameter(mandatory=$false)] - [string] $ResourceID=[system.guid]::NewGuid(), - [Parameter(mandatory=$true)] - [string] $PublicIPAddress) - - $publicIP = @{} - $publicIP.resourceId = $ResourceID - $publicIP.properties = @{} - $publicIP.properties.ipAddress = $PublicIPAddress - $publicIP.properties.publicIPAllocationMethod = "Static" - - JSONPost $script:NetworkControllerRestIP "/publicIPAddresses" $publicIP -Credential $script:NetworkControllerCred | out-null - return JSONGet $script:NetworkControllerRestIP "/publicIPAddresses/$resourceID" -WaitForUpdate -Credential $script:NetworkControllerCred -} - -function Get-NCPublicIPAddress -{ - param( - [Parameter(mandatory=$false)] - [string] $resourceID = "" - ) - return JSONGet $script:NetworkControllerRestIP "/publicIPAddresses/$resourceID" -Credential $script:NetworkControllerCred -} - -function Remove-NCPublicIPAddress -{ - param( - [Parameter(mandatory=$true)] - [string[]] $ResourceIDs - ) - foreach ($resourceId in $ResourceIDs) { - JSONDelete $script:NetworkControllerRestIP "/publicIPAddresses/$ResourceId" -Waitforupdate -Credential $script:NetworkControllerCred | out-null - } -} - -function New-NCGatewayPool -{ - param( - [Parameter(mandatory=$true)] - [string] $resourceID, - [Parameter(mandatory=$true)] - [string] $Type, - [Parameter(mandatory=$false)] - [string] $GreVipSubnetResourceRef, - [Parameter(mandatory=$false)] - [string] $PublicIPAddressId, - [Parameter(mandatory=$false)] - [System.UInt64] $Capacity = 10000000, - [Parameter(mandatory=$false)] - [System.UInt32] $RedundantGatewayCount = 0 - ) - - $gwPool = @{} - $gwPool.resourceID = $resourceID - - $gwPool.properties = @{} - $gwPool.properties.type = $Type - $gwPool.properties.ipConfiguration = @{} - - if (-not([String]::IsNullOrEmpty($GreVipSubnetResourceRef))) - { - $gwPool.properties.ipConfiguration.greVipSubnets = @() - $greVipSubnet = @{} - $greVipSubnet.resourceRef = $GreVipSubnetResourceRef - $gwPool.properties.ipConfiguration.greVipSubnets += $greVipSubnet - } - - $publicIPAddresses = @{} - if (-not([String]::IsNullOrEmpty($PublicIPAddressId))) - { - $publicIPAddresses.resourceRef = "/publicIPAddresses/$PublicIPAddressId" - $gwPool.properties.ipConfiguration.publicIPAddresses = @() - $gwPool.properties.ipConfiguration.publicIPAddresses += $publicIPAddresses - } - $gwPool.properties.redundantGatewayCount = $RedundantGatewayCount - $gwPool.properties.gatewayCapacityKiloBitsPerSecond = $Capacity - - JSONPost $script:NetworkControllerRestIP "/GatewayPools" $gwPool -Credential $script:NetworkControllerCred | out-null - return JSONGet $script:NetworkControllerRestIP "/GatewayPools/$resourceID" -WaitForUpdate -Credential $script:NetworkControllerCred -} - -function Get-NCGatewayPool -{ - param( - [Parameter(mandatory=$false)] - [string] $ResourceID = "" - ) - return JSONGet $script:NetworkControllerRestIP "/GatewayPools/$ResourceID" -Credential $script:NetworkControllerCred -} - -function Remove-NCGatewayPool -{ - param( - [Parameter(mandatory=$true)] - [string[]] $ResourceIDs - ) - foreach ($ResourceId in $ResourceIDs) { - JSONDelete $script:NetworkControllerRestIP "/GatewayPools/$ResourceId" -Waitforupdate -Credential $script:NetworkControllerCred | out-null - } -} - - -function New-NCGateway -{ - param( - [Parameter(mandatory=$true)] - [string] $resourceID, - [Parameter(mandatory=$true)] - [string] $GatewayPoolRef, - [Parameter(mandatory=$true)] - [string] $Type, - [Parameter(mandatory=$false)] - [object] $BgpConfig, - [Parameter(mandatory=$true)] - [string] $VirtualServerRef, - [Parameter(mandatory=$true)] - [string] $InternalInterfaceRef, - [Parameter(mandatory=$true)] - [string] $ExternalInterfaceRef - ) - - $gateway = @{} - $gateway.resourceID = $resourceID - $gateway.properties = @{} - - $gateway.properties.pool = @{} - $gateway.properties.pool.resourceRef = $GatewayPoolRef - - $gateway.properties.type = $Type - $gateway.properties.bgpConfig = @{} - $gateway.properties.bgpConfig = $BgpConfig - - $gateway.properties.virtualserver = @{} - $gateway.properties.virtualserver.resourceRef = $VirtualServerRef - - $gateway.properties.networkInterfaces = @{} - $gateway.properties.networkInterfaces.externalNetworkInterface = @{} - $gateway.properties.networkInterfaces.externalNetworkInterface.resourceRef = $ExternalInterfaceRef - $gateway.properties.networkInterfaces.internalNetworkInterface = @{} - $gateway.properties.networkInterfaces.internalNetworkInterface.resourceRef = $InternalInterfaceRef - - JSONPost $script:NetworkControllerRestIP "/Gateways" $gateway -Credential $script:NetworkControllerCred | out-null - return JSONGet $script:NetworkControllerRestIP "/Gateways/$resourceID" -WaitForUpdate -Credential $script:NetworkControllerCred -} - -function Get-NCGateway -{ - param( - [Parameter(mandatory=$false)] - [string] $resourceID = "" - ) - return JSONGet $script:NetworkControllerRestIP "/Gateways/$resourceID" -Credential $script:NetworkControllerCred -} - -function Remove-NCGateway -{ - param( - [Parameter(mandatory=$true)] - [string] $ResourceID - ) - JSONDelete $script:NetworkControllerRestIP "/Gateways/$ResourceId" -Waitforupdate -Credential $script:NetworkControllerCred | out-null -} - -function New-NCVpnClientAddressSpace -{ - param( - [Parameter(mandatory=$true)] - [string] $TenantName, - [Parameter(mandatory=$true)] - [System.UInt64] $VpnCapacity, - [Parameter(mandatory=$true)] - [string] $Ipv4AddressPool, - [Parameter(mandatory=$true)] - [string] $Ipv6AddressPool - ) - - $vpnClientAddressSpace = @{} - $vpnClientAddressSpace.AddressPrefixes = @() - $vpnClientAddressSpace.AddressPrefixes += @($Ipv4AddressPool, $Ipv6AddressPool) - $vpnClientAddressSpace.Capacity = $VpnCapacity.ToString() - $vpnClientAddressSpace.Realm = $TenantName - - return $vpnClientAddressSpace -} - -function New-NCIPSecTunnel -{ - param( - [Parameter(mandatory=$true)] - [string] $ResourceId, - [Parameter(mandatory=$true)] - [system.uint64] $OutboundCapacity, - [Parameter(mandatory=$true)] - [system.uint64] $InboundCapacity, - [Parameter(mandatory=$false)] - [object[]] $IPAddresses, - [Parameter(mandatory=$false)] - [string[]] $PeerIPAddresses, - [Parameter(mandatory=$false)] - [string] $DestinationIPAddress, - [Parameter(mandatory=$false)] - [string] $SharedSecret, - [Parameter(mandatory=$false)] - [object[]] $IPv4Subnets - ) - - $AuthenticationMethod = "PSK" - - $ipSecVpn = @{} - $ipsecVpn.resourceId = $ResourceId - $ipSecVpn.properties = @{} - - $ipSecVpn.properties.connectionType = "IPSec" - $ipSecVpn.properties.outboundKiloBitsPerSecond = $outboundCapacity - $ipSecVpn.properties.inboundKiloBitsPerSecond = $inboundCapacity - - $routes = @() - foreach ($IPv4Subnet in $IPv4Subnets) - { - $route = @{} - $route.destinationPrefix = $IPv4Subnet.Prefix - $route.metric = $IPv4Subnet.Metric - $routes += $route - } - $ipSecVpn.properties.routes = @() - $ipSecVpn.properties.routes = $routes - - $ipSecVpn.properties.ipSecConfiguration = @{} - $ipSecVpn.properties.ipSecConfiguration.QuickMode = @{} - $ipSecVpn.properties.ipSecConfiguration.MainMode = @{} - - $ipSecVpn.properties.ipSecConfiguration.authenticationMethod = $AuthenticationMethod - if ($AuthenticationMethod -eq "PSK") - { $ipSecVpn.properties.ipSecConfiguration.sharedSecret = $SharedSecret } - - $ipSecVpn.properties.ipSecConfiguration.quickMode.perfectForwardSecrecy = "PFS2048" - $ipSecVpn.properties.ipSecConfiguration.quickMode.authenticationTransformationConstant = "SHA256128" - $ipSecVpn.properties.ipSecConfiguration.quickMode.cipherTransformationConstant = "DES3" - $ipSecVpn.properties.ipSecConfiguration.quickMode.saLifeTimeSeconds = 1233 - $ipSecVpn.properties.ipSecConfiguration.quickMode.idleDisconnectSeconds = 500 - $ipSecVpn.properties.ipSecConfiguration.quickMode.saLifeTimeKiloBytes = 2000 - - $ipSecVpn.properties.ipSecConfiguration.mainMode.diffieHellmanGroup = "Group2" - $ipSecVpn.properties.ipSecConfiguration.mainMode.integrityAlgorithm = "SHA256" - $ipSecVpn.properties.ipSecConfiguration.mainMode.encryptionAlgorithm = "AES256" - $ipSecVpn.properties.ipSecConfiguration.mainMode.saLifeTimeSeconds = 1234 - $ipSecVpn.properties.ipSecConfiguration.mainMode.saLifeTimeKiloBytes = 2000 - - if ($IPAddresses -eq $null) {$IPAddresses = @()} - if ($PeerIPAddresses -eq $null) {$PeerIPAddresses = @()} - - $ipSecVpn.properties.ipAddresses = $IPAddresses - $ipSecVpn.properties.peerIPAddresses = $PeerIPAddresses - $ipSecVpn.properties.destinationIPAddress = $DestinationIPAddress - - return $ipSecVpn -} - -function New-NCGreTunnel -{ - param( - [Parameter(mandatory=$true)] - [string] $ResourceId, - [Parameter(mandatory=$true)] - [system.uint64] $OutboundCapacity, - [Parameter(mandatory=$true)] - [system.uint64] $InboundCapacity, - [Parameter(mandatory=$false)] - [object[]] $IPAddresses, - [Parameter(mandatory=$false)] - [string[]] $PeerIPAddresses, - [Parameter(mandatory=$false)] - [string] $DestinationIPAddress, - [Parameter(mandatory=$false)] - [object[]] $IPv4Subnets, - [Parameter(mandatory=$false)] - [string] $GreKey - ) - - $greTunnel = @{} - $greTunnel.resourceId = $ResourceId - $greTunnel.properties = @{} - - $greTunnel.properties.connectionType = "GRE" - $greTunnel.properties.outboundKiloBitsPerSecond = $outboundCapacity - $greTunnel.properties.inboundKiloBitsPerSecond = $inboundCapacity - - $greTunnel.properties.greConfiguration = @{} - $greTunnel.properties.greConfiguration.GreKey = $GreKey - - if ($IPAddresses -eq $null) {$IPAddresses = @()} - if ($PeerIPAddresses -eq $null) {$PeerIPAddresses = @()} - - $greTunnel.properties.ipAddresses = $IPAddresses - $greTunnel.properties.peerIPAddresses = $PeerIPAddresses - - $routes = @() - foreach ($IPv4Subnet in $IPv4Subnets) - { - $route = @{} - $route.destinationPrefix = $IPv4Subnet.Prefix - $route.metric = $IPv4Subnet.Metric - $routes += $route - } - $greTunnel.properties.routes = @() - $greTunnel.properties.routes = $routes - - $greTunnel.properties.destinationIPAddress = $DestinationIPAddress - - return $greTunnel -} - -function New-NCL3Tunnel -{ - param( - [Parameter(mandatory=$true)] - [string] $ResourceId, - [Parameter(mandatory=$true)] - [system.uint64] $OutboundCapacity, - [Parameter(mandatory=$true)] - [system.uint64] $InboundCapacity, - [Parameter(mandatory=$false)] - [string] $VlanSubnetResourceRef, - [Parameter(mandatory=$false)] - [object[]] $L3IPAddresses, - [Parameter(mandatory=$false)] - [System.UInt16] $PrefixLength, - [Parameter(mandatory=$false)] - [string[]] $L3PeerIPAddresses, - [Parameter(mandatory=$false)] - [object[]] $IPv4Subnets - ) - - $l3Tunnel = @{} - $l3Tunnel.resourceId = $ResourceId - $l3Tunnel.properties = @{} - - $l3Tunnel.properties.connectionType = "L3" - $l3Tunnel.properties.outboundKiloBitsPerSecond = $outboundCapacity - $l3Tunnel.properties.inboundKiloBitsPerSecond = $inboundCapacity - - $l3Tunnel.properties.l3Configuration = @{} - $l3Tunnel.properties.l3Configuration.vlanSubnet = @{} - $l3Tunnel.properties.l3Configuration.vlanSubnet.resourceRef = $VlanSubnetResourceRef - - $l3Tunnel.properties.ipAddresses = @($L3IPAddresses) - $l3Tunnel.properties.peerIPAddresses = @($L3PeerIPAddresses) - - $routes = @() - foreach ($IPv4Subnet in $IPv4Subnets) - { - $route = @{} - $route.destinationPrefix = $IPv4Subnet.Prefix - $route.metric = $IPv4Subnet.Metric - $routes += $route - } - $l3Tunnel.properties.routes = @() - $l3Tunnel.properties.routes = $routes - - return $l3Tunnel -} - -function New-NCBgpRoutingPolicy -{ - param( - [Parameter(mandatory=$true)] - [string] $PolicyName, - [Parameter(mandatory=$true)] - [string] $PolicyType, - [Parameter(mandatory=$true)] - [object[]] $MatchCriteriaList, - [Parameter(mandatory=$false)] - [object[]] $Actions, - [Parameter(mandatory=$false)] - [string] $EgressPolicyMapResourceRef - ) - - $bgpPolicy = @{} - $bgpPolicy.policyName = $PolicyName - $bgpPolicy.policyType = $policyType - - $bgpPolicy.matchCriteria = @() - $bgpPolicy.setActions = @() - - foreach ($criteria in $MatchCriteriaList) - { - $matchCriteria = @{} - $matchCriteria.clause = $criteria.clause - $matchCriteria.operator = "And" - $matchCriteria.value = $criteria.value - - $bgpPolicy.matchCriteria += $matchCriteria - } - - $bgpPolicy.setActions += @($Actions) - - return $bgpPolicy -} - -function New-NCBgpRoutingPolicyMap -{ - param( - [Parameter(mandatory=$true)] - [string] $PolicyMapName, - [Parameter(mandatory=$true)] - [object[]] $PolicyList - ) - - $bgpPolicyMap = @{} - $bgpPolicyMap.resourceId = $PolicyMapName - $bgpPolicyMap.properties = @{} - - $bgpPolicyMap.properties.policyList = @($PolicyList) - - return $bgpPolicyMap -} - -function New-NCBgpPeer -{ - param( - [Parameter(mandatory=$true)] - [string] $PeerName, - [Parameter(mandatory=$true)] - [string] $PeerIP, - [Parameter(mandatory=$true)] - [string] $PeerASN, - [Parameter(mandatory=$false)] - [string] $IngressPolicyMapResourceRef, - [Parameter(mandatory=$false)] - [string] $EgressPolicyMapResourceRef - ) - - $bgpPeer = @{} - $bgpPeer.resourceId = $PeerName - $bgpPeer.properties = @{} - - $bgpPeer.properties.peerIPAddress = $PeerIP - $bgpPeer.properties.peerAsNumber = $PeerASN - $bgpPeer.properties.ExtAsNumber = "0.$PeerASN" - - $bgpPeer.properties.policyMapIn = $null - $bgpPeer.properties.policyMapOut = $null - - if (![string]::IsNullOrEmpty($IngressPolicyMapResourceRef)) - { - $bgpPeer.properties.policyMapIn = @{} - $bgpPeer.properties.policyMapIn.resourceRef = $IngressPolicyMapResourceRef - } - if (![string]::IsNullOrEmpty($EgressPolicyMapResourceRef)) - { - $bgpPeer.properties.policyMapOut = @{} - $bgpPeer.properties.policyMapOut.resourceRef = $EgressPolicyMapResourceRef - } - - return $bgpPeer -} - -function New-NCBgpRouter -{ - param( - [Parameter(mandatory=$true)] - [string] $RouterName, - [Parameter(mandatory=$true)] - [string] $LocalASN, - [Parameter(mandatory=$false)] - [object[]] $BgpPeers - ) - - $bgpRouter = @{} - $bgpRouter.resourceId = $RouterName - $bgpRouter.properties = @{} - - $bgpRouter.properties.isEnabled = "true" - $bgpRouter.properties.requireIGPSync = "true" - $bgpRouter.properties.extAsNumber = "0.$LocalASN" - $bgpRouter.properties.routerIP = @() - $bgpRouter.properties.bgpNetworks = @() - $bgpRouter.properties.isGenerated = $false - - $bgpRouter.properties.bgpPeers = @($BgpPeers) - - return $bgpRouter -} - -function New-NCVirtualGateway -{ - param( - [Parameter(mandatory=$true)] - [string] $resourceID, - [Parameter(mandatory=$true)] - [string[]] $GatewayPools, - [Parameter(mandatory=$true)] - [string] $vNetIPv4SubnetResourceRef, - [Parameter(mandatory=$false)] - [object] $VpnClientAddressSpace, - [Parameter(mandatory=$false)] - [object[]] $NetworkConnections, - [Parameter(mandatory=$false)] - [object[]] $BgpRouters, - [Parameter(mandatory=$false)] - [object[]] $PolicyMaps, - [Parameter(mandatory=$false)] - [string] $RoutingType = "Dynamic" - ) - - $virtualGW = @{} - $virtualGW.resourceID = $resourceID - $virtualGW.properties = @{} - - $virtualGW.properties.gatewayPools = @() - foreach ($gatewayPool in $GatewayPools) - { - - $gwPool = @{} - $gwPool.resourceRef = "/gatewayPools/$gatewayPool" - $virtualGW.properties.gatewayPools += $gwPool - } - - $gatewaySubnetsRef = @{} - $gatewaySubnetsRef.resourceRef = $vNetIPv4SubnetResourceRef - $virtualGW.properties.gatewaySubnets = @() - $virtualGW.properties.gatewaySubnets += $gatewaySubnetsRef - - $virtualGW.properties.vpnClientAddressSpace = @{} - $virtualGW.properties.vpnClientAddressSpace = $VpnClientAddressSpace - - $virtualGW.properties.networkConnections = @() - $virtualGW.properties.networkConnections += @($Networkconnections) - - $virtualGW.properties.bgpRouters = @() - $virtualGW.properties.bgpRouters += $BgpRouters - - $virtualGW.properties.policyMaps = @() - $virtualGW.properties.policyMaps += $PolicyMaps - - $virtualGW.properties.routingType = $RoutingType - - JSONPost $script:NetworkControllerRestIP "/VirtualGateways" $virtualGW -Credential $script:NetworkControllerCred | out-null - return JSONGet $script:NetworkControllerRestIP "/VirtualGateways/$resourceID" -WaitForUpdate -Credential $script:NetworkControllerCred -} -function Get-NCVirtualGateway -{ - param( - [Parameter(mandatory=$false)] - [string] $ResourceID = "" - ) - return JSONGet $script:NetworkControllerRestIP "/VirtualGateways/$ResourceID" -Credential $script:NetworkControllerCred -} -function Remove-NCVirtualGateway -{ - param( - [Parameter(mandatory=$true)] - [string] $ResourceID - ) - JSONDelete $script:NetworkControllerRestIP "/VirtualGateways/$ResourceId" -Waitforupdate -Credential $script:NetworkControllerCred | out-null -} - -function Add-LoadBalancerToNetworkAdapter -{ - param( - [parameter(mandatory=$false)] - [string] $LoadBalancerResourceID, - [parameter(mandatory=$false)] - [string[]] $VMNicResourceIds - ) - $loadBalancer = Get-NCLoadBalancer -resourceId $LoadBalancerResourceID - $lbbeResourceRef = $loadBalancer.Properties.backendAddressPools.resourceRef - foreach($nicResourceID in $VMNicResourceIds) - { - $nicResource = Get-NCNetworkInterface -resourceid $nicResourceID - $loadBalancerBackendAddressPools = @{} - $loadBalancerBackendAddressPools.resourceRef = $lbbeResourceRef - if(-not $nicResource.properties.ipConfigurations[0].properties.loadBalancerBackendAddressPools) - { - $nicResource.properties.ipConfigurations[0].properties.loadBalancerBackendAddressPools= @() - } - else - { - $found = $false - foreach ($backendAddressPool in $nicResource.properties.ipConfigurations[0].properties.loadBalancerBackendAddressPools) - { - $resourceRef = $backendAddressPool.resourceRef - if ($resourceRef -eq $lbbeResourceRef) - { - $found = $true - break - } - } - - if ($found -eq $true) - { - continue - } - } - $nicResource.properties.ipConfigurations[0].properties.loadBalancerBackendAddressPools += $loadBalancerBackendAddressPools - JSONPost $script:NetworkControllerRestIP "/NetworkInterfaces" $nicResource -Credential $script:NetworkControllerCred | out-null - } -} - - -function Remove-LoadBalancerFromNetworkAdapter -{ - param( - [parameter(mandatory=$false)] - [string[]] $VMNicResourceIds - ) - foreach($nicResourceID in $VMNicResourceIds) - { - $nicResource = Get-NCNetworkInterface -resourceid $nicResourceID - $nicResource.properties.ipConfigurations[0].loadBalancerBackendAddressPools.resourceRef = "" - JSONPost $script:NetworkControllerRestIP "/NetworkInterfaces" $nicResource -Credential $script:NetworkControllerCred | out-null - } -} - -function Get-NCConnectivityCheckResult { - param( - [Parameter(mandatory=$false)] - [string] $resourceID = "" - ) - return JSONGet $script:NetworkControllerRestIP "/diagnostics/ConnectivityCheckResults/$resourceID" -Credential $script:NetworkControllerCred -} -function Get-NCRouteTable { - param( - [Parameter(mandatory=$false)] - [string] $resourceID = "" - ) - return JSONGet $script:NetworkControllerRestIP "/RouteTables/$resourceID" -Credential $script:NetworkControllerCred -} - diff --git a/azure_jumpstart_hcibox/artifacts/SDN/NetworkControllerWorkloadHelpers.psm1 b/azure_jumpstart_hcibox/artifacts/SDN/NetworkControllerWorkloadHelpers.psm1 deleted file mode 100644 index 096f4f24ee..0000000000 --- a/azure_jumpstart_hcibox/artifacts/SDN/NetworkControllerWorkloadHelpers.psm1 +++ /dev/null @@ -1,380 +0,0 @@ -Import-Module ".\NetworkControllerRESTWrappers.ps1" -Force - -function New-ACL -{ - param( - [Parameter(mandatory=$false)] - [String] $ResourceId=[System.Guid]::NewGuid(), - [Parameter(mandatory=$true)] - [object[]] $aclRules - ) - - $ar = @() - foreach ($rule in $aclRules) { - $ar += New-NCAccessControlListRule -Protocol $rule.Protocol -SourcePortRange $rule.SourcePortRange -DestinationPortRange $rule.DestinationPortRange -sourceAddressPrefix $rule.sourceAddressPrefix -destinationAddressPrefix $rule.destinationAddressPrefix -Action $rule.Action -ACLType $rule.Type -Logging $true -Priority $rule.Priority - } - - $acl1 = New-NCAccessControlList -resourceId $ResourceId -AccessControlListRules $ar - return $acl1 -} - -function Get-PortProfileId -{ - param( - [Parameter(mandatory=$true)] - [String] $VMName, - [Parameter(mandatory=$false)] - [String] $VMNetworkAdapterName=$null, - [Parameter(mandatory=$false)] - [String] $ComputerName="localhost" - ) - write-verbose ("Getting port profile for [$vmname] on [$computername]" ) - - try - { - $pssession = new-pssession -ComputerName $computername - - invoke-command -session $pssession -ScriptBlock { - if ([String]::IsNullOrEmpty($using:VMNetworkAdapterName)) - { - $vmNics = Get-VMNetworkAdapter -VMName $using:VMName - } - else - { - $vmNics = @(Get-VMNetworkAdapter -VMName $using:VMName -Name $using:VMNetworkAdapterName) - } - - $result = @() - - foreach ($vmNic in $vmNics) { - $currentProfile = Get-VMSwitchExtensionPortFeature -FeatureId "9940cd46-8b06-43bb-b9d5-93d50381fd56" -VMNetworkAdapter $vmNic - if ( $currentProfile -eq $null) - { - $result += $null - } - else - { - $result += [system.guid]::parse($currentProfile.SettingData.ProfileId).tostring() - } - } - return $result - } - } - catch - { - Write-Error "Failed with error: $_" - } - finally - { - Remove-PSSession $pssession - } -} - -function get-MacAddress -{ - param( - [Parameter(mandatory=$true)] - [String] $VMName, - [Parameter(mandatory=$false)] - [String] $VMNetworkAdapterName=$null, - [Parameter(mandatory=$false)] - [String] $ComputerName="localhost" - ) - write-verbose ("Getting mac address for [$vmname] on [$computername]" ) - - try - { - $pssession = new-pssession -ComputerName $computername - - invoke-command -session $pssession -ScriptBlock { - if ([String]::IsNullOrEmpty($using:VMNetworkAdapterName)) - { - $vmNics = Get-VMNetworkAdapter -VMName $using:VMName - } - else - { - $vmNics = @(Get-VMNetworkAdapter -VMName $using:VMName -Name $using:VMNetworkAdapterName) - } - - $result = @() - - foreach ($vmNic in $vmNics) { - $result += $VMNic.MacAddress - } - return $result - } - } - catch - { - Write-Error "Failed with error: $_" - } - finally - { - Remove-PSSession $pssession - } -} - -function Add-NetworkAdapterToNetwork -{ - param( - [Parameter(mandatory=$true,ParameterSetName="ByVNIC")] - [String] $VMName, - [Parameter(mandatory=$false,ParameterSetName="ByVNIC")] - [String] $VMNetworkAdapterName = $null, - [Parameter(mandatory=$true,ParameterSetName="ByVNIC")] - [String] $ComputerName, - [Parameter(mandatory=$false,ParameterSetName="ByVNIC")] - [Parameter(mandatory=$true,ParameterSetName="ByResourceId")] - [String] $NetworkInterfaceResourceId="", - [Parameter(mandatory=$true,ParameterSetName="ByVNIC")] - [Parameter(mandatory=$true,ParameterSetName="ByResourceId")] - [Object] $LogicalNetworkResourceId="", - [Parameter(mandatory=$true,ParameterSetName="ByVNIC")] - [Parameter(mandatory=$true,ParameterSetName="ByResourceId")] - [String] $SubnetAddressPrefix="", - [Parameter(mandatory=$false,ParameterSetName="ByVNIC")] - [Parameter(mandatory=$false,ParameterSetName="ByResourceId")] - [String] $ACLResourceId=$null, - [Parameter(mandatory=$false,ParameterSetName="ByVNIC")] - [Parameter(mandatory=$false,ParameterSetName="ByResourceId")] - [String] $IPAddress="" - ) - - if ($psCmdlet.ParameterSetName -eq "ByVNIC") { - $NetworkInterfaceInstanceId = Get-PortProfileId -vmname $vmname -vmnetworkadaptername $VMNetworkAdapterName -computername $computername - $NetworkInterfaceResourceId = Get-NCNetworkInterfaceResourceId -InstanceId $NetworkInterfaceInstanceId - } - - $mac = get-macaddress -vmname $vmname -VMNetworkAdapterName $VMNetworkAdapterName -ComputerName $ComputerName - - if ($mac.count -gt 1) { - throw "More than one MACaddress found on VM. You must specify VMNetworkAdapterName if more than one network adapter is present on the VM." - } - - $ln = Get-NCLogicalNetwork -ResourceId $LogicalNetworkResourceId - - foreach ($lnsubnet in $ln.properties.subnets) { - if ($subnetaddressprefix -eq $lnsubnet.properties.Addressprefix) { - $subnet = $lnsubnet - } - } - - if (([String]::IsNullOrEmpty($NetworkInterfaceResourceId)) -or ($NetworkInterfaceResourceId -eq "") -or ($NetworkInterfaceResourceId -eq [System.Guid]::Empty)) { - $NetworkInterfaceResourceId = [System.Guid]::NewGuid() - } - $nic = get-ncnetworkinterface -resourceID $NetworkInterfaceResourceId - - if ($nic -ne $null -and !$Force) { - throw "Network interface [$networkinterfaceresourceid] already exists. Use -Force to replace it." - } - - #TODO: add acl if specified - if (![String]::IsNullOrEmpty($ACLResourceId)) { - $acl = Get-NCAccessControlList -resourceID $ACLResourceId - if ($acl -eq $null) { - throw "ACL with resource id $aclresourceid was not found on the network controller." - } - $nic = New-NCNetworkInterface -resourceId $NetworkInterfaceResourceId -Subnet $subnet -MACAddress $mac -acl $acl -ipaddress $ipaddress - } else { - $nic = New-NCNetworkInterface -resourceId $NetworkInterfaceResourceId -Subnet $subnet -MACAddress $mac -ipaddress $ipaddress - } - set-portprofileid -resourceID $nic.instanceid -VMName $vmname -VMNetworkAdapterName $vmnetworkadaptername -computername $computername -Force - - return $nic - - #TODO: add virtual server for topology -} - -function Unblock-NetworkAdapter -{ - param( - [Parameter(mandatory=$true,ParameterSetName="ByVNIC")] - [String] $VMName, - [Parameter(mandatory=$false,ParameterSetName="ByVNIC")] - [String] $VMNetworkAdapterName = $null, - [Parameter(mandatory=$true,ParameterSetName="ByVNIC")] - [String] $ComputerName - ) - - if ($psCmdlet.ParameterSetName -eq "ByVNIC") { - $NetworkInterfaceInstanceId = Get-PortProfileId $vmname $VMNetworkAdapterName $computername - $NetworkInterfaceResourceId = Get-NCNetworkInterfaceResourceId -InstanceId $NetworkInterfaceInstanceId - } - - #if networkadapter exists, remove it - remove-ncnetworkinterface -resourceid $NetworkInterfaceResourceId - - #remove-ncvirtualserver -resourceid $vsresourceid - - set-portprofileid -resourceID ([guid]::empty) -VMName $vmname -ComputerName $computername -Force -} - - -function Remove-NetworkAdapterFromNetwork -{ - param( - [Parameter(mandatory=$true,ParameterSetName="ByVNIC")] - [String] $VMName, - [Parameter(mandatory=$false,ParameterSetName="ByVNIC")] - [String] $VMNetworkAdapterName = $null, - [Parameter(mandatory=$true,ParameterSetName="ByVNIC")] - [String] $ComputerName, - [Parameter(mandatory=$false,ParameterSetName="ByVNIC")] - [Parameter(mandatory=$true,ParameterSetName="ByResourceId")] - [String] $NetworkInterfaceResourceId="" - ) - - if ($psCmdlet.ParameterSetName -eq "ByVNIC") { - $NetworkInterfaceInstanceId = Get-PortProfileId $vmname $VMNetworkAdapterName $computername - $NetworkInterfaceResourceId = Get-NCNetworkInterfaceResourceId -InstanceId $NetworkInterfaceInstanceId - } - - if($NetworkInterfaceResourceId) - { - remove-ncnetworkinterface -resourceid $NetworkInterfaceResourceId - } - - $nullguid = $([System.Guid]::Empty) - set-portprofileid -ResourceID $nullguid -vmname $vmname -VMNetworkAdapterName $VMNetworkAdapterName -ComputerName $computername -force - #remove-ncvirtualserver -resourceid $vsresourceid -} - -function Set-NetworkAdapterACL -{ - param( - [Parameter(mandatory=$true,ParameterSetName="ByVNIC")] - [String] $VMName, - [Parameter(mandatory=$false,ParameterSetName="ByVNIC")] - [String] $VMNetworkAdapterName = $null, - [Parameter(mandatory=$true,ParameterSetName="ByVNIC")] - [String] $ComputerName, - [Parameter(mandatory=$true,ParameterSetName="ByResourceId")] - [String] $NetworkInterfaceResourceId, - [Parameter(mandatory=$true)] - [String] $ACLResourceId - ) - - if ($psCmdlet.ParameterSetName -eq "ByVNIC") { - $NetworkInterfaceInstanceId = Get-PortProfileId $vmname $VMNetworkAdapterName $computername - if ($NetworkInterfaceInstanceId -eq $null) { - throw "Could not find port profile id. Either $vmname does not exist on $computername, or it does not have a port profile defined which would indicate that it has not been added to the network controller." - } - - if ($NetworkInterfaceInstanceId -ne [System.Guid]::Empty) - { - $NetworkInterfaceResourceId = Get-NCNetworkInterfaceResourceId -InstanceId $NetworkInterfaceInstanceId - } - } - - $nic = get-ncnetworkinterface -resourceid $NetworkInterfaceResourceId - - if ($nic -eq $null) { - throw "ACL can't be set because a network interface was not found for port profile id $NetworkInterfaceResourceId in the network controller." - } - - $acl = Get-NCAccessControlList -resourceID $ACLResourceId - if ($acl -eq $null) { - throw "ACL with resource id $aclresourceid was not found on the network controller." - } - - $nic.properties.ipConfigurations[0].properties | add-member -Name "accessControlList" -MemberType NoteProperty -Value @{ resourceRef = $acl.resourceRef } - - JSONPost -path "/NetworkInterfaces" -bodyObject $nic -} - -function New-LoadBalancerVIP -{ -param( - [Parameter(mandatory=$false)] - [Microsoft.HyperV.PowerShell.VirtualMachine[]]$VMPool = $n, - [Parameter(mandatory=$true)] - [string]$Vip, - [Parameter(mandatory=$false)] - [string]$protocol="TCP", - [Parameter(mandatory=$true)] - [int] $frontendPort, - [Parameter(mandatory=$false)] - [int] $backendPort=$frontendport, - [Parameter(mandatory=$false)] - [Switch] $EnableOutboundNat, - [parameter(mandatory=$false)] - [string] $LoadBalancerResourceID=[system.guid]::NewGuid() -) - $slbm = get-ncloadbalancermanager - - if ($slbm.properties.vipippools.count -lt 1) { - throw "New-LoadBalancerVIP requires at least one VIP pool in the NC Load balancer manager." - } - - $vipPools = $slbm.properties.vipippools - - # check if the input VIP is within range of one of the VIP pools - foreach ($vippool in $vipPools) { - # IP pool's resourceRef is in this format: - # /logicalnetworks/f8f67956-3906-4303-94c5-09cf91e7e311/subnets/aaf28340-30fe-4f27-8be4-40eca97b052d/ipPools/ed48962b-2789-41bf-aa7b-3e6d5b247384 - $sp = $vippool.resourceRef.split("/") - - $ln = Get-NCLogicalNetwork -resourceId $sp[2] #LN resourceid is always the first ID (after /logicalnetwork/) - if (-not $ln) { - throw "Can't find logical network with resourceId $($sp[2]) from NC." - } - - $subnet = $ln.properties.subnets | ? {$_.resourceId -eq $sp[4]} - if (-not $subnet) { - throw "can't find subnet with resourceId $($sp[4]) from NC." - } - - $pool = $subnet.properties.ipPools | ? {$_.resourceId -eq $sp[6]} - if (-not $pool) { - throw "can't find IP pool with resourceId $($sp[6]) from NC." - } - - $startIp = $pool.properties.startIpAddress - $endIp = $pool.properties.endIpAddress - if (IsIpWithinPoolRange -targetIp $Vip -startIp $startIp -endIp $endIp) { - $isPoolPublic = $subnet.properties.isPublic - $vipLn = $ln - break; - } - } - - if (-not $vipLn) { - throw "$Vip is not within range of any of the VIP pools managed by SLB manager." - } - - # if the VIP is within the range of a pool whose subnet is public, we should create a PublicIPAddress in NC for the VIP - # so that NC won't accidentially allocate same VIP for tenant use - if ($isPoolPublic) { - $publicIp = Get-NCPublicIPAddress | ? {$_.properties.ipaddress -eq $Vip} - if ($publicIp -eq $null) { - New-NCPublicIPAddress -PublicIPAddress $Vip - } - } - - $lbfe = @(New-NCLoadBalancerFrontEndIPConfiguration -PrivateIPAddress $Vip -Subnet ($vipLn.properties.Subnets[0])) - - $ips = @() - foreach ($VM in $VMPool) { - $vm_name = $VM.Name - $vm_computer = $VM.ComputerName - $vm_nic = $VM.NetworkAdapters[0].Name - $instanceid = Get-PortProfileId -VMName $vm_name -VMNetworkAdapterName $vm_nic -ComputerName $vm_computer - - #convert port profile id to from instance id to resource id - $ppid = $NetworkInterfaceResourceId = Get-NCNetworkInterfaceResourceId -InstanceId $instanceid - - $vnic = get-ncnetworkinterface -resourceId $ppid - $ips += $vnic.properties.ipConfigurations[0] - } - - $lbbe = @(New-NCLoadBalancerBackendAddressPool -IPConfigurations $ips) - $rules = @(New-NCLoadBalancerLoadBalancingRule -protocol $protocol -frontendPort $frontendPort -backendport $backendPort -enableFloatingIP $False -frontEndIPConfigurations $lbfe -backendAddressPool $lbbe) - - if ($EnableOutboundNat) { - $onats = @(New-NCLoadBalancerOutboundNatRule -frontendipconfigurations $lbfe -backendaddresspool $lbbe) - $lb = New-NCLoadBalancer -ResourceID $LoadBalancerResourceID -frontendipconfigurations $lbfe -backendaddresspools $lbbe -loadbalancingrules $rules -outboundnatrules $onats - } else { - $lb = New-NCLoadBalancer -ResourceID $LoadBalancerResourceID -frontendipconfigurations $lbfe -backendaddresspools $lbbe -loadbalancingrules $rules - } - return $lb -} diff --git a/azure_jumpstart_hcibox/artifacts/SDN/SDNExplorer.ps1 b/azure_jumpstart_hcibox/artifacts/SDN/SDNExplorer.ps1 deleted file mode 100644 index 18a6a73952..0000000000 --- a/azure_jumpstart_hcibox/artifacts/SDN/SDNExplorer.ps1 +++ /dev/null @@ -1,3269 +0,0 @@ - -param( - [string] - $NCIP = "restserver", - [object] - $NCCredential= [System.Management.Automation.PSCredential]::Empty, - [bool] - $EnableMultiWindow = $true, - [bool] - $IsModule = $false -) - -function GenerateMainForm { - -param( - [Parameter(mandatory=$true)] - [object[]] $DataArr - ) - - [reflection.assembly]::loadwithpartialname(“System.Windows.Forms”) | Out-Null - [reflection.assembly]::loadwithpartialname(“System.Drawing”) | Out-Null - #endregion - - #region Generated Form Objects - $ExplorerForm = New-Object System.Windows.Forms.Form - $InitialFormWindowState = New-Object System.Windows.Forms.FormWindowState - #endregion Generated Form Objects - - - $OnLoadForm_StateCorrection= - {#Correct the initial state of the form to prevent the .Net maximized form issue - $ExplorerForm.WindowState = $InitialFormWindowState - } - - #———————————————- - #region Generated Form Code - $ExplorerForm.Text = “SDN Explorer NC:$NCIP” - $ExplorerForm.Name = “SDN Explorer NC:$NCIP” - $ExplorerForm.DataBindings.DefaultDataSourceUpdateMode = 0 - - # panel to have scroll bar - $panel = New-Object System.Windows.Forms.Panel - $panel.BackColor = [System.Drawing.Color]::Silver - $panel.BorderStyle = [System.Windows.Forms.BorderStyle]::FixedSingle - $panel.Location = New-Object System.Drawing.Point (5,5) - - - $System_Drawing_Point = New-Object System.Drawing.Point - $System_Drawing_Point.X = 80 - $System_Drawing_Point.Y = 20 - for ($it = 0; $it -lt $DataArr.Count ;$it++) - { - $button = New-Object System.Windows.Forms.Button - $System_Drawing_SizeButton = New-Object System.Drawing.Size - $System_Drawing_SizeButton.Width = 240 - $System_Drawing_SizeButton.Height = 23 - $button.TabIndex = 0 - $button.Name = “UnlockAccountButton” - $button.Size = $System_Drawing_SizeButton - $button.UseVisualStyleBackColor = $True - $button.Text = $DataArr[$it].Name - $button.Location = $System_Drawing_Point - $button.DataBindings.DefaultDataSourceUpdateMode = 0 - $scriptBlock = $DataArr[$it].Value[0] - $button.add_Click($scriptBlock) - $panel.Controls.Add($button) - - - $putButton = New-Object System.Windows.Forms.Button - $System_Drawing_SizeButton = New-Object System.Drawing.Size - $System_Drawing_SizeButton.Width = 60 - $System_Drawing_SizeButton.Height = 23 - $putButton.TabIndex = 0 - $putButton.Name = "Put” - $putButton.Size = $System_Drawing_SizeButton - $putButton.UseVisualStyleBackColor = $True - $putButton.Text = "Put" - $putButton.Location = New-Object System.Drawing.Size(340,$System_Drawing_Point.Y) - $putButton.DataBindings.DefaultDataSourceUpdateMode = 0 - if($DataArr[$it].Value.Count -gt 1) - { - $scriptBlock = $DataArr[$it].Value[1] - } - else - { - $putButton.Enabled = $false - } - $putButton.add_Click($scriptBlock) - $panel.Controls.Add($putButton) - - - $DeleteButton = New-Object System.Windows.Forms.Button - $System_Drawing_SizeButton = New-Object System.Drawing.Size - $System_Drawing_SizeButton.Width = 60 - $System_Drawing_SizeButton.Height = 23 - $DeleteButton.TabIndex = 0 - $DeleteButton.Name = "Delete” - $DeleteButton.Size = $System_Drawing_SizeButton - $DeleteButton.UseVisualStyleBackColor = $True - $DeleteButton.Text = "Delete" - $DeleteButton.Location = New-Object System.Drawing.Size(420,$System_Drawing_Point.Y) - $DeleteButton.DataBindings.DefaultDataSourceUpdateMode = 0 - if($DataArr[$it].Value.Count -gt 2) - { - $scriptBlock = $DataArr[$it].Value[2] - } - else - { - $DeleteButton.Enabled = $false - } - $DeleteButton.add_Click($scriptBlock) - $panel.Controls.Add($DeleteButton) - - - $System_Drawing_Point.Y += 33 - } - - - if($System_Drawing_Point.Y -ge 700) - { - $yPoint = 700 - } - else - { - $yPoint = $System_Drawing_Point.Y + 50 - } - - $System_Drawing_Size = New-Object System.Drawing.Size - $System_Drawing_Size.Width = 560 - $System_Drawing_Size.Height = $yPoint - $ExplorerForm.ClientSize = $System_Drawing_Size - - $System_Drawing_Size.Width -= 10 - $System_Drawing_Size.Height -= 10 - $panel.Size = $System_Drawing_Size - $panel.AutoScroll = $true - $ExplorerForm.Controls.Add($panel) - - #endregion Generated Form Code - - #Save the initial state of the form - $InitialFormWindowState = $ExplorerForm.WindowState - #Init the OnLoad event to correct the initial state of the form - $ExplorerForm.add_Load($OnLoadForm_StateCorrection) - #Show the Form - $ExplorerForm.ShowDialog()| Out-Null - -} - -function GenerateArrayForm { - -param( - [Parameter(mandatory=$true)] - [string] $HandlerFunc, - - [Parameter(mandatory=$true)] - [string] $RemoveFunc, - - [Parameter(mandatory=$true)] - [string] $NCIP, - - [Parameter(mandatory=$false)] - [object] - $NCCredential= [System.Management.Automation.PSCredential]::Empty, - - [Parameter(mandatory=$true)] - [bool] - $EnableMultiWindow=$true - ) - - if ($HandlerFunc -eq "Get-NCConnectivityCheckResult" -and $script:ncVMCredentials -eq [System.Management.Automation.PSCredential]::Empty) - { - $script:ncVMCredentials = Get-Credential -Message "Please give administrator credential of NC" -UserName "Administrator" - } - - - if($EnableMultiWindow) - { - $progress = [powershell]::create() - - $progressScript = { - param( - [string] $HandlerFunc, - [string] $RemoveFunc, - [string] $NCIP, - [object] $NCCredential= [System.Management.Automation.PSCredential]::Empty, - [bool] $EnableMultiWindow=$true, - [string] $CurWorDir, - [object] $NCVMCredential= [System.Management.Automation.PSCredential]::Empty - ) - - try{ - - Set-Location $CurWorDir - Import-Module .\SDNExplorer.ps1 -ArgumentList $NCIP,$NCCredential,$true,$true - GenerateArrayFormHelper -HandlerFunc $HandlerFunc -RemoveFunc $RemoveFunc -NCIP $NCIP -NCCredential $NCCredential -EnableMultiWindow $EnableMultiWindow -NCVMCredential $NCVMCredential - } - catch - { - [System.Windows.Forms.MessageBox]::Show($_) - } - } - - $parameters = @{} - $parameters.HandlerFunc = $HandlerFunc - $parameters.RemoveFunc = $RemoveFunc - $parameters.NCIP = $NCIP - $parameters.NCCredential = $NCCredential - $parameters.EnableMultiWindow = $EnableMultiWindow - $parameters.CurWorDir = $pwd - $parameters.NCVMCredential = $script:ncVMCredentials - - $progress.AddScript($progressScript) - $progress.AddParameters($parameters) - $progress.BeginInvoke() - - } - else{ - GenerateArrayFormHelper -HandlerFunc $HandlerFunc -RemoveFunc $RemoveFunc -NCIP $NCIP -NCCredential $NCCredential -EnableMultiWindow $EnableMultiWindow -NCVMCredential $script:ncVMCredentials - } - -} - -function GenerateArrayFormHelper { - -param( - [Parameter(mandatory=$true)] - [string] $HandlerFunc, - - [Parameter(mandatory=$true)] - [string] $RemoveFunc, - - [Parameter(mandatory=$true)] - [string] $NCIP, - - [Parameter(mandatory=$false)] - [object] - $NCCredential= [System.Management.Automation.PSCredential]::Empty, - - [Parameter(mandatory=$true)] - [bool] - $EnableMultiWindow=$true, - - [Parameter(mandatory=$false)] - [object] - $NCVMCredential= [System.Management.Automation.PSCredential]::Empty - ) - - . .\NetworkControllerRESTWrappers.ps1 -ComputerName $NCIP -Username $null -Password $null -Credential $Script:NCCredential - - [reflection.assembly]::loadwithpartialname(“System.Windows.Forms”) | Out-Null - [reflection.assembly]::loadwithpartialname(“System.Drawing”) | Out-Null - #endregion - - #region Generated Form Objects - $ExplorerForm = New-Object System.Windows.Forms.Form - $InitialFormWindowState = New-Object System.Windows.Forms.FormWindowState - #endregion Generated Form Objects - - - $OnLoadForm_StateCorrection= - {#Correct the initial state of the form to prevent the .Net maximized form issue - $ExplorerForm.WindowState = $InitialFormWindowState - } - - #———————————————- - #region Generated Form Code - $ExplorerForm.Text = “$HandlerFunc NC:$NCIP” - $ExplorerForm.Name = “$HandlerFunc NC:$NCIP” - $ExplorerForm.DataBindings.DefaultDataSourceUpdateMode = 0 - - # panel to have scroll bar - $panel = New-Object System.Windows.Forms.Panel - $panel.BackColor = [System.Drawing.Color]::Silver - $panel.BorderStyle = [System.Windows.Forms.BorderStyle]::FixedSingle - $panel.Location = New-Object System.Drawing.Point (5,5) - - $extraSpace = 0 - - $dataArr = @() - $dataArr += &$HandlerFunc - - $failed = $false - foreach ($data in $dataArr) - { - if ($data.PSobject.Properties.name -match "nextLink") - { - $failed = $true - break; - } - } - - $System_Drawing_Point = New-Object System.Drawing.Point - $System_Drawing_Point.X = 80 - $System_Drawing_Point.Y = 20 - - if ($HandlerFunc -eq "Get-NCConnectivityCheckResult") - { - $diagButton = New-Object System.Windows.Forms.Button - $System_Drawing_SizeButton = New-Object System.Drawing.Size - $System_Drawing_SizeButton.Width = 240 - $System_Drawing_SizeButton.Height = 23 - $diagButton.TabIndex = 0 - $diagButton.Name = $data.resourceRef - $diagButton.Size = $System_Drawing_SizeButton - $diagButton.UseVisualStyleBackColor = $True - $diagButton.Text = "PUT=>/diagnostics/networkcontrollerstate" - $diagButton.Location = $System_Drawing_Point - $diagButton.DataBindings.DefaultDataSourceUpdateMode = 0 - $diagButton_add = $diagButton.add_Click - $diagButton_add.Invoke({ - - try - { - $verify = VerifyUserAction -String "Do you want to Put networkcontrollerstate?" - - if ($verify -eq $true) - { - $object = @{} - $object.properties = @{} - JSONPost -path "/diagnostics/networkcontrollerstate" -bodyObject $object - [System.Windows.Forms.MessageBox]::Show("Posted!!!") - } - } - catch - { - [System.Windows.Forms.MessageBox]::Show($_) - } - }) - $panel.Controls.Add($diagButton) - $System_Drawing_Point.Y += 33 - - - # Adding network controller statistics button - $ncStatsButton = New-Object System.Windows.Forms.Button - $System_Drawing_SizeButton = New-Object System.Drawing.Size - $System_Drawing_SizeButton.Width = 240 - $System_Drawing_SizeButton.Height = 23 - $ncStatsButton.TabIndex = 1 - $ncStatsButton.Name = $data.resourceRef - $ncStatsButton.Size = $System_Drawing_SizeButton - $ncStatsButton.UseVisualStyleBackColor = $True - $ncStatsButton.Text = "GET=>/monitoring/networkcontrollerstatistics" - $ncStatsButton.Location = $System_Drawing_Point - $ncStatsButton.DataBindings.DefaultDataSourceUpdateMode = 0 - $ncStatsButton_add = $ncStatsButton.add_Click - $ncStatsButton_add.Invoke({ - param([object]$sender) - - if($EnableMultiWindow) - { - $ps = [powershell]::create() - - $script = { - param( - [string] $ResourceRef, - - [string] $NCIP, - - [object]$NCCredential= [System.Management.Automation.PSCredential]::Empty, - - [string]$CurWorDir, - - [bool]$EnableMultiWindow - - ) - try{ - - Set-Location $CurWorDir - Import-Module -Force -Name .\SDNExplorer.ps1 -ArgumentList $NCIP,$NCCredential,$true,$true - JsonForm -ResourceRef $ResourceRef -NCIP $NCIP -NCCredential $NCCredential -EnableMultiWindow $true - } - catch{ - [System.Windows.Forms.MessageBox]::Show($_) - } - } - $parameters = @{} - $parameters.ResourceRef = "/monitoring/networkcontrollerstatistics" - $parameters.NCIP = $NCIP - $parameters.NCCredential = $NCCredential - $parameters.CurWorDir = $pwd - $parameters.EnableMultiWindow = $EnableMultiWindow - - $ps.AddScript( - $script - ) - $ps.AddParameters($parameters) - $ps.BeginInvoke() - } - else - { - JsonForm -ResourceRef $sender.Text -NCIP $NCIP -NCCredential $NCCredential - } - - }) - $panel.Controls.Add($ncStatsButton) - $System_Drawing_Point.Y += 33 - - $debugSFNSButton = New-Object System.Windows.Forms.Button - $System_Drawing_SizeButton = New-Object System.Drawing.Size - $System_Drawing_SizeButton.Width = 240 - $System_Drawing_SizeButton.Height = 23 - $debugSFNSButton.TabIndex = 0 - $debugSFNSButton.Name = "Debug-ServiceFabricNodeStatus" - $debugSFNSButton.Size = $System_Drawing_SizeButton - $debugSFNSButton.UseVisualStyleBackColor = $True - $debugSFNSButton.Text = "Debug-ServiceFabricNodeStatus" - $debugSFNSButton.Location = $System_Drawing_Point - $debugSFNSButton.DataBindings.DefaultDataSourceUpdateMode = 0 - $debugSFNSButton_add = $debugSFNSButton.add_Click - $debugSFNSButton.Enabled = $false - $debugSFNSButton_add.Invoke({ - - if ($EnableMultiWindow) - { - $ps = [powershell]::create() - - $script = { - param( - - [string]$Cmdlet, - - [object]$NCVMCredential= [System.Management.Automation.PSCredential]::Empty, - - [string] $NCIP, - - [object]$NCCredential= [System.Management.Automation.PSCredential]::Empty, - - [string]$CurWorDir, - - [bool]$EnableMultiWindow - ) - - try{ - Set-Location $CurWorDir - Import-Module .\SDNExplorer.ps1 -ArgumentList $NCIP,$NCCredential,$true,$true - RunNCCMDLet -CmdLet $Cmdlet -NCVMCred $NCVMCredential -NCIP $NCIP - } - catch{ - [System.Windows.Forms.MessageBox]::Show($_) - } - } - $parameters = @{} - $parameters.Cmdlet = "Debug-ServiceFabricNodeStatus" - $parameters.NCVMCredential = $NCVMCredential - $parameters.NCIP = $NCIP - $parameters.NCCredential = $NCCredential - $parameters.CurWorDir = $pwd - $parameters.EnableMultiWindow = $EnableMultiWindow - $ps.AddScript( - $script - ) - $ps.AddParameters($parameters) - $ps.BeginInvoke() - } - else - { - RunNCCMDLet -CmdLet "Debug-ServiceFabricNodeStatus" -NCVMCred $NCVMCredential -NCIP $NCIP - } - }) - $panel.Controls.Add($debugSFNSButton) - $System_Drawing_Point.Y += 33 - - $debugNCCSButton = New-Object System.Windows.Forms.Button - $System_Drawing_SizeButton = New-Object System.Drawing.Size - $System_Drawing_SizeButton.Width = 240 - $System_Drawing_SizeButton.Height = 23 - $debugNCCSButton.TabIndex = 0 - $debugNCCSButton.Name = "Debug-NetworkControllerConfigurationState" - $debugNCCSButton.Size = $System_Drawing_SizeButton - $debugNCCSButton.UseVisualStyleBackColor = $True - $debugNCCSButton.Text = "Debug-NetworkControllerConfigurationState" - $debugNCCSButton.Location = $System_Drawing_Point - $debugNCCSButton.DataBindings.DefaultDataSourceUpdateMode = 0 - $debugNCCSButton_add = $debugNCCSButton.add_Click - $debugNCCSButton_add.Invoke({ - - if ($EnableMultiWindow) - { - $ps = [powershell]::create() - - $script = { - param( - - [string]$Cmdlet, - - [object]$NCVMCredential= [System.Management.Automation.PSCredential]::Empty, - - [string] $NCIP, - - [object]$NCCredential= [System.Management.Automation.PSCredential]::Empty, - - [string]$CurWorDir, - - [bool]$EnableMultiWindow - ) - - try{ - Set-Location $CurWorDir - Import-Module .\SDNExplorer.ps1 -ArgumentList $NCIP,$NCCredential,$true,$true - RunNCCMDLet -CmdLet $Cmdlet -NCVMCred $NCVMCredential -NCIP $NCIP - } - catch{ - [System.Windows.Forms.MessageBox]::Show($_) - } - } - $parameters = @{} - $parameters.Cmdlet = "Debug-NetworkControllerConfigurationState" - $parameters.NCVMCredential = $NCVMCredential - $parameters.NCIP = $NCIP - $parameters.NCCredential = $NCCredential - $parameters.CurWorDir = $pwd - $parameters.EnableMultiWindow = $EnableMultiWindow - $ps.AddScript( - $script - ) - $ps.AddParameters($parameters) - $ps.BeginInvoke() - } - else - { - RunNCCMDLet -CmdLet "Debug-NetworkControllerConfigurationState" -NCVMCred $NCVMCredential -NCIP $NCIP - } - }) - $panel.Controls.Add($debugNCCSButton) - $System_Drawing_Point.Y += 33 - - $debugNCButton = New-Object System.Windows.Forms.Button - $System_Drawing_SizeButton = New-Object System.Drawing.Size - $System_Drawing_SizeButton.Width = 240 - $System_Drawing_SizeButton.Height = 23 - $debugNCButton.TabIndex = 0 - $debugNCButton.Name = "Debug-NetworkController" - $debugNCButton.Size = $System_Drawing_SizeButton - $debugNCButton.UseVisualStyleBackColor = $True - $debugNCButton.Text = "Debug-NetworkController" - $debugNCButton.Location = $System_Drawing_Point - $debugNCButton.DataBindings.DefaultDataSourceUpdateMode = 0 - $debugNCButton_add = $debugNCButton.add_Click - $debugNCButton_add.Invoke({ - - if ($EnableMultiWindow) - { - $ps = [powershell]::create() - - $script = { - param( - - [string]$Cmdlet, - - [object]$NCVMCredential= [System.Management.Automation.PSCredential]::Empty, - - [string] $NCIP, - - [object]$NCCredential= [System.Management.Automation.PSCredential]::Empty, - - [string]$CurWorDir, - - [bool]$EnableMultiWindow - ) - - try{ - Set-Location $CurWorDir - Import-Module .\SDNExplorer.ps1 -ArgumentList $NCIP,$NCCredential,$true,$true - RunNCCMDLet -CmdLet $Cmdlet -NCVMCred $NCVMCredential -NCIP $NCIP - } - catch{ - [System.Windows.Forms.MessageBox]::Show($_) - } - } - $parameters = @{} - $parameters.Cmdlet = "Debug-NetworkController" - $parameters.NCVMCredential = $NCVMCredential - $parameters.NCIP = $NCIP - $parameters.NCCredential = $NCCredential - $parameters.CurWorDir = $pwd - $parameters.EnableMultiWindow = $EnableMultiWindow - $ps.AddScript( - $script - ) - $ps.AddParameters($parameters) - $ps.BeginInvoke() - } - else - { - RunNCCMDLet -CmdLet "Debug-NetworkController" -NCVMCred $NCVMCredential -NCIP $NCIP - } - - [System.Windows.Forms.MessageBox]::Show("Started your request in background!!") - }) - $panel.Controls.Add($debugNCButton) - $System_Drawing_Point.Y += 33 - - } - elseif ($HandlerFunc -eq "Get-NCServer") - { - $runButton = New-Object System.Windows.Forms.Button - $System_Drawing_SizeButton = New-Object System.Drawing.Size - $System_Drawing_SizeButton.Width = 280 - $System_Drawing_SizeButton.Height = 23 - $runButton.TabIndex = 0 - $runButton.Name = $data.resourceRef - $runButton.Size = $System_Drawing_SizeButton - $runButton.UseVisualStyleBackColor = $True - $runButton.Text = "--Run Script Block--" - $locationY = $System_Drawing_Point.Y + 1 - $runButton.Location = New-Object System.Drawing.Size(10,$locationY) - $runButton.DataBindings.DefaultDataSourceUpdateMode = 0 - $runButton_add = $runButton.add_Click - $runButton_add.Invoke({ - if ($EnableMultiWindow) - { - $ps = [powershell]::create() - - $script = { - param( - - [object[]]$jsonObject, - - [string]$CurWorDir, - - [bool]$EnableMultiWindow - ) - - try{ - Set-Location $CurWorDir - Import-Module .\SDNExplorer.ps1 -ArgumentList $NCIP,$NCCredential,$true,$true - RunScriptForm -Servers $jsonObject - } - catch{ - [System.Windows.Forms.MessageBox]::Show($_) - } - } - $parameters = @{} - $parameters.jsonObject = $dataArr - $parameters.CurWorDir = $pwd - $parameters.EnableMultiWindow = $EnableMultiWindow - $ps.AddScript( - $script - ) - $ps.AddParameters($parameters) - $ps.BeginInvoke() - } - else - { - RunScriptForm -Servers $dataArr - } - }) - $panel.Controls.Add($runButton) - $System_Drawing_Point.Y += 33 - } - - - if ($dataArr.Count -gt 0 -and $failed -eq $false) - { - if ($dataArr.Count -ge 1) - { - if ($DataArr[0].resourceRef.Contains("networkInterfaces") -or $DataArr[0].resourceRef.Contains("loadBalancers")) - { - $extraSpace = 40 - } - } - - foreach ($data in $dataArr) - { - $System_Drawing_Point.X = 10 - $button = New-Object System.Windows.Forms.Button - $button.TabIndex = 0 - $button.Name = $data.resourceRef - $button.Size = New-Object System.Drawing.Size(280,23) - $button.UseVisualStyleBackColor = $True - $button.Text = $data.resourceRef - $locationY = $System_Drawing_Point.Y + 1 - $button.Location = New-Object System.Drawing.Size(10,$locationY) - $button.DataBindings.DefaultDataSourceUpdateMode = 0 - $button_add = $button.add_Click - $button_add.Invoke({ - - param([object]$sender,[string]$message) - - if($EnableMultiWindow) - { - $ps = [powershell]::create() - - $script = { - param( - [string] $ResourceRef, - - [string] $NCIP, - - [object]$NCCredential= [System.Management.Automation.PSCredential]::Empty, - - [string]$CurWorDir, - - [bool]$EnableMultiWindow - - ) - try{ - - Set-Location $CurWorDir - Import-Module -Force -Name .\SDNExplorer.ps1 -ArgumentList $NCIP,$NCCredential,$true,$true - JsonForm -ResourceRef $ResourceRef -NCIP $NCIP -NCCredential $NCCredential -EnableMultiWindow $true - } - catch{ - [System.Windows.Forms.MessageBox]::Show($_) - } - } - $parameters = @{} - $parameters.ResourceRef = $sender.Text - $parameters.NCIP = $NCIP - $parameters.NCCredential = $NCCredential - $parameters.CurWorDir = $pwd - $parameters.EnableMultiWindow = $EnableMultiWindow - - $ps.AddScript( - $script - ) - $ps.AddParameters($parameters) - $ps.BeginInvoke() - } - else - { - JsonForm -ResourceRef $sender.Text -NCIP $NCIP -NCCredential $NCCredential - } - - }) - $panel.Controls.Add($button) - $System_Drawing_Point.X += 285 - - if ($data.resourceRef.Contains("networkInterfaces")) - { - $ipBox = New-Object System.Windows.Forms.TextBox - $locationY = $System_Drawing_Point.Y + 1 - $locationX = $System_Drawing_Point.X + 1 - $ipBox.Location = New-Object System.Drawing.Size($locationX,$locationY) - $ipBox.Multiline = $false - $ipBox.WordWrap = $false - $ipBox.Size = New-Object System.Drawing.Size(80,23) - - try - { - $ipBox.Text = $data.properties.ipConfigurations[0].properties.privateIPAddress - } - catch - { - $ipBox.Text = "NULL" - } - $ipBox.Enabled = $false - $panel.Controls.Add($ipBox) - $System_Drawing_Point.X += 85 - } - elseif ($data.resourceRef.Contains("loadBalancers")) - { - $ipBox = New-Object System.Windows.Forms.TextBox - $locationY = $System_Drawing_Point.Y + 1 - $locationX = $System_Drawing_Point.X + 1 - $ipBox.Location = New-Object System.Drawing.Size($locationX,$locationY) - $ipBox.Multiline = $false - $ipBox.WordWrap = $false - $ipBox.Size = New-Object System.Drawing.Size(80,23) - - try - { - $ipBox.Text = $data.properties.frontendIPConfigurations[0].properties.privateIPAddress - } - catch - { - $ipBox.Text = "NULL" - } - $ipBox.Enabled = $false - $panel.Controls.Add($ipBox) - $System_Drawing_Point.X += 85 - } - - $instanceidbox = New-Object System.Windows.Forms.TextBox - $locationY = $System_Drawing_Point.Y + 1 - $locationX = $System_Drawing_Point.X + 1 - $instanceidbox.Location = New-Object System.Drawing.Size($locationX,$locationY) - $instanceidbox.Multiline = $false - $instanceidbox.WordWrap = $false - $instanceidbox.Size = New-Object System.Drawing.Size(210,23) - $instanceidbox.Text = $data.instanceid - $instanceidbox.Enabled = $false - $panel.Controls.Add($instanceidbox) - $System_Drawing_Point.X += 215 - $extraSpace = 100 - - $ProvisioningStateLabel = New-Object System.Windows.Forms.Label - $System_Drawing_SizeButton = New-Object System.Drawing.Size - $System_Drawing_SizeButton.Width = 80 - $System_Drawing_SizeButton.Height = 21 - $ProvisioningStateLabel.TabIndex = 0 - $ProvisioningStateLabel.Name = "Provisioning State" - $ProvisioningStateLabel.Size = $System_Drawing_SizeButton - $ProvisioningStateLabel.BorderStyle = [System.Windows.Forms.BorderStyle]::FixedSingle - - $provisioningState = "" - if ($data.resourceRef.Contains("connectivityCheckResults")) - { - $provisioningState = $data.properties.result.status - switch($data.properties.result.status) - { - "Success" { $ProvisioningStateLabel.ForeColor = [System.Drawing.Color]::Green } - "Failure" { $ProvisioningStateLabel.ForeColor = [System.Drawing.Color]::Red } - default { $ProvisioningStateLabel.ForeColor = [System.Drawing.Color]::Yellow } - } - } - else - { - $provisioningState = $data.properties.provisioningState - switch($data.properties.provisioningState) - { - "Succeeded" { $ProvisioningStateLabel.ForeColor = [System.Drawing.Color]::Green } - "Failed" { $ProvisioningStateLabel.ForeColor = [System.Drawing.Color]::Red } - default { $ProvisioningStateLabel.ForeColor = [System.Drawing.Color]::Yellow } - } - } - $ProvisioningStateLabel.BackColor = [System.Drawing.Color]::Silver; - $ProvisioningStateLabel.Text = $provisioningState - $ProvisioningStateLabel.TextAlign = [System.Drawing.ContentAlignment]::MiddleCenter - $locationX = $System_Drawing_Point.X + 5 - $ProvisioningStateLabel.Location = New-Object System.Drawing.Size($locationX,($System_Drawing_Point.Y + 1)) - $ProvisioningStateLabel.DataBindings.DefaultDataSourceUpdateMode = 0 - $panel.Controls.Add($ProvisioningStateLabel) - $System_Drawing_Point.X += 85 - - $DeleteButton = New-Object System.Windows.Forms.Button - $System_Drawing_SizeButton = New-Object System.Drawing.Size - $System_Drawing_SizeButton.Width = 60 - $System_Drawing_SizeButton.Height = 23 - $DeleteButton.TabIndex = 0 - $DeleteButton.Name = $data.resourceId - $DeleteButton.Size = $System_Drawing_SizeButton - $DeleteButton.UseVisualStyleBackColor = $True - $DeleteButton.Text = "Delete" - $locationX = $System_Drawing_Point.X + 5 - $DeleteButton.Location = New-Object System.Drawing.Size($locationX,$System_Drawing_Point.Y) - $DeleteButton.DataBindings.DefaultDataSourceUpdateMode = 0 - - $DeleteButton_add = $DeleteButton.add_Click - $DeleteButton_add.Invoke({ - param([object]$sender,[string]$message) - - $verify = VerifyUserAction - - if ($verify -eq $true) - { - &$RemoveFunc -ResourceIDs $sender.Name - $ExplorerForm.Close() - } - }) - $panel.Controls.Add($DeleteButton) - $System_Drawing_Point.Y += 33 - } - } - elseif ($HandlerFunc -ne "Get-NCConnectivityCheckResult") - { - [System.Windows.Forms.MessageBox]::Show("Not Configured!!!!") - return; - } - - if($System_Drawing_Point.Y -ge 700) - { - $yPoint = 700 - } - else - { - $yPoint = $System_Drawing_Point.Y + 50 - } - - $System_Drawing_Size = New-Object System.Drawing.Size - $System_Drawing_Size.Width = 600 + ( 2 * $extraSpace) - $System_Drawing_Size.Height = $yPoint - $ExplorerForm.ClientSize = $System_Drawing_Size - - $System_Drawing_Size.Width -= 10 - $System_Drawing_Size.Height -= 10 - $panel.Size = $System_Drawing_Size - $panel.AutoScroll = $true - $ExplorerForm.Controls.Add($panel) - - #endregion Generated Form Code - - #Save the initial state of the form - $InitialFormWindowState = $ExplorerForm.WindowState - #Init the OnLoad event to correct the initial state of the form - $ExplorerForm.add_Load($OnLoadForm_StateCorrection) - #Show the Form - $ExplorerForm.ShowDialog()| Out-Null - -} - -function RemoveObjForm { - -param( - [Parameter(mandatory=$true)] - [string] $HandlerFunc, - - [Parameter(mandatory=$true)] - [string] $GetFunc, - - [Parameter(mandatory=$true)] - [string] $NCIP, - - [Parameter(mandatory=$false)] - [object]$NCCredential= [System.Management.Automation.PSCredential]::Empty - ) - - . .\NetworkControllerRESTWrappers.ps1 -ComputerName $NCIP -Username $null -Password $null -Credential $Script:NCCredential - - try - { - $Allobjects = &$GetFunc - - $resourceIds = @() - $resourceIds += "None" - foreach ($obj in $Allobjects) - { - $resourceIds += $obj.resourceId - } - - $selectedResource = RadioForm -Name "$HandlerFunc" -Values $resourceIds - - if ($selectedResource -ne "None") - { - &$HandlerFunc -ResourceIDs $selectedResource - } - - } - catch - { - [System.Windows.Forms.MessageBox]::Show($_) - } - -} - -function PutNetworkInterface { - -param( - [Parameter(mandatory=$true)] - [string] $HandlerFunc, - - [Parameter(mandatory=$true)] - [string] $NCIP, - - [Parameter(mandatory=$false)] - [object]$NCCredential= [System.Management.Automation.PSCredential]::Empty - ) - - . .\NetworkControllerRESTWrappers.ps1 -ComputerName $NCIP -Username $null -Password $null -Credential $Script:NCCredential - - - try{ - $value = RadioForm -Name "Network type" -Values "Logical Network","Virtual Network" - - if ($value -eq "Logical Network") - { - $networks = Get-NCLogicalNetwork - } - else - { - $networks = Get-NCVirtualNetwork - } - - $networkRefArray = @() - foreach ($network in $networks) - { - $networkRefArray += $network.resourceId - } - - $selectedNetworkId = RadioForm -Name "Network" -Values $networkRefArray - - if ($value -eq "Logical Network") - { - $network = Get-NCLogicalNetwork -ResourceID $selectedNetworkId - } - else - { - $network = Get-NCVirtualNetwork -resourceID $selectedNetworkId - } - - $subnets = @() - foreach ($subnet in $network.properties.subnets) - { - $subnets += $subnet.resourceId - } - - $selectedSubnetId = RadioForm -Name "Subnet" -Values $subnets - - foreach ($snet in $network.properties.subnets) - { - if($snet.resourceId -eq $selectedSubnetId) - { - $subnet = $snet - #break - } - } - - $ip = GetValueForm -Name "IP Address" - if ([string]::IsNullOrEmpty($ip)) - { - throw "Missing IP!!!!" - } - - $mac = GetValueForm -Name "Mac Address" - if ([string]::IsNullOrEmpty($mac)) - { - throw "Missing Mac!!!!" - } - - $DNSServer = GetValueForm -Name "DNS Server" - - $acls = Get-NCAccessControlList - - $aclRes = @() - $aclRes += "None" - foreach ( $aclObj in $acls) - { - $aclRes += $aclObj.resourceId - } - $selectedAclId = RadioForm -Name "Acl" -Values $aclRes - - $acl = $null - foreach ( $aclObj in $acls) - { - if ($aclObj.resourceId -eq $selectedAclId) - { - $acl = $aclObj - } - } - - $resId = [system.guid]::NewGuid() - if ($value -eq "Logical Network") - { - $networkInterface = New-NCNetworkInterface -Subnet $subnet -IPAddress $ip -MACAddress $mac -DNSServers $DNSServer -acl $acl -resourceID $resId - } - else - { - $networkInterface = New-NCNetworkInterface -VirtualSubnet $subnet -IPAddress $ip -MACAddress $mac -DNSServers $DNSServer -acl $acl -resourceID $resId - } - - [System.Windows.Forms.MessageBox]::Show("Done!!!") - - JsonForm -ResourceRef $networkInterface.resourceRef -NCIP $NCIP -NCCredential $NCCredential - - } - catch - { - [System.Windows.Forms.MessageBox]::Show($_) - } - -} - -function PutLoadBalancer { - -param( - [Parameter(mandatory=$true)] - [string] $HandlerFunc, - - [Parameter(mandatory=$true)] - [string] $NCIP, - - [Parameter(mandatory=$false)] - [object]$NCCredential= [System.Management.Automation.PSCredential]::Empty - ) - - Import-Module .\NetworkControllerWorkloadHelpers.psm1 -Force - . .\NetworkControllerRESTWrappers.ps1 -ComputerName $NCIP -Username $null -Password $null -Credential $Script:NCCredential - - - try{ - - $vip = GetValueForm -Name "VIP Address" - if ([string]::IsNullOrEmpty($vip)) - { - throw "Missing VIP!!!!" - } - - $protocol = RadioForm -Name "Protocol" -Values "Tcp","Udp" - - $frontendPort = [int](GetValueForm -Name "Front End Port") - - $backendPort = [int](GetValueForm -Name "Front End Port") - - $enableOutboundNatstr = RadioForm -Name "Enable Outbound Nat" -Values "true","false" - - $enableOutboundNat = $false - if ($enableOutboundNatstr -eq "true") - { - $enableOutboundNat = $true - } - - #just to load all dependencies - $slbm = get-ncloadbalancermanager - - if ($slbm.properties.vipippools.count -lt 1) { - throw "New-LoadBalancerVIP requires at least one VIP pool in the NC Load balancer manager." - } - - $vipPools = $slbm.properties.vipippools - - # check if the input VIP is within range of one of the VIP pools - foreach ($vippool in $vipPools) { - # IP pool's resourceRef is in this format: - # /logicalnetworks/f8f67956-3906-4303-94c5-09cf91e7e311/subnets/aaf28340-30fe-4f27-8be4-40eca97b052d/ipPools/ed48962b-2789-41bf-aa7b-3e6d5b247384 - $sp = $vippool.resourceRef.split("/") - - $ln = Get-NCLogicalNetwork -resourceId $sp[2] #LN resourceid is always the first ID (after /logicalnetwork/) - if (-not $ln) { - throw "Can't find logical network with resourceId $($sp[2]) from NC." - } - - $subnet = $ln.properties.subnets | ? {$_.resourceId -eq $sp[4]} - if (-not $subnet) { - throw "can't find subnet with resourceId $($sp[4]) from NC." - } - - $pool = $subnet.properties.ipPools | ? {$_.resourceId -eq $sp[6]} - if (-not $pool) { - throw "can't find IP pool with resourceId $($sp[6]) from NC." - } - - $startIp = $pool.properties.startIpAddress - $endIp = $pool.properties.endIpAddress - if (IsIpWithinPoolRange -targetIp $vip -startIp $startIp -endIp $endIp) { - $isPoolPublic = $subnet.properties.isPublic - $vipLn = $ln - break; - } - } - - if (-not $vipLn) { - throw "$vip is not within range of any of the VIP pools managed by SLB manager." - } - - $lbfe = @(New-NCLoadBalancerFrontEndIPConfiguration -PrivateIPAddress $vip -Subnet ($vipLn.properties.Subnets[0])) - - $ips = @() - - $lbbe = @(New-NCLoadBalancerBackendAddressPool -IPConfigurations $ips) - $rules = @(New-NCLoadBalancerLoadBalancingRule -protocol $protocol -frontendPort $frontendPort -backendport $backendPort -enableFloatingIP $False -frontEndIPConfigurations $lbfe -backendAddressPool $lbbe) - - $LoadBalancerResourceID = [system.guid]::NewGuid() - - if ($enableOutboundNat) { - $onats = @(New-NCLoadBalancerOutboundNatRule -frontendipconfigurations $lbfe -backendaddresspool $lbbe) - $lb = New-NCLoadBalancer -ResourceID $LoadBalancerResourceID -frontendipconfigurations $lbfe -backendaddresspools $lbbe -loadbalancingrules $rules -outboundnatrules $onats - } else { - $lb = New-NCLoadBalancer -ResourceID $LoadBalancerResourceID -frontendipconfigurations $lbfe -backendaddresspools $lbbe -loadbalancingrules $rules - } - - [System.Windows.Forms.MessageBox]::Show("Done!!!") - - JsonForm -ResourceRef $lb.resourceRef -NCIP $NCIP -NCCredential $NCCredential - - } - catch - { - [System.Windows.Forms.MessageBox]::Show($_) - } - -} - -function RadioForm { - -[OutputType([string])] -param( - [string] $Name, - [string[]] $Values - ) - - - [reflection.assembly]::loadwithpartialname(“System.Windows.Forms”) | Out-Null - [reflection.assembly]::loadwithpartialname(“System.Drawing”) | Out-Null - #endregion - - #region Generated Form Objects - $ExplorerForm = New-Object System.Windows.Forms.Form - $InitialFormWindowState = New-Object System.Windows.Forms.FormWindowState - #endregion Generated Form Objects - - - $OnLoadForm_StateCorrection= - {#Correct the initial state of the form to prevent the .Net maximized form issue - $ExplorerForm.WindowState = $InitialFormWindowState - } - - #———————————————- - #region Generated Form Code - $ExplorerForm.Text = “Please select $Name” - $ExplorerForm.Name = “$Name” - $ExplorerForm.DataBindings.DefaultDataSourceUpdateMode = 0 - - # panel to have scroll bar - $panel = New-Object System.Windows.Forms.Panel - $panel.BackColor = [System.Drawing.Color]::Silver - $panel.BorderStyle = [System.Windows.Forms.BorderStyle]::FixedSingle - $panel.Location = New-Object System.Drawing.Point (5,5) - - $System_Drawing_Point = New-Object System.Drawing.Point - $System_Drawing_Point.X = 80 - $System_Drawing_Point.Y = 20 - $radioButtons = @() - - for ($it = 0; $it -lt $Values.Count ;$it++) - { - $radioButton = New-Object System.Windows.Forms.RadioButton - $radioButton.Location = $System_Drawing_Point - $radioButton.Name = $Values[$it] - $radioButton.TabIndex = 5 - $radioButton.Text = $Values[$it] - $radioButton.Size = New-Object System.Drawing.Size(500, 20) - $radioButtons += $radioButton - - if ([string]::IsNullOrEmpty($selectedValue)) - { - $selectedValue = $Values[$it] - $radioButton.Checked = $true - } - - $System_Drawing_Point.Y += 33 - } - - $groupBox1 = New-Object System.Windows.Forms.GroupBox - $groupBox1.Location = New-Object System.Drawing.Point(60, 10) - $groupBox1.Name = "groupBox1 $Name" - $groupBox1.Size = New-Object System.Drawing.Size(500, $System_Drawing_Point.Y) - $groupBox1.TabIndex = 0 - $groupBox1.TabStop = $false - $groupBox1.Text = "Select $Name" - $groupBox1.Controls.AddRange($radioButtons) - $panel.Controls.Add($groupBox1) - $System_Drawing_Point.Y += 33 - - $button = New-Object System.Windows.Forms.Button - $System_Drawing_SizeButton = New-Object System.Drawing.Size - $System_Drawing_SizeButton.Width = 240 - $System_Drawing_SizeButton.Height = 23 - $button.TabIndex = 0 - $button.Name = “Select” - $button.Size = $System_Drawing_SizeButton - $button.UseVisualStyleBackColor = $True - $button.Text = "Select $Name" - $button.Location = $System_Drawing_Point - $button.DataBindings.DefaultDataSourceUpdateMode = 0 - #$scriptBlock = $DataArr[$it].Value - - - $button.add_Click( - { - $ExplorerForm.Close() - }) - $panel.Controls.Add($button) - - $System_Drawing_Point.Y += 33 - - if($System_Drawing_Point.Y -ge 700) - { - $yPoint = 700 - } - else - { - $yPoint = $System_Drawing_Point.Y + 50 - } - - $System_Drawing_Size = New-Object System.Drawing.Size - $System_Drawing_Size.Width = 600 - $System_Drawing_Size.Height = $yPoint - $ExplorerForm.ClientSize = $System_Drawing_Size - - $System_Drawing_Size.Width -= 10 - $System_Drawing_Size.Height -= 10 - $panel.Size = $System_Drawing_Size - $panel.AutoScroll = $true - $ExplorerForm.Controls.Add($panel) - - #endregion Generated Form Code - - #Save the initial state of the form - $InitialFormWindowState = $ExplorerForm.WindowState - #Init the OnLoad event to correct the initial state of the form - $ExplorerForm.add_Load($OnLoadForm_StateCorrection) - #Show the Form - $ExplorerForm.ShowDialog()| Out-Null - - foreach ($radioButton in $radioButtons) - { - if ($radioButton.Checked) - { - $selectedValue = $radioButton.Text - } - } - - return $selectedValue - -} #End Function RadioForm - -function GetValueForm { - -param( - [string] $Name - ) - - [reflection.assembly]::loadwithpartialname(“System.Windows.Forms”) | Out-Null - [reflection.assembly]::loadwithpartialname(“System.Drawing”) | Out-Null - #endregion - - #region Generated Form Objects - $ExplorerForm = New-Object System.Windows.Forms.Form - $InitialFormWindowState = New-Object System.Windows.Forms.FormWindowState - $selectedValue = $null - #endregion Generated Form Objects - - - $OnLoadForm_StateCorrection= - {#Correct the initial state of the form to prevent the .Net maximized form issue - $ExplorerForm.WindowState = $InitialFormWindowState - } - - #———————————————- - #region Generated Form Code - $ExplorerForm.Text = “Please select $Name” - $ExplorerForm.Name = “$Name” - $ExplorerForm.DataBindings.DefaultDataSourceUpdateMode = 0 - - $System_Drawing_Point = New-Object System.Drawing.Point - $System_Drawing_Point.X = 80 - $System_Drawing_Point.Y = 20 - - - $getBox = New-Object System.Windows.Forms.TextBox - $getBox.Location = $System_Drawing_Point - $getBox.Multiline = $false - $getBox.WordWrap = $false - $getBox.Size = New-Object System.Drawing.Size(240,23) - $getBox.Text = "" - $ExplorerForm.Controls.Add($getBox) - - $System_Drawing_Point.Y += 33 - - $button = New-Object System.Windows.Forms.Button - $System_Drawing_SizeButton = New-Object System.Drawing.Size - $System_Drawing_SizeButton.Width = 240 - $System_Drawing_SizeButton.Height = 23 - $button.TabIndex = 0 - $button.Name = “Select” - $button.Size = $System_Drawing_SizeButton - $button.UseVisualStyleBackColor = $True - $button.Text = "Select $Name" - $button.Location = $System_Drawing_Point - $button.DataBindings.DefaultDataSourceUpdateMode = 0 - $scriptBlock = $DataArr[$it].Value - $button.add_Click( - { - $ExplorerForm.Close() - }) - $ExplorerForm.Controls.Add($button) - - $System_Drawing_Point.Y += 33 - - $System_Drawing_Size = New-Object System.Drawing.Size - $System_Drawing_Size.Width = 600 - $System_Drawing_Size.Height = $System_Drawing_Point.Y + 50 - $ExplorerForm.ClientSize = $System_Drawing_Size - - #endregion Generated Form Code - - #Save the initial state of the form - $InitialFormWindowState = $ExplorerForm.WindowState - #Init the OnLoad event to correct the initial state of the form - $ExplorerForm.add_Load($OnLoadForm_StateCorrection) - #Show the Form - $ExplorerForm.ShowDialog()| Out-Null - - return $getBox.Text - -} #End Function GetValueForm - -function VerifyUserAction { - param( - [string] $String - ) - - [reflection.assembly]::loadwithpartialname(“System.Windows.Forms”) | Out-Null - [reflection.assembly]::loadwithpartialname(“System.Drawing”) | Out-Null - #endregion - - #region Generated Form Objects - $ExplorerForm = New-Object System.Windows.Forms.Form - $InitialFormWindowState = New-Object System.Windows.Forms.FormWindowState - $ret = $false - #endregion Generated Form Objects - - - $OnLoadForm_StateCorrection= - {#Correct the initial state of the form to prevent the .Net maximized form issue - $ExplorerForm.WindowState = $InitialFormWindowState - } - - #———————————————- - #region Generated Form Code - if ([string]::IsNullOrEmpty($String)) - { - $String = “DO YOU WANT TO CONTINUE???” - } - $ExplorerForm.Text = $String - $ExplorerForm.Name = “Verify!!!” - $ExplorerForm.DataBindings.DefaultDataSourceUpdateMode = 0 - - $System_Drawing_Point = New-Object System.Drawing.Point - $System_Drawing_Point.X = 80 - $System_Drawing_Point.Y = 20 - - $Stop = New-Object System.Windows.Forms.Button - $System_Drawing_SizeButton = New-Object System.Drawing.Size - $System_Drawing_SizeButton.Width = 200 - $System_Drawing_SizeButton.Height = 23 - $Stop.TabIndex = 0 - $Stop.Name = “Stop” - $Stop.Size = $System_Drawing_SizeButton - $Stop.UseVisualStyleBackColor = $True - $Stop.Text = "Stop" - $Stop.Location = $System_Drawing_Point - $Stop.DataBindings.DefaultDataSourceUpdateMode = 0 - $Stop.add_Click( - { - $ret = $false - $ExplorerForm.Close() - }) - $ExplorerForm.Controls.Add($Stop) - - $System_Drawing_Point.X += 210 - - $Continue = New-Object System.Windows.Forms.Button - $System_Drawing_SizeButton = New-Object System.Drawing.Size - $System_Drawing_SizeButton.Width = 200 - $System_Drawing_SizeButton.Height = 23 - $Continue.TabIndex = 0 - $Continue.Name = “Continue” - $Continue.Size = $System_Drawing_SizeButton - $Continue.UseVisualStyleBackColor = $True - $Continue.Text = "Continue" - $Continue.Location = $System_Drawing_Point - $Continue.DataBindings.DefaultDataSourceUpdateMode = 0 - $Continue.add_Click( - { - $Continue.Text = "true" - $ExplorerForm.Close() - }) - $ExplorerForm.Controls.Add($Continue) - - $System_Drawing_Point.Y += 33 - - $System_Drawing_Size = New-Object System.Drawing.Size - $System_Drawing_Size.Width = 570 - $System_Drawing_Size.Height = $System_Drawing_Point.Y + 50 - $ExplorerForm.ClientSize = $System_Drawing_Size - - #endregion Generated Form Code - - #Save the initial state of the form - $InitialFormWindowState = $ExplorerForm.WindowState - #Init the OnLoad event to correct the initial state of the form - $ExplorerForm.add_Load($OnLoadForm_StateCorrection) - #Show the Form - - $ExplorerForm.ShowDialog()| Out-Null - - if ($Continue.Text -eq "true") - { - $ret = $True - } - - return $ret - -} #End Function VerifyUserAction - -function JsonForm { - -param( - [Parameter(mandatory=$true)] - [string] $ResourceRef, - - [Parameter(mandatory=$true)] - [string] $NCIP, - - [Parameter(mandatory=$true)] - [object]$NCCredential= [System.Management.Automation.PSCredential]::Empty, - - [Parameter(mandatory=$false)] - [bool] $EnableMultiWindow=$true - ) - - . .\NetworkControllerRESTWrappers.ps1 -ComputerName $NCIP -Username $null -Password $null -Credential $Script:NCCredential - - [reflection.assembly]::loadwithpartialname(“System.Windows.Forms”) | Out-Null - [reflection.assembly]::loadwithpartialname(“System.Drawing”) | Out-Null - #endregion - - #region Generated Form Objects - $ExplorerForm = New-Object System.Windows.Forms.Form - $InitialFormWindowState = New-Object System.Windows.Forms.FormWindowState - $objTextBoxVFP = $null - #endregion Generated Form Objects - - - $OnLoadForm_StateCorrection= - {#Correct the initial state of the form to prevent the .Net maximized form issue - $ExplorerForm.WindowState = $InitialFormWindowState - } - - #———————————————- - #region Generated Form Code - $ExplorerForm.Text = “$ResourceRef NC:$NCIP $pwd” - $ExplorerForm.Name = “$ResourceRef NC:$NCIP” - $ExplorerForm.DataBindings.DefaultDataSourceUpdateMode = 0 - - $ExplorerForm.ClientSize = New-Object System.Drawing.Size(700,800) - - $jsonObject = JSONGet -NetworkControllerRestIP $NCIP -path $ResourceRef -credential $NCCredential - - $getBox = New-Object System.Windows.Forms.TextBox - $getBox.Location = New-Object System.Drawing.Size(40,20) - $getBox.Multiline = $true - $getBox.ScrollBars = [System.Windows.Forms.ScrollBars]::Both - - $getBox.WordWrap = $false - $getBox.Size = New-Object System.Drawing.Size(250,60) - $getBox.Text = "Any Resource reference" - $ExplorerForm.Controls.Add($getBox) - - - $button1 = New-Object System.Windows.Forms.Button - $button1.TabIndex = 0 - $button1.Name = “Get” - $button1.Size = New-Object System.Drawing.Size(80,60) - $button1.UseVisualStyleBackColor = $True - $button1.Text = "Get" - $button1.Location = New-Object System.Drawing.Size(310,20) - $button1.DataBindings.DefaultDataSourceUpdateMode = 0 - - $scriptBlock = { - - if ($EnableMultiWindow) - { - $ps = [powershell]::create() - - $script = { - param( - [string] $ResourceRef, - - [string] $NCIP, - - [object]$NCCredential= [System.Management.Automation.PSCredential]::Empty, - - [string]$CurWorDir, - - [bool]$EnableMultiWindow - ) - try{ - Set-Location $CurWorDir - Import-Module -Force -Name .\SDNExplorer.ps1 -ArgumentList $NCIP,$NCCredential,$true,$true - JsonForm -ResourceRef $ResourceRef -NCIP $NCIP -NCCredential $NCCredential -EnableMultiWindow $true - } - catch{ - [System.Windows.Forms.MessageBox]::Show($_) - } - } - $parameters = @{} - $parameters.ResourceRef = $getBox.Text - $parameters.NCIP = $NCIP - $parameters.NCCredential = $NCCredential - $parameters.CurWorDir = $pwd - $parameters.EnableMultiWindow = $EnableMultiWindow - $ps.AddScript( - $script - ) - $ps.AddParameters($parameters) - $ps.BeginInvoke() - } - else - { - JsonForm -ResourceRef $getBox.Text -NCIP $NCIP -NCCredential $NCCredential - } - } - - $button1.add_Click($scriptBlock) - $ExplorerForm.Controls.Add($button1) - - $button2 = New-Object System.Windows.Forms.Button - $button2.TabIndex = 0 - $button2.Name = “Enable Editing” - $button2.Size = New-Object System.Drawing.Size(80,60) - $button2.UseVisualStyleBackColor = $True - $button2.Text = "Enable Editing" - $button2.Location = New-Object System.Drawing.Size(410,20) - $button2.DataBindings.DefaultDataSourceUpdateMode = 0 - $scriptBlockEnable = { - $objTextBox.Enabled = $true - $ExplorerForm.Controls.Remove($button2) - $ExplorerForm.Controls.Add($buttonPost) - $objTextBox.ReadOnly = $false - - } - $button2.add_Click($scriptBlockEnable) - $ExplorerForm.Controls.Add($button2) - - $buttonPost = New-Object System.Windows.Forms.Button - $buttonPost.TabIndex = 0 - $buttonPost.Name = “Post” - $buttonPost.Size = New-Object System.Drawing.Size(80,60) - $buttonPost.UseVisualStyleBackColor = $True - $buttonPost.Text = "Post" - $buttonPost.Location = New-Object System.Drawing.Size(410,20) - $buttonPost.DataBindings.DefaultDataSourceUpdateMode = 0 - $scriptBlockPost = { - $body = ConvertFrom-Json $objTextBox.Text - $parse = $ResourceRef.Split("/") - $rid = "" - - for($it = 0 ;$it -lt $parse.Count -1; $it++) - { - if( -not [string]::IsNullOrEmpty($parse[$it])) - { - $rid += "/" - $rid += $parse[$it] - } - } - - try - { - JSONPost -path $rid -bodyObject $body - [System.Windows.Forms.MessageBox]::Show("Done!!!!") - } - catch - { - [System.Windows.Forms.MessageBox]::Show("Post Failed!!!!") - } - } - $buttonPost.add_Click($scriptBlockPost) - - - - $objTextBox = New-Object System.Windows.Forms.RichTextBox - $objTextBox.Location = New-Object System.Drawing.Size(40,120) - $objTextBox.Multiline = $true - $objTextBox.ScrollBars = [System.Windows.Forms.ScrollBars]::Both - - $objTextBox.WordWrap = $false - $objTextBox.Size = New-Object System.Drawing.Size(600,630) - $objTextBox.Text = $jsonObject | ConvertTo-Json -Depth 20 - $objTextBox.ReadOnly = $true - $ExplorerForm.Controls.Add($objTextBox) - - - $SearchBox1 = New-Object System.Windows.Forms.RichTextBox - $SearchBox1.Location = New-Object System.Drawing.Size(40,100) - $SearchBox1.Multiline = $false - - $SearchBox1.WordWrap = $false - $SearchBox1.Size = New-Object System.Drawing.Size(500,20) - $SearchBox1.Text = "Enter Text to search here..." - $SearchBox1.ForeColor = [Drawing.Color]::Gray - $SearchBox1.add_KeyPress({ - - #Event Argument: $_ = [System.Windows.Forms.KeyEventArgs] - if($_.KeyChar -eq 13) - { - &$scriptBlockfindButton - } - elseif ($SearchBox1.Text -eq "Enter Text to search here...") - { - $SearchBox1.Text = "" - } - }) - $ExplorerForm.Controls.Add($SearchBox1) - - $findButton = New-Object System.Windows.Forms.Button - $findButton.TabIndex = 0 - $findButton.Name = “Find” - $findButton.Size = New-Object System.Drawing.Size(100,20) - $findButton.UseVisualStyleBackColor = $True - $findButton.Text = "Find" - $findButton.Location = New-Object System.Drawing.Size(540,100) - $findButton.DataBindings.DefaultDataSourceUpdateMode = 0 - $scriptBlockfindButton = { - $textBoxes = @() - $textBoxes += $objTextBox - - if ($objTextBoxVFP -ne $null) - { - $textBoxes += $objTextBoxVFP - } - $searchStr = $SearchBox1.Text - $found = $false - foreach ( $textBox in $textBoxes) - { - $i = 0 - $textBox.Text -Split '\n' | % { - $textBox.SelectionStart = $i - $line = $_ - $textBox.SelectionLength = $line.Length - if (Select-String -Pattern $searchStr -InputObject $line) - { - $textBox.SelectionColor = [Drawing.Color]::DarkGreen - $textBox.SelectionBackColor = [Drawing.Color]::White - - if (-not $found) - { - $textBox.ScrollToCaret() - $found = $true - } - } - else - { - $textBox.SelectionColor = [Drawing.Color]::Black - $textBox.SelectionBackColor = [System.Drawing.Color]::FromArgb(240,240,240) - } - $i += $line.Length + 1 - } - } - - $searchBox1.ForeColor = [Drawing.Color]::Black - - if ($found) - { - $SearchBox1.ForeColor = [Drawing.Color]::DarkGreen - } - else - { - $SearchBox1.ForeColor = [Drawing.Color]::Red - $SearchBox1.Text += " <-- NOT FOUND" - } - - } - $findButton.add_Click($scriptBlockfindButton) - $ExplorerForm.Controls.Add($findButton) - - #endregion Generated Form Code - - #Save the initial state of the form - $InitialFormWindowState = $ExplorerForm.WindowState - #Init the OnLoad event to correct the initial state of the form - $ExplorerForm.add_Load($OnLoadForm_StateCorrection) - - - if ($ResourceRef.Contains("virtualServers")) - { - $runCommand = New-Object System.Windows.Forms.Button - $runCommand.TabIndex = 0 - $runCommand.Name = “Run Command” - $runCommand.Size = New-Object System.Drawing.Size(80,60) - $runCommand.UseVisualStyleBackColor = $True - $runCommand.Text = "Run Command" - $runCommand.Location = New-Object System.Drawing.Size(510,20) - $runCommand.DataBindings.DefaultDataSourceUpdateMode = 0 - $scriptBlock = { - - foreach ($address in $jsonObject.properties.connections[0].managementAddresses) - { - try - { - [ipaddress]$address - - try - { - $ServerName = ([System.Net.Dns]::GetHostByAddress($address)).hostname - } - catch - { - [System.Windows.Forms.MessageBox]::Show("GetHostByAddress failed!!!!") - return - } - } - catch - { - $ServerName = $address - break; - } - } - - if([string]::IsNullOrEmpty($ServerName)) - { - [System.Windows.Forms.MessageBox]::Show("Server Name Missing!!!!") - return - } - - start-process -FilePath powershell -ArgumentList @('-NoExit',"-command etsn $ServerName -Credential Get-Credential") - } - $runCommand.add_Click($scriptBlock) - $ExplorerForm.Controls.Add($runCommand) - } - elseif ($ResourceRef.Contains("server")) - { - $ExplorerForm.ClientSize = New-Object System.Drawing.Size(900,800) - - $ovsdb = New-Object System.Windows.Forms.Button - $ovsdb.TabIndex = 0 - $ovsdb.Name = “OVSDB Policies” - $ovsdb.Size = New-Object System.Drawing.Size(100,40) - $ovsdb.UseVisualStyleBackColor = $True - $ovsdb.Text = "OVSDB Policies" - $ovsdb.Location = New-Object System.Drawing.Size(700,100) - $ovsdb.DataBindings.DefaultDataSourceUpdateMode = 0 - $scriptBlock1 = { - - if ($EnableMultiWindow) - { - $ps = [powershell]::create() - - $script = { - param( - - [object]$jsonObject, - - [string]$CurWorDir, - - [bool]$EnableMultiWindow - ) - - try{ - Set-Location $CurWorDir - Import-Module .\SDNExplorer.ps1 -ArgumentList $NCIP,$NCCredential,$true,$true - OvsdbForm -Server $jsonObject -EnableMultiWindow $true - } - catch{ - [System.Windows.Forms.MessageBox]::Show($_) - } - } - $parameters = @{} - $parameters.jsonObject = $jsonObject - $parameters.CurWorDir = $pwd - $parameters.EnableMultiWindow = $EnableMultiWindow - $ps.AddScript( - $script - ) - $ps.AddParameters($parameters) - $ps.BeginInvoke() - } - else - { - OvsdbForm -Server $jsonObject - } - } - $ovsdb.add_Click($scriptBlock1) - $ExplorerForm.Controls.Add($ovsdb) - - $vfp = New-Object System.Windows.Forms.Button - $vfp.TabIndex = 0 - $vfp.Name = “VFP Policies” - $vfp.Size = New-Object System.Drawing.Size(100,40) - $vfp.UseVisualStyleBackColor = $True - $vfp.Text = "VFP Policies" - $vfp.Location = New-Object System.Drawing.Size(700,160) - - $vfp.DataBindings.DefaultDataSourceUpdateMode = 0 - $scriptBlock2 = { - if ($EnableMultiWindow) - { - $ps = [powershell]::create() - - $script = { - param( - - [object]$jsonObject, - - [string]$CurWorDir - ) - - try{ - Set-Location $CurWorDir - Import-Module .\SDNExplorer.ps1 -ArgumentList $NCIP,$NCCredential,$true,$true - GetAllVFPPolices -Server $jsonObject -EnableMultiWindow $true - } - catch{ - [System.Windows.Forms.MessageBox]::Show($_) - } - } - $parameters = @{} - $parameters.jsonObject = $jsonObject - $parameters.CurWorDir = $pwd - $ps.AddScript( - $script - ) - $ps.AddParameters($parameters) - $ps.BeginInvoke() - } - else - { - GetAllVFPPolices -Server $jsonObject - } - } - $vfp.add_Click($scriptBlock2) - $ExplorerForm.Controls.Add($vfp) - - $runCommand = New-Object System.Windows.Forms.Button - $runCommand.TabIndex = 0 - $runCommand.Name = “Run Command” - $runCommand.Size = New-Object System.Drawing.Size(100,40) - $runCommand.UseVisualStyleBackColor = $True - $runCommand.Text = "Run Command" - $runCommand.Location = New-Object System.Drawing.Size(700,220) - $runCommand.DataBindings.DefaultDataSourceUpdateMode = 0 - $scriptBlock3 = { - - foreach ($address in $jsonObject.properties.connections[0].managementAddresses) - { - try - { - [ipaddress]$address - } - catch - { - $ServerName = $address - break; - } - } - - if([string]::IsNullOrEmpty($ServerName)) - { - [System.Windows.Forms.MessageBox]::Show("Server Name Missing!!!!") - return - } - - start-process -FilePath powershell -ArgumentList @('-NoExit',"-command etsn $ServerName") - } - $runCommand.add_Click($scriptBlock3) - $ExplorerForm.Controls.Add($runCommand) - - - $RDMA = New-Object System.Windows.Forms.Button - $RDMA.TabIndex = 0 - $RDMA.Name = “Verify RDMA” - $RDMA.Size = New-Object System.Drawing.Size(100,40) - $RDMA.UseVisualStyleBackColor = $True - $RDMA.Text = "Verify RDMA" - $RDMA.Location = New-Object System.Drawing.Size(700,280) - $RDMA.DataBindings.DefaultDataSourceUpdateMode = 0 - $scriptBlock4 = { - - - foreach ($address in $jsonObject.properties.connections[0].managementAddresses) - { - try - { - [ipaddress]$address - } - catch - { - $ServerName = $address - break; - } - } - - - RDMAValidation -ServerName $ServerName - } - $RDMA.add_Click($scriptBlock4) - $ExplorerForm.Controls.Add($RDMA) - - $Cert = New-Object System.Windows.Forms.Button - $Cert.TabIndex = 0 - $Cert.Name = “Verify Certs” - $Cert.Size = New-Object System.Drawing.Size(100,40) - $Cert.UseVisualStyleBackColor = $True - $Cert.Text = "Verify Certs" - $Cert.Location = New-Object System.Drawing.Size(700,340) - $Cert.DataBindings.DefaultDataSourceUpdateMode = 0 - $scriptBlock5 = { - - foreach ($address in $jsonObject.properties.connections[0].managementAddresses) - { - try - { - [ipaddress]$address - } - catch - { - $ServerName = $address - break; - } - } - - VerifyCerts -NCIP $NCIP -ServerName $ServerName -ServerObject $jsonObject -NCCredential $NCCredential - } - $Cert.add_Click($scriptBlock5) - $ExplorerForm.Controls.Add($Cert) - - $jumboPkt = New-Object System.Windows.Forms.Button - $jumboPkt.TabIndex = 0 - $jumboPkt.Name = “Verify Jumbo pkt” - $jumboPkt.Size = New-Object System.Drawing.Size(100,40) - $jumboPkt.UseVisualStyleBackColor = $True - $jumboPkt.Text = "Verify Jumbo pkt" - $jumboPkt.Location = New-Object System.Drawing.Size(700,400) - $jumboPkt.DataBindings.DefaultDataSourceUpdateMode = 0 - $scriptBlock6 = { - - foreach ($address in $jsonObject.properties.connections[0].managementAddresses) - { - try - { - [ipaddress]$address - } - catch - { - $ServerName = $address - break; - } - } - - VerifyJumboPkt -ServerName $ServerName -NCCredential $NCCredential - } - $jumboPkt.add_Click($scriptBlock6) - $ExplorerForm.Controls.Add($jumboPkt) - } - elseif($ResourceRef.Contains("networkInterfaces")) - { - $ExplorerForm.ClientSize = New-Object System.Drawing.Size(1400,800) - - $scriptBlockVfpRules = { - - $objTextBoxVFP.text = "Extracting VFP Rules..." - - $ServerResource = $jsonObject.properties.server.resourceRef - - if(-not [string]::IsNullOrEmpty($ServerResource)) - { - $server = JSONGet -NetworkControllerRestIP $NCIP -path $ServerResource -credential $NCCredential - - foreach ($address in $server.properties.connections[0].managementAddresses) - { - try - { - [ipaddress]$address - } - catch - { - $ServerName = $address - break; - } - } - - if(-not [string]::IsNullOrEmpty($ServerName)) - { - - $mac = $jsonObject.properties.privateMacAddress - $mac = $mac -replace "-" - $mac = $mac -replace ":" - - $scriptBlockVFP = { - - param( - [Parameter(mandatory=$true)] - [string] $Mac - ) - $vms = gwmi -na root\virtualization\v2 msvm_computersystem | Where Description -Match "Virtual" - $port = $null - $vms | foreach { - $vm=$_; $vm.GetRelated("Msvm_SyntheticEthernetPort") | foreach { - $vma = $_; - if($vma.PermanentAddress -eq $Mac) - { - $port = $vma.GetRelated("Msvm_SyntheticEthernetPortSettingData").GetRelated("Msvm_EthernetPortAllocationSettingData").GetRelated("Msvm_EthernetSwitchPort"); - } - } - } - - $portGuid = $port.Name - $vfpCtrlExe = "vfpctrl.exe" - echo "Policy for port : " $portGuid - & $vfpCtrlExe /list-space /port $portGuid - & $vfpCtrlExe /list-mapping /port $portGuid - & $vfpCtrlExe /list-rule /port $portGuid - & $vfpCtrlExe /port $portGuid /get-port-state - } - - $text = @() - $text = RunServerCommand -ServerName $ServerName -scriptBlock $scriptBlockVFP -argumentList $mac - - $objTextBoxVFP.Enabled = $true - - $objTextBoxVFP.text = "" - - foreach ($line in $text) { - $objTextBoxVFP.Appendtext($line) - $objTextBoxVFP.AppendText("`n") - } - } - else - { - [System.Windows.Forms.MessageBox]::Show("Server Name Missing!!!!") - } - } - else - { - [System.Windows.Forms.MessageBox]::Show("Server Resource Missing!!!!") - } - } - - $buttonVfpRule = New-Object System.Windows.Forms.Button - $buttonVfpRule.TabIndex = 0 - $buttonVfpRule.Name = “VFP Rules” - $buttonVfpRule.Size = New-Object System.Drawing.Size(80,60) - $buttonVfpRule.UseVisualStyleBackColor = $True - $buttonVfpRule.Text = “VFP Rules” - $buttonVfpRule.Location = New-Object System.Drawing.Size(800,20) - $buttonVfpRule.DataBindings.DefaultDataSourceUpdateMode = 0 - $buttonVfpRule.add_Click($scriptBlockVfpRules) - $ExplorerForm.Controls.Add($buttonVfpRule) - - $buttonVfpRule = New-Object System.Windows.Forms.Button - $buttonVfpRule.TabIndex = 0 - $buttonVfpRule.Name = “Start-CAPing” - $buttonVfpRule.Size = New-Object System.Drawing.Size(80,60) - $buttonVfpRule.UseVisualStyleBackColor = $True - $buttonVfpRule.Text = “Start-CAPing” - $buttonVfpRule.Location = New-Object System.Drawing.Size(700,20) - $buttonVfpRule.DataBindings.DefaultDataSourceUpdateMode = 0 - $buttonVfpRule.add_Click( - { - CAPing -NCIP $NCIP -Source $jsonObject -NCCredential $NCCredential - }) - $ExplorerForm.Controls.Add($buttonVfpRule) - - $objTextBoxVFP = New-Object System.Windows.Forms.RichTextBox - $objTextBoxVFP.Location = New-Object System.Drawing.Size(700,100) - $objTextBoxVFP.Multiline = $true - $objTextBoxVFP.ScrollBars = [System.Windows.Forms.ScrollBars]::Both - - $objTextBoxVFP.WordWrap = $false - $objTextBoxVFP.Size = New-Object System.Drawing.Size(600,650) - $objTextBoxVFP.font = "lucida console" - $objTextBoxVFP.Enabled = $false - $objTextBoxVFP.ReadOnly = $true - $ExplorerForm.Controls.Add($objTextBoxVFP) - - } - - - #Show the Form - $ExplorerForm.ShowDialog()| Out-Null - -} #End Function JsonForm - -function RunNCCMDLet { - -param( - [Parameter(mandatory=$true)] - [string] $Cmdlet, - [Parameter(mandatory=$true)] - [object] $NCVMCred, - [Parameter(mandatory=$true)] - [string] $NCIP - ) - try - { - # Generate Random names for prefix - $rand = New-Object System.Random - $prefixLen = 8 - [string]$namingPrefix = '' - for($i = 0; $i -lt $prefixLen; $i++) - { - $namingPrefix += [char]$rand.Next(65,90) - } - - - if ($Cmdlet -eq "Debug-NetworkController") - { - if ($NCIP -eq "restserver") - { - $ip = ([System.Net.Dns]::GetHostAddresses("restserver"))[0].IPAddressToString - } - else - { - $ip = $NCIP - } - $copyfolder = "Debug-NetworkController_$namingPrefix" - $cmdstring += "$Cmdlet -NetworkController $ip -OutputDirectory c:\temp\Debug-NetworkController_$namingPrefix" - } - elseif ($Cmdlet -eq "Debug-NetworkControllerConfigurationState") - { - if ($Script:NCIP -eq "restserver") - { - $cmdstring += " echo `"`n`r192.14.0.22 restserver`" > C:\Windows\System32\drivers\etc\hosts;" - } - - $cmdstring += "$Cmdlet -NetworkController $NCIP" - } - - $scriptBlock = ([scriptblock]::Create($cmdstring)) - - $result = Invoke-Command -ComputerName $NCIP -ScriptBlock $scriptBlock -Credential $NCVMCred - - if ($copyfolder) - { - $psDriver = New-PSDrive -Name Y -PSProvider filesystem -Root \\$ip\c$\temp -Credential $NCVMCred - - Copy-Item Y:\$copyfolder .\$copyfolder -Recurse - } - - [System.Windows.Forms.MessageBox]::Show("$Cmdlet completed") - - if ($copyfolder) - { - start .\$copyfolder - } - else - { - DisplayTextForm -FormName $Cmdlet -Text $result - } - - } - catch - { - [System.Windows.Forms.MessageBox]::Show($_) - } - finally - { - if ($psDriver) - { - Remove-PSDrive -Name Y - } - } - -} - -function OvsdbForm { - -param( - [Parameter(mandatory=$true)] - [object] $Server, - [Parameter(mandatory=$false)] - [bool] $EnableMultiWindow=$true - ) - - [reflection.assembly]::loadwithpartialname(“System.Windows.Forms”) | Out-Null - [reflection.assembly]::loadwithpartialname(“System.Drawing”) | Out-Null - #endregion - - if($EnableMultiWindow) - { - $progress = [powershell]::create() - - $progressScript = { - [System.Windows.Forms.MessageBox]::Show("Fetching Policies, it will take a few seconds to complete") - } - $progress.AddScript($progressScript) - - $progressObj = $progress.BeginInvoke() - } - - foreach ($address in $Server.properties.connections[0].managementAddresses) - { - try - { - [ipaddress]$address - } - catch - { - $ServerName = $address - break; - } - } - - if([string]::IsNullOrEmpty($ServerName)) - { - [System.Windows.Forms.MessageBox]::Show("Server Name Missing!!!!") - return - } - - #region Generated Form Objects - $ExplorerForm = New-Object System.Windows.Forms.Form - $InitialFormWindowState = New-Object System.Windows.Forms.FormWindowState - #endregion Generated Form Objects - - - $OnLoadForm_StateCorrection= - {#Correct the initial state of the form to prevent the .Net maximized form issue - $ExplorerForm.WindowState = $InitialFormWindowState - } - - #———————————————- - #region Generated Form Code - $ExplorerForm.Text = $ServerName - $ExplorerForm.Name = $ServerName - $ExplorerForm.DataBindings.DefaultDataSourceUpdateMode = 0 - - $ExplorerForm.ClientSize = New-Object System.Drawing.Size(900,800) - - $vtep = @() - $vtep = GetOvsDBVtep -ServerName $ServerName - - $firewall = @() - $firewall = GetOvsDBfirewall -ServerName $ServerName - - - $objTextBoxVtep = New-Object System.Windows.Forms.RichTextBox - $objTextBoxVtep.Location = New-Object System.Drawing.Size(40,100) - $objTextBoxVtep.Multiline = $true - $objTextBoxVtep.ScrollBars = [System.Windows.Forms.ScrollBars]::Both - - $objTextBoxVtep.WordWrap = $false - $objTextBoxVtep.Size = New-Object System.Drawing.Size(390,650) - $objTextBoxVtep.font = "lucida console" - foreach ($line in $vtep) { - $objTextBoxVtep.Appendtext($line) - $objTextBoxVtep.AppendText("`n") - } - $ExplorerForm.Controls.Add($objTextBoxVtep) - - $objTextBoxFirewall = New-Object System.Windows.Forms.TextBox - $objTextBoxFirewall.Location = New-Object System.Drawing.Size(470,100) - $objTextBoxFirewall.Multiline = $true - $objTextBoxFirewall.ScrollBars = [System.Windows.Forms.ScrollBars]::Both - - $objTextBoxFirewall.WordWrap = $false - $objTextBoxFirewall.Size = New-Object System.Drawing.Size(390,650) - foreach ($line in $firewall) { - $objTextBoxFirewall.Appendtext($line) - $objTextBoxFirewall.AppendText("`n") - } - $ExplorerForm.Controls.Add($objTextBoxFirewall) - - #endregion Generated Form Code - - #Save the initial state of the form - $InitialFormWindowState = $ExplorerForm.WindowState - #Init the OnLoad event to correct the initial state of the form - $ExplorerForm.add_Load($OnLoadForm_StateCorrection) - - #Show the Form - $ExplorerForm.ShowDialog()| Out-Null - if($EnableMultiWindow) - { - $progress.Dispose() - } - -} #End Function OvsdbForm - -function RunScriptForm { - -param( - [Parameter(mandatory=$false)] - [object[]] $Servers - ) - - [reflection.assembly]::loadwithpartialname(“System.Windows.Forms”) | Out-Null - [reflection.assembly]::loadwithpartialname(“System.Drawing”) | Out-Null - #endregion - - #region Generated Form Objects - $ExplorerForm = New-Object System.Windows.Forms.Form - $InitialFormWindowState = New-Object System.Windows.Forms.FormWindowState - #endregion Generated Form Objects - - - $OnLoadForm_StateCorrection= - {#Correct the initial state of the form to prevent the .Net maximized form issue - $ExplorerForm.WindowState = $InitialFormWindowState - } - - #———————————————- - #region Generated Form Code - $ExplorerForm.Text = "Run Script Block on all Servers" - $ExplorerForm.Name = $ServerName - $ExplorerForm.DataBindings.DefaultDataSourceUpdateMode = 0 - - $ExplorerForm.ClientSize = New-Object System.Drawing.Size(900,800) - - - $runScript = New-Object System.Windows.Forms.Button - $System_Drawing_SizeButton = New-Object System.Drawing.Size - $System_Drawing_SizeButton.Width = 240 - $System_Drawing_SizeButton.Height = 23 - $runScript.TabIndex = 0 - $runScript.Name = “Select” - $runScript.Size = $System_Drawing_SizeButton - $runScript.UseVisualStyleBackColor = $True - $runScript.Text = "--Run Script Block--" - $runScript.Location = New-Object System.Drawing.Size(50,50) - $runScript.DataBindings.DefaultDataSourceUpdateMode = 0 - $scriptBlock = { - $objTextBoxOutPut.text = "" - $objTextInput.ReadOnly = $true - - foreach ($server in $Servers) - { - try - { - foreach ($address in $server.properties.connections[0].managementAddresses) - { - try - { - [ipaddress]$address - } - catch - { - $ServerName = $address - break; - } - } - - $line = "==============================`n" - $objTextBoxOutPut.text += $line - $line = "Running Command on $ServerName `n" - $objTextBoxOutPut.text += $line - $line = "==============================`n" - $objTextBoxOutPut.text += $line - - $command = "try{" - $command += $objTextInput.text - $command += "}catch {return `$_}" - - $data = RunServerCommand -ServerName $ServerName -scriptBlock $command - - foreach ($line in $data) { - if ($line.Length -ne 0) - { - $formattedData = $line | Format-Table - $formattedData = $formattedData | Out-String - $objTextBoxOutPut.Appendtext($formattedData) - $objTextBoxOutPut.ScrollToCaret() - } - } - } - catch - { - [System.Windows.Forms.MessageBox]::Show($_) - } - } - - $i = 0 - $objTextBoxOutPut.Text -Split '\n' | % { - $objTextBoxOutPut.SelectionStart = $i - $line = $_ - $searchStr1 = "Running Command on " - $searchStr2 = "====================" - $objTextBoxOutPut.SelectionLength = $line.Length - if (Select-String -Pattern $searchStr1 -InputObject $line) - { - $objTextBoxOutPut.SelectionColor = [Drawing.Color]::Blue - } - elseif (Select-String -Pattern $searchStr2 -InputObject $line) - { - $objTextBoxOutPut.SelectionColor = [Drawing.Color]::DarkBlue - } - else - { - $objTextBoxOutPut.SelectionColor = [Drawing.Color]::Black - } - $i += $line.Length + 1 - } - - $objTextInput.ReadOnly = $false - } - $runScript.add_Click($scriptBlock) - $ExplorerForm.Controls.Add($runScript) - - $objTextInput = New-Object System.Windows.Forms.RichTextBox - $objTextInput.Location = New-Object System.Drawing.Size(50,100) - $objTextInput.Multiline = $true - $objTextInput.ScrollBars = [System.Windows.Forms.ScrollBars]::Both - - $objTextInput.WordWrap = $false - $objTextInput.Size = New-Object System.Drawing.Size(800,300) - $objTextInput.font = "lucida console" - foreach ($line in $vtep) { - $objTextInput.Appendtext($line) - $objTextInput.AppendText("`n") - } - $ExplorerForm.Controls.Add($objTextInput) - - $objTextBoxOutPut = New-Object System.Windows.Forms.RichTextBox - $objTextBoxOutPut.Location = New-Object System.Drawing.Size(50,450) - $objTextBoxOutPut.Multiline = $true - $objTextBoxOutPut.ScrollBars = [System.Windows.Forms.ScrollBars]::Both - $objTextBoxOutPut.ReadOnly = $true - - $objTextBoxOutPut.WordWrap = $false - $objTextBoxOutPut.Size = New-Object System.Drawing.Size(800,300) - foreach ($line in $firewall) { - $objTextBoxOutPut.Appendtext($line) - $objTextBoxOutPut.AppendText("`n") - } - $ExplorerForm.Controls.Add($objTextBoxOutPut) - - #endregion Generated Form Code - - #Save the initial state of the form - $InitialFormWindowState = $ExplorerForm.WindowState - #Init the OnLoad event to correct the initial state of the form - $ExplorerForm.add_Load($OnLoadForm_StateCorrection) - - #Show the Form - $ExplorerForm.ShowDialog()| Out-Null - -} #End Function RunScriptForm - -function GetOvsDBVtep { - -param( - [Parameter(mandatory=$true)] - [string] $ServerName - ) - - - return RunServerCommand -ServerName $ServerName -scriptBlock {C:\windows\system32\ovsdb-client.exe dump tcp:127.0.0.1:6641 ms_vtep} - -} #End Function GetOvsDBVtep - -function GetOvsDBfirewall { - -param( - [Parameter(mandatory=$true)] - [string] $ServerName - ) - - return RunServerCommand -ServerName $ServerName -scriptBlock {C:\windows\system32\ovsdb-client.exe dump tcp:127.0.0.1:6641 ms_firewall} - -} #End Function GetOvsDBfirewall - -function GetAllVFPPolices { - -param( - [Parameter(mandatory=$true)] - [object] $Server, - [Parameter(mandatory=$false)] - [object] $EnableMultiWindow=$true - - - ) - - if($EnableMultiWindow) - { - $progress = [powershell]::create() - - $progressScript = { - [System.Windows.Forms.MessageBox]::Show("Fetching Policies, it will take a few seconds to complete") - } - $progress.AddScript($progressScript) - - $progressObj = $progress.BeginInvoke() - } - - foreach ($address in $Server.properties.connections[0].managementAddresses) - { - try - { - [ipaddress]$address - } - catch - { - $ServerName = $address - break; - } - } - - if([string]::IsNullOrEmpty($ServerName)) - { - [System.Windows.Forms.MessageBox]::Show("Server Name Missing!!!!") - return - } - - $scriptBlock = { - - $switches = Get-WmiObject -Namespace root\virtualization\v2 -Class Msvm_VirtualEthernetSwitch - foreach ($switch in $switches) { - $vfpCtrlExe = "vfpctrl.exe" - $ports = $switch.GetRelated("Msvm_EthernetSwitchPort", "Msvm_SystemDevice", $null, $null, $null, $null, $false, $null) - foreach ($port in $ports) { - $portGuid = $port.Name - echo "Policy for port : " $portGuid - & $vfpCtrlExe /list-space /port $portGuid - & $vfpCtrlExe /list-mapping /port $portGuid - & $vfpCtrlExe /list-rule /port $portGuid - & $vfpCtrlExe /port $portGuid /get-port-state - } - } - } - - $text = @() - $text = RunServerCommand -ServerName $ServerName -scriptBlock $scriptBlock - - DisplayTextForm -FormName $ServerName -Text $text - - if($EnableMultiWindow) - { - $progress.Dispose() - } - -} #End Function GetAllVFPPolices - -function RunServerCommand { - -param( - [Parameter(mandatory=$true)] - [string] $ServerName, - - [Parameter(mandatory=$false)] - [string] $scriptBlock, - - [Parameter(mandatory=$false)] - [object[]] $argumentList = $null - ) - - - $text = @() - $script = ([scriptblock]::Create($scriptBlock)) - - if (-not $argumentList) - { - $text = Invoke-Command -ComputerName $ServerName -ScriptBlock $script - } - else - { - $text = Invoke-Command -ComputerName $ServerName -ScriptBlock $script -ArgumentList $argumentList - } - - return $text -} #End Function RunServerCommand - -function DisplayTextForm { - -param( - [Parameter(mandatory=$true)] - [string] $FormName, - - [Parameter(mandatory=$false)] - [string[]] $Text - ) - - [reflection.assembly]::loadwithpartialname(“System.Windows.Forms”) | Out-Null - [reflection.assembly]::loadwithpartialname(“System.Drawing”) | Out-Null - #endregion - - try - { - foreach ($address in $Server.properties.connections[0].managementAddresses) - { - try - { - [ipaddress]$address - } - catch - { - $ServerName = $address - break; - } - } - - if([string]::IsNullOrEmpty($ServerName)) - { - [System.Windows.Forms.MessageBox]::Show("Server Name Missing!!!!") - } - - $FormName = $ServerName - } - catch - { - } - - #region Generated Form Objects - $ExplorerForm = New-Object System.Windows.Forms.Form - $InitialFormWindowState = New-Object System.Windows.Forms.FormWindowState - #endregion Generated Form Objects - - - $OnLoadForm_StateCorrection= - {#Correct the initial state of the form to prevent the .Net maximized form issue - $ExplorerForm.WindowState = $InitialFormWindowState - } - - #———————————————- - #region Generated Form Code - $ExplorerForm.Text = $FormName - $ExplorerForm.Name = $FormName - $ExplorerForm.DataBindings.DefaultDataSourceUpdateMode = 0 - - $ExplorerForm.ClientSize = New-Object System.Drawing.Size(700,800) - - - $objTextBoxVtep = New-Object System.Windows.Forms.RichTextBox - $objTextBoxVtep.Location = New-Object System.Drawing.Size(40,100) - $objTextBoxVtep.Multiline = $true - $objTextBoxVtep.ScrollBars = [System.Windows.Forms.ScrollBars]::Both - - $objTextBoxVtep.WordWrap = $false - $objTextBoxVtep.Size = New-Object System.Drawing.Size(600,650) - $objTextBoxVtep.font = "lucida console" - foreach ($line in $Text) { - $objTextBoxVtep.Appendtext($line) - $objTextBoxVtep.AppendText("`n") - } - $ExplorerForm.Controls.Add($objTextBoxVtep) - - #endregion Generated Form Code - - #Save the initial state of the form - $InitialFormWindowState = $ExplorerForm.WindowState - #Init the OnLoad event to correct the initial state of the form - $ExplorerForm.add_Load($OnLoadForm_StateCorrection) - - #Show the Form - $ExplorerForm.ShowDialog()| Out-Null - -} #End Function DisplayTextForm - -function CAPing -{ - param($NCIP, $Source, $NCCredential= [System.Management.Automation.PSCredential]::Empty) - - . .\NetworkControllerRESTWrappers.ps1 -ComputerName $NCIP -Username $null -Password $null -Credential $Script:NCCredential - - $headers = @{"Accept"="application/json"} - $content = "application/json; charset=UTF-8" - $network = "https://$NCIP/Networking/v1" - $retry = 30 - - $method = "Put" - $uri = "$network/diagnostics/ConnectivityCheck" - $body = $caJson - - $networkInterfaces = Get-NCNetworkInterface - - $selectIps = @() - - foreach ($ni in $networkInterfaces) - { - try - { - if($Source.properties.ipConfigurations[0].properties.privateIPAddress -ne $ni.properties.ipConfigurations[0].properties.privateIPAddress) - { - $selectIps += $ni.properties.ipConfigurations[0].properties.privateIPAddress - } - } - catch - { - #skip - } - } - - $selectedIp = RadioForm -Name "Dest IP" -Values $selectIps - - foreach ($ni in $networkInterfaces) - { - try - { - if ( $selectedIp -eq $ni.properties.ipConfigurations[0].properties.privateIPAddress) - { - $destination = $ni - } - } - catch - { - #skip - } - } - - $caJson = @{} - $caJson.resourceId = "" - $caJson.properties = @{} - $caJson.properties.senderIpAddress = $Source.properties.ipConfigurations[0].properties.privateIPAddress - $caJson.properties.receiverIpAddress = $destination.properties.ipConfigurations[0].properties.privateIPAddress - - - $parse = $Source.properties.ipConfigurations[0].properties.subnet.resourceRef.Split("/") - $Vnet = "" - for($it = 0 ;$it -lt 3; $it++) - { - if( -not [string]::IsNullOrEmpty($parse[$it])) - { - $Vnet += "/" - $Vnet += $parse[$it] - } - } - $caJson.properties.sendervirtualNetwork = @{} - $caJson.properties.sendervirtualNetwork.resourceRef = $Vnet - $caJson.properties.receivervirtualNetwork = @{} - $caJson.properties.receivervirtualNetwork.resourceRef = $Vnet - $caJson.properties.disableTracing = $false - $caJson.properties.protocol = "Icmp" - $caJson.properties.icmpProtocolConfig = @{} - $caJson.properties.icmpProtocolConfig.sequenceNumber = 1 - $caJson.properties.icmpProtocolConfig.length = 0 - - $body = ConvertTo-Json -Depth 20 $caJson - try - { - $result = Invoke-WebRequest -Headers $headers -ContentType $content -Method $method -Uri $uri -Body $body -DisableKeepAlive -UseBasicParsing - - $body = ConvertFrom-Json $result.Content - - $operationId = $body.properties.operationId - - [System.Windows.Forms.MessageBox]::Show("CAPing started:$operationId") - } - catch - { - [System.Windows.Forms.MessageBox]::Show("$_") - } -} #End Function CAPing - -function RDMAValidation -{ - Param( - [Parameter(Mandatory=$True, Position=1, HelpMessage="Interface index of the adapter for which RDMA config is to be verified")] - [string] $ServerName - ) - - $vnics = Invoke-Command -ComputerName $ServerName -ScriptBlock { Get-NetAdapter | Where-Object {$_.DriverName -eq "\SystemRoot\System32\drivers\vmswitch.sys" } } - - - $vnicNames = @() - - foreach ($vnic in $vnics) - { - $vnicNames += $vnic.Name - } - try{ - $selectedVName = RadioForm -Name "Adapter Name" -Values $vnicNames - } - catch{ - [System.Windows.Forms.MessageBox]::Show("Main error" + $_) - return - } - - foreach ($vnic in $vnics) - { - if ($selectedVName -eq $vnic.Name) - { - $selectedVNic= $vnic - break - } - } - - $IsRoceStr = RadioForm -Name "IsRoce" -Values "true","false" - - $IsRoce = $false - if ($IsRoceStr -eq "true") - { - $IsRoce = $true - } - - - $scriptBlock = { - - Param( - [string] $IfIndex, - [bool] $IsRoCE - ) - - $rdmaAdapter = Get-NetAdapter -IfIndex $IfIndex - - if ($rdmaAdapter -eq $null) - { - Write-Host "ERROR: The adapter with interface index $IfIndex not found" - return - } - - $rdmaAdapterName = $rdmaAdapter.Name - $virtualAdapter = Get-VMNetworkAdapter -ManagementOS | where DeviceId -eq $rdmaAdapter.DeviceID - - if ($virtualAdapter -eq $null) - { - $isRdmaAdapterVirtual = $false - Write-Host "VERBOSE: The adapter $rdmaAdapterName is a physical adapter" - } - else - { - $isRdmaAdapterVirtual = $true - Write-Host "VERBOSE: The adapter $rdmaAdapterName is a virtual adapter" - } - - $rdmaCapabilities = Get-NetAdapterRdma -InterfaceDescription $rdmaAdapter.InterfaceDescription - - if ($rdmaCapabilities -eq $null -or $rdmaCapabilities.Enabled -eq $false) - { - return "ERROR: The adapter $rdmaAdapterName is not enabled for RDMA" - } - - if ($rdmaCapabilities.MaxQueuePairCount -eq 0) - { - return "ERROR: RDMA capabilities for adapter $rdmaAdapterName are not valid : MaxQueuePairCount is 0" - - } - - if ($rdmaCapabilities.MaxCompletionQueueCount -eq 0) - { - return "ERROR: RDMA capabilities for adapter $rdmaAdapterName are not valid : MaxCompletionQueueCount is 0" - - } - - $smbClientNetworkInterfaces = Get-SmbClientNetworkInterface - - if ($smbClientNetworkInterfaces -eq $null) - { - return "ERROR: No network interfaces detected by SMB (Get-SmbClientNetworkInterface)" - } - - $rdmaAdapterSmbClientNetworkInterface = $null - foreach ($smbClientNetworkInterface in $smbClientNetworkInterfaces) - { - if ($smbClientNetworkInterface.InterfaceIndex -eq $IfIndex) - { - $rdmaAdapterSmbClientNetworkInterface = $smbClientNetworkInterface - } - } - - if ($rdmaAdapterSmbClientNetworkInterface -eq $null) - { - return "ERROR: No network interfaces found by SMB for adapter $rdmaAdapterName (Get-SmbClientNetworkInterface)" - } - - if ($rdmaAdapterSmbClientNetworkInterface.RdmaCapable -eq $false) - { - return "ERROR: SMB did not detect adapter $rdmaAdapterName as RDMA capable. Make sure the adapter is bound to TCP/IP and not to other protocol like vmSwitch." - } - - $rdmaAdapters = $rdmaAdapter - if ($isRdmaAdapterVirtual -eq $true) - { - Write-Host "VERBOSE: Retrieving vSwitch bound to the virtual adapter" - $switchName = $virtualAdapter.SwitchName - Write-Host "VERBOSE: Found vSwitch: $switchName" - $vSwitch = Get-VMSwitch -Name $switchName - $rdmaAdapters = Get-NetAdapter -InterfaceDescription $vSwitch.NetAdapterInterfaceDescriptions - $vSwitchAdapterMessage = "VERBOSE: Found the following physical adapter(s) bound to vSwitch: " - $index = 1 - foreach ($qosAdapter in $rdmaAdapters) - { - $qosAdapterName = $qosAdapter.Name - $vSwitchAdapterMessage = $vSwitchAdapterMessage + [string]$qosAdapterName - if ($index -lt $rdmaAdapters.Length) - { - $vSwitchAdapterMessage = $vSwitchAdapterMessage + ", " - } - $index = $index + 1 - } - Write-Host $vSwitchAdapterMessage - } - - - if ($IsRoCE -eq $true) - { - Write-Host "VERBOSE: Underlying adapter is RoCE. Checking if QoS/DCB/PFC is configured on each physical adapter(s)" - foreach ($qosAdapter in $rdmaAdapters) - { - $qosAdapterName = $qosAdapter.Name - $qos = Get-NetAdapterQos -Name $qosAdapterName - if ($qos.Enabled -eq $false) - { - return "ERROR: QoS is not enabled for adapter $qosAdapterName" - } - - if ($qos.OperationalFlowControl -eq "All Priorities Disabled") - { - return "ERROR: Flow control is not enabled for adapter $qosAdapterName" - } - } - Write-Host "VERBOSE: QoS/DCB/PFC configuration is correct." - } - - return " RDMA configuration on the host is correct, please check switch configuration for E2E RDMA to work." - } - - $strOutput = Invoke-Command -ComputerName $ServerName -ScriptBlock $scriptBlock -ArgumentList $selectedVNic.ifIndex,$IsRoce - - [System.Windows.Forms.MessageBox]::Show("$strOutput") -} #End Function RDMAValidation - -function VerifyJumboPkt -{ - Param( - [string] $ServerName, - [object]$NCCredential= [System.Management.Automation.PSCredential]::Empty - ) - try - { - $allServers = Get-NCServer - - $serverNames = @() - - foreach ($server in $allServers) - { - foreach ($address in $server.properties.connections[0].managementAddresses) - { - try - { - [ipaddress]$address - } - catch - { - if ($address -ne $ServerName) - { - $serverNames += $address - } - break; - } - } - } - - $destServer = RadioForm -Name "Dest Server" -Values $serverNames - - if ($NCCredential -eq [System.Management.Automation.PSCredential]::Empty) - { - $cred = Get-Credential -Message "Enter Server Creds" - } - else - { - $cred = $NCCredential - } - - $result = Test-LogicalNetworkSupportsJumboPacket -SourceHost $ServerName -DestinationHost $destServer -SourceHostCreds $cred -DestinationHostCreds $cred - - $result = $result | ConvertTo-Json -Depth 10 - - [System.Windows.Forms.MessageBox]::Show($result) - } - catch - { - [System.Windows.Forms.MessageBox]::Show($_) - } - -} - -function VerifyCerts -{ - Param( - [string] $NCIP, - [string] $ServerName, - [object] $ServerObject, - [object] $NCCredential= [System.Management.Automation.PSCredential]::Empty - ) - . .\NetworkControllerRESTWrappers.ps1 -ComputerName $NCIP -Username $null -Password $null -Credential $Script:NCCredential - - $NCCertHash = $null - foreach ($conn in $ServerObject.properties.connections) - { - $cred = JSONGet -path $conn.credential.resourceRef -NetworkControllerRestIP $NCIP -credential $NCCredential - - if ($cred.properties.type -eq "X509Certificate") - { - $NCCertHash = $cred.properties.value - } - } - - if ([string]::IsNullOrEmpty($NCCertHash)) - { - [System.Windows.Forms.MessageBox]::Show("NC Cert is not configured in Server($ServerName) Json.") - } - - $ServerCert = $ServerObject.properties.certificate - - $scriptBlock = - { - Param( - [string] $NCCertHash, - [string] $ServerCert - ) - - $rootCerts = dir Cert:\LocalMachine\Root - - $NCCert = $null - foreach ($cert in $rootCerts) - { - if ($cert.Thumbprint -eq $NCCertHash) - { - $NCCert = $cert - } - } - - if (-not $NCCert) - { - return "NC Cert is Missing" - } - - $myCerts = dir Cert:\LocalMachine\my - $serverCertificate = $null - foreach ($cert in $myCerts) - { - $base64 = [System.Convert]::ToBase64String($cert.RawData) - if ($base64 -eq $ServerCert) - { - $serverCertificate = $cert - } - } - - if (-not $serverCertificate) - { - return "Server Cert is Missing" - } - - $certToVerify = @() - $certToVerify += $NCCert - $certToVerify += $serverCertificate - - foreach ($cert in $certToVerify) - { - - $server = $false - $client = $false - foreach ($eku in $cert.EnhancedKeyUsageList) - { - if ($eku.FriendlyName -eq "Server Authentication") - { - $server = $true - } - - if ($eku.FriendlyName -eq "Client Authentication") - { - $client = $true - } - } - - $thumbprint = $cert.Thumbprint - - if ($server -eq $false) - { - return "Server EKU is missing on NC Cert($thumbprint) on Server." - } - - if ($client -eq $false) - { - return "Client EKU is missing on NC Cert($thumbprint) on Server." - } - } - - $key = 'HKLM:\SYSTEM\CurrentControlSet\Services\NcHostAgent\Parameters\' - $peerCertificateCName = "CN=" - $peerCertificateCName += (Get-ItemProperty -Path $key -Name PeerCertificateCName).PeerCertificateCName - - if ($peerCertificateCName -ne $NCCert.Subject) - { - $subject = $NCCert.Subject - return "NCHostAgent has wrong PeerCertificateCName($peerCertificateCName) instead of $subject" - } - - $hostAgentCertificateCName = "CN=" - $hostAgentCertificateCName += (Get-ItemProperty -Path $key -Name HostAgentCertificateCName).HostAgentCertificateCName - - if ($hostAgentCertificateCName -ne $serverCertificate.Subject) - { - $subject = $serverCertificate.Subject - return "NCHostAgent has wrong PeerCertificateCName($hostAgentCertificateCName) instead of $subject" - } - - return "Certificates are configured correctly!!" - } - - $strOutput = Invoke-Command -ComputerName $ServerName -ScriptBlock $scriptBlock -ArgumentList $NCCertHash,$ServerCert - - [System.Windows.Forms.MessageBox]::Show("$strOutput") - -} #End Function VerifyCerts - -Import-Module .\NetworkControllerWorkloadHelpers.psm1 -Force -. .\NetworkControllerRESTWrappers.ps1 -ComputerName $NCIP -Username $null -Password $null -Credential $Script:NCCredential - -$ncVMCredentials = [System.Management.Automation.PSCredential]::Empty - -$InputData = @() - -$LNs = @{} -$LNs.Name = "Logical Networks" -$LNs.Value = @() -$LNs.Value += {GenerateArrayForm -HandlerFunc "Get-NCLogicalNetwork" -RemoveFunc "Remove-NCLogicalNetwork" -NCIP $NCIP -NCCredential $Script:NCCredential -EnableMultiWindow $Script:EnableMultiWindow} -$InputData += $LNs - -$VNs = @{} -$VNs.Name = "VirtualNetworks" -$VNs.Value = @() -$VNs.Value += {GenerateArrayForm -HandlerFunc "Get-NCVirtualNetwork" -RemoveFunc "Remove-NCVirtualNetwork" -NCIP $NCIP -NCCredential $Script:NCCredential -EnableMultiWindow $Script:EnableMultiWindow} -$InputData += $VNs - - -$VSs = @{} -$VSs.Name = "Virtual Servers" -$VSs.Value = @() -$VSs.Value += {GenerateArrayForm -HandlerFunc "Get-NCVirtualServer" -RemoveFunc "Remove-NCVirtualServer" -NCIP $NCIP -NCCredential $Script:NCCredential -EnableMultiWindow $Script:EnableMultiWindow} -$InputData += $VSs - -$NIs = @{} -$NIs.Name = "Network Interfaces" -$NIs.Value = @() -$NIs.Value += {GenerateArrayForm -HandlerFunc "Get-NCNetworkInterface" -RemoveFunc "Remove-NCNetworkInterface" -NCIP $NCIP -NCCredential $Script:NCCredential -EnableMultiWindow $Script:EnableMultiWindow} -$NIs.Value += {PutNetworkInterface -HandlerFunc "New-NCNetworkInterface" -NCIP $NCIP -NCCredential $Script:NCCredential} -$NIs.Value += {RemoveObjForm -HandlerFunc "Remove-NCNetworkInterface" -GetFunc "Get-NCNetworkInterface" -NCIP $NCIP -NCCredential $Script:NCCredential} -$InputData += $NIs - - -$NS = @{} -$NS.Name = "Servers" -$NS.Value = @() -$NS.Value = {GenerateArrayForm -HandlerFunc "Get-NCServer" -RemoveFunc "Remove-NCServer" -NCIP $NCIP -NCCredential $Script:NCCredential -EnableMultiWindow $Script:EnableMultiWindow} -$InputData += $NS - -$LB = @{} -$LB.Name = "Load Balancer" -$LB.Value = @() -$LB.Value += {GenerateArrayForm -HandlerFunc "Get-NCLoadBalancer" -RemoveFunc "Remove-NCLoadBalancer" -NCIP $NCIP -NCCredential $Script:NCCredential -EnableMultiWindow $Script:EnableMultiWindow} -$LB.Value += {PutLoadBalancer -HandlerFunc "New-LoadBalancerVIP" -NCIP $NCIP -NCCredential $Script:NCCredential} -$InputData += $LB - -$Acls = @{} -$Acls.Name = "Access Control List" -$Acls.Value = @() -$Acls.Value += {GenerateArrayForm -HandlerFunc "Get-NCAccessControlList" -RemoveFunc "Remove-NCAccessControlList" -NCIP $NCIP -NCCredential $Script:NCCredential -EnableMultiWindow $Script:EnableMultiWindow} -$InputData += $Acls - -$Credentials = @{} -$Credentials.Name = "NC Credentials" -$Credentials.Value = @() -$Credentials.Value += {GenerateArrayForm -HandlerFunc "Get-NCCredential" -RemoveFunc "Remove-NCCredential" -NCIP $NCIP -NCCredential $Script:NCCredential -EnableMultiWindow $Script:EnableMultiWindow} -$InputData += $Credentials - -$LBM = @{} -$LBM.Name = "Load Balancer Manager" -$LBM.Value = @() -$LBM.Value += {GenerateArrayForm -HandlerFunc "Get-NCLoadbalancerManager" -RemoveFunc "null" -NCIP $NCIP -NCCredential $Script:NCCredential -EnableMultiWindow $Script:EnableMultiWindow} -$InputData += $LBM - -$LBMUX = @{} -$LBMUX.Name = "Load Balancer Mux" -$LBMUX.Value = @() -$LBMUX.Value += {GenerateArrayForm -HandlerFunc "Get-NCLoadbalancerMux" -RemoveFunc "Remove-NCLoadBalancerMux" -NCIP $NCIP -NCCredential $Script:NCCredential -EnableMultiWindow $Script:EnableMultiWindow} -$InputData += $LBMUX - -$CR = @{} -$CR.Name = "Diagnostics Panel" -$CR.Value = @() -$CR.Value += {GenerateArrayForm -HandlerFunc "Get-NCConnectivityCheckResult" -RemoveFunc "null" -NCIP $NCIP -NCCredential $Script:NCCredential -EnableMultiWindow $Script:EnableMultiWindow} -$InputData += $CR - -$Publicip = @{} -$Publicip.Name = "Public IP Addresses" -$Publicip.Value = @() -$Publicip.Value += {GenerateArrayForm -HandlerFunc "Get-NCPublicIPAddress" -RemoveFunc "null" -NCIP $NCIP -NCCredential $Script:NCCredential -EnableMultiWindow $Script:EnableMultiWindow} -$InputData += $Publicip - -$RT = @{} -$RT.Name = "Route Tables" -$RT.Value = @() -$RT.Value += {GenerateArrayForm -HandlerFunc "Get-NCRouteTable" -RemoveFunc "null" -NCIP $NCIP -NCCredential $Script:NCCredential -EnableMultiWindow $Script:EnableMultiWindow} -$InputData += $RT - -$Gapteways = @{} -$Gapteways.Name = "Gateways" -$Gapteways.Value = @() -$Gapteways.Value += {GenerateArrayForm -HandlerFunc "Get-NCGateway" -RemoveFunc "null" -NCIP $NCIP -NCCredential $Script:NCCredential -EnableMultiWindow $Script:EnableMultiWindow} -$InputData += $Gapteways - -$GatewayPools = @{} -$GatewayPools.Name = "Gateway Pools" -$GatewayPools.Value = @() -$GatewayPools.Value += {GenerateArrayForm -HandlerFunc "Get-NCGatewayPool" -RemoveFunc "Remove-NCGatewayPool" -NCIP $NCIP -NCCredential $Script:NCCredential -EnableMultiWindow $Script:EnableMultiWindow} -$InputData += $GatewayPools - -$VirtualGateway = @{} -$VirtualGateway.Name = "Virtual Gateway" -$VirtualGateway.Value = @() -$VirtualGateway.Value += {GenerateArrayForm -HandlerFunc "Get-NCVirtualGateway" -RemoveFunc "Remove-NCVirtualGateway" -NCIP $NCIP -NCCredential $Script:NCCredential -EnableMultiWindow $Script:EnableMultiWindow} -$InputData += $VirtualGateway - -if(-not $script:IsModule) -{ - #Call the Function - GenerateMainForm -DataArr $InputData -} \ No newline at end of file diff --git a/azure_jumpstart_hcibox/artifacts/SDN/SDNExpress.ps1 b/azure_jumpstart_hcibox/artifacts/SDN/SDNExpress.ps1 deleted file mode 100644 index 67b2e10b28..0000000000 --- a/azure_jumpstart_hcibox/artifacts/SDN/SDNExpress.ps1 +++ /dev/null @@ -1,304 +0,0 @@ -# -------------------------------------------------------------- -# Copyright © Microsoft Corporation. All Rights Reserved. -# Microsoft Corporation (or based on where you live, one of its affiliates) licenses this sample code for your internal testing purposes only. -# Microsoft provides the following sample code AS IS without warranty of any kind. The sample code arenot supported under any Microsoft standard support program or services. -# Microsoft further disclaims all implied warranties including, without limitation, any implied warranties of merchantability or of fitness for a particular purpose. -# The entire risk arising out of the use or performance of the sample code remains with you. -# In no event shall Microsoft, its authors, or anyone else involved in the creation, production, or delivery of the code be liable for any damages whatsoever -# (including, without limitation, damages for loss of business profits, business interruption, loss of business information, or other pecuniary loss) -# arising out of the use of or inability to use the sample code, even if Microsoft has been advised of the possibility of such damages. -# --------------------------------------------------------------- -<# -.SYNOPSIS - Deploys and configures the Microsoft SDN infrastructure, - including creation of the network controller, Software Load Balancer MUX - and gateway VMs. Then the VMs and Hyper-V hosts are configured to be - used by the Network Controller. When this script completes the SDN - infrastructure is ready to be fully used for workload deployments. -.EXAMPLE - .\SDNExpress.ps1 -ConfigurationDataFile .\MyConfig.psd1 - Reads in the configuration from a PSD1 file that contains a hash table - of settings data. -.EXAMPLE - .\SDNExpress -ConfigurationData $MyConfigurationData - Uses the hash table that is passed in as the configuration data. This - parameter set is useful when programatically generating the - configuration data. -.EXAMPLE - .\SDNExpress - Displays a user interface for interactively defining the configuraiton - data. At the end you have the option to save as a configuration file - before deploying. -.NOTES - Prerequisites: - * All Hyper-V hosts must have Hyper-V enabled and the Virtual Switch - already created. - * All Hyper-V hosts must be joined to Active Directory. - * The physical network must be preconfigured for the necessary subnets and - VLANs as defined in the configuration data. - * The VHD specified in the configuration data must be reachable from the - computer where this script is run. -#> - -[CmdletBinding(DefaultParameterSetName="NoParameters")] -param( - [Parameter(Mandatory=$true,ParameterSetName="ConfigurationFile")] - [String] $ConfigurationDataFile=$null, - [Parameter(Mandatory=$true,ParameterSetName="ConfigurationData")] - [object] $ConfigurationData=$null, - [Switch] $SkipValidation, - [Switch] $SkipDeployment, - [PSCredential] $DomainJoinCredential = $null, - [PSCredential] $NCCredential = $null, - [PSCredential] $LocalAdminCredential = $null - ) - - -# Script version, should be matched with the config files -$ScriptVersion = "2.0" - - -import-module networkcontroller -import-module .\SDNExpressModule.psm1 -force - -write-SDNExpressLog "*** Begin SDN Express Deployment ***" -write-SDNExpressLog "ParameterSet: $($psCmdlet.ParameterSetName)" -write-SDNExpressLog " -ConfigurationDataFile: $ConfigurationDataFile" -write-SDNExpressLog " -ConfigurationData: $ConfigurationData" -write-SDNExpressLog " -SkipValidation: $SkipValidation" -write-SDNExpressLog " -SkipDeployment: $SkipValidation" - -if ($psCmdlet.ParameterSetName -eq "NoParameters") { - write-sdnexpresslog "Begin interactive mode." - - import-module .\SDNExpressUI.psm1 -force - $configData = SDNExpressUI - if ($configData -eq $null) - { - # user cancelled - exit - } - -} elseif ($psCmdlet.ParameterSetName -eq "ConfigurationFile") { - write-sdnexpresslog "Using configuration file passed in by parameter." - $configdata = [hashtable] (iex (gc $ConfigurationDataFile | out-string)) -} elseif ($psCmdlet.ParameterSetName -eq "ConfigurationData") { - write-sdnexpresslog "Using configuration data object passed in by parameter." - $configdata = $configurationData -} - -if ($Configdata.ScriptVersion -ne $scriptversion) { - write-error "Configuration file version $($ConfigData.ScriptVersion) is not compatible with this version of SDN express. Please update your config file to match the version $scriptversion example." - return -} - -function GetPassword -{ - param( - [String] $SecurePasswordText, - [PSCredential] $Credential, - [String] $Message, - [String] $UserName - ) - if ([String]::IsNullOrEmpty($SecurePasswordText) -and ($Credential -eq $null)) { - write-sdnexpresslog "No credentials found on command line or in config file. Prompting." - $Credential = get-Credential -Message $Message -UserName $UserName - } - - if ($Credential -ne $null) { - write-sdnexpresslog "Using credentials from the command line." - return $Credential.GetNetworkCredential().Password - } - - try { - write-sdnexpresslog "Using credentials from config file." - $securepassword = $SecurePasswordText | convertto-securestring -erroraction Ignore - $BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecurePassword) - return [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR) - } catch { - write-sdnexpresslog "Unable to decrpypt credentials in config file. Could be from a different user or generated on different computer. Prompting instead." - $Credential = get-Credential -Message $Message -UserName $UserName - if ($credential -eq $null) { - write-sdnexpresslog "User cancelled credential input. Exiting." - exit - } - return $Credential.GetNetworkCredential().Password - } - -} - -$DomainJoinPassword = GetPassword $ConfigData.DomainJoinSecurePassword $DomainJoinCredential "Enter credentials for joining VMs to the AD domain." $configdata.DomainJoinUserName -$NCPassword = GetPassword $ConfigData.NCSecurePassword $NCCredential "Enter credentials for the Network Controller to use." $configdata.NCUserName -$LocalAdminPassword = GetPassword $ConfigData.LocalAdminSecurePassword $LocalAdminCredential "Enter the password for the local administrator of newly created VMs. Username is ignored." "Administrator" - -$NCSecurePassword = $NCPassword | convertto-securestring -AsPlainText -Force - -$credential = New-Object System.Management.Automation.PsCredential($ConfigData.NCUsername, $NCSecurePassword) - -$ManagementSubnetBits = $ConfigData.ManagementSubnet.Split("/")[1] -$PASubnetBits = $ConfigData.PASubnet.Split("/")[1] -$DomainJoinUserNameDomain = $ConfigData.DomainJoinUserName.Split("\")[0] -$DomainJoinUserNameName = $ConfigData.DomainJoinUserName.Split("\")[1] -$LocalAdminDomainUserDomain = $ConfigData.LocalAdminDomainUser.Split("\")[0] -$LocalAdminDomainUserName = $ConfigData.LocalAdminDomainUser.Split("\")[1] - -if ($ConfigData.VMProcessorCount -eq $null) {$ConfigData.VMProcessorCount = 4} -if ($ConfigData.VMMemory -eq $null) {$ConfigData.VMMemory = 3GB} - -write-SDNExpressLog "STAGE 1: Create VMs" - -$params = @{ - 'ComputerName'=''; - 'VMLocation'=$ConfigData.VMLocation; - 'VMName'=''; - 'VHDSrcPath'=$ConfigData.VHDPath; - 'VHDName'=$ConfigData.VHDFile; - 'VMMemory'=$ConfigData.VMMemory; - 'VMProcessorCount'=$ConfigData.VMProcessorCount; - 'Nics'=@(); - 'CredentialDomain'=$DomainJoinUserNameDomain; - 'CredentialUserName'=$DomainJoinUserNameName; - 'CredentialPassword'=$DomainJoinPassword; - 'JoinDomain'=$ConfigData.JoinDomain; - 'LocalAdminPassword'=$LocalAdminPassword; - 'DomainAdminDomain'=$LocalAdminDomainUserDomain; - 'DomainAdminUserName'=$LocalAdminDomainUserName; - 'SwitchName'=$ConfigData.SwitchName -} - -if (![String]::IsNullOrEmpty($ConfigData.ProductKey)) { - $params.ProductKey = $ConfigData.ProductKey -} -if (![String]::IsNullOrEmpty($ConfigData.Locale)) { - $params.Locale = $ConfigData.Locale -} -if (![String]::IsNullOrEmpty($ConfigData.TimeZone)) { - $params.TimeZone = $ConfigData.TimeZone -} - -write-SDNExpressLog "STAGE 1.1: Create NC VMs" -foreach ($NC in $ConfigData.NCs) { - $params.ComputerName=$NC.HostName; - $params.VMName=$NC.ComputerName; - $params.Nics=@( - @{Name="Management"; MacAddress=$NC.MacAddress; IPAddress="$($NC.ManagementIP)/$ManagementSubnetBits"; Gateway=$ConfigData.ManagementGateway; DNS=$ConfigData.ManagementDNS; VLANID=$ConfigData.ManagementVLANID} - ); - - New-SDNExpressVM @params -} - -write-SDNExpressLog "STAGE 1.2: Create Mux VMs" - -foreach ($Mux in $ConfigData.Muxes) { - $params.ComputerName=$mux.HostName; - $params.VMName=$mux.ComputerName; - $params.Nics=@( - @{Name="Management"; MacAddress=$Mux.MacAddress; IPAddress="$($Mux.ManagementIP)/$ManagementSubnetBits"; Gateway=$ConfigData.ManagementGateway; DNS=$ConfigData.ManagementDNS; VLANID=$ConfigData.ManagementVLANID}, - @{Name="HNVPA"; MacAddress=$Mux.PAMacAddress; IPAddress="$($Mux.PAIPAddress)/$PASubnetBits"; VLANID=$ConfigData.PAVLANID; IsMuxPA=$true} - ); - - New-SDNExpressVM @params -} - -write-SDNExpressLog "STAGE 1.3: Create Gateway VMs" - -foreach ($Gateway in $ConfigData.Gateways) { - $params.ComputerName=$Gateway.HostName; - $params.InstallRasRoutingProtocols = $true; - $params.VMName=$Gateway.ComputerName; - $params.Nics=@( - @{Name="Management"; MacAddress=$Gateway.MacAddress; IPAddress="$($Gateway.ManagementIP)/$ManagementSubnetBits"; Gateway=$ConfigData.ManagementGateway; DNS=$ConfigData.ManagementDNS; VLANID=$ConfigData.ManagementVLANID} - @{Name="FrontEnd"; MacAddress=$Gateway.FrontEndMac; IPAddress="$($Gateway.FrontEndIp)/$PASubnetBits"; VLANID=$ConfigData.PAVLANID}, - @{Name="BackEnd"; MacAddress=$Gateway.BackEndMac; VLANID=$ConfigData.PAVLANID} - ); - - New-SDNExpressVM @params -} - -write-SDNExpressLog "STAGE 2: Network Controller Configuration" - -$NCNodes = @() -foreach ($NC in $ConfigData.NCs) { - $NCNodes += $NC.ComputerName -} - -WaitforComputertobeready $NCNodes $false - - -New-SDNExpressNetworkController -ComputerNames $NCNodes -RESTName $ConfigData.RestName -Credential $Credential - -write-SDNExpressLog "STAGE 2.1: Getting REST cert thumbprint in order to find it in local root store." -$NCHostCertThumb = invoke-command -ComputerName $NCNodes[0] { - param( - $RESTName - ) - return (get-childitem "cert:\localmachine\my" | where {$_.Subject -eq "CN=$RestName"}).Thumbprint -} -ArgumentList $ConfigData.RestName - -$NCHostCert = get-childitem "cert:\localmachine\root\$NCHostCertThumb" - -$params = @{ - 'RestName' = $ConfigData.RestName; - 'MacAddressPoolStart' = $ConfigData.SDNMacPoolStart; - 'MacAddressPoolEnd' = $ConfigData.SDNMacPoolEnd; - 'NCHostCert' = $NCHostCert - 'NCUsername' = $ConfigData.NCUsername; - 'NCPassword' = $NCPassword -} -New-SDNExpressVirtualNetworkManagerConfiguration @Params - -$params = @{ - 'RestName' = $ConfigData.RestName; - 'PrivateVIPPrefix' = $ConfigData.PrivateVIPSubnet; - 'PublicVIPPrefix' = $ConfigData.PublicVIPSubnet -} - -New-SDNExpressLoadBalancerManagerConfiguration @Params - -$params = @{ - 'RestName' = $ConfigData.RestName; - 'AddressPrefix' = $ConfigData.PASubnet; - 'VLANID' = $ConfigData.PAVLANID; - 'DefaultGateways' = $ConfigData.PAGateway; - 'IPPoolStart' = $ConfigData.PAPoolStart; - 'IPPoolEnd' = $ConfigData.PAPoolEnd -} -Add-SDNExpressVirtualNetworkPASubnet @params - -write-SDNExpressLog "STAGE 3: Host Configuration" - -foreach ($h in $ConfigData.hypervhosts) { - Add-SDNExpressHost -ComputerName $h -RestName $ConfigData.RestName -HostPASubnetPrefix $ConfigData.PASubnet -NCHostCert $NCHostCert -Credential $Credential -VirtualSwitchName $ConfigData.SwitchName -} - -write-SDNExpressLog "STAGE 4: Mux Configuration" - -foreach ($Mux in $ConfigData.muxes) { - Add-SDNExpressMux -ComputerName $Mux.ComputerName -PAMacAddress $Mux.PAMacAddress -LocalPeerIP $Mux.PAIPAddress -MuxASN $ConfigData.SDNASN -Routers $ConfigData.Routers -RestName $ConfigData.RestName -NCHostCert $NCHostCert -Credential $Credential -} - -write-SDNExpressLog "STAGE 5: Gateway Configuration" - -New-SDNExpressGatewayPool -IsTypeAll -PoolName $ConfigData.PoolName -Capacity $ConfigData.Capacity -GreSubnetAddressPrefix $ConfigData.GreSubnet -RestName $ConfigData.RestName -Credential $Credential - -foreach ($G in $ConfigData.Gateways) { - $params = @{ - 'RestName'=$ConfigData.RestName - 'ComputerName'=$g.computername - 'HostName'=$g.Hostname - 'NCHostCert'= $NCHostCert - 'PoolName'=$ConfigData.PoolName - 'FrontEndIp'=$G.FrontEndIP - 'FrontEndLogicalNetworkName'='HNVPA' - 'FrontEndAddressPrefix'=$ConfigData.PASubnet - 'FrontEndMac'=$G.FrontEndMac - 'BackEndMac'=$G.BackEndMac - 'RouterASN'=$ConfigData.Routers[0].RouterASN - 'RouterIP'=$ConfigData.Routers[0].RouterIPAddress - 'LocalASN'=$ConfigData.SDNASN - } - New-SDNExpressGateway @params -} - - -write-SDNExpressLog "SDN Express deployment complete." diff --git a/azure_jumpstart_hcibox/artifacts/SDN/SDNExpressModule.psm1 b/azure_jumpstart_hcibox/artifacts/SDN/SDNExpressModule.psm1 deleted file mode 100644 index 2bd66bfb92..0000000000 --- a/azure_jumpstart_hcibox/artifacts/SDN/SDNExpressModule.psm1 +++ /dev/null @@ -1,1975 +0,0 @@ -# -------------------------------------------------------------- -# Copyright © Microsoft Corporation. All Rights Reserved. -# Microsoft Corporation (or based on where you live, one of its affiliates) licenses this sample code for your internal testing purposes only. -# Microsoft provides the following sample code AS IS without warranty of any kind. The sample code arenot supported under any Microsoft standard support program or services. -# Microsoft further disclaims all implied warranties including, without limitation, any implied warranties of merchantability or of fitness for a particular purpose. -# The entire risk arising out of the use or performance of the sample code remains with you. -# In no event shall Microsoft, its authors, or anyone else involved in the creation, production, or delivery of the code be liable for any damages whatsoever -# (including, without limitation, damages for loss of business profits, business interruption, loss of business information, or other pecuniary loss) -# arising out of the use of or inability to use the sample code, even if Microsoft has been advised of the possibility of such damages. -# --------------------------------------------------------------- - -$VerbosePreference = 'Continue' - -<# - -ooooo ooo .oooooo. .oooooo. . -`888b. `8' d8P' `Y8b d8P' `Y8b .o8 - 8 `88b. 8 888 888 oooo d8b .ooooo. .oooo. .o888oo .ooooo. - 8 `88b. 8 888 888 `888""8P d88' `88b `P )88b 888 d88' `88b - 8 `88b.8 888 888 888 888ooo888 .oP"888 888 888ooo888 - 8 `888 `88b ooo `88b ooo 888 888 .o d8( 888 888 . 888 .o -o8o `8 `Y8bood8P' `Y8bood8P' d888b `Y8bod8P' `Y888""8o "888" `Y8bod8P' - - - -#> -function New-SDNExpressNetworkController -{ - param( - [String[]] $ComputerNames, - [String] $RESTName, - [String] $ManagementSecurityGroupName = "", - [String] $ClientSecurityGroupName = "", - [PSCredential] $Credential = $null, - [Switch] $Force - ) - write-sdnexpresslog "New-SDNExpressNetworkController" - write-sdnexpresslog " -ComputerNames: $ComputerNames" - write-sdnexpresslog " -RestName: $RestName" - write-sdnexpresslog " -ManagementSecurityGroup: $ManagementSecurityGroup" - write-sdnexpresslog " -ClientSecurityGroup: $ClientSecurityGroup" - write-sdnexpresslog " -Force: $Force" - - $RESTName = $RESTNAme.ToUpper() - - write-sdnexpresslog ("Checking if Controller already deployed by looking for REST response.") - try { - get-networkcontrollerCredential -ConnectionURI "https://$RestName" -Credential $Credential | out-null - if (!$force) { - write-sdnexpresslog "Network Controller at $RESTNAME already exists, exiting New-SDNExpressNetworkController." - return - } - } - catch { - write-sdnexpresslog "Network Controller does not exist, will continue." - } - - write-sdnexpresslog "Setting properties and adding NetworkController role on all computers in parallel." - invoke-command -ComputerName $ComputerNames { - reg add hklm\system\currentcontrolset\services\tcpip6\parameters /v DisabledComponents /t REG_DWORD /d 255 /f | out-null - Set-Item WSMan:\localhost\Shell\MaxConcurrentUsers -Value 100 | out-null - Set-Item WSMan:\localhost\MaxEnvelopeSizekb -Value 7000 | out-null - - add-windowsfeature NetworkController -IncludeAllSubFeature -IncludeManagementTools -Restart | out-null - } - - write-sdnexpresslog "Creating local temp directory." - - $TempFile = New-TemporaryFile - Remove-Item $TempFile.FullName -Force - $TempDir = $TempFile.FullName - New-Item -ItemType Directory -Force -Path $TempDir | out-null - - write-sdnexpresslog "Temp directory is: $($TempFile.FullName)" - write-sdnexpresslog "Creating REST cert on: $($computernames[0])" - - $RestCertPfxData = invoke-command -computername $ComputerNames[0] { - param( - [String] $RestName - ) - $verbosepreference=$using:verbosepreference - - $Cert = get-childitem "Cert:\localmachine\my" | where {$_.Subject.ToUpper().StartsWith("CN=$RestName".ToUpper())} - - if ($Cert -eq $Null) { - write-verbose "Creating new REST certificate." - $Cert = New-SelfSignedCertificate -Type Custom -KeySpec KeyExchange -Subject "CN=$RESTName" -KeyExportPolicy Exportable -HashAlgorithm sha256 -KeyLength 2048 -CertStoreLocation "Cert:\LocalMachine\My" -TextExtension @("2.5.29.37={text}1.3.6.1.5.5.7.3.1,1.3.6.1.5.5.7.3.2") - } else { - write-verbose "Found existing REST certficate." - $HasServerEku = ($cert.EnhancedKeyUsageList | where {$_.ObjectId -eq "1.3.6.1.5.5.7.3.1"}) -ne $null - $HasClientEku = ($cert.EnhancedKeyUsageList | where {$_.ObjectId -eq "1.3.6.1.5.5.7.3.2"}) -ne $null - - if (!$HasServerEku) { - throw "Rest cert exists on $(hostname) but is missing the EnhancedKeyUsage for Server Authentication." - } - if (!$HasClientEku) { - throw "Rest cert exists but $(hostname) is missing the EnhancedKeyUsage for Client Authentication." - } - write-verbose "Existing certificate meets criteria. Exporting." - } - - $TempFile = New-TemporaryFile - Remove-Item $TempFile.FullName -Force | out-null - [System.io.file]::WriteAllBytes($TempFile.FullName, $cert.Export("PFX", "secret")) - $CertData = Get-Content $TempFile.FullName -Encoding Byte - Remove-Item $TempFile.FullName -Force | out-null - - return $CertData - - } -ArgumentList $RestName - - write-sdnexpresslog "Temporarily exporting Cert to My store." - $TempFile = New-TemporaryFile - Remove-Item $TempFile.FullName -Force - $RestCertPfxData | set-content $TempFile.FullName -Encoding Byte - $pwd = ConvertTo-SecureString "secret" -AsPlainText -Force - $cert = import-pfxcertificate -filepath $TempFile.FullName -certstorelocation "cert:\localmachine\my" -password $pwd -exportable - Remove-Item $TempFile.FullName -Force - - $RESTCertThumbprint = $cert.Thumbprint - write-sdnexpresslog "REST cert thumbprint: $RESTCertThumbprint" - write-sdnexpresslog "Exporting REST cert to PFX and CER in temp directory." - - [System.io.file]::WriteAllBytes("$TempDir\$RESTName.pfx", $cert.Export("PFX", "secret")) - Export-Certificate -Type CERT -FilePath "$TempDir\$RESTName" -cert $cert | out-null - - write-sdnexpresslog "Importing REST cert (public key only) into Root store." - import-certificate -filepath "$TempDir\$RESTName" -certstorelocation "cert:\localmachine\root" | out-null - - write-sdnexpresslog "Deleting REST cert from My store." - remove-item -path cert:\localmachine\my\$RESTCertThumbprint - - write-sdnexpresslog "Installing REST cert to my and root store of each NC node." - - foreach ($ncnode in $ComputerNames) { - write-sdnexpresslog "Installing REST cert to my and root store of: $ncnode" - invoke-command -computername $ncnode { - param( - [String] $RESTName, - [byte[]] $RESTCertPFXData, - [String] $RESTCertThumbprint - ) - - $pwd = ConvertTo-SecureString "secret" -AsPlainText -Force - - $TempFile = New-TemporaryFile - Remove-Item $TempFile.FullName -Force - $RESTCertPFXData | set-content $TempFile.FullName -Encoding Byte - - $Cert = get-childitem "Cert:\localmachine\my" | where {$_.Subject.ToUpper().StartsWith("CN=$RestName".ToUpper())} - - if ($Cert -eq $null) { - $cert = import-pfxcertificate -filepath $TempFile.FullName -certstorelocation "cert:\localmachine\my" -password $pwd -Exportable - } else { - if ($cert.Thumbprint -ne $RestCertThumbprint) { - Remove-Item $TempFile.FullName -Force - throw "REST cert already exists in My store on $(hostname), but thumbprint does not match cert on other nodes." - } - } - - $targetCertPrivKey = $Cert.PrivateKey - $privKeyCertFile = Get-Item -path "$ENV:ProgramData\Microsoft\Crypto\RSA\MachineKeys\*" | where {$_.Name -eq $targetCertPrivKey.CspKeyContainerInfo.UniqueKeyContainerName} - $privKeyAcl = Get-Acl $privKeyCertFile - $permission = "NT AUTHORITY\NETWORK SERVICE","Read","Allow" - $accessRule = new-object System.Security.AccessControl.FileSystemAccessRule $permission - $privKeyAcl.AddAccessRule($accessRule) - Set-Acl $privKeyCertFile.FullName $privKeyAcl - - $Cert = get-childitem "Cert:\localmachine\root\$RestCertThumbprint" -erroraction Ignore - if ($cert -eq $Null) { - $cert = import-pfxcertificate -filepath $TempFile.FullName -certstorelocation "cert:\localmachine\root" -password $pwd - } - - Remove-Item $TempFile.FullName -Force - } -Argumentlist $RESTName, $RESTCertPFXData, $RESTCertThumbprint - - } - - # Create Node cert for each NC - - foreach ($ncnode in $ComputerNames) { - write-sdnexpresslog "Creating node cert for: $ncnode" - - [byte[]] $CertData = invoke-command -computername $ncnode { - - # Set Trusted Hosts - Set-Item WSMan:\localhost\Client\TrustedHosts * -Confirm:$false -Force - - $NodeFQDN = (Get-WmiObject win32_computersystem).DNSHostName+"."+(Get-WmiObject win32_computersystem).Domain - $Cert = get-childitem "Cert:\localmachine\my" | where {$_.Subject.ToUpper().StartsWith("CN=$NodeFQDN".ToUpper())} - - if ($Cert -eq $null) { - $cert = New-SelfSignedCertificate -Type Custom -KeySpec KeyExchange -Subject "CN=$NodeFQDN" -KeyExportPolicy Exportable -HashAlgorithm sha256 -KeyLength 2048 -CertStoreLocation "Cert:\LocalMachine\My" -TextExtension @("2.5.29.37={text}1.3.6.1.5.5.7.3.1,1.3.6.1.5.5.7.3.2") - } else { - $HasServerEku = ($cert.EnhancedKeyUsageList | where {$_.ObjectId -eq "1.3.6.1.5.5.7.3.1"}) -ne $null - $HasClientEku = ($cert.EnhancedKeyUsageList | where {$_.ObjectId -eq "1.3.6.1.5.5.7.3.2"}) -ne $null - - if (!$HasServerEku) { - throw "Node cert exists on $(hostname) but is missing the EnhancedKeyUsage for Server Authentication." - } - if (!$HasClientEku) { - throw "Node cert exists but $(hostname) is missing the EnhancedKeyUsage for Client Authentication." - } - } - - $targetCertPrivKey = $Cert.PrivateKey - $privKeyCertFile = Get-Item -path "$ENV:ProgramData\Microsoft\Crypto\RSA\MachineKeys\*" | where {$_.Name -eq $targetCertPrivKey.CspKeyContainerInfo.UniqueKeyContainerName} - $privKeyAcl = Get-Acl $privKeyCertFile - $permission = "NT AUTHORITY\NETWORK SERVICE","Read","Allow" - $accessRule = new-object System.Security.AccessControl.FileSystemAccessRule $permission - $privKeyAcl.AddAccessRule($accessRule) - Set-Acl $privKeyCertFile.FullName $privKeyAcl - - $TempFile = New-TemporaryFile - Remove-Item $TempFile.FullName -Force | out-null - [System.io.file]::WriteAllBytes($TempFile.FullName, $cert.Export("PFX", "secret")) - $CertData = Get-Content $TempFile.FullName -Encoding Byte - Remove-Item $TempFile.FullName -Force | out-null - - return $CertData - } - - foreach ($othernode in $ComputerNames) { - write-sdnexpresslog "Installing node cert for $ncnode into root store of $othernode." - - invoke-command -computername $othernode { - param( - [Byte[]] $CertData - ) - - $TempFile = New-TemporaryFile - Remove-Item $TempFile.FullName -Force - - $CertData | set-content $TempFile.FullName -Encoding Byte - $pwd = ConvertTo-SecureString "secret" -AsPlainText -Force - $cert = import-pfxcertificate -filepath $TempFile.FullName -certstorelocation "cert:\localmachine\root" -password $pwd - Remove-Item $TempFile.FullName -Force - } -ArgumentList (,$CertData) - } - } - - write-sdnexpresslog "Configuring Network Controller role using node: $($ComputerNames[0])" - invoke-command -computername $ComputerNames[0] { - param( - [String] $RestName, - [String] $ManagementSecurityGroup, - [String] $ClientSecurityGroup, - [String[]] $ComputerNames, - [PSCredential] $Credential - ) - $SelfFQDN = (Get-WmiObject win32_computersystem).DNSHostName+"."+(Get-WmiObject win32_computersystem).Domain - - try { $controller = get-networkcontroller -erroraction Ignore } catch {} - if ($controller -ne $null) { - if ($force) { - uninstall-networkcontroller -force - uninstall-networkcontrollercluster -force - } else { - return - } - } - - $Nodes = @() - - foreach ($server in $ComputerNames) { - $NodeFQDN = "$server."+(Get-WmiObject win32_computersystem).Domain - - $cert = get-childitem "Cert:\localmachine\root" | where {$_.Subject.ToUpper().StartsWith("CN=$nodefqdn".ToUpper())} - - $nic = get-netadapter - if ($nic.count -gt 1) { - write-verbose ("WARNING: Invalid number of network adapters found in network Controller node.") - write-verbose ("WARNING: Using first adapter returned: $($nic[0].name)") - $nic = $nic[0] - } elseif ($nic.count -eq 0) { - write-verbose ("ERROR: No network adapters found in network Controller node.") - throw "Network controller node requires at least one network adapter." - } - - $nodes += New-NetworkControllerNodeObject -Name $server -Server $NodeFQDN -FaultDomain ("fd:/"+$server) -RestInterface $nic.Name -NodeCertificate $cert -verbose - } - - $RESTCert = get-childitem "Cert:\localmachine\root" | where {$_.Subject.ToUpper().StartsWith("CN=$RESTName".ToUpper())} - - $params = @{ - 'Node'=$nodes; - 'CredentialEncryptionCertificate'=$RESTCert; - 'Credential'=$Credential; - } - - if ([string]::isnullorempty($ManagementSecurityGroupName)) { - $params.add('ClusterAuthentication', 'X509'); - } else { - $params.add('ClusterAuthentication', 'Kerberos'); - $params.add('ManagementSecurityGroup', $ManagementSecurityGroup) - } - - Install-NetworkControllerCluster @Params -Force | out-null - - $params = @{ - 'Node'=$nodes; - 'ServerCertificate'=$RESTCert; - 'Credential'=$Credential; - } - - if ([string]::isnullorempty($ClientSecurityGroupName)) { - $params.add('ClientAuthentication', 'None'); - } else { - $params.add('ClusterAuthentication', 'Kerberos'); - $params.add('ClientSecurityGroup', $ClientSecurityGroup) - } - - if (![string]::isnullorempty($RestIpAddress)) { - $params.add('RestIPAddress', 'addr/bits'); - } else { - $params.add('RestName', $RESTName); - } - - Install-NetworkController @params -force | out-null - - } -ArgumentList $RestName, $ManagementSecurityGroup, $ClientSecurityGroup, $ComputerNames, $Credential - - Write-SDNExpressLog "Network Controller cluster creation complete." - #Verify that SDN REST endpoint is working before returning - - $dnsServers = (Get-DnsClientServerAddress -AddressFamily ipv4).ServerAddresses | select -uniq - $dnsWorking = $true - - foreach ($dns in $dnsServers) - { - $dnsResponse = $null - $count = 0 - - while (($dnsResponse -eq $null) -or ($count -eq 30)) { - $dnsResponse = Resolve-DnsName -name $RESTName -Server $dns -ErrorAction Ignore - if ($dnsREsponse -eq $null) { - sleep 10 - } - $count++ - } - - if ($count -eq 30) { - write-sdnexpresslog "REST name not resolving from $dns after 5 minutes." - $dnsWorking = $false - } else { - write-sdnexpresslog "REST name resolved from $dns after $count tries." - } - } - - if (!$dnsWorking) { - return - } - - write-sdnexpresslog ("Checking for REST response.") - $NotResponding = $true - while ($NotResponding) { - try { - $NotResponding = $false - get-networkcontrollerCredential -ConnectionURI "https://$RestName" -Credential $Credential | out-null - } - catch { - write-sdnexpresslog "Network Controller is not responding. Will try again in 10 seconds." - sleep 10 - $NotResponding = $true - } - } - - write-sdnexpresslog ("Network controller setup is complete and ready to use.") - write-sdnexpresslog "New-SDNExpressNetworkController Exit" -} - - - - - -<# - -ooooo ooo .oooooo. .oooooo. .o88o. o8o -`888b. `8' d8P' `Y8b d8P' `Y8b 888 `" `"' - 8 `88b. 8 888 888 .ooooo. ooo. .oo. o888oo oooo .oooooooo - 8 `88b. 8 888 888 d88' `88b `888P"Y88b 888 `888 888' `88b - 8 `88b.8 888 888 888 888 888 888 888 888 888 888 - 8 `888 `88b ooo `88b ooo 888 888 888 888 888 888 `88bod8P' -o8o `8 `Y8bood8P' `Y8bood8P' `Y8bod8P' o888o o888o o888o o888o `8oooooo. - d" YD - "Y88888P' - -#> -function New-SDNExpressVirtualNetworkManagerConfiguration -{ - param( - [String] $RestName, - [String] $MacAddressPoolStart, - [String] $MacAddressPoolEnd, - [Object] $NCHostCert, - [String] $NCUsername, - [String] $NCPassword, - [PSCredential] $Credential = $null - ) - - write-sdnexpresslog "New-SDNExpressVirtualNetworkManagerConfiguration" - write-sdnexpresslog " -RestName: $RestName" - write-sdnexpresslog " -MacAddressPoolEnd: $MacAddressPoolStart" - write-sdnexpresslog " -NCHostCert: $($NCHostCert.Thumbprint)" - write-sdnexpresslog " -NCUsername: $NCUsername" - write-sdnexpresslog " -NCPassword: ********" - write-sdnexpresslog " -Credential: $($Credential.UserName)" - - $uri = "https://$RestName" - - $MacAddressPoolStart = [regex]::matches($MacAddressPoolStart.ToUpper().Replace(":", "").Replace("-", ""), '..').groups.value -join "-" - $MacAddressPoolEnd = [regex]::matches($MacAddressPoolEnd.ToUpper().Replace(":", "").Replace("-", ""), '..').groups.value -join "-" - - $MacPoolProperties = new-object Microsoft.Windows.NetworkController.MacPoolProperties - $MacPoolProperties.StartMacAddress = $MacAddressPoolStart - $MacPoolProperties.EndMacAddress = $MacAddressPoolEnd - $MacPoolObject = New-NetworkControllerMacPool -connectionuri $uri -ResourceId "DefaultMacPool" -properties $MacPoolProperties -Credential $Credential -Force - - $CredentialProperties = new-object Microsoft.Windows.NetworkController.CredentialProperties - $CredentialProperties.Type = "X509Certificate" - $CredentialProperties.Value = $NCHostCert.thumbprint - $HostCertObject = New-NetworkControllerCredential -ConnectionURI $uri -ResourceId "NCHostCert" -properties $CredentialProperties -Credential $Credential -force - - $CredentialProperties = new-object Microsoft.Windows.NetworkController.CredentialProperties - $CredentialProperties.Type = "UsernamePassword" - $CredentialProperties.UserName = $NCUsername - $CredentialProperties.Value = $NCPassword - $HostUserObject = New-NetworkControllerCredential -ConnectionURI $uri -ResourceId "NCHostUser" -properties $CredentialProperties -Credential $Credential -force - - try { - $LogicalNetworkObject = get-NetworkControllerLogicalNetwork -ConnectionURI $uri -ResourceID "HNVPA" -Credential $Credential - } - catch - { - $LogicalNetworkProperties = new-object Microsoft.Windows.NetworkController.LogicalNetworkProperties - $LogicalNetworkProperties.NetworkVirtualizationEnabled = $true - $LogicalNetworkObject = New-NetworkControllerLogicalNetwork -ConnectionURI $uri -ResourceID "HNVPA" -properties $LogicalNetworkProperties -Credential $Credential -Force - } - write-sdnexpresslog "New-SDNExpressVirtualNetworkManagerConfiguration Exit" -} - - - - - -function Add-SDNExpressVirtualNetworkPASubnet -{ - param( - [String] $RestName, - [String] $AddressPrefix, - [String] $VLANID, - [String[]] $DefaultGateways, - [Object] $IPPoolStart, - [String] $IPPoolEnd, - [PSCredential] $Credential = $null - ) - - write-sdnexpresslog "New-SDNExpressVirtualNetworkPASubnet" - write-sdnexpresslog " -RestName: $RestName" - write-sdnexpresslog " -AddressPrefix: $AddressPrefix" - write-sdnexpresslog " -VLANID: $VLANID" - write-sdnexpresslog " -DefaultGateways: $DefaultGateways" - write-sdnexpresslog " -IPPoolStart: $IPPoolStart" - write-sdnexpresslog " -IPPoolStart: $IPPoolEnd" - write-sdnexpresslog " -Credential: $($Credential.UserName)" - - $uri = "https://$RestName" - - $PALogicalSubnets = get-networkcontrollerLogicalSubnet -Connectionuri $URI -LogicalNetworkId "HNVPA" -Credential $Credential - $PALogicalSubnet = $PALogicalSubnets | where {$_.properties.AddressPrefix -eq $AddressPrefix} - - if ($PALogicalSubnet -eq $null) { - $LogicalSubnetProperties = new-object Microsoft.Windows.NetworkController.LogicalSubnetProperties - $logicalSubnetProperties.VLANId = $VLANID - $LogicalSubnetProperties.AddressPrefix = $AddressPrefix - $LogicalSubnetProperties.DefaultGateways = $DefaultGateways - - $LogicalSubnetObject = New-NetworkControllerLogicalSubnet -ConnectionURI $uri -LogicalNetworkId "HNVPA" -ResourceId $AddressPrefix.Replace("/", "_") -properties $LogicalSubnetProperties -Credential $Credential -Force - } - - $IPpoolProperties = new-object Microsoft.Windows.NetworkController.IPPoolproperties - $ippoolproperties.startipaddress = $IPPoolStart - $ippoolproperties.endipaddress = $IPPoolEnd - - $IPPoolObject = New-networkcontrollerIPPool -ConnectionURI $uri -NetworkId "HNVPA" -SubnetId $AddressPrefix.Replace("/", "_") -ResourceID $AddressPrefix.Replace("/", "_") -Properties $IPPoolProperties -force -Credential $Credential - - write-sdnexpresslog "New-SDNExpressVirtualNetworkPASubnet Exit" -} - - - - - - - -function New-SDNExpressLoadBalancerManagerConfiguration -{ - param( - [String] $RestName, - [String] $PrivateVIPPrefix, - [String] $PublicVIPPrefix, - [String] $SLBMVip = (Get-IPv4AddressInSubnet -subnet $PrivateVIPPrefix -offset 1), - [String] $PrivateVIPPoolStart = (Get-IPv4AddressInSubnet -subnet $PrivateVIPPrefix -offset 1), - [String] $PrivateVIPPoolEnd = (Get-IPv4LastAddressInSubnet -subnet $PrivateVIPPrefix), - [String] $PublicVIPPoolStart = (Get-IPv4AddressInSubnet -subnet $PublicVIPPrefix -offset 1), - [String] $PublicVIPPoolEnd = (Get-IPv4LastAddressInSubnet -subnet $PublicVIPPrefix), - [PSCredential] $Credential = $null - ) - - write-sdnexpresslog "New-SDNExpressLoadBalancerManagerConfiguration" - write-sdnexpresslog " -RestName: $RestName" - write-sdnexpresslog " -PrivateVIPPrefix: $PrivateVipPrefix" - write-sdnexpresslog " -PublicVIPPrefix: $PublicVIPPrefix" - write-sdnexpresslog " -SLBMVip: $SLBMVip" - write-sdnexpresslog " -PrivateVIPPoolStart: $PrivateVIPPoolStart" - write-sdnexpresslog " -PrivateVIPPoolEnd: $PrivateVIPPoolEnd" - write-sdnexpresslog " -PublicVIPPoolStart: $PublicVIPPoolStart" - write-sdnexpresslog " -PublicVIPPoolEnd: $PrivateVIPPoolEnd" - write-sdnexpresslog " -Credential: $($Credential.UserName)" - - $uri = "https://$RestName" - - #PrivateVIP LN - try - { - $PrivateVIPLNObject = Get-NetworkControllerLogicalNetwork -ConnectionURI $uri -ResourceID "PrivateVIP" -Credential $Credential - } - catch - { - $LogicalNetworkProperties = new-object Microsoft.Windows.NetworkController.LogicalNetworkProperties - $LogicalNetworkProperties.NetworkVirtualizationEnabled = $false - $LogicalNetworkProperties.Subnets = @() - $LogicalNetworkProperties.Subnets += new-object Microsoft.Windows.NetworkController.LogicalSubnet - $logicalNetworkProperties.Subnets[0].ResourceId = $PrivateVIPPrefix.Replace("/", "_") - $logicalNetworkProperties.Subnets[0].Properties = new-object Microsoft.Windows.NetworkController.LogicalSubnetProperties - $logicalNetworkProperties.Subnets[0].Properties.AddressPrefix = $PrivateVIPPrefix - $logicalNetworkProperties.Subnets[0].Properties.DefaultGateways = @(Get-IPv4AddressInSubnet -subnet $PrivateVIPPrefix) - - $PrivateVIPLNObject = New-NetworkControllerLogicalNetwork -ConnectionURI $uri -ResourceID "PrivateVIP" -properties $LogicalNetworkProperties -Credential $Credential -Force - } - - $IPpoolProperties = new-object Microsoft.Windows.NetworkController.IPPoolproperties - $ippoolproperties.startipaddress = $PrivateVIPPoolStart - $ippoolproperties.endipaddress = $PrivateVIPPoolEnd - - $PrivatePoolObject = new-networkcontrollerIPPool -ConnectionURI $uri -NetworkId "PrivateVIP" -SubnetId $PrivateVIPPrefix.Replace("/", "_") -ResourceID $PrivateVIPPrefix.Replace("/", "_") -Properties $IPPoolProperties -force - - #PublicVIP LN - try - { - $PublicVIPLNObject = get-NetworkControllerLogicalNetwork -ConnectionURI $uri -ResourceID "PublicVIP" -Credential $Credential - } - catch - { - $LogicalNetworkProperties = new-object Microsoft.Windows.NetworkController.LogicalNetworkProperties - $LogicalNetworkProperties.NetworkVirtualizationEnabled = $false - $LogicalNetworkProperties.Subnets = @() - $LogicalNetworkProperties.Subnets += new-object Microsoft.Windows.NetworkController.LogicalSubnet - $logicalNetworkProperties.Subnets[0].ResourceId = $PublicVIPPrefix.Replace("/", "_") - $logicalNetworkProperties.Subnets[0].Properties = new-object Microsoft.Windows.NetworkController.LogicalSubnetProperties - $logicalNetworkProperties.Subnets[0].Properties.AddressPrefix = $PublicVIPPrefix - $logicalNetworkProperties.Subnets[0].Properties.DefaultGateways = @(Get-IPv4AddressInSubnet -subnet $PublicVIPPrefix) - $logicalnetworkproperties.subnets[0].properties.IsPublic = $true - - $PublicVIPLNObject = New-NetworkControllerLogicalNetwork -ConnectionURI $uri -ResourceID "PublicVIP" -properties $LogicalNetworkProperties -Credential $Credential -Force - } - - $IPpoolProperties = new-object Microsoft.Windows.NetworkController.IPPoolproperties - $ippoolproperties.startipaddress = $PublicVIPPoolStart - $ippoolproperties.endipaddress = $PublicVIPPoolEnd - - $PublicPoolObject = new-networkcontrollerIPPool -ConnectionURI $uri -NetworkId "PublicVIP" -SubnetId $PublicVIPPrefix.Replace("/", "_") -ResourceID $PublicVIPPrefix.Replace("/", "_") -Properties $IPPoolProperties -force - - #SLBManager Config - - $managerproperties = new-object Microsoft.Windows.NetworkController.LoadBalancerManagerProperties - $managerproperties.LoadBalancerManagerIPAddress = $SLBMVip - $managerproperties.OutboundNatIPExemptions = @("$SLBMVIP/32") - $managerproperties.VipIPPools = @($PrivatePoolObject, $PublicPoolObject) - - $SLBMObject = new-networkcontrollerloadbalancerconfiguration -connectionuri $uri -properties $managerproperties -resourceid "config" -Force - write-sdnexpresslog "New-SDNExpressLoadBalancerManagerConfiguration Exit" -} - - - - -function New-SDNExpressiDNSConfiguration -{ - param( - [String] $RestName, - [String] $Username, - [String] $Password, - [String] $IPAddress, - [String] $ZoneName, - [PSCredential] $Credential = $null - ) - - write-sdnexpresslog "New-SDNExpressiDNSConfiguration" - write-sdnexpresslog " -RestName: $RestName" - write-sdnexpresslog " -UserName: $UserName" - write-sdnexpresslog " -Password: ********" - write-sdnexpresslog " -IPAddress: $IPAddress" - write-sdnexpresslog " -ZoneName: $ZoneName" - write-sdnexpresslog " -Credential: $($Credential.UserName)" - - $uri = "https://$RestName" - - $CredentialProperties = new-object Microsoft.Windows.NetworkController.CredentialProperties - $CredentialProperties.Type = "UsernamePassword" - $CredentialProperties.UserName = $Username - $CredentialProperties.Value = $Password - $iDNSUserObject = New-NetworkControllerCredential -ConnectionURI $uri -ResourceId "iDNSUser" -properties $CredentialProperties -Credential $Credential -force - - $iDNSProperties = new-object microsoft.windows.networkcontroller.InternalDNSServerProperties - $iDNSProperties.Connections += new-object Microsoft.Windows.NetworkController.Connection - $iDNSProperties.Connections[0].Credential = $iDNSUserObject - $iDNSProperties.Connections[0].CredentialType = $iDNSUserObject.properties.Type - $iDNSProperties.Connections[0].ManagementAddresses = $IPAddress - - $iDNSProperties.Zone = $ZoneName - - New-NetworkControllerIDnsServerConfiguration -connectionuri $RestName -ResourceId "configuration" -properties $iDNSProperties -force -credential $Credential -} - - - - - -function Enable-SDNExpressVMPort { - param( - [String] $ComputerName, - [String] $VMName, - [String] $VMNetworkAdapterName - ) - - invoke-command -ComputerName $ComputerName -ScriptBlock { - param( - [String] $VMName, - [String] $VMNetworkAdapterName - ) - $PortProfileFeatureId = "9940cd46-8b06-43bb-b9d5-93d50381fd56" - $NcVendorId = "{1FA41B39-B444-4E43-B35A-E1F7985FD548}" - - $vnic = Get-VMNetworkAdapter -VMName $VMName -Name $VMNetworkAdapterName - - $currentProfile = Get-VMSwitchExtensionPortFeature -FeatureId $PortProfileFeatureId -VMNetworkAdapter $vNic - - if ( $currentProfile -eq $null) - { - $portProfileDefaultSetting = Get-VMSystemSwitchExtensionPortFeature -FeatureId $PortProfileFeatureId - - $portProfileDefaultSetting.SettingData.ProfileId = "{$([Guid]::Empty)}" - $portProfileDefaultSetting.SettingData.NetCfgInstanceId = "{56785678-a0e5-4a26-bc9b-c0cba27311a3}" - $portProfileDefaultSetting.SettingData.CdnLabelString = "TestCdn" - $portProfileDefaultSetting.SettingData.CdnLabelId = 1111 - $portProfileDefaultSetting.SettingData.ProfileName = "Testprofile" - $portProfileDefaultSetting.SettingData.VendorId = $NcVendorId - $portProfileDefaultSetting.SettingData.VendorName = "NetworkController" - $portProfileDefaultSetting.SettingData.ProfileData = 1 - - Add-VMSwitchExtensionPortFeature -VMSwitchExtensionFeature $portProfileDefaultSetting -VMNetworkAdapter $vNic | out-null - } - else - { - $currentProfile.SettingData.ProfileId = "{$([Guid]::Empty)}" - $currentProfile.SettingData.ProfileData = 1 - Set-VMSwitchExtensionPortFeature -VMSwitchExtensionFeature $currentProfile -VMNetworkAdapter $vNic | out-null - } - } -ArgumentList $VMName, $VMNetworkAdapterName -} - - - - - - - -<# - -ooooo ooooo . -`888' `888' .o8 - 888 888 .ooooo. .oooo.o .o888oo - 888ooooo888 d88' `88b d88( "8 888 - 888 888 888 888 `"Y88b. 888 - 888 888 888 888 o. )88b 888 . -o888o o888o `Y8bod8P' 8""888P' "888" - -#> - -Function Add-SDNExpressHost { - param( - [String] $RestName, - [string] $ComputerName, - [String] $HostPASubnetPrefix, - [String] $VirtualSwitchName = "", - [Object] $NCHostCert, - [String] $iDNSIPAddress = "", - [String] $iDNSMacAddress = "", - [PSCredential] $Credential = $null - ) - - write-sdnexpresslog "New-SDNExpressHost" - write-sdnexpresslog " -RestName: $RestName" - write-sdnexpresslog " -ComputerName: $ComputerName" - write-sdnexpresslog " -HostPASubnetPrefix: $HostPASubnetPrefix" - write-sdnexpresslog " -VirtualSwitchName: $VirtualSwitchName" - write-sdnexpresslog " -NCHostCert: $($NCHostCert.Thumbprint)" - write-sdnexpresslog " -iDNSIPAddress: $iDNSIPAddress" - write-sdnexpresslog " -iDNSMacAddress: $iDNSMacAddress" - write-sdnexpresslog " -Credential: $($Credential.UserName)" - - $uri = "https://$RestName" - - write-sdnexpresslog "Get the SLBM VIP" - - $SLBMConfig = get-networkcontrollerloadbalancerconfiguration -connectionuri $uri -credential $Credential - - $slbmvip = $slbmconfig.properties.loadbalancermanageripaddress - - write-sdnexpresslog "SLBM VIP is $slbmvip" - - if ([String]::IsNullOrEmpty($VirtualSwitchName)) { - $VirtualSwitchName = invoke-command -ComputerName $ComputerName { - $vmswitch = get-vmswitch - if (($vmswitch -eq $null) -or ($vmswitch.count -eq 0)) { - throw "No virtual switch found on this host. Please create the virtual switch before adding this host." - } - if ($vmswitch.count -gt 1) { - throw "More than one virtual switch exists on the specified host. Use the VirtualSwitchName parameter to specify which switch you want configured for use with SDN." - } - - return $vmswitch.Name - } - } - - add-windowsfeature -computername $ComputerName NetworkVirtualization -IncludeAllSubFeature -IncludeManagementTools -Restart -ErrorAction Ignore | out-null - - $NodeFQDN = invoke-command -ComputerName $ComputerName { - param( - [String] $RestName, - [String] $iDNSIPAddress, - [String] $iDNSMacAddress - ) - $NodeFQDN = (Get-WmiObject win32_computersystem).DNSHostName+"."+(Get-WmiObject win32_computersystem).Domain - - $connections = "ssl:$($RestName):6640","pssl:6640" - $peerCertCName = $RestName.ToUpper() - $hostAgentCertCName = $NodeFQDN.ToUpper() - - Set-Item WSMan:\localhost\MaxEnvelopeSizekb -Value 7000 | out-null - - new-itemproperty -path "HKLM:\SYSTEM\CurrentControlSet\Services\NcHostAgent\Parameters" -Name "Connections" -Value $connections -PropertyType "MultiString" -Force | out-null - new-itemproperty -path "HKLM:\SYSTEM\CurrentControlSet\Services\NcHostAgent\Parameters" -Name "PeerCertificateCName" -Value $peerCertCName -PropertyType "String" -Force | out-null - new-itemproperty -path "HKLM:\SYSTEM\CurrentControlSet\Services\NcHostAgent\Parameters" -Name "HostAgentCertificateCName" -Value $hostAgentCertCName -PropertyType "String" -Force | out-null - - if (![String]::IsNullOrEmpty($iDNSIPAddress) -and ![String]::IsNullOrEmpty($iDNSMacAddress)) { - new-item -path "HKLM:\SYSTEM\CurrentControlSet\Services\NcHostAgent\Parameters\Plugins\Vnet" -name "InfraServices" -force | out-null - new-item -path "HKLM:\SYSTEM\CurrentControlSet\Services\NcHostAgent\Parameters\Plugins\Vnet\InfraServices" -name "DnsProxyService" -force | out-null - new-itemproperty -path "HKLM:\SYSTEM\CurrentControlSet\Services\NcHostAgent\Parameters\Plugins\Vnet\InfraServices\DnsProxyService" -Name "Port" -Value 53 -PropertyType "Dword" -Force | out-null - new-itemproperty -path "HKLM:\SYSTEM\CurrentControlSet\Services\NcHostAgent\Parameters\Plugins\Vnet\InfraServices\DnsProxyService" -Name "ProxyPort" -Value 53 -PropertyType "Dword" -Force | out-null - new-itemproperty -path "HKLM:\SYSTEM\CurrentControlSet\Services\NcHostAgent\Parameters\Plugins\Vnet\InfraServices\DnsProxyService" -Name "IP" -Value "169.254.169.254" -PropertyType "String" -Force | out-null - new-itemproperty -path "HKLM:\SYSTEM\CurrentControlSet\Services\NcHostAgent\Parameters\Plugins\Vnet\InfraServices\DnsProxyService" -Name "MAC" -Value $iDNSMacAddress -PropertyType "String" -Force | out-null - - new-item -path "HKLM:\SYSTEM\CurrentControlSet\Services" -name "DnsProxy" -force | out-null - new-item -path "HKLM:\SYSTEM\CurrentControlSet\Services\DnsProxy" -name "Parameters" -force | out-null - new-itemproperty -path "HKLM:\SYSTEM\CurrentControlSet\Services\DNSProxy\Parameters" -Name "Forwarders" -Value $iDNSIPAddress -PropertyType "String" -Force | out-null - - Enable-NetFirewallRule -DisplayGroup 'DNS Proxy Service' -ErrorAction Ignore | out-null - } - - - $fwrule = Get-NetFirewallRule -Name "Firewall-REST" -ErrorAction SilentlyContinue - if ($fwrule -eq $null) { - New-NetFirewallRule -Name "Firewall-REST" -DisplayName "Network Controller Host Agent REST" -Group "NcHostAgent" -Action Allow -Protocol TCP -LocalPort 80 -Direction Inbound -Enabled True | Out-Null - } - - $fwrule = Get-NetFirewallRule -Name "Firewall-OVSDB" -ErrorAction SilentlyContinue - if ($fwrule -eq $null) { - New-NetFirewallRule -Name "Firewall-OVSDB" -DisplayName "Network Controller Host Agent OVSDB" -Group "NcHostAgent" -Action Allow -Protocol TCP -LocalPort 6640 -Direction Inbound -Enabled True | Out-Null - } - - $fwrule = Get-NetFirewallRule -Name "Firewall-HostAgent-TCP-IN" -ErrorAction SilentlyContinue - if ($fwrule -eq $null) { - New-NetFirewallRule -Name "Firewall-HostAgent-TCP-IN" -DisplayName "Network Controller Host Agent (TCP-In)" -Group "Network Controller Host Agent Firewall Group" -Action Allow -Protocol TCP -LocalPort Any -Direction Inbound -Enabled True | Out-Null - } - - $fwrule = Get-NetFirewallRule -Name "Firewall-HostAgent-WCF-TCP-IN" -ErrorAction SilentlyContinue - if ($fwrule -eq $null) { - New-NetFirewallRule -Name "Firewall-HostAgent-WCF-TCP-IN" -DisplayName "Network Controller Host Agent WCF(TCP-In)" -Group "Network Controller Host Agent Firewall Group" -Action Allow -Protocol TCP -LocalPort 80 -Direction Inbound -Enabled True | Out-Null - } - - $fwrule = Get-NetFirewallRule -Name "Firewall-HostAgent-TLS-TCP-IN" -ErrorAction SilentlyContinue - if ($fwrule -eq $null) { - New-NetFirewallRule -Name "Firewall-HostAgent-TLS-TCP-IN" -DisplayName "Network Controller Host Agent WCF over TLS (TCP-In)" -Group "Network Controller Host Agent Firewall Group" -Action Allow -Protocol TCP -LocalPort 443 -Direction Inbound -Enabled True | Out-Null - } - - return $NodeFQDN - } -ArgumentList $RestName, $iDNSIPAddress, $iDNSMacAddress - - write-sdnexpresslog "Create and return host certificate." - - $CertData = invoke-command -ComputerName $ComputerName { - $NodeFQDN = (Get-WmiObject win32_computersystem).DNSHostName+"."+(Get-WmiObject win32_computersystem).Domain - - $cert = get-childitem "cert:\localmachine\my" | where {$_.Subject.ToUpper() -eq "CN=$NodeFQDN".ToUpper()} - if ($Cert -eq $Null) { - write-verbose "Creating new host certificate." - $Cert = New-SelfSignedCertificate -Type Custom -KeySpec KeyExchange -Subject "CN=$NodeFQDN" -KeyExportPolicy Exportable -HashAlgorithm sha256 -KeyLength 2048 -CertStoreLocation "Cert:\LocalMachine\My" -TextExtension @("2.5.29.37={text}1.3.6.1.5.5.7.3.1,1.3.6.1.5.5.7.3.2") - } else { - write-verbose "Found existing host certficate." - $HasServerEku = ($cert.EnhancedKeyUsageList | where {$_.ObjectId -eq "1.3.6.1.5.5.7.3.1"}) -ne $null - $HasClientEku = ($cert.EnhancedKeyUsageList | where {$_.ObjectId -eq "1.3.6.1.5.5.7.3.2"}) -ne $null - - if (!$HasServerEku) { - throw "Host cert exists on $(hostname) but is missing the EnhancedKeyUsage for Server Authentication." - } - if (!$HasClientEku) { - throw "Host cert exists but $(hostname) is missing the EnhancedKeyUsage for Client Authentication." - } - write-verbose "Existing certificate meets criteria. Exporting." - } - - $targetCertPrivKey = $Cert.PrivateKey - $privKeyCertFile = Get-Item -path "$ENV:ProgramData\Microsoft\Crypto\RSA\MachineKeys\*" | where {$_.Name -eq $targetCertPrivKey.CspKeyContainerInfo.UniqueKeyContainerName} - $privKeyAcl = Get-Acl $privKeyCertFile - $permission = "NT AUTHORITY\NETWORK SERVICE","Read","Allow" - $accessRule = new-object System.Security.AccessControl.FileSystemAccessRule $permission - $privKeyAcl.AddAccessRule($accessRule) - Set-Acl $privKeyCertFile.FullName $privKeyAcl - - $TempFile = New-TemporaryFile - Remove-Item $TempFile.FullName -Force | out-null - Export-Certificate -Type CERT -FilePath $TempFile.FullName -cert $cert | out-null - - $CertData = Get-Content $TempFile.FullName -Encoding Byte - Remove-Item $TempFile.FullName -Force | out-null - - return $CertData - } - #Hold on to CertData, we will need it later when adding the host to the NC. - - write-sdnexpresslog "Install NC host cert into Root store on host." - - $TempFile = New-TemporaryFile - Remove-Item $TempFile.FullName -Force | out-null - Export-Certificate -Type CERT -FilePath $TempFile.FullName -cert $NCHostCert | out-null - $NCHostCertData = Get-Content $TempFile.FullName -Encoding Byte - Remove-Item $TempFile.FullName -Force | out-null - - invoke-command -ComputerName $ComputerName { - param( - [byte[]] $CertData - ) - $TempFile = New-TemporaryFile - Remove-Item $TempFile.FullName -Force - - $CertData | set-content $TempFile.FullName -Encoding Byte - import-certificate -filepath $TempFile.FullName -certstorelocation "cert:\localmachine\root" | out-null - Remove-Item $TempFile.FullName -Force - } -ArgumentList (,$NCHostCertData) - - write-sdnexpresslog "Restart NC Host Agent and enable VFP." - - $VirtualSwitchId = invoke-command -ComputerName $ComputerName { - param( - [String] $VirtualSwitchName - ) - Stop-Service -Name NCHostAgent -Force | out-null - Set-Service -Name NCHostAgent -StartupType Automatic | out-null - Start-Service -Name NCHostAgent | out-null - - Disable-VmSwitchExtension -VMSwitchName $VirtualSwitchName -Name "Microsoft Windows Filtering Platform" | out-null - Enable-VmSwitchExtension -VMSwitchName $VirtualSwitchName -Name "Microsoft Azure VFP Switch Extension" | out-null - - return (get-vmswitch -Name $VirtualSwitchName).Id - } -ArgumentList $VirtualSwitchName - - write-sdnexpresslog "Configure and start SLB Host Agent." - - invoke-command -computername $ComputerNAme { - param( - [String] $SLBMVip, - [String] $RestName - ) - $NodeFQDN = (Get-WmiObject win32_computersystem).DNSHostName+"."+(Get-WmiObject win32_computersystem).Domain - - $slbhpconfigtemplate = @" -<?xml version=`"1.0`" encoding=`"utf-8`"?> -<SlbHostPluginConfiguration xmlns:xsd=`"http://www.w3.org/2001/XMLSchema`" xmlns:xsi=`"http://www.w3.org/2001/XMLSchema-instance`"> - <SlbManager> - <HomeSlbmVipEndpoints> - <HomeSlbmVipEndpoint>$($SLBMVIP):8570</HomeSlbmVipEndpoint> - </HomeSlbmVipEndpoints> - <SlbmVipEndpoints> - <SlbmVipEndpoint>$($SLBMVIP):8570</SlbmVipEndpoint> - </SlbmVipEndpoints> - <SlbManagerCertSubjectName>$RESTName</SlbManagerCertSubjectName> - </SlbManager> - <SlbHostPlugin> - <SlbHostPluginCertSubjectName>$NodeFQDN</SlbHostPluginCertSubjectName> - </SlbHostPlugin> - <NetworkConfig> - <MtuSize>0</MtuSize> - <JumboFrameSize>4088</JumboFrameSize> - <VfpFlowStatesLimit>500000</VfpFlowStatesLimit> - </NetworkConfig> -</SlbHostPluginConfiguration> -"@ - - set-content -value $slbhpconfigtemplate -path 'c:\windows\system32\slbhpconfig.xml' -encoding UTF8 - - Stop-Service -Name SLBHostAgent -Force - Set-Service -Name SLBHostAgent -StartupType Automatic - Start-Service -Name SLBHostAgent - } -ArgumentList $SLBMVIP, $RESTName - - $nchostcertObject = get-networkcontrollerCredential -Connectionuri $URI -ResourceId "NCHostCert" -credential $Credential - - $PALogicalNetwork = get-networkcontrollerLogicalNetwork -Connectionuri $URI -ResourceId "HNVPA" -credential $Credential - $PALogicalSubnet = $PALogicalNetwork.Properties.Subnets | where {$_.properties.AddressPrefix -eq $HostPASubnetPrefix} - - $ServerProperties = new-object Microsoft.Windows.NetworkController.ServerProperties - - $ServerProperties.Connections = @() - $ServerProperties.Connections += new-object Microsoft.Windows.NetworkController.Connection - $ServerProperties.Connections[0].Credential = $nchostcertObject - $ServerProperties.Connections[0].CredentialType = $nchostcertObject.properties.Type - $ServerProperties.Connections[0].ManagementAddresses = @($NodeFQDN) - - $ServerProperties.NetworkInterfaces = @() - $serverProperties.NetworkInterfaces += new-object Microsoft.Windows.NetworkController.NwInterface - $serverProperties.NetworkInterfaces[0].ResourceId = $VirtualSwitchName - $serverProperties.NetworkInterfaces[0].Properties = new-object Microsoft.Windows.NetworkController.NwInterfaceProperties - $ServerProperties.NetworkInterfaces[0].Properties.LogicalSubnets = @($PALogicalSubnet) - - $ServerProperties.Certificate = [System.Convert]::ToBase64String($CertData) - - $Server = New-NetworkControllerServer -ConnectionURI $uri -ResourceId $VirtualSwitchId -Properties $ServerProperties -Credential $Credential -Force - - invoke-command -computername $ComputerName { - param( - [String] $InstanceId - ) - new-itemproperty -path "HKLM:\SYSTEM\CurrentControlSet\Services\NcHostAgent\Parameters" -Name "HostId" -Value $InstanceId -PropertyType "String" -Force | out-null - - $dnsproxy = get-service DNSProxy -ErrorAction Ignore - if ($dnsproxy -ne $null) { - $dnsproxy | Stop-Service -Force - } - - Stop-Service SlbHostAgent -Force - Stop-Service NcHostAgent -Force - - Start-Service NcHostAgent - Start-Service SlbHostAgent - - if ($dnsproxy -ne $null) { - Set-Service -Name "DnsProxy" -StartupType Automatic - $dnsproxy | Start-Service - } - - } -ArgumentList $Server.InstanceId - - write-sdnexpresslog "New-SDNExpressHost Exit" -} - - - - -<# -ooooo ooo . o8o oooo o8o . -`888' `8' .o8 `"' `888 `"' .o8 - 888 8 .o888oo oooo 888 oooo .o888oo oooo ooo - 888 8 888 `888 888 `888 888 `88. .8' - 888 8 888 888 888 888 888 `88..8' - `88. .8' 888 . 888 888 888 888 . `888' - `YbodP' "888" o888o o888o o888o "888" .8' - .o..P' - `Y8P' -#> -function Write-SDNExpressLog -{ - Param([String] $Message) - - $FormattedDate = date -Format "yyyyMMdd-HH:mm:ss" - $FormattedMessage = "[$FormattedDate] $Message" - write-verbose $FormattedMessage - - $formattedMessage | out-file ".\SDNExpressLog.txt" -Append -} -function Get-IPv4AddressInSubnet -{ - param([string] $subnet, [int] $offset) - - $prefix = ($subnet.split("/"))[0] - $bits = ($subnet.split("/"))[1] - - $sp = $prefix.Split(".", 4) - $val = [System.Convert]::ToInt64($sp[0]) - $val = $val -shl 8 - $val += [System.Convert]::ToInt64($sp[1]) - $val = $val -shl 8 - $val += [System.Convert]::ToInt64($sp[2]) - $val = $val -shl 8 - $val += [System.Convert]::ToInt64($sp[3]) - - $val = $val -shr (32 - $bits) - $val = $val -shl (32 - $bits) - $val += $offset - - "{0}.{1}.{2}.{3}" -f (($val -shr 24) -band 0xff), (($val -shr 16) -band 0xff), (($val -shr 8) -band 0xff), ($val -band 0xff ) -} -function Get-IPv4LastAddressInSubnet -{ - param([string] $subnet, [Int32]$offset = 0) - - $bits = ($subnet.split("/"))[1] - $Count = [math]::pow(2, 32-$bits) - return get-ipv4addressinsubnet $subnet (($count-1)+$offset) -} - - -function WaitForComputerToBeReady -{ - param( - [string[]] $ComputerName, - [Switch]$CheckPendingReboot - ) - - - foreach ($computer in $computername) { - write-sdnexpresslog "Waiting for $Computer to become active." - Start-Sleep -Seconds 120 - - $continue = $true - while ($continue) { - try { - $ps = $null - $result = "" - - klist purge | out-null #clear kerberos ticket cache - Clear-DnsClientCache #clear DNS cache in case IP address is stale - - write-sdnexpresslog "Attempting to contact $Computer." - $ps = new-pssession -computername $Computer -erroraction ignore - if ($ps -ne $null) { - if ($CheckPendingReboot) { - $result = Invoke-Command -Session $ps -ScriptBlock { - if (Test-Path "HKLM:\Software\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending") { - "Reboot pending" - } - else { - hostname - } - } - } - else { - try { - $result = Invoke-Command -Session $ps -ScriptBlock { hostname } - } catch { } - } - remove-pssession $ps - } - if ($result -eq $Computer) { - $continue = $false - break - } - if ($result -eq "Reboot pending") { - write-sdnexpresslog "Reboot pending on $Computer. Waiting for restart." - } - } - catch - { - } - write-sdnexpresslog "$Computer is not active, sleeping for 10 seconds." - sleep 10 - } - write-sdnexpresslog "$Computer IS ACTIVE. Continuing with deployment." - } -} - - - - -<# - -ooo ooooo -`88. .888' - 888b d'888 oooo oooo oooo ooo - 8 Y88. .P 888 `888 `888 `88b..8P' - 8 `888' 888 888 888 Y888' - 8 Y 888 888 888 .o8"'88b -o8o o888o `V88V"V8P' o88' 888o - - - -#> -Function Add-SDNExpressMux { - param( - [String] $RestName, - [string] $ComputerName, - [Object] $NCHostCert, - [String] $PAMacAddress, - [String] $LocalPeerIP, - [String] $MuxASN, - [Object] $Routers, - [PSCredential] $Credential = $null - ) - - write-sdnexpresslog "New-SDNExpressMux" - write-sdnexpresslog " -RestName: $RestName" - write-sdnexpresslog " -ComputerName: $ComputerName" - write-sdnexpresslog " -NCHostCert: $($NCHostCert.Thumbprint)" - write-sdnexpresslog " -PAMacAddress: $PAMacAddress" - write-sdnexpresslog " -LocalPeerIP: $LocalPeerIP" - write-sdnexpresslog " -MuxASN: $MuxASN" - write-sdnexpresslog " -Routers: $Routers" - write-sdnexpresslog " -Credential: $($Credential.UserName)" - - $uri = "https://$RestName" - - #TODO: Add PA Routes - - invoke-command -computername $ComputerName { - param( - [String] $PAMacAddress - ) - reg add hklm\system\currentcontrolset\services\tcpip6\parameters /v DisabledComponents /t REG_DWORD /d 255 /f | out-null - - $PAMacAddress = [regex]::matches($PAMacAddress.ToUpper().Replace(":", "").Replace("-", ""), '..').groups.value -join "-" - $nic = Get-NetAdapter -ErrorAction Ignore | where {$_.MacAddress -eq $PAMacAddress} - - if ($nic -eq $null) - { - throw "No adapter with the HNVPA MAC $PAMacAddress was found" - } - - $nicProperty = Get-NetAdapterAdvancedProperty -Name $nic.Name -AllProperties -RegistryKeyword *EncapOverhead -ErrorAction Ignore - if($nicProperty -eq $null) - { - New-NetAdapterAdvancedProperty -Name $nic.Name -RegistryKeyword *EncapOverhead -RegistryValue 160 | out-null - } - else - { - Set-NetAdapterAdvancedProperty -Name $nic.Name -AllProperties -RegistryKeyword *EncapOverhead -RegistryValue 160 - } - - add-windowsfeature SoftwareLoadBalancer -Restart | out-null - } -argumentlist $PAMacAddress - - WaitforComputerToBeReady $ComputerName $true - - $MuxFQDN = invoke-command -computername $ComputerName { - Return (Get-WmiObject win32_computersystem).DNSHostName+"."+(Get-WmiObject win32_computersystem).Domain - } - - #wait for comptuer to restart. - - $CertData = invoke-command -computername $ComputerName { - write-verbose "Creating self signed certificate..."; - - $NodeFQDN = (Get-WmiObject win32_computersystem).DNSHostName+"."+(Get-WmiObject win32_computersystem).Domain - - $cert = get-childitem "cert:\localmachine\my" | where {$_.Subject.ToUpper() -eq "CN=$NodeFQDN".ToUpper()} - if ($cert -eq $null) { - $cert = New-SelfSignedCertificate -Type Custom -KeySpec KeyExchange -Subject "CN=$NodeFQDN" -KeyExportPolicy Exportable -HashAlgorithm sha256 -KeyLength 2048 -CertStoreLocation "Cert:\LocalMachine\My" -TextExtension @("2.5.29.37={text}1.3.6.1.5.5.7.3.1,1.3.6.1.5.5.7.3.2") - } - - $targetCertPrivKey = $Cert.PrivateKey - $privKeyCertFile = Get-Item -path "$ENV:ProgramData\Microsoft\Crypto\RSA\MachineKeys\*" | where {$_.Name -eq $targetCertPrivKey.CspKeyContainerInfo.UniqueKeyContainerName} - $privKeyAcl = Get-Acl $privKeyCertFile - $permission = "NT AUTHORITY\NETWORK SERVICE","Read","Allow" - $accessRule = new-object System.Security.AccessControl.FileSystemAccessRule $permission - $privKeyAcl.AddAccessRule($accessRule) - Set-Acl $privKeyCertFile.FullName $privKeyAcl - - $TempFile = New-TemporaryFile - Remove-Item $TempFile.FullName -Force | out-null - Export-Certificate -Type CERT -FilePath $TempFile.FullName -cert $cert | out-null - - $CertData = Get-Content $TempFile.FullName -Encoding Byte - Remove-Item $TempFile.FullName -Force | out-null - - return $CertData - } - - $TempFile = New-TemporaryFile - Remove-Item $TempFile.FullName -Force | out-null - Export-Certificate -Type CERT -FilePath $TempFile.FullName -cert $NCHostCert | out-null - $NCHostCertData = Get-Content $TempFile.FullName -Encoding Byte - Remove-Item $TempFile.FullName -Force | out-null - - invoke-command -ComputerName $ComputerName { - param( - [byte[]] $CertData - ) - $TempFile = New-TemporaryFile - Remove-Item $TempFile.FullName -Force - - $CertData | set-content $TempFile.FullName -Encoding Byte - import-certificate -filepath $TempFile.FullName -certstorelocation "cert:\localmachine\root" | out-null - Remove-Item $TempFile.FullName -Force - } -ArgumentList (,$NCHostCertData) - - - $vmguid = invoke-command -computername $ComputerName { - param( - [String] $RestName - ) - - $NodeFQDN = (Get-WmiObject win32_computersystem).DNSHostName+"."+(Get-WmiObject win32_computersystem).Domain - $cert = get-childitem "cert:\localmachine\my" | where {$_.Subject.ToUpper() -eq "CN=$NodeFQDN".ToUpper()} - - New-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\SlbMux" -Force -Name SlbmThumb -PropertyType String -Value $RestName | out-null - New-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\SlbMux" -Force -Name MuxCert -PropertyType String -Value $NodeFQDN | out-null - - Get-ChildItem -Path WSMan:\localhost\Listener | Where {$_.Keys.Contains("Transport=HTTPS") } | Remove-Item -Recurse -Force | out-null - New-Item -Path WSMan:\localhost\Listener -Address * -HostName $NodeFQDN -Transport HTTPS -CertificateThumbPrint $cert.Thumbprint -Force | out-null - - Get-Netfirewallrule -Group "@%SystemRoot%\system32\firewallapi.dll,-36902" | Enable-NetFirewallRule - - start-service slbmux - - return (get-childitem -Path "HKLM:\software\microsoft\virtual machine\guest" | get-itemproperty).virtualmachineid - } -ArgumentList $RestName - - write-sdnexpresslog "Add VirtualServerToNC"; - $nchostcertObject = get-networkcontrollerCredential -Connectionuri $URI -ResourceId "NCHostCert" -credential $Credential - - $VirtualServerProperties = new-object Microsoft.Windows.NetworkController.VirtualServerProperties - $VirtualServerProperties.Connections = @() - $VirtualServerProperties.Connections += new-object Microsoft.Windows.NetworkController.Connection - $VirtualServerProperties.Connections[0].Credential = $nchostcertObject - $VirtualServerProperties.Connections[0].CredentialType = $nchostcertObject.properties.Type - $VirtualServerProperties.Connections[0].ManagementAddresses = @($MuxFQDN) - $VirtualServerProperties.Certificate = [System.Convert]::ToBase64String($CertData) - $VirtualServerProperties.vmguid = $vmGuid - - $VirtualServer = new-networkcontrollervirtualserver -connectionuri $uri -credential $Credential -MarkServerReadOnly $false -ResourceId $MuxFQDN -Properties $VirtualServerProperties -force - - $MuxProperties = new-object Microsoft.Windows.NetworkController.LoadBalancerMuxProperties - $muxProperties.RouterConfiguration = new-object Microsoft.Windows.NetworkController.RouterConfiguration - $muxProperties.RouterConfiguration.LocalASN = $MuxASN - $muxProperties.RouterConfiguration.PeerRouterConfigurations = @() - foreach ($router in $routers) { - $peerRouter = new-object Microsoft.Windows.NetworkController.PeerRouterConfiguration - $peerRouter.LocalIPAddress = $LocalPeerIP - $peerRouter.PeerASN = $Router.RouterASN - $peerRouter.RouterIPAddress = $Router.RouterIPAddress - $peerRouter.RouterName = $Router.RouterIPAddress.Replace(".", "_") - $muxProperties.RouterConfiguration.PeerRouterConfigurations += $PeerRouter - } - $muxProperties.VirtualServer = $VirtualServer - - $Mux = new-networkcontrollerloadbalancermux -connectionuri $uri -credential $Credential -ResourceId $MuxFQDN -Properties $MuxProperties -force - write-sdnexpresslog "New-SDNExpressMux Exit" -} - -<# - - .oooooo. . - d8P' `Y8b .o8 -888 .oooo. .o888oo .ooooo. oooo oooo ooo .oooo. oooo ooo .oooo.o -888 `P )88b 888 d88' `88b `88. `88. .8' `P )88b `88. .8' d88( "8 -888 ooooo .oP"888 888 888ooo888 `88..]88..8' .oP"888 `88..8' `"Y88b. -`88. .88' d8( 888 888 . 888 .o `888'`888' d8( 888 `888' o. )88b - `Y8bood8P' `Y888""8o "888" `Y8bod8P' `8' `8' `Y888""8o .8' 8""888P' - .o..P' - `Y8P' - -#> -function New-SDNExpressGatewayPool -{ - param( - [String] $RestName, - [PSCredential] $Credential, - [String] $PoolName, - [Parameter(Mandatory=$true,ParameterSetName="TypeAll")] - [Switch] $IsTypeAll, - [Parameter(Mandatory=$true,ParameterSetName="TypeIPSec")] - [Switch] $IsTypeIPSec, - [Parameter(Mandatory=$true,ParameterSetName="TypeGre")] - [Switch] $IsTypeGre, - [Parameter(Mandatory=$true,ParameterSetName="TypeForwarding")] - [Switch] $IsTypeForwarding, - [Parameter(Mandatory=$false,ParameterSetName="TypeAll")] - [Parameter(Mandatory=$false,ParameterSetName="TypeGre")] - [String] $PublicIPAddress, - [Parameter(Mandatory=$false,ParameterSetName="TypeAll")] - [Parameter(Mandatory=$true,ParameterSetName="TypeGre")] - [String] $GreSubnetAddressPrefix, - [Parameter(Mandatory=$false,ParameterSetName="TypeGre")] - [String] $GrePoolStart = (Get-IPv4AddressInSubnet -subnet $GreSubnetAddressPrefix -offset 1), - [Parameter(Mandatory=$false,ParameterSetName="TypeGre")] - [String] $GrePoolEnd = (Get-IPv4LastAddressInSubnet -subnet $GreSubnetAddressPrefix), - [String] $Capacity, - [String] $RedundantCount=1 - ) - - write-sdnexpresslog "New-SDNExpressGatewayPool" - write-sdnexpresslog " -RestName: $RestName" - write-sdnexpresslog " -Credential: $($Credential.UserName)" - write-sdnexpresslog " -PoolName: $PoolName" - write-sdnexpresslog " -IsTypeAll: $IsTypeAll" - write-sdnexpresslog " -IsTypeIPSec: $IsTypeIPSec" - write-sdnexpresslog " -IsTypeGre: $IsTypeGre" - write-sdnexpresslog " -IsTypeForwarding: $IsTypeForwarding" - write-sdnexpresslog " -PublicIPAddress: $PublicIPAddress" - write-sdnexpresslog " -GRESubnetAddressPrefix: $GRESubnetAddressPrefix" - write-sdnexpresslog " -GrePoolStart: $GrePoolStart" - write-sdnexpresslog " -GrePoolEnd: $GrePoolEnd" - write-sdnexpresslog " -Capacity: $Capacity" - write-sdnexpresslog " -RedundantCount: $RedundantCount" - - $uri = "https://$RestName" - - $gresubnet = $null - - if ($IsTypeAll -or $IsTypeIPSec) { - $PublicIPProperties = new-object Microsoft.Windows.NetworkController.PublicIPAddressProperties - $publicIPProperties.IdleTimeoutInMinutes = 4 - - if ([String]::IsNullOrEmpty($PublicIPAddress)) { - $PublicIPProperties.PublicIPAllocationMethod = "Dynamic" - } else { - $PublicIPProperties.PublicIPAllocationMethod = "Static" - $PublicIPProperites.IPAddress = $PublicIPAddress - } - $PublicIPAddressObject = New-NetworkControllerPublicIPAddress -connectionURI $uri -ResourceId $PoolName -Properties $PublicIPProperties -Force -Credential $Credential - } - - if ($IsTypeGre -or $IsTypeAll) { - $logicalNetwork = try { get-networkcontrollerlogicalnetwork -ResourceId "GreVIP" -connectionuri $uri -credential $Credential } catch {} - - if ($logicalNetwork -eq $null) { - $LogicalNetworkProperties = new-object Microsoft.Windows.NetworkController.LogicalNetworkProperties - $LogicalNetworkProperties.NetworkVirtualizationEnabled = $false - $LogicalNetwork = New-NetworkControllerLogicalNetwork -ConnectionURI $uri -ResourceID "GreVIP" -properties $LogicalNetworkProperties -Credential $Credential -Force - } - - foreach ($subnet in $logicalnetwork.properties.subnets) { - if ($Subnet.properties.AddressPrefix -eq $GreSubnetAddressPrefix) { - $GreSubnet = $subnet - } - } - - if ($GreSubnet -eq $Null) { - $LogicalSubnetProperties = new-object Microsoft.Windows.NetworkController.LogicalSubnetProperties - $LogicalSubnetProperties.AddressPrefix = $GreSubnetAddressPrefix - $logicalSubnetProperties.DefaultGateways = @(Get-IPv4AddressInSubnet -subnet $GreSubnetAddressPrefix) - - $greSubnet = New-NetworkControllerLogicalSubnet -ConnectionURI $uri -LogicalNetworkId "GreVIP" -ResourceId $GreSubnetAddressPrefix.Replace("/", "_") -properties $LogicalSubnetProperties -Credential $Credential -Force - - $IPpoolProperties = new-object Microsoft.Windows.NetworkController.IPPoolproperties - $ippoolproperties.startipaddress = $GrePoolStart - $ippoolproperties.endipaddress = $GrePoolEnd - - $IPPoolObject = New-networkcontrollerIPPool -ConnectionURI $uri -NetworkId "GreVIP" -SubnetId $GreSubnetAddressPrefix.Replace("/", "_") -ResourceID $GreSubnetAddressPrefix.Replace("/", "_") -Properties $IPPoolProperties -Credential $Credential -force - } - } - - $GatewayPoolProperties = new-object Microsoft.Windows.NetworkController.GatewayPoolProperties - $GatewayPoolProperties.RedundantGatewayCount = $RedundantCount - $GatewayPoolProperties.GatewayCapacityKiloBitsPerSecond = $Capacity - - if ($IsTypeAll) { - $GatewayPoolProperties.Type = "All" - - $GatewayPoolProperties.IPConfiguration = new-object Microsoft.Windows.NetworkController.IPConfig - $GatewayPoolProperties.IPConfiguration.PublicIPAddresses = @() - $GatewayPoolProperties.IPConfiguration.PublicIPAddresses += $PublicIPAddressObject - - $GatewayPoolProperties.IpConfiguration.GreVipSubnets = @() - $GatewayPoolProperties.IPConfiguration.GreVipSubnets += $GreSubnet - } elseif ($IsTypeIPSec) { - $GatewayPoolProperties.Type = "S2sIpSec" - - $GatewayPoolProperties.IPConfiguration = new-object Microsoft.Windows.NetworkController.IPConfig - $GatewayPoolProperties.IPConfiguration.PublicIPAddresses = @() - $GatewayPoolProperties.IPConfiguration.PublicIPAddresses += $PublicIPAddressObject - } elseif ($IsTypeGre) { - $GatewayPoolProperties.Type = "S2sGre" - - $GatewayPoolProperties.IPConfiguration = new-object Microsoft.Windows.NetworkController.IPConfig - $GatewayPoolProperties.IpConfiguration.GreVipSubnets = @() - $GatewayPoolProperties.IPConfiguration.GreVipSubnets += $GreSubnet - } elseif ($IsForwarding) { - $GatewayPoolProperties.Type = "Forwarding" - } - - $GWPoolObject = new-networkcontrollergatewaypool -connectionURI $URI -ResourceId $PoolName -Properties $GatewayPoolProperties -Force -Credential $Credential - write-sdnexpresslog "New-SDNExpressGatewayPool Exit" -} - - - - - -Function New-SDNExpressGateway { - param( - [String] $RestName, - [string] $ComputerName, - [String] $HostName, - [Object] $NCHostCert, - [String] $PoolName, - [String] $FrontEndLogicalNetworkName, - [String] $FrontEndAddressPrefix, - [String] $FrontEndIp, - [String] $FrontEndMac, - [String] $BackEndMac, - [String] $RouterASN = $null, - [String] $RouterIP = $null, - [String] $LocalASN = $null, - [PSCredential] $Credential = $null - ) - - write-sdnexpresslog "New-SDNExpressGateway" - write-sdnexpresslog " -RestName: $RestName" - write-sdnexpresslog " -ComputerName: $ComputerName" - write-sdnexpresslog " -HostName: $HostName" - write-sdnexpresslog " -NCHostCert: $($NCHostCert.thumbprint)" - write-sdnexpresslog " -PoolName: $PoolName" - write-sdnexpresslog " -FrontEndLogicalNetworkName: $FrontEndLogicalNetworkName" - write-sdnexpresslog " -FrontEndAddressPrefix: $FrontEndAddressPrefix" - write-sdnexpresslog " -FrontEndIp: $FrontEndIp" - write-sdnexpresslog " -FrontEndMac: $FrontEndMac" - write-sdnexpresslog " -BackEndMac: $BackEndMac" - write-sdnexpresslog " -RouterASN: $RouterASN" - write-sdnexpresslog " -RouterIP: $RouterIP" - write-sdnexpresslog " -LocalASN: $LocalASN" - write-sdnexpresslog " -Credential: $($Credential.UserName)" - - $uri = "https://$RestName" - - - invoke-command -computername $ComputerName { - param( - [String] $FrontEndMac, - [String] $BackEndMac - ) - - # Get-NetAdapter returns MacAddresses with hyphens '-' - $FrontEndMac = [regex]::matches($FrontEndMac.ToUpper().Replace(":", "").Replace("-", ""), '..').groups.value -join "-" - $BackEndMac = [regex]::matches($BackEndMac.ToUpper().Replace(":", "").Replace("-", ""), '..').groups.value -join "-" - - Set-Item WSMan:\localhost\MaxEnvelopeSizekb -Value 7000 - - $adapters = Get-NetAdapter - - $adapter = $adapters | where {$_.MacAddress -eq $BackEndMac} - $adapter | Rename-NetAdapter -NewName "Internal" -Confirm:$false -ErrorAction Ignore - - $adapter = $adapters | where {$_.MacAddress -eq $FrontEndMac} - $adapter | Rename-NetAdapter -NewName "External" -Confirm:$false -ErrorAction Ignore - - Add-WindowsFeature -Name RemoteAccess -IncludeAllSubFeature -IncludeManagementTools | out-null - - $RemoteAccess = get-RemoteAccess - if ($RemoteAccess -eq $null -or $RemoteAccess.VpnMultiTenancyStatus -ne "Installed") - { - Install-RemoteAccess -MultiTenancy | out-null - } - - Get-Netfirewallrule -Group "@%SystemRoot%\system32\firewallapi.dll,-36902" | Enable-NetFirewallRule - - $GatewayService = get-service GatewayService -erroraction Ignore - if ($gatewayservice -ne $null) { - Set-Service -Name GatewayService -StartupType Automatic | out-null - Start-Service -Name GatewayService | out-null - } - - } -ArgumentList $FrontEndMac, $BackEndMac - - $GatewayFQDN = invoke-command -computername $ComputerName { - Return (Get-WmiObject win32_computersystem).DNSHostName+"."+(Get-WmiObject win32_computersystem).Domain - } - - $vmGuid = invoke-command -computername $ComputerName { - return (get-childitem -Path "HKLM:\software\microsoft\virtual machine\guest" | get-itemproperty).virtualmachineid - } - - $TempFile = New-TemporaryFile - Remove-Item $TempFile.FullName -Force | out-null - Export-Certificate -Type CERT -FilePath $TempFile.FullName -cert $NCHostCert | out-null - $NCHostCertData = Get-Content $TempFile.FullName -Encoding Byte - Remove-Item $TempFile.FullName -Force | out-null - - invoke-command -ComputerName $ComputerName { - param( - [byte[]] $CertData - ) - $TempFile = New-TemporaryFile - Remove-Item $TempFile.FullName -Force - - $CertData | set-content $TempFile.FullName -Encoding Byte - import-certificate -filepath $TempFile.FullName -certstorelocation "cert:\localmachine\root" | out-null - Remove-Item $TempFile.FullName -Force - } -ArgumentList (,$NCHostCertData) - - # Get-VMNetworkAdapter returns MacAddresses without hyphens '-'. NetworkInterface prefers without hyphens also. - - $FrontEndMac = [regex]::matches($FrontEndMac.ToUpper().Replace(":", "").Replace("-", ""), '..').groups.value -join "" - $BackEndMac = [regex]::matches($BackEndMac.ToUpper().Replace(":", "").Replace("-", ""), '..').groups.value -join "" - - $LogicalSubnet = get-networkcontrollerlogicalSubnet -LogicalNetworkId $FrontEndLogicalNetworkName -ConnectionURI $uri -Credential $Credential - $LogicalSubnet = $LogicalSubnet | where {$_.properties.AddressPrefix -eq $FrontEndAddressPrefix } - - $NicProperties = new-object Microsoft.Windows.NetworkController.NetworkInterfaceProperties - $nicproperties.PrivateMacAddress = $BackEndMac - $NicProperties.privateMacAllocationMethod = "Static" - $BackEndNic = new-networkcontrollernetworkinterface -connectionuri $uri -credential $Credential -ResourceId "$($GatewayFQDN)_BackEnd" -Properties $NicProperties -force - - $NicProperties = new-object Microsoft.Windows.NetworkController.NetworkInterfaceProperties - $nicproperties.PrivateMacAddress = $FrontEndMac - $NicProperties.privateMacAllocationMethod = "Static" - $NicProperties.IPConfigurations = @() - $NicProperties.IPConfigurations += new-object Microsoft.Windows.NetworkController.NetworkInterfaceIpConfiguration - $NicProperties.IPConfigurations[0].ResourceId = "FrontEnd" - $NicProperties.IPConfigurations[0].Properties = new-object Microsoft.Windows.NetworkController.NetworkInterfaceIpConfigurationProperties - $NicProperties.IPConfigurations[0].Properties.Subnet = new-object Microsoft.Windows.NetworkController.Subnet - $nicProperties.IpConfigurations[0].Properties.Subnet.ResourceRef = $LogicalSubnet.ResourceRef - $NicProperties.IPConfigurations[0].Properties.PrivateIPAddress = $FrontEndIp - $NicProperties.IPConfigurations[0].Properties.PrivateIPAllocationMethod = "Static" - $FrontEndNic = new-networkcontrollernetworkinterface -connectionuri $uri -credential $Credential -ResourceId "$($GatewayFQDN)_FrontEnd" -Properties $NicProperties -force - - $SetPortProfileBlock = { - param( - [String] $VMName, - [String] $MacAddress, - [String] $InstanceId - ) - $PortProfileFeatureId = "9940cd46-8b06-43bb-b9d5-93d50381fd56" - $NcVendorId = "{1FA41B39-B444-4E43-B35A-E1F7985FD548}" - - $vnic = Get-VMNetworkAdapter -VMName $VMName | where {$_.MacAddress -eq $MacAddress} - - $currentProfile = Get-VMSwitchExtensionPortFeature -FeatureId $PortProfileFeatureId -VMNetworkAdapter $vNic - - if ( $currentProfile -eq $null) - { - $portProfileDefaultSetting = Get-VMSystemSwitchExtensionPortFeature -FeatureId $PortProfileFeatureId - $portProfileDefaultSetting.SettingData.NetCfgInstanceId = "{56785678-a0e5-4a26-bc9b-c0cba27311a3}" - $portProfileDefaultSetting.SettingData.CdnLabelString = "TestCdn" - $portProfileDefaultSetting.SettingData.CdnLabelId = 1111 - $portProfileDefaultSetting.SettingData.ProfileName = "Testprofile" - $portProfileDefaultSetting.SettingData.VendorId = $NcVendorId - $portProfileDefaultSetting.SettingData.VendorName = "NetworkController" - - $portProfileDefaultSetting.SettingData.ProfileId = "{$InstanceId}" - $portProfileDefaultSetting.SettingData.ProfileData = 1 - - Add-VMSwitchExtensionPortFeature -VMSwitchExtensionFeature $portProfileDefaultSetting -VMNetworkAdapter $vNic | out-null - } - else - { - $currentProfile.SettingData.ProfileId = "{$InstanceId}" - $currentProfile.SettingData.ProfileData = 1 - Set-VMSwitchExtensionPortFeature -VMSwitchExtensionFeature $currentProfile -VMNetworkAdapter $vNic | out-null - } - } - - invoke-command -ComputerName $HostName -ScriptBlock $SetPortProfileBlock -ArgumentList $ComputerName, $BackEndMac, $BackEndNic.InstanceId - invoke-command -ComputerName $HostName -ScriptBlock $SetPortProfileBlock -ArgumentList $ComputerName, $FrontEndMac, $FrontEndNic.InstanceId - - $nchostUserObject = get-networkcontrollerCredential -Connectionuri $URI -ResourceId "NCHostUser" -credential $Credential - $GatewayPoolObject = get-networkcontrollerGatewayPool -Connectionuri $URI -ResourceId $PoolName -credential $Credential - - $VirtualServerProperties = new-object Microsoft.Windows.NetworkController.VirtualServerProperties - $VirtualServerProperties.Connections = @() - $VirtualServerProperties.Connections += new-object Microsoft.Windows.NetworkController.Connection - $VirtualServerProperties.Connections[0].Credential = $nchostUserObject - $VirtualServerProperties.Connections[0].CredentialType = $nchostUserObject.properties.Type - $VirtualServerProperties.Connections[0].ManagementAddresses = @($GatewayFQDN) - $VirtualServerProperties.vmguid = $vmGuid - - $VirtualServerObject = new-networkcontrollervirtualserver -connectionuri $uri -credential $Credential -MarkServerReadOnly $false -ResourceId $GatewayFQDN -Properties $VirtualServerProperties -force - - $GatewayProperties = new-object Microsoft.Windows.NetworkController.GatewayProperties - $GatewayProperties.NetworkInterfaces = new-object Microsoft.Windows.NetworkController.NetworkInterfaces - $GatewayProperties.NetworkInterfaces.InternalNetworkInterface = $BackEndNic - $GatewayProperties.NetworkInterfaces.ExternalNetworkInterface = $FrontEndNic - $GatewayProperties.Pool = $GatewayPoolObject - $GatewayProperties.VirtualServer = $VirtualServerObject - - if (($GatewayPoolObject.Properties.Type -eq "All") -or ($GatewayPoolObject.Properties.Type -eq "S2sIpsec" )) { - $GatewayProperties.BGPConfig = new-object Microsoft.Windows.NetworkController.GatewayBgpConfig - - $GatewayProperties.BGPConfig.BgpPeer = @() - $GatewayProperties.BGPConfig.BgpPeer += new-object Microsoft.Windows.NetworkController.GatewayBgpPeer - $GatewayProperties.BGPConfig.BgpPeer[0].PeerExtAsNumber = "0.$RouterASN" - $GatewayProperties.BGPConfig.BgpPeer[0].PeerIP = $RouterIP - - $GatewayProperties.BgpConfig.ExtASNumber = "0.$LocalASN" - } - - $Gw = new-networkcontrollerGateway -connectionuri $uri -credential $Credential -ResourceId $GatewayFQDN -Properties $GatewayProperties -force - - write-sdnexpresslog "New-SDNExpressGateway Exit" -} - - - - - - - -function New-SDNExpressVM -{ - param( - [String] $ComputerName, - [String] $VMLocation, - [String] $VMName, - [String] $VHDSrcPath, - [String] $VHDName, - [Int64] $VMMemory=3GB, - [String] $SwitchName="", - [Object] $Nics, - [String] $CredentialDomain, - [String] $CredentialUserName, - [String] $CredentialPassword, - [String] $JoinDomain, - [String] $LocalAdminPassword, - [String] $DomainAdminDomain, - [String] $DomainAdminUserName, - [String] $ProductKey="", - [int] $VMProcessorCount = 4, - [String] $Locale = [System.Globalization.CultureInfo]::CurrentCulture.Name, - [String] $TimeZone = [TimeZoneInfo]::Local.Id, - [Bool] $InstallRasRoutingProtocols - ) - - write-sdnexpresslog "New-SDNExpressVM" - write-sdnexpresslog " -ComputerName: $ComputerName" - write-sdnexpresslog " -VMLocation: $VMLocation" - write-sdnexpresslog " -VMName: $VMName" - write-sdnexpresslog " -VHDSrcPath: $VHDSrcPath" - write-sdnexpresslog " -VHDName: $VHDName" - write-sdnexpresslog " -VMMemory: $VMMemory" - write-sdnexpresslog " -SwitchName: $SwitchName" - write-sdnexpresslog " -Nics: $Nics" - write-sdnexpresslog " -CredentialDomain: $CredentialDomain" - write-sdnexpresslog " -CredentialUserName: $CredentialUserName" - write-sdnexpresslog " -CredentialPassword: ********" - write-sdnexpresslog " -JoinDomain: $JoinDomain" - write-sdnexpresslog " -LocalAdminPassword: ********" - write-sdnexpresslog " -DomainAdminDomain: $DomainAdminDomain" - write-sdnexpresslog " -DomainAdminUserName: $DomainAdminUserName" - write-sdnexpresslog " -ProductKey: ********" - write-sdnexpresslog " -VMProcessorCount: $VMProcessorCount" - write-sdnexpresslog " -Locale: $Locale" - write-sdnexpresslog " -TimeZone: $TimeZone" - - $LocalVMPath = "$vmLocation\$VMName" - $LocalVHDPath = "$localVMPath\$VHDName" - $VHDFullPath = "$VHDSrcPath\$VHDName" - - if ($VMLocation.startswith("\\")) { - $VMPath = "$VMLocation\$VMName" - } else { - $VMPath = "\\$ComputerName\VMShare\$VMName" - } - - $VHDVMPath = "$VMPath\$VHDName" - - write-sdnexpresslog "Checking for previously mounted image." - - $mounted = get-WindowsImage -Mounted - foreach ($mount in $mounted) - { - if ($mount.ImagePath -eq $VHDVMPath) { - DisMount-WindowsImage -Discard -path $mount.Path | out-null - } - } - - $vm = $null - try { - $VM = get-vm -computername $ComputerName -Name $VMName -erroraction Ignore - if ($VM -ne $Null) { - write-sdnexpresslog "VM already exists, exiting VM creation." - return - } - } catch - { - #Continue - } - - if ([String]::IsNullOrEmpty($SwitchName)) { - write-sdnexpresslog "Finding virtual switch." - $SwitchName = invoke-command -computername $computername { - $VMSwitches = Get-VMSwitch - if ($VMSwitches -eq $Null) { - throw "No Virtual Switches found on the host. Can't create VM. Please create a virtual switch before continuing." - } - if ($VMSwitches.count -gt 1) { - throw "More than one virtual switch found on host. Please specify virtual switch name using SwitchName parameter." - } - - return $VMSwitches.Name - } - } - write-sdnexpresslog "Will attach VM to virtual switch: $SwitchName" - - write-sdnexpresslog "Creating VM root directory and share on host." - - invoke-command -computername $computername { - param( - [String] $VMLocation, - [String] $UserName - ) - New-Item -ItemType Directory -Force -Path $VMLocation | out-null - if (!$VMLocation.startswith("\\")) { - get-SmbShare -Name VMShare -ErrorAction Ignore | remove-SMBShare -Force - New-SmbShare -Name VMShare -Path $VMLocation -FullAccess $UserName -Temporary | out-null - } - } -ArgumentList $VMLocation, ([System.Security.Principal.WindowsIdentity]::GetCurrent()).Name - - write-sdnexpresslog "Creating VM directory and copying VHD. This may take a few minutes." - - New-Item -ItemType Directory -Force -Path $VMPath | out-null - copy-item -Path $VHDFullPath -Destination $VMPath | out-null - - write-sdnexpresslog "Creating mount directory and mounting VHD." - - $TempFile = New-TemporaryFile - Remove-Item $TempFile.FullName -Force - $MountPath = $TempFile.FullName - - New-Item -ItemType Directory -Force -Path $MountPath | out-null - - Mount-WindowsImage -ImagePath $VHDVMPath -Index 1 -path $MountPath | out-null - - If ($InstallRasRoutingProtocols) { - write-sdnexpresslog "Installing RasRoutingProtocols Offline" - Enable-WindowsOptionalFeature -Path $MountPath -FeatureName RasRoutingProtocols -All -LimitAccess | Out-Null - } - - write-sdnexpresslog "Generating unattend.xml" - - $count = 1 - $TCPIPInterfaces = "" - $dnsinterfaces = "" - - foreach ($nic in $Nics) { - - $MacAddress = [regex]::matches($nic.MacAddress.ToUpper().Replace(":", "").Replace("-", ""), '..').groups.value -join "-" - - - if (![String]::IsNullOrEmpty($Nic.IPAddress)) { - $sp = $NIC.IPAddress.Split("/") - $IPAddress = $sp[0] - $SubnetMask = $sp[1] - - $Gateway = $Nic.Gateway - $gatewaysnippet = "" - - if (![String]::IsNullOrEmpty($gateway)) { - $gatewaysnippet = @" - <routes> - <Route wcm:action="add"> - <Identifier>0</Identifier> - <Prefix>0.0.0.0/0</Prefix> - <Metric>20</Metric> - <NextHopAddress>$Gateway</NextHopAddress> - </Route> - </routes> -"@ - } - - $TCPIPInterfaces += @" - <Interface wcm:action="add"> - <Ipv4Settings> - <DhcpEnabled>false</DhcpEnabled> - </Ipv4Settings> - <Identifier>$MacAddress</Identifier> - <UnicastIpAddresses> - <IpAddress wcm:action="add" wcm:keyValue="1">$IPAddress/$SubnetMask</IpAddress> - </UnicastIpAddresses> - $gatewaysnippet - </Interface> -"@ - } else { - $TCPIPInterfaces += @" - <Interface wcm:action="add"> - <Ipv4Settings> - <DhcpEnabled>true</DhcpEnabled> - </Ipv4Settings> - <Identifier>$MacAddress</Identifier> - </Interface> -"@ - - } - $alldns = "" - foreach ($dns in $Nic.DNS) { - $alldns += '<IpAddress wcm:action="add" wcm:keyValue="{1}">{0}</IpAddress>' -f $dns, $count++ - } - - if ($Nic.DNS -eq $null -or $Nic.DNS.count -eq 0) { - $dnsregistration = "false" - } else { - $dnsregistration = "true" - } - - $dnsinterfaces += @" - <Interface wcm:action="add"> - <DNSServerSearchOrder> - $alldns - </DNSServerSearchOrder> - <Identifier>$MacAddress</Identifier> - <EnableAdapterDomainNameRegistration>$DNSRegistration</EnableAdapterDomainNameRegistration> - </Interface> -"@ - } - - $ProductKeyField = "" - if (![String]::IsNullOrEmpty($ProductKey)) { - $ProductKeyField = "<ProductKey>$ProductKey</ProductKey>" - } - - $unattendfile = @" - <?xml version="1.0" encoding="utf-8"?> - <unattend xmlns="urn:schemas-microsoft-com:unattend"> - <settings pass="specialize"> - <component name="Microsoft-Windows-TCPIP" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - <Interfaces> - $TCPIPInterfaces - </Interfaces> - </component> - <component name="Microsoft-Windows-DNS-Client" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - <Interfaces> - $DNSInterfaces - </Interfaces> - </component> - <component name="Microsoft-Windows-UnattendedJoin" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - <Identification> - <Credentials> - <Domain>$CredentialDomain</Domain> - <Password>$CredentialPassword</Password> - <Username>$CredentialUsername</Username> - </Credentials> - <JoinDomain>$JoinDomain</JoinDomain> - </Identification> - </component> - <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - <ComputerName>$VMName</ComputerName> - $ProductKeyField - </component> - </settings> - <settings pass="oobeSystem"> - <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - <UserAccounts> - <AdministratorPassword> - <Value>$LocalAdminPassword</Value> - <PlainText>true</PlainText> - </AdministratorPassword> - <DomainAccounts> - <DomainAccountList wcm:action="add"> - <DomainAccount wcm:action="add"> - <Name>$DomainAdminUserName</Name> - <Group>Administrators</Group> - </DomainAccount> - <Domain>$DomainAdminDomain</Domain> - </DomainAccountList> - </DomainAccounts> - </UserAccounts> - <TimeZone>$TimeZone</TimeZone> - <OOBE> - <HideEULAPage>true</HideEULAPage> - <SkipUserOOBE>true</SkipUserOOBE> - <HideOEMRegistrationScreen>true</HideOEMRegistrationScreen> - <HideOnlineAccountScreens>true</HideOnlineAccountScreens> - <HideWirelessSetupInOOBE>true</HideWirelessSetupInOOBE> - <NetworkLocation>Work</NetworkLocation> - <ProtectYourPC>1</ProtectYourPC> - <HideLocalAccountScreen>true</HideLocalAccountScreen> - </OOBE> - </component> - <component name="Microsoft-Windows-International-Core" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - <UserLocale>$Locale</UserLocale> - <SystemLocale>$Locale</SystemLocale> - <InputLocale>$Locale</InputLocale> - <UILanguage>$Locale</UILanguage> - </component> - </settings> - <cpi:offlineImage cpi:source="" xmlns:cpi="urn:schemas-microsoft-com:cpi" /> - </unattend> -"@ - - write-sdnexpresslog "Writing unattend.xml to $MountPath\unattend.xml" - Set-Content -value $UnattendFile -path "$MountPath\unattend.xml" | out-null - - write-sdnexpresslog "Cleaning up" - - DisMount-WindowsImage -Save -path $MountPath | out-null - Remove-Item $MountPath -Force - Invoke-Command -computername $computername { - Get-SmbShare -Name VMShare -ErrorAction Ignore | remove-SMBShare -Force | out-null - } - - write-sdnexpresslog "Creating VM: $computername" - $NewVM = New-VM -ComputerName $computername -Generation 2 -Name $VMName -Path $LocalVMPath -MemoryStartupBytes $VMMemory -VHDPath $LocalVHDPath -SwitchName $SwitchName - $NewVM | Set-VM -processorcount $VMProcessorCount | out-null - - $first = $true - foreach ($nic in $Nics) { - write-sdnexpresslog "Configuring NIC" - $FormattedMac = [regex]::matches($nic.MacAddress.ToUpper().Replace(":", "").Replace("-", ""), '..').groups.value -join "-" - write-sdnexpresslog "Configuring NIC with MAC $FormattedMac" - if ($first) { - $vnic = $NewVM | get-vmnetworkadapter - $vnic | rename-vmnetworkadapter -newname $Nic.Name - $vnic | Set-vmnetworkadapter -StaticMacAddress $FormattedMac - $first = $false - } else { - #Note: add-vmnetworkadapter doesn't actually return the vnic object for some reason which is why this does a get immediately after. - $vnic = $NewVM | Add-VMNetworkAdapter -SwitchName $SwitchName -Name $Nic.Name -StaticMacAddress $FormattedMac - $vnic = $NewVM | get-vmnetworkadapter -Name $Nic.Name - } - - if ($nic.vlanid) { - write-sdnexpresslog "Setting VLANID to $($nic.vlanid)" - $vnic | Set-VMNetworkAdapterIsolation -AllowUntaggedTraffic $true -IsolationMode VLAN -defaultisolationid $nic.vlanid | out-null - } - - if ($nic.IsMuxPA) { - write-sdnexpresslog "This is a mux PA nic, so ProfileData set to 2." - $ProfileData = 2 - } else { - $ProfileData = 1 - } - - write-sdnexpresslog "Applying Null Guid to ensure initial ability to communicate with VFP enabled." - - invoke-command -ComputerName $ComputerName -ScriptBlock { - param( - [String] $VMName, - [String] $VMNetworkAdapterName, - [Int] $ProfileData - ) - $PortProfileFeatureId = "9940cd46-8b06-43bb-b9d5-93d50381fd56" - $NcVendorId = "{1FA41B39-B444-4E43-B35A-E1F7985FD548}" - - $vnic = Get-VMNetworkAdapter -VMName $VMName -Name $VMNetworkAdapterName - - $currentProfile = Get-VMSwitchExtensionPortFeature -FeatureId $PortProfileFeatureId -VMNetworkAdapter $vNic - - if ( $currentProfile -eq $null) - { - $portProfileDefaultSetting = Get-VMSystemSwitchExtensionPortFeature -FeatureId $PortProfileFeatureId - - $portProfileDefaultSetting.SettingData.ProfileId = "{$([Guid]::Empty)}" - $portProfileDefaultSetting.SettingData.NetCfgInstanceId = "{56785678-a0e5-4a26-bc9b-c0cba27311a3}" - $portProfileDefaultSetting.SettingData.CdnLabelString = "TestCdn" - $portProfileDefaultSetting.SettingData.CdnLabelId = 1111 - $portProfileDefaultSetting.SettingData.ProfileName = "Testprofile" - $portProfileDefaultSetting.SettingData.VendorId = $NcVendorId - $portProfileDefaultSetting.SettingData.VendorName = "NetworkController" - $portProfileDefaultSetting.SettingData.ProfileData = $ProfileData - - Add-VMSwitchExtensionPortFeature -VMSwitchExtensionFeature $portProfileDefaultSetting -VMNetworkAdapter $vNic | out-null - } - else - { - $currentProfile.SettingData.ProfileId = "{$([Guid]::Empty)}" - $currentProfile.SettingData.ProfileData = $ProfileData - Set-VMSwitchExtensionPortFeature -VMSwitchExtensionFeature $currentProfile -VMNetworkAdapter $vNic | out-null - } - } -ArgumentList $VMName, $nic.Name, $ProfileData - } - - write-sdnexpresslog "Starting VM." - - $NewVM | Start-VM | out-null - write-sdnexpresslog "New-SDNExpressVM is complete." -} diff --git a/azure_jumpstart_hcibox/artifacts/SDN/SDNExpressUI.psm1 b/azure_jumpstart_hcibox/artifacts/SDN/SDNExpressUI.psm1 deleted file mode 100644 index 849f094176..0000000000 --- a/azure_jumpstart_hcibox/artifacts/SDN/SDNExpressUI.psm1 +++ /dev/null @@ -1,1206 +0,0 @@ - -function SDNExpressUI { - - [void][System.Reflection.Assembly]::LoadWithPartialName('presentationframework') - [xml]$XAML = @' - <Window - xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" - xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" - Title="SDN Express" ResizeMode="NoResize" Height="600" Width="800" WindowStartupLocation="CenterScreen" > - <Window.Resources> - <ControlTemplate x:Key="ErrorTemplate" TargetType="{x:Type Control}"> - <DockPanel> - <TextBlock Foreground="Red" TextAlignment="Center" Width="16" FontSize="18" DockPanel.Dock="Right">!</TextBlock> - <Border BorderThickness="1" BorderBrush="Red"> - <ScrollViewer x:Name="PART_ContentHost"/> - </Border> - </DockPanel> - </ControlTemplate> - <ControlTemplate x:Key="NormalTemplate" TargetType="{x:Type Control}"> - <DockPanel> - <TextBlock Foreground="Red" TextAlignment="Center" Width="16" FontSize="18" DockPanel.Dock="Right"></TextBlock> - <Border BorderThickness="1" BorderBrush="{DynamicResource {x:Static SystemColors.ControlDarkBrushKey}}"> - <ScrollViewer x:Name="PART_ContentHost" /> - </Border> - </DockPanel> - </ControlTemplate> - <Style TargetType="{x:Type TextBox}"> - <Setter Property="OverridesDefaultStyle" Value="True" /> - <Setter Property="Template" Value="{DynamicResource ErrorTemplate}" /> - </Style> - <Style TargetType="{x:Type PasswordBox}"> - <Setter Property="OverridesDefaultStyle" Value="True" /> - <Setter Property="Template" Value="{DynamicResource ErrorTemplate}" /> - </Style> - </Window.Resources> - <Grid> - <StackPanel Name="panel0" HorizontalAlignment="Left" Width="169.149" Background="{DynamicResource {x:Static SystemColors.ControlLightBrushKey}}"> - <Rectangle Height="10" Margin="0,0,159,0" /> - <Grid> - <Rectangle Name="mark1" Fill="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" Height="27.976" Margin="0,0,159,0" /> - <Label Content="Introduction" Margin="10,0,0,0"/> - </Grid> - <Grid> - <Rectangle Name="mark2" Fill="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" Height="27.976" Margin="0,0,159,0" Visibility="Hidden"/> - <Label Content="VM Creation" Margin="10,0,0,0"/> - </Grid> - <Grid> - <Rectangle Name="mark3" Fill="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" Height="27.976" Margin="0,0,159,0" Visibility="Hidden"/> - <Label Content="Management Network" Margin="10,0,0,0"/> - </Grid> - <Grid> - <Rectangle Name="mark4" Fill="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" Height="27.976" Margin="0,0,159,0" Visibility="Hidden"/> - <Label Content="Provider Network" Margin="10,0,0,0"/> - </Grid> - <Grid> - <Rectangle Name="mark5" Fill="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" Height="27.976" Margin="0,0,159,0" Visibility="Hidden"/> - <Label Content="Network Controller" Margin="10,0,0,0"/> - </Grid> - <Grid> - <Rectangle Name="mark6" Fill="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" Height="27.976" Margin="0,0,159,0" Visibility="Hidden"/> - <Label Content="Software Load Balancer" Margin="10,0,0,0"/> - </Grid> - <Grid> - <Rectangle Name="mark7" Fill="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" Height="27.976" Margin="0,0,159,0" Visibility="Hidden"/> - <Label Content="Gateways" Margin="10,0,0,0"/> - </Grid> - <Grid> - <Rectangle Name="mark8" Fill="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" Height="27.976" Margin="0,0,159,0" Visibility="Hidden"/> - <Label Content="BGP" Margin="10,0,0,0"/> - </Grid> - <Grid> - <Rectangle Name="mark9" Fill="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" Height="27.976" Margin="0,0,159,0" Visibility="Hidden"/> - <Label Content="Review" Margin="10,0,0,0"/> - </Grid> - </StackPanel> - <StackPanel Name="panel1" HorizontalAlignment="Left" Height="522.101" VerticalAlignment="Top" Margin="169.149,0,0,0" Width="615.137"> - <TextBlock FontSize="20" Margin="10,0,0,0"><Run Text="Welcome to the SDN Express deployment wizard"/></TextBlock> - <TextBlock Margin="10,0,10,0" TextWrapping="WrapWithOverflow"> - <LineBreak/> - <Run Text="For additional information on any of these steps, click on the Docs link below. Before you can complete this wizard you must perform some prerequisite configuration steps in your network:"/><LineBreak/> - </TextBlock> - <BulletDecorator Margin="10,0,0,0"> - <BulletDecorator.Bullet><Ellipse Height="5" Width="5" Fill="Black"/></BulletDecorator.Bullet> - <TextBlock TextWrapping="Wrap" HorizontalAlignment="Left" Margin="19,0,0,0"> - Allocate a block of static IP addresses from your management subnet for each Network Controller, Mux and Gateway VM to be created. - </TextBlock> - </BulletDecorator> - <BulletDecorator Margin="10,0,0,0"> - <BulletDecorator.Bullet><Ellipse Height="5" Width="5" Fill="Black"/></BulletDecorator.Bullet> - <TextBlock TextWrapping="Wrap" HorizontalAlignment="Left" Margin="19,0,0,0"> - Allocate a subnet and vlan for Hyper-V Network Virtualization Provider Addresses (HNV PA). - </TextBlock> - </BulletDecorator> - <BulletDecorator Margin="10,0,0,0"> - <BulletDecorator.Bullet><Ellipse Height="5" Width="5" Fill="Black"/></BulletDecorator.Bullet> - <TextBlock TextWrapping="Wrap" HorizontalAlignment="Left" Margin="19,0,0,0"> - Allocate a set of subnets for Private VIPs, Public VIPs and GRE VIPs. Do not configure these on a VLAN, instead enable them to be advertized by SDN through BGP. - </TextBlock> - </BulletDecorator> - <BulletDecorator Margin="10,0,0,0"> - <BulletDecorator.Bullet><Ellipse Height="5" Width="5" Fill="Black"/></BulletDecorator.Bullet> - <TextBlock TextWrapping="Wrap" HorizontalAlignment="Left" Margin="19,0,0,0"> - Configure HNV PA network's routers for BGP, with a 16-bit ASN for the router and one for SDN. SDN should peer with the loopback address of each router. - </TextBlock> - </BulletDecorator> - <TextBlock Margin="10,0,0,0" TextWrapping="WrapWithOverflow"> - <LineBreak/> - <Run Text="Physical switch configuration examples are "/> - <Hyperlink Name="uri4" NavigateUri="https://github.com/Microsoft/SDN/tree/master/SwitchConfigExamples">available on Github.</Hyperlink><LineBreak/> - <LineBreak/> - <Run Text="In addition you will need to have the following ready:"/><LineBreak/> - </TextBlock> - <BulletDecorator Margin="10,0,0,0"> - <BulletDecorator.Bullet><Ellipse Height="5" Width="5" Fill="Black"/></BulletDecorator.Bullet> - <TextBlock TextWrapping="Wrap" HorizontalAlignment="Left" Margin="19,0,0,0"> - A set of Hyper-V hosts configured with a virtual switch. - </TextBlock> - </BulletDecorator> - <BulletDecorator Margin="10,0,0,0"> - <BulletDecorator.Bullet><Ellipse Height="5" Width="5" Fill="Black"/></BulletDecorator.Bullet> - <TextBlock TextWrapping="Wrap" HorizontalAlignment="Left" Margin="19,0,0,0"> - A virtual hard disk containing Windows Server 2016 or 2019, Datacenter Edition. - </TextBlock> - </BulletDecorator> - <BulletDecorator Margin="10,0,0,0"> - <BulletDecorator.Bullet><Ellipse Height="5" Width="5" Fill="Black"/></BulletDecorator.Bullet> - <TextBlock TextWrapping="Wrap" HorizontalAlignment="Left" Margin="19,0,0,0"> - An Active Directory domain to join and credentials with Domain Join permission. - </TextBlock> - </BulletDecorator> - <BulletDecorator Margin="10,0,0,0"> - <BulletDecorator.Bullet><Ellipse Height="5" Width="5" Fill="Black"/></BulletDecorator.Bullet> - <TextBlock TextWrapping="Wrap" HorizontalAlignment="Left" Margin="19,0,0,0"> - Domain credentials with DNS update and host administrator priviliges. - </TextBlock> - </BulletDecorator> - <TextBlock Margin="10,0,0,0" TextWrapping="WrapWithOverflow"> - <LineBreak/> - <Run Text="When you have completed the above you can proceed by clicking Next."/> - <LineBreak/> - <LineBreak/> - <Run Text="Help make SDN Express better by "/> - <Hyperlink Name="uri2" NavigateUri="mail:sdnfeedback@microsoft.com">providing feedback.</Hyperlink><LineBreak/> - </TextBlock> - </StackPanel> - <StackPanel Name="panel2" HorizontalAlignment="Left" Height="522.101" VerticalAlignment="Top" Margin="169.149,0,0,0" Width="615.137"> - <Label Content="VM Creation" FontSize="18" Margin="10,0"/> - <Label Content="SDN Express is going to create a number of VMs. This information is used for customizing those VMs." Margin="10,0"/> - <Grid Margin="0,10"/> - <Grid Margin="0,2"> - <Label Content="VHD Location" Margin="10,0,0,0" HorizontalAlignment="Left" Width="122.089"/> - <TextBox Name="txtVHDLocation" Text="" Margin="192.739,0,119.71,0" > - - </TextBox> - <Button Name="btnBrowse" Content="Browse..." Margin="0,0,10,0" HorizontalAlignment="Right" Width="104.71" Height="25.426" VerticalAlignment="Bottom"/> - </Grid> - <Grid Margin="0,2"> - <Label Content="VM Path (on host)" Margin="10,0,0,0" HorizontalAlignment="Left" Width="122.089"/> - <TextBox Name="txtVMPath" Text="" Margin="192.739,0,119.71,0"/> - </Grid> - <Grid Margin="0,2"> - <Label Content="VM Name Prefix" Margin="10,0,0,0" HorizontalAlignment="Left" Width="122.089"/> - <TextBox Name="txtVMNamePrefix" Text="" Margin="192.739,0,281.032,0"/> - </Grid> - <Grid Margin="0,10"/> - <Grid Margin="0,2"> - <Label Content="VM Domain" Margin="10,0,0,0" HorizontalAlignment="Left" Width="178.852"/> - <TextBox Name="txtVMDomain" Text="" Margin="192.739,0,119.71,0"/> - </Grid> - <Grid Margin="0,2"> - <Label Content="Domain Join Username" Margin="10,0,0,0" HorizontalAlignment="Left" Width="178.852"/> - <TextBox Name="txtDomainJoinUsername" Text="" Margin="192.739,0,281.032,0"/> - </Grid> - <Grid Margin="0,2"> - <Label Content="Domain Join Password" Margin="10,0,0,0" HorizontalAlignment="Left" Width="178.852"/> - <PasswordBox Name="txtDomainJoinPassword" Margin="192.739,0,281.032,0"/> - </Grid> - <Grid Margin="0,10"/> - <Grid Margin="0,2"> - <Label Content="Local Admin Password" Margin="10,0,0,0" HorizontalAlignment="Left" Width="177.739"/> - <PasswordBox Name="txtLocalAdminPassword" Margin="192.739,0,282.145,0"/> - </Grid> - </StackPanel> - <StackPanel Name="panel3" HorizontalAlignment="Left" Height="522.101" VerticalAlignment="Top" Margin="169.149,0,0,0" Width="615.137"> - <Label Content="Management Network" FontSize="18" Margin="10,0"/> - <TextBlock Margin="14,0" TextWrapping="WrapWithOverflow"> - <Run Text="Provide information about the management network the SDN infrastructure will use to communicate. This information is used to provide each VM with a network adapter configured for this network."/> - </TextBlock> - <StackPanel Margin="0,10"/> - <Label Content="Subnet Information" Margin="10,0"/> - <StackPanel Orientation="Horizontal" Margin="0,2"> - <Label Content="VLAN ID" Margin="10,0,0,0" HorizontalAlignment="Left" Width="130"/> - <TextBox Name="txtManagementVLANID" Text="" Width="75"/> - </StackPanel> - <StackPanel Orientation="Horizontal" Margin="0,2" > - <Label Content="Subnet Prefix" Margin="10,0,0,0" HorizontalAlignment="Left" Width="130"/> - <TextBox Name="txtManagementSubnetPrefix" Text="" Width="150"/> - </StackPanel> - <StackPanel Orientation="Horizontal" Margin="0,2" > - <Label Content="Gateway" Margin="10,0,0,0" HorizontalAlignment="Left" Width="130"/> - <TextBox Name="txtManagementGateway" Text="" Width="150"/> - </StackPanel> - <StackPanel Margin="0,10"/> - <StackPanel Orientation="Horizontal" Margin="0,2"> - <Label Content="IP Address Pool" Margin="10,0"/> - </StackPanel> - <StackPanel Orientation="Horizontal" Margin="0,2"> - <Label Content="First Address" Margin="10,0,0,0" HorizontalAlignment="Left" Width="130"/> - <TextBox Name="txtManagementIPPoolStart" Text="" Width="150"/> - </StackPanel> - <StackPanel Orientation="Horizontal" Margin="0,2"> - <Label Content="Last Address" Margin="10,0,0,0" HorizontalAlignment="Left" Width="130"/> - <TextBox Name="txtManagementIPPoolEnd" Text="" Width="150"/> - </StackPanel> - <StackPanel Margin="0,10"/> - <StackPanel Orientation="Horizontal" Margin="0,2"> - <Label Content="DNS Servers" Margin="10,0"/> - </StackPanel> - <StackPanel Orientation="Horizontal" Margin="0,2" > - <Label Content="DNS Server 1" Margin="10,0,0,0" HorizontalAlignment="Left" Width="130"/> - <TextBox Name="txtManagementDNS1" Width="150"/> - </StackPanel> - <StackPanel Orientation="Horizontal" Margin="0,2" > - <Label Content="DNS Server 2" Margin="10,0,0,0" HorizontalAlignment="Left" Width="130"/> - <TextBox Name="txtManagementDNS2" Width="150" Template="{DynamicResource NormalTemplate}"/> - <Label Content="Optional" Margin="10,0,0,0" HorizontalAlignment="Left" Width="130" FontStyle="Italic"/> - </StackPanel> - <StackPanel Orientation="Horizontal" Margin="0,2" > - <Label Content="DNS Server 3" Margin="10,0,0,0" HorizontalAlignment="Left" Width="130"/> - <TextBox Name="txtManagementDNS3" Width="150" Template="{DynamicResource NormalTemplate}"/> - <Label Content="Optional" Margin="10,0,0,0" HorizontalAlignment="Left" Width="130" FontStyle="Italic"/> - </StackPanel> - </StackPanel> - <StackPanel Name="panel4" HorizontalAlignment="Left" Height="522.101" VerticalAlignment="Top" Margin="169.149,0,0,0" Width="615.137"> - <Label Content="Provider Network" FontSize="18" Margin="10,0"/> - <TextBlock Margin="14,0" TextWrapping="WrapWithOverflow"><Run Text="Provide information about the provider network which is used for all workload VM communication."/></TextBlock> - <StackPanel Margin="0,10"/> - <StackPanel Orientation="Horizontal" Margin="0,2"> - <Label Content="Subnet Information" Margin="10,0"/> - </StackPanel> - <StackPanel Orientation="Horizontal" Margin="0,2"> - <Label Content="VLAN ID" Margin="10,0,0,0" HorizontalAlignment="Left" Width="130"/> - <TextBox Name="txtPAVLANID" Text="" Width="75"/> - </StackPanel> - <StackPanel Orientation="Horizontal" Margin="0,2"> - <Label Content="Subnet Prefix" Margin="10,0,0,0" HorizontalAlignment="Left" Width="130"/> - <TextBox Name="txtPASubnetPrefix" Text="" Width="150"/> - </StackPanel> - <StackPanel Orientation="Horizontal" Margin="0,2"> - <Label Content="Default Gateway" Margin="10,0,0,0" HorizontalAlignment="Left" Width="130"/> - <TextBox Name="txtPAGateway" Text="" Width="150"/> - </StackPanel> - <StackPanel Margin="0,10"/> - <StackPanel Orientation="Horizontal" Margin="0,2"> - <Label Content="IP Address Pool" Margin="10,0"/> - </StackPanel> - <StackPanel Orientation="Horizontal" Margin="0,2"> - <Label Content="First IP Address" Margin="10,0,0,0" HorizontalAlignment="Left" Width="130"/> - <TextBox Name="txtPAIPPoolStart" Text="" Width="150"/> - </StackPanel> - <StackPanel Orientation="Horizontal" Margin="0,2"> - <Label Content="Last IP Address" Margin="10,0,0,0" HorizontalAlignment="Left" Width="130"/> - <TextBox Name="txtPAIPPoolEnd" Text="" Width="150"/> - </StackPanel> - <StackPanel Margin="0,10"/> - <StackPanel Orientation="Horizontal" Margin="0,2"> - <Label Content="MAC Address Pool" Margin="10,0"/> - </StackPanel> - <StackPanel Orientation="Horizontal" Margin="0,2"> - <Label Content="First MAC Address" Margin="10,0,0,0" HorizontalAlignment="Left" Width="130"/> - <TextBox Name="txtMACPoolStart" Text="" Width="150"/> - </StackPanel> - <StackPanel Orientation="Horizontal" Margin="0,2"> - <Label Content="Last MAC Address" Margin="10,0,0,0" HorizontalAlignment="Left" Width="130"/> - <TextBox Name="txtMACPoolEnd" Text="" Width="150"/> - </StackPanel> - </StackPanel> - <StackPanel Name="panel5" HorizontalAlignment="Left" Height="522.101" VerticalAlignment="Top" Margin="169.149,0,0,0" Width="615.137"> - <Label Content="Network Controller" FontSize="18" Margin="10,0"/> - <TextBlock Margin="14,0" TextWrapping="WrapWithOverflow"> - <Run Text="Provide information to be used for the creation of the Network Controller and the Hyper-V hosts to be added to the controller."/> - </TextBlock> - <Grid Margin="0,10"/> - <StackPanel Orientation="Horizontal" Margin="0,2"> - <Label Content="Network Controller" Margin="10,0,0,0" HorizontalAlignment="Left" Width="150"/> - <RadioButton Name="rdoMultiNode" Content="Multi-node" HorizontalAlignment="Left" VerticalAlignment="Center" Width="91.96" IsChecked="True"/> - <RadioButton Name="rdoSingleode" Content="Single-node" HorizontalAlignment="Left" VerticalAlignment="Center" Width="91.96"/> - </StackPanel> - <StackPanel Orientation="Horizontal" Margin="0,2"> - <Label Content="REST Name (FQDN)" Margin="10,0,0,0" HorizontalAlignment="Left" Width="150"/> - <TextBox Name="txtRESTName" Text="" Width="240"/> - </StackPanel> - <StackPanel Margin="0,10"/> - <StackPanel Orientation="Horizontal" Margin="0,2"> - <Label Content="Hyper-V Hosts" Margin="10,0,0,0" HorizontalAlignment="Left" Width="150"/> - <TextBox Name="txtHyperVHosts" Width="300" Height="160" TextWrapping="Wrap" AcceptsReturn="True" VerticalScrollBarVisibility="Visible" VerticalContentAlignment="Top"/> - </StackPanel> - <StackPanel Margin="0,10"/> - <StackPanel Orientation="Horizontal" Margin="0,2"> - <Label Content="Host Credentials" Margin="10,0"/> - </StackPanel> - <StackPanel Orientation="Horizontal" Margin="0,2"> - <Label Content="Username" Margin="10,0,0,0" HorizontalAlignment="Left" Width="150"/> - <TextBox Name="txtHostUsername" Text="" Width="150"/> - </StackPanel> - <StackPanel Orientation="Horizontal" Margin="0,2"> - <Label Content="Password" Margin="10,0,0,0" HorizontalAlignment="Left" Width="150"/> - <PasswordBox Name="txtHostPassword" Width="150"/> - </StackPanel> - </StackPanel> - <StackPanel Name="panel6" HorizontalAlignment="Left" Height="522.101" VerticalAlignment="Top" Margin="169.149,0,0,0" Width="615.137"> - <Label Content="Software Load Balancer" FontSize="18" Margin="10,0"/> - <TextBlock Margin="14,0" TextWrapping="WrapWithOverflow"> - <Run Text="The Software Load Balancer is an SDN integrated L3 and L4 load balancer that is also used for network address translation (NAT). Muxes are the routers for the virtual IP (VIP) endpoints. Use this panel to define how many muxes you want to deploy. All Muxes are active and traffic is spread across them automatically."/> - </TextBlock> - <Grid Margin="0,10"/> - <StackPanel Orientation="Horizontal" Margin="0,2"> - <Label Content="Load Balancer Muxes" Margin="10,0,0,0" HorizontalAlignment="Left" Width="150"/> - <TextBlock Name="txtMuxCount" VerticalAlignment="Center" Margin="10,0" Text="{Binding ElementName=sliMuxCount, Path=Value, UpdateSourceTrigger=PropertyChanged}" /> - <Slider Name="sliMuxCount" Width="280" Minimum="1" Maximum="8" Value="2" TickFrequency="1" VerticalAlignment="Center" TickPlacement="BottomRight" SmallChange="1" IsSnapToTickEnabled="True"/> - </StackPanel> - <StackPanel Margin="0,10"/> - <StackPanel Orientation="Horizontal" Margin="0,2"> - <Label Content="Private VIP Subnet" FontSize="14" Margin="10,0"/> - </StackPanel> - <TextBlock Margin="14,0" TextWrapping="WrapWithOverflow"> - <Run Text="Private VIPs are used internally by the SDN infrastructure. This subnet must not be configured on a VLAN in the physical switch as it will be advertized by the Muxes through BGP."/> - </TextBlock> - <StackPanel Margin="0,10"/> - <StackPanel Orientation="Horizontal" Margin="0,2"> - <Label Content="Subnet Prefix" Margin="10,0,0,0" HorizontalAlignment="Left" Width="150"/> - <TextBox Name="txtPrivateVIPs" Text="" Width="150"/> - </StackPanel> - <StackPanel Margin="0,10"/> - <StackPanel Orientation="Horizontal" Margin="0,2"> - <Label Content="Public VIP Subnet" Margin="10,0" FontSize="14" /> - </StackPanel> - <TextBlock Margin="14,0" TextWrapping="WrapWithOverflow"> - <Run Text="Public VIPs are used to directly access workloads as load balanced VIPs or for NAT. If these need to be reached directly from the internet, then you must obtain an internet routable subnet from your Internet Service Provider (ISP). This subnet must not be configured on a VLAN in the physical switch as it will be advertized by the Muxes through BGP."/> - </TextBlock> - <StackPanel Margin="0,10"/> - <StackPanel Orientation="Horizontal" Margin="0,2"> - <Label Content="Subnet Prefix" Margin="10,0,0,0" HorizontalAlignment="Left" Width="150"/> - <TextBox Name="txtPublicVIPs" Text="" Width="150"/> - </StackPanel> - </StackPanel> - <StackPanel Name="panel7" HorizontalAlignment="Left" Height="522.101" VerticalAlignment="Top" Margin="169.149,0,0,0" Width="615.137"> - <Label Content="Gateways" FontSize="18" Margin="10,0"/> - <TextBlock Margin="14,0" TextWrapping="WrapWithOverflow"><Run Text="Gateways are used for routing between a virtual network and another network (local or remote). SDN Express creates a default gateway pool that supports all connection types. Within this pool you can select how many gateways are reserved on standby in case an active gateway fails."/></TextBlock> - <Grid Margin="0,10"/> - <StackPanel Orientation="Horizontal" Margin="0,2"> - <Label Content="Gateways" Margin="10,0,0,0" HorizontalAlignment="Left" Width="150"/> - <TextBlock Name="txtGatewayCount" VerticalAlignment="Center" Margin="10,0" Text="{Binding ElementName=sliGatewayCount, Path=Value, UpdateSourceTrigger=PropertyChanged}" /> - <Slider Name="sliGatewayCount" Margin="35,0" Width="240" Minimum="2" Maximum="8" Value="2" TickFrequency="1" VerticalAlignment="Center" TickPlacement="BottomRight" SmallChange="1" IsSnapToTickEnabled="True"/> - </StackPanel> - <StackPanel Margin="0,10"/> - <StackPanel Orientation="Horizontal" Margin="0,2"> - <Label Content="Gateways on standby" Margin="10,0,0,0" HorizontalAlignment="Left" Width="150"/> - <TextBlock Name="txtRedundantCount" VerticalAlignment="Center" Margin="10,0" Text="{Binding ElementName=sliRedundantCount, Path=Value, UpdateSourceTrigger=PropertyChanged}" /> - <Slider Name="sliRedundantCount" Width="0" Minimum="1" Maximum="7" Value="1" VerticalAlignment="Center" TickPlacement="BottomRight" SmallChange="1" IsSnapToTickEnabled="True" /> - </StackPanel> - <StackPanel Margin="0,10"/> - <StackPanel Orientation="Horizontal" Margin="0,2"> - <Label Content="GRE Endpoints" Margin="10,0,0,0" HorizontalAlignment="Left" Width="150"/> - </StackPanel> - <TextBlock Margin="14,0" TextWrapping="WrapWithOverflow"><Run Text="GRE connections require an endpoint IP address that will be allocated from subnet specified below. This subnet must not be configured on a VLAN in the physical switch as the endpoints will be advertised to the physical network through BGP."/></TextBlock> - <StackPanel Margin="0,10"/> - <StackPanel Orientation="Horizontal" Margin="0,2"> - <Label Content="Subnet Prefix" Margin="10,0,0,0" HorizontalAlignment="Left" Width="150"/> - <TextBox Name="txtGREVIPs" Text="" Width="150"/> - </StackPanel> - </StackPanel> - <StackPanel Name="panel8" HorizontalAlignment="Left" Height="522.101" VerticalAlignment="Top" Margin="169.149,0,0,0" Width="615.137"> - <Label Content="Border Gateway Protocol (BGP)" FontSize="18" Margin="10,0"/> - <TextBlock Margin="14,0" TextWrapping="WrapWithOverflow"><Run Text="BGP is used by the Software Load Balancer to advertise VIPs to the physical network. It is also used by the gateways for advertising GRE endpoints."/></TextBlock> - <StackPanel Margin="0,10"/> - <StackPanel Orientation="Horizontal" Margin="0,2"> - <Label Content="SDN ASN" Margin="10,0,0,0" HorizontalAlignment="Left" Width="150"/> - <TextBox Name="txtSDNASN" Text="" Width="150"/> - </StackPanel> - <StackPanel Margin="0,10"/> - <StackPanel Orientation="Horizontal" Margin="0,2"> - <Label Content="Router 1" Margin="10,0,0,0" HorizontalAlignment="Left" Width="150"/> - </StackPanel> - <StackPanel Orientation="Horizontal" Margin="0,2"> - <Label Content="Router IP Address" Margin="10,0,0,0" HorizontalAlignment="Left" Width="150"/> - <TextBox Name="txtRouterIP1" Text="" Width="150"/> - </StackPanel> - <StackPanel Orientation="Horizontal" Margin="0,2"> - <Label Content="Router ASN" Margin="10,0,0,0" HorizontalAlignment="Left" Width="150"/> - <TextBox Name="txtRouterASN1" Text="" Width="150"/> - </StackPanel> - <StackPanel Margin="0,10"/> - <StackPanel Orientation="Horizontal" Margin="0,2"> - <Label Content="Router 2" Margin="10,0,0,0" HorizontalAlignment="Left" Width="150"/> - </StackPanel> - <StackPanel Orientation="Horizontal" Margin="0,2"> - <Label Content="Router IP Address" Margin="10,0,0,0" HorizontalAlignment="Left" Width="150"/> - <TextBox Name="txtRouterIP2" Text="" Width="150" Template="{DynamicResource NormalTemplate}"/> - <Label Content="Optional" Margin="10,0,0,0" HorizontalAlignment="Left" Width="150" FontStyle="Italic"/> - </StackPanel> - <StackPanel Orientation="Horizontal" Margin="0,2"> - <Label Content="Router ASN" Margin="10,0,0,0" HorizontalAlignment="Left" Width="150"/> - <TextBox Name="txtRouterASN2" Text="" Width="150" Template="{DynamicResource NormalTemplate}"/> - <Label Content="Optional" Margin="10,0,0,0" HorizontalAlignment="Left" Width="150" FontStyle="Italic"/> - </StackPanel> - </StackPanel> - <StackPanel Name="panel9" HorizontalAlignment="Left" Height="522.101" VerticalAlignment="Top" Margin="169.149,0,0,0" Width="615.137"> - <Label Content="Review" FontSize="18" Margin="10,0"/> - <TextBlock Margin="14,0" TextWrapping="WrapWithOverflow"><Run Text="You have entered everything required for SDN Express to configure SDN on this system. If you would like to save this configuration, select Export. You can re-run SDN Express later with this file using the ConfigurationDataFile parameter."/></TextBlock> - <Grid Margin="0,10"/> - <TextBox Name="txtReview" Text="" Margin="14,0,0,0" Height="300" Template="{DynamicResource NormalTemplate}"/> - <Grid Margin="0,5"/> - <Button Name="btnExport" Content="Export..." Margin="0,0,14,0" HorizontalAlignment="Right" Width="153.868" Height="34.328" /> - <TextBlock Margin="10,0,0,0" TextWrapping="WrapWithOverflow"> - <Run Text="Help make SDN Express better by "/> - <Hyperlink Name="uri3" NavigateUri="mail:sdnfeedback@microsoft.com">providing feedback.</Hyperlink><LineBreak/> - </TextBlock> - - </StackPanel> - <TextBlock Margin="179.149,0,0,74.328" HorizontalAlignment="Left" VerticalAlignment="Bottom"> - <Run Text="For additional help and guidance, refer to the "/> - <Hyperlink Name="uri1" NavigateUri="https://learn.microsoft.com/windows-server/networking/sdn/plan/plan-software-defined-networking">Plan SDN topic on docs.microsoft.com.</Hyperlink> - </TextBlock> - <Button Name="btnBack1" Content="Back" Margin="0,0,168.868,10" HorizontalAlignment="Right" Width="153.868" Height="34.328" VerticalAlignment="Bottom"/> - <Button Name="btnNext1" Content="Next" Margin="0,0,10,10" HorizontalAlignment="Right" Width="153.868" Height="34.328" VerticalAlignment="Bottom"/> - </Grid> - </Window> -'@ - - -function ConfigDataToString { - param ( - [object] $InputData, - [string] $indent = "" - ) - if ($InputData.GetType().Name.EndsWith("String")) { - return "$indent $InputData" - } - - foreach ($i in $InputData.GetEnumerator()) { - if ($i.Value.GetType().Name.EndsWith("[]")) { - $result += ("`r`n$indent {0}:`r`n" -f $i.key) - foreach ($v in ($i.value)) { - $result += "$(ConfigDataToString $v "$indent ")`r`n" - } - $result += "`r`n" - } else { - if ($i.Value.GetType().Name.EndsWith("Object")) { - $result += ("$indent {0,-20}: {1}`r`n" -f $i.key, (convertto-psd1 $i.Value "$indent ")) - } - else { - if (!$i.key.Contains("Password")) { - $result += ("$indent {0,-20}: {1}`r`n" -f $i.key, $i.Value) - } - } - } - } - return $result -} - -function convertto-psd1 { -param( - [object] $InputData, - [string] $Indent = "" -) - if ($InputData.GetType().Name.EndsWith("String")) { - return "'$InputData'" - } - - $result = "$indent@{`r`n" - - foreach ($i in $InputData.GetEnumerator()) { - if ($i.Value.GetType().Name.EndsWith("Object[]")) { - $result += "$indent $($i.key) = @(" - $first = $true - foreach ($v in ($i.value)) { - if (!$first) { $result += ","} - $result += "`r`n" - $result += convertto-psd1 $v "$indent " - $first = $false - } - $result += "`r`n$indent )`r`n" - } elseif ($i.Value.GetType().Name.EndsWith("String[]")) { - $result += "$indent $($i.key) = @(" - $first = $true - foreach ($v in ($i.value)) { - if (!$first) { $result += ", "} - $result += "'$v'" - $first = $false - } - $result += " )`r`n" - } else { - if ($i.Value.GetType().Name.EndsWith("Object")) { - $result += "$indent $($i.key) = $(convertto-psd1 $i.Value "$indent ")`r`n" - } - else { - $result += "$indent $($i.key) = '$($i.Value)'`r`n" - } - } - } - $result += "$indent}" - return $result -} - - -#WARNING: this may be too slow -$ValidateFileExistsBlock = { - if(Test-path $this.Text) { - $this.Template=$global:defaulttxttemplate - } else { - $this.Template=$form.FindResource("ErrorTemplate") - } -} - - -function ValidateNotBlank { -param( - [Object] $ctl, - [String] $message = "This field is required." -) - if([String]::IsNullOrEmpty($ctl.text)) { - $ctl.Template = $form.FindResource("ErrorTemplate") - if ([String]::IsNullOrEmpty($ctl.Tooltip)) { - $ctl.tooltip = "Invalid value: this field is required.`r`nDetail: $message" - } - return $true - } else { - $ctl.tooltip = $message - $ctl.Template = $global:defaulttxttemplate - return $false - } -} - -function ValidatePassword { -param( - [Object] $ctl -) - if([String]::IsNullOrEmpty($ctl.password)) { - $ctl.Template=$form.FindResource("ErrorTemplate") - $ctl.tooltip = "Invalid value: This field is required." - return $true - } else { - $ctl.tooltip = "" - $ctl.Template=$global:defaulttxttemplate - return $false - } -} - - -function ValidateVLAN { -param( - [Object] $ctl -) - if ([Regex]::Match($ctl.text, "^\d{1,4}$").Success) { - $value = [Int32]::Parse($ctl.text) - if ($value -le 4096) { - $ctl.Template=$global:defaulttxttemplate - $ctl.tooltip = "" - return $false - } - $ctl.tooltip = "Invalid value: VLAN ID must be a value between 0 and 4096." - } else { - $ctl.tooltip = "Invalid value: VLAN ID can't contain non-numeric characters." - } - $ctl.Template=$form.FindResource("ErrorTemplate") - return $true -} - -function ValidateRegex { - param( - [Object] $ctl, - [string] $Regex, - [bool] $IsOptional = $false, - [string] $errormessage = "Field syntax is incorrect.", - [string] $message = "" - ) - if ($IsOptional -and [string]::IsNullOrEmpty($ctl.text)) { - $ctl.ToolTip = "Invalid value: $errormessage`r`nDetail: $message" - $ctl.Template=$global:defaulttxttemplate - return $FALSE - } - - if([Regex]::Match($ctl.text, $regex).Success) { - $ctl.Template=$global:defaulttxttemplate - $ctl.tooltip = $message - return $FALSE - } else { - $ctl.ToolTip = "Invalid value: $errormessage`r`nDetail: $message" - $ctl.Template=$form.FindResource("ErrorTemplate") - return $TRUE - } -} - -function ValidateIPAddress { - param( - [Object] $ctl, - [bool] $IsOptional = $false, - [string] $message = "" - ) - return ValidateRegex $ctl "^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$" $IsOptional "IP address syntax is not correct." $message -} - -function ValidateSubnetPrefix { - param( - [Object] $ctl, - [bool] $IsOptional = $false, - [string] $message = "" - ) - return ValidateRegex $ctl "^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1-2][0-9]|3[0-2]))$" $IsOptional "Subnet prefix does not match required format of <subnet>/<bits>." $message -} - -function ValidateASN { - param( - [Object] $ctl, - [bool] $IsOptional = $false - ) - if ($IsOptional -and [string]::IsNullOrEmpty($ctl.text)) { - $ctl.Template=$global:defaulttxttemplate - $ctl.ToolTip = "" - return $FALSE - } - - if ([Regex]::Match($ctl.text, "^\d{1,5}$").Success) { - $value = [Int32]::Parse($ctl.text) - if (($value -lt 65535) -and ($value -gt 0)) { - $ctl.ToolTip = "" - $ctl.Template=$global:defaulttxttemplate - return $false - } - $ctl.ToolTip = "ASN is outside the valid range of values. It must be an integer number between 1 and 65534." - } else { - $ctl.ToolTip = "ASN contains non-numeric characters. It must be an integer number between 1 and 65534." - } - $ctl.Template=$form.FindResource("ErrorTemplate") - return $true -} - -function ValidateMACAddress { - param( - [Object] $ctl, - [bool] $IsOptional = $false - ) - if ($IsOptional -and [string]::IsNullOrEmpty($ctl.text)) { - $ctl.Template=$global:defaulttxttemplate - return $false - } - - $phys = [regex]::matches($ctl.text.ToUpper().Replace(":", "").Replace("-", ""), '.{1,2}').groups.value -join "-" - - if((![bool]($phys -as [physicaladdress])) -or ($phys.length -gt 17)) { - $ctl.tooltip = "Invalid mac address. Must contain 12 hexadecimal digits, can be optionally separated by : or - every two digits. Example: 00:11:22:33:44:55" - $ctl.Template=$form.FindResource("ErrorTemplate") - return $true - } else { - $ctl.tooltip = "" - $ctl.Template=$global:defaulttxttemplate - return $false - } -} - -function IsIPAddressInSubnet { - param( - [String] $IP, - [String] $subnet - ) - - $parts = $subnet.split("/") - if ($parts.count -ne 2) { - return $false - } - - $prefix = $parts[0] - - if (!($ip -as [IPAddress]) -or !($prefix -as [IPAddress])) { - return $false - } - - $bits = [int] $parts[1] - - $ipbytes = ($IP -as [IPaddress]).getaddressbytes() - $prebytes = ($prefix -as [IPaddress]).getaddressbytes() - - $fullbytes = [int] ((32-$bits) / 8) - $partbits = [int] ((32-$bits) % 8) - - for ($i=3; $i -ge (4-$fullbytes); $i--) { - $ipbytes[$i] = 0 - $prebytes[$i] = 0 - } - - $bitmask = [byte] 0xff -shl $partbits - $ipbytes[$i] = $ipbytes[$i] -band $bitmask - $prebytes[$i] = $prebytes[$i] -band $bitmask - - for ($i = 0; $i -lt $ipbytes.count ; $i++) { - if ($ipbytes[$i] -ne $prebytes[$i]) { - return $false - } - } - return $true -} - -function ValidateIPAddressInSubnet { - param( - [Object] $ctl, - [string] $subnet - ) - - if(!(IsIPAddressInSubnet $ctl.text $subnet)) { - $ctl.tooltip = "IP Address must fall within the specified subnet prefix of $subnet." - $ctl.Template=$form.FindResource("ErrorTemplate") - return $true - } else { - $ctl.tooltip = "" - $ctl.Template=$global:defaulttxttemplate - return $false - } -} - -function ValidateIPAddressIsGreater { - param( - [Object] $ctl, - [string] $lower - ) - - $greater = $ctl.text - - if (!($lower -as [IPAddress]) -or !($greater -as [IPAddress])) { - $ctl.Template=$form.FindResource("ErrorTemplate") - return $true - } - - $lbytes = ($lower -as [IPaddress]).getaddressbytes() - $gbytes = ($greater -as [IPaddress]).getaddressbytes() - - for ($i = 0; $i -lt $lbytes.count ; $i++) { - if ($gbytes[$i] -lt $lbytes[$i]) { - $ctl.Template=$form.FindResource("ErrorTemplate") - $ctl.tooltip = "This IP address must be squentially higher than $lower." - return $true - } - if ($gbytes[$i] -gt $lbytes[$i]) { - $ctl.Template=$global:defaulttxttemplate - $ctl.tooltip = "" - return $false - } - } - -} - -$ValidatePanel2 = { - $results = @() - $results += ValidateNotBlank $txtVHDLocation "This field must contain the full path and filename of the VHD or VHDX to use for VM creation." - $results += ValidateNotBlank $txtVMPath "This field must contain the path on the Hyper-V host where VM files will be placed. This can be a UNC or CSV path as long as the host has the necessary access privileges for the share and file system." - $results += ValidateNotBlank $txtVMNamePrefix "This field must contain a prefix which is applied to the beginning of the VM and computer name of VMs created by SDN Express." - $results += ValidateNotBlank $txtVMDomain "This field must contain the name of the active directory domain to which the VMs will join." - #Needs domain user validation - $results += ValidateNotBlank $txtDomainJoinUsername "This field must contain the domain and username of a domain account that has permission to join machines to the above specified domain. Example: CONTOSO\alyoung" - $results += ValidatePassword $txtDomainJoinPassword - $results += ValidatePassword $txtLocalAdminPassword - - foreach ($result in $results) { - if ($result) { - $btnNext1.IsEnabled = $false - return - } - } - $btnNext1.IsEnabled = $true -} - -$ValidatePanel3 = { - $results = @() - $results += ValidateVLAN $txtManagementVLANID - $results += ValidateSubnetPrefix $txtManagementSubnetPrefix $false "Enter the subnet prefix of the management subnet. Example: 192.168.0.0/24" - $results += ValidateIPAddress $txtManagementGateway $false "Enter the IP address of managemetn subnet's gateway." - $results += ValidateIPAddress $txtManagementIPPoolStart $false "Enter the first IP address to assign to the management interface of the SDN infrastructure VMs created by SDN Express." - $results += ValidateIPAddress $txtManagementIPPoolEnd $false "Enter the last IP address to assign to the management interface of the SDN infrastructure VMs created by SDN Express. There must be enough addresses in this pool to assign one address to each VM created." - $results += ValidateIPAddress $txtManagementDNS1 $false "Enter a DNS server to assign to the SDN infrastructure VMs created by SDN express." - $results += ValidateIPAddress $txtManagementDNS2 $true "Optionally enter additional DNS servers to assign to the SDN infrastructure VMs created by SDN Express." - $results += ValidateIPAddress $txtManagementDNS3 $true "Optionally enter additional DNS servers to assign to the SDN infrastructure VMs created by SDN Express." - - $results += ValidateIPAddressInSubnet $txtManagementGateway $txtManagementSubnetPrefix.Text - $results += ValidateIPAddressInSubnet $txtManagementIPPoolStart $txtManagementSubnetPrefix.Text - $results += ValidateIPAddressInSubnet $txtManagementIPPoolEnd $txtManagementSubnetPrefix.Text - $results += ValidateIPAddressIsGreater $txtManagementIPPoolEnd $txtManagementIPPoolStart.Text - - foreach ($result in $results) { - if ($result) { - $btnNext1.IsEnabled = $false - return - } - } - $btnNext1.IsEnabled = $true -} - -$ValidatePanel4 = { - $results = @() - $results += ValidateVLAN $txtPAVLANID - $results += ValidateSubnetPrefix $txtPASubnetPrefix - $results += ValidateIPAddress $txtPAGateway - $results += ValidateIPAddress $txtPAIPPoolStart - $results += ValidateIPAddress $txtPAIPPoolEnd - $results += ValidateMACAddress $txtMacPoolStart - $results += ValidateMACAddress $txtMacPoolEnd - - foreach ($result in $results) { - if ($result) { - $btnNext1.IsEnabled = $false - return - } - } - $btnNext1.IsEnabled = $true -} - -$ValidatePanel5 = { - $results = @() - $results += ValidateNotBlank $txtRESTName "This field must contain the fully qualified domain name to be assigned to the REST interface of the network controller." - $results += ValidateNotBlank $txtHyperVHosts "This field must contain a list of Hyper-V hosts to be added to the network controller. They must be separated by newlines, commas or semicolons." - $results += ValidateNotBlank $txtHostUsername "This domain and username is used by the network controller to access the Hyper-V hosts and SDN gateways running on the hsots. Example: CONTOSO\AlYoung" - $results += ValidatePassword $txtHostPassword - - foreach ($result in $results) { - if ($result) { - $btnNext1.IsEnabled = $false - return - } - } - $btnNext1.IsEnabled = $true -} - -$ValidatePanel6 = { - $results = @() - $results += ValidateSubnetPrefix $txtPrivateVIPs - $results += ValidateSubnetPrefix $txtPublicVIPs - - foreach ($result in $results) { - if ($result) { - $btnNext1.IsEnabled = $false - return - } - } - $btnNext1.IsEnabled = $true -} -$ValidatePanel7 = { - $results = @() - $results += ValidateSubnetPrefix $txtGREVIPs - - foreach ($result in $results) { - if ($result) { - $btnNext1.IsEnabled = $false - return - } - } - $btnNext1.IsEnabled = $true -} - -$ValidatePanel8 = { - $results = @() - $results += ValidateASN $txtSDNASN - $results += ValidateIPAddress $txtRouterIP1 - $results += ValidateASN $txtRouterASN1 - $results += ValidateIPAddress $txtRouterIP2 $true - $results += ValidateASN $txtRouterASN2 $true - - foreach ($result in $results) { - if ($result) { - $btnNext1.IsEnabled = $false - return - } - } - $btnNext1.IsEnabled = $true -} - - function AddTxtValidation { - param( - $objtxt, - $block - ) - $objtxt.Add_TextChanged($block) - } - - -function GetNextIP { - param ( - $Ip - ) - if (!($IP -as [IPAddress])) - { - return "" - } - - $mb = ($IP -as [IPaddress]).getaddressbytes() - - for ($c = $mb.count; $c -gt 0; $c--) { - if ($mb[$c-1] -eq 0xff) { - $mb[$c-1] = 0 - } else { - $mb[$c-1]++ - return ($mb -as [ipaddress]).ToString() - } - } - } - -function GetNextMAC { -param ( - $Mac - ) - $mac = [regex]::matches($mac.ToUpper().Replace(":", "").Replace("-", ""), '..').groups.value -join "-" - - if (!($mac -as [physicaladdress])) { - return "" - } - - $mb = ($mac -as [physicaladdress]).getaddressbytes() - - for ($c = $mb.count; $c -gt 0; $c--) { - if ($mb[$c-1] -eq 0xff) { - $mb[$c-1] = 0 - } else { - $mb[$c-1]++ - $newmac = ($mb -as [physicaladdress]).ToString() - return [regex]::matches($newmac.ToUpper().Replace(":", "").Replace("-", ""), '..').groups.value -join "-" - } - } -} - - function GenerateConfigData { - $ConfigData = [ordered] @{} - - $Path = $txtVHDLocation.Text - if (![string]::IsNullOrEmpty($path)) { - $PathParts = $path.Split("\") - - $ConfigData.ScriptVersion = "2.0" - - $ConfigData.VHDPath = $Path.substring(0, $Path.length-$PathParts[$PathParts.Count-1].length-1) - $ConfigData.VHDFile = $PathParts[$PathParts.Count-1] - } - - $ConfigData.VMLocation = $txtVMPath.Text - $ConfigData.JoinDomain = $txtVMDomain.text - - $ConfigData.ManagementVLANID = $txtManagementVLANID.text - $ConfigData.ManagementSubnet = $txtManagementSubnetPrefix.text - $ConfigData.ManagementGateway = $txtManagementGateway.text - $ConfigData.ManagementDNS = @() - $ConfigData.ManagementDNS += $txtManagementDNS1.text - if (![String]::IsNullOrEmpty($txtManagementDNS2.text)) { $ConfigData.ManagementDNS += $txtManagementDNS2.text } - if (![String]::IsNullOrEmpty($txtManagementDNS3.text)) { $ConfigData.ManagementDNS += $txtManagementDNS3.text } - - $ConfigData.DomainJoinUsername = $txtDomainJoinUsername.text - $ConfigData.DomainJoinSecurePassword = $txtDomainJoinPassword.Password | ConvertTo-SecureString -AsPlainText -Force | convertfrom-securestring - - $ConfigData.LocalAdminSecurePassword = $txtLocalAdminPassword.Password | ConvertTo-SecureString -AsPlainText -Force | convertfrom-securestring - - $ConfigData.LocalAdminDomainUser = $txtHostUserName.text - - $ConfigData.RestName = $txtRESTName.Text - - $hosttxt = $txtHyperVHosts.text - $hosttxt = $hosttxt.Replace("`r", "").Replace(" ", "") - $hosts = $hosttxt.Split("`n,;") - $ConfigData.HyperVHosts = $hosts - - - $nexthost = 0 - $nextIP = $txtManagementIPPoolStart.Text - $nextPA = $txtPAIPPoolStart.Text - $nextMAC = $txtMacPoolStart.Text - - $ConfigData.NCs = @() - $ConfigData.NCs += [ordered] @{ComputerName="$($txtVMNamePrefix.Text)NC01"; HostName=$hosts[$nexthost]; ManagementIP=$nextIP; MACAddress=$nextMac} - - $nextip = GetNextIP $nextip - $nextmac = GetNextMac $nextmac - $nexthost = ($nexthost + 1) % $hosts.count - - if ($rdoMultiNode.IsChecked) { - - $ConfigData.NCs += [ordered] @{ComputerName="$($txtVMNamePrefix.Text)NC02"; HostName=$hosts[$nexthost]; ManagementIP=$nextIP; MACAddress=$nextMac} - $nextip = GetNextIP $nextip - $nextmac = GetNextMac $nextmac - $nexthost = ($nexthost + 1) % $hosts.count - - $ConfigData.NCs += [ordered] @{ComputerName="$($txtVMNamePrefix.Text)NC03"; HostName=$hosts[$nexthost]; ManagementIP=$nextIP; MACAddress=$nextMac} - $nextip = GetNextIP $nextip - $nextmac = GetNextMac $nextmac - $nexthost = ($nexthost + 1) % $hosts.count - } - - $ConfigData.Muxes = @() - for ($c = 1; $c -le $sliMuxCount.Value; $c++) { - - $mgmtmac = $nextmac - $nextmac = getnextmac $nextmac - $pamac = $nextmac - $nextmac = getnextmac $nextmac - - $ConfigData.Muxes += [ordered] @{ComputerName="$($txtVMNamePrefix.Text)Mux{0:00}" -f $c; HostName=$hosts[$nexthost]; ManagementIP=$nextip; MACAddress=$mgmtmac; PAIPAddress=$nextpa; PAMACAddress=$pamac} - - $nexthost = ($nexthost + 1) % $hosts.count - $nextip = getnextip $nextip - $nextpa = getnextip $nextpa - - } - - $papoolstart = $nextpa - - $ConfigData.Gateways = @() - for ($c = 1; $c -le $sliGatewayCount.Value; $c++) { - $mgmtmac = $nextmac - $nextmac = getnextmac $nextmac - $femac = $nextmac - $nextmac = getnextmac $nextmac - $bemac = $nextmac - $nextmac = getnextmac $nextmac - - $ConfigData.Gateways += [ordered] @{ComputerName="$($txtVMNamePrefix.Text)GW{0:00}" -f $c; HostName=$hosts[$nexthost]; ManagementIP=$nextip; MACAddress=$mgmtmac; FrontEndIp=$nextpa; FrontEndMac=$femac; BackEndMac=$bemac} - - $nexthost = ($nexthost + 1) % $hosts.count - $nextip = getnextip $nextip - $nextpa = getnextip $nextpa - - } - - $ConfigData.NCUsername = $txtHostUsername.Text - $ConfigData.NCSecurePassword = $txtHostPassword.Password | ConvertTo-SecureString -AsPlainText -Force | convertfrom-securestring - - $ConfigData.PAVLANID = $txtPAVLANID.text - $ConfigData.PASubnet = $txtPASubnetPrefix.text - $ConfigData.PAGateway = $txtPAGateway.text - $ConfigData.PAPoolStart = $papoolstart - $ConfigData.PAPoolEnd = $txtPAIPPoolEnd.Text - - $ConfigData.SDNMacPoolStart = $nextMAC - $ConfigData.SDNMacPoolEnd = $txtMacPoolEnd.Text - - $ConfigData.SDNASN = $txtSDNASN.text - $ConfigData.Routers = @( - [ordered] @{ RouterASN=$txtRouterASN1.text; RouterIPAddress=$txtRouterIP1.text} - ) - if (![String]::IsNullOrEmpty($txtRouterIP2.text)) { - $ConfigData.Routers += [ordered] @{ RouterASN=$txtRouterASN2.text; RouterIPAddress=$txtRouterIP2.text} - } - - $ConfigData.PrivateVIPSubnet = $txtPrivateVIPs.text - $ConfigData.PublicVIPSubnet = $txtPublicVIPs.text - - $ConfigData.PoolName = "DefaultAll" - $ConfigData.GRESubnet = $txtGREVIPs.text - - - $ConfigData.Capacity = 10000 - - - return $ConfigData - } - - - function SetPanel - { - param( - $PanelIndex - ) - if ($panelIndex -eq 1) { $mark1.Visibility = "Visible"; $panel1.Visibility = "Visible"; } else { $mark1.Visibility = "Hidden"; $panel1.Visibility = "Hidden" } - if ($panelIndex -eq 2) { $mark2.Visibility = "Visible"; $panel2.Visibility = "Visible"; invoke-command $ValidatePanel2 } else { $mark2.Visibility = "Hidden"; $panel2.Visibility = "Hidden" } - if ($panelIndex -eq 3) { $mark3.Visibility = "Visible"; $panel3.Visibility = "Visible"; invoke-command $ValidatePanel3 } else { $mark3.Visibility = "Hidden"; $panel3.Visibility = "Hidden" } - if ($panelIndex -eq 4) { $mark4.Visibility = "Visible"; $panel4.Visibility = "Visible"; invoke-command $ValidatePanel4 } else { $mark4.Visibility = "Hidden"; $panel4.Visibility = "Hidden" } - if ($panelIndex -eq 5) { $mark5.Visibility = "Visible"; $panel5.Visibility = "Visible"; invoke-command $ValidatePanel5 } else { $mark5.Visibility = "Hidden"; $panel5.Visibility = "Hidden" } - if ($panelIndex -eq 6) { $mark6.Visibility = "Visible"; $panel6.Visibility = "Visible"; invoke-command $ValidatePanel6 } else { $mark6.Visibility = "Hidden"; $panel6.Visibility = "Hidden" } - if ($panelIndex -eq 7) { $mark7.Visibility = "Visible"; $panel7.Visibility = "Visible"; invoke-command $ValidatePanel7 } else { $mark7.Visibility = "Hidden"; $panel7.Visibility = "Hidden" } - if ($panelIndex -eq 8) { $mark8.Visibility = "Visible"; $panel8.Visibility = "Visible" } else { $mark8.Visibility = "Hidden"; $panel8.Visibility = "Hidden" } - if ($panelIndex -eq 9) { - $mark9.Visibility = "Visible"; - $panel9.Visibility = "Visible"; - $btnNext1.Content = "Deploy" - $txtReview.Text = ConfigDataToString (GenerateConfigData) - } else { - $mark9.Visibility = "Hidden"; - $panel9.Visibility = "Hidden"; - $btnNext1.Content = "Next" - } - if ($panelIndex -eq 10) { $global:Deploy = $true; $form.Close() } - } - - - #Read XAML - $reader=(New-Object System.Xml.XmlNodeReader $xaml) - try{$Form=[Windows.Markup.XamlReader]::Load( $reader )} - catch{Write-Host "Unable to load Windows.Markup.XamlReader. Some possible causes for this problem include: .NET Framework is missing PowerShell must be launched with PowerShell -sta, invalid XAML code was encountered."; exit} - - $xaml.SelectNodes("//*[@Name]") | %{Set-Variable -Name ($_.Name) -Value $Form.FindName($_.Name)} - - $global:PanelIndex = 1 - $global:Deploy = $false - $global:defaulttxttemplate = $form.FindResource("NormalTemplate") - - $btnBack1.IsEnabled = $false - - $uri1.Add_Click({ Start-Process -FilePath $this.NavigateUri}) - $uri2.Add_Click({ Start-Process -FilePath $this.NavigateUri}) - $uri3.Add_Click({ Start-Process -FilePath $this.NavigateUri}) - $uri4.Add_Click({ Start-Process -FilePath $this.NavigateUri}) - - $btnBack1.Add_Click({$global:PanelIndex=$global:panelIndex - 1; SetPanel $global:panelIndex; if ($global:panelIndex -eq 1) { $btnBack1.IsEnabled = $false }}) - $btnNext1.Add_Click({$global:PanelIndex=$global:panelIndex + 1; SetPanel $global:panelIndex; if ($global:panelIndex -gt 1) { $btnBack1.IsEnabled = $true }}) - $btnBrowse.Add_Click({ - [System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") | Out-Null - - $ofd = New-Object System.Windows.Forms.OpenFileDialog - $ofd.initialDirectory = $txtVHDLocation.text - $ofd.filter = "Virtual Hard Disks (*.vhdx; *.vhd)|*.vhdx;*.vhd" - $ofd.ShowDialog() | Out-Null - $txtVHDLocation.text = $ofd.Filename - }) - $btnExport.Add_Click({ - [System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") | Out-Null - - $ofd = New-Object System.Windows.Forms.SaveFileDialog - $ofd.filter = "Powershell (*.psd1)|*.psd1" - $result = $ofd.ShowDialog() - - if ($result) - { - $fn = $ofd.filename - $ConfigData = GenerateConfigData - - "" | out-file $fn - Convertto-psd1 $ConfigData | out-file $fn -append - - $Result = $null - } - }) - - - # Panel 2 Validation - AddTxtValidation $txtVHDLocation $ValidatePanel2 - AddTxtValidation $txtVMPath $ValidatePanel2 - AddTxtValidation $txtVMNamePrefix $ValidatePanel2 - AddTxtValidation $txtVMDomain $ValidatePanel2 - AddTxtValidation $txtDomainJoinUsername $ValidatePanel2 #Needs domain user validation - $txtDomainJoinPassword.Add_PasswordChanged($ValidatePanel2) - $txtLocalAdminPassword.Add_PasswordChanged($ValidatePanel2) - - # Panel 3 Validation - AddTxtValidation $txtManagementVLANID $ValidatePanel3 - AddTxtValidation $txtManagementSubnetPrefix $ValidatePanel3 - AddTxtValidation $txtManagementGateway $ValidatePanel3 - AddTxtValidation $txtManagementIPPoolStart $ValidatePanel3 - AddTxtValidation $txtManagementIPPoolEnd $ValidatePanel3 - AddTxtValidation $txtManagementDNS1 $ValidatePanel3 - AddTxtValidation $txtManagementDNS2 $ValidatePanel3 - AddTxtValidation $txtManagementDNS3 $ValidatePanel3 - - # Panel 4 Validation - AddTxtValidation $txtPAVLANID $ValidatePanel4 - AddTxtValidation $txtPASubnetPrefix $ValidatePanel4 - AddTxtValidation $txtPAGateway $ValidatePanel4 - AddTxtValidation $txtPAIPPoolStart $ValidatePanel4 - AddTxtValidation $txtPAIPPoolEnd $ValidatePanel4 - - $txtMacPoolStart.Text = "00:1D:D8:B7:1C:00" - $txtMacPoolEnd.Text = "00:1D:D8:B7:1F:FF" - - AddTxtValidation $txtMacPoolStart $ValidatePanel4 - AddTxtValidation $txtMacPoolEnd $ValidatePanel4 - - # Panel 5 Validation - AddTxtValidation $txtRESTName $ValidatePanel5 - AddTxtValidation $txtHyperVHosts $ValidatePanel5 # Needs multiline host validation - AddTxtValidation $txtHostUsername $ValidatePanel5 # Needs domain user validation - $txtHostPassword.Add_PasswordChanged($ValidatePanel5) - - # Panel 6 Validation - AddTxtValidation $txtPrivateVIPs $ValidatePanel6 - AddTxtValidation $txtPublicVIPs $ValidatePanel6 - - # Panel 7 Validation - AddTxtValidation $txtGREVIPs $ValidatePanel7 - - # Panel 8 Validation - AddTxtValidation $txtSDNASN $ValidatePanel8 - AddTxtValidation $txtRouterIP1 $ValidatePanel8 - AddTxtValidation $txtRouterASN1 $ValidatePanel8 - AddTxtValidation $txtRouterIP2 $ValidatePanel8 - AddTxtValidation $txtRouterASN2 $ValidatePanel8 - - SetPanel $PanelIndex - - $sliGatewayCount.Add_ValueChanged({ - $newmax = $sliGatewayCount.Value-1 - if ($sliRedundantCount.Value -gt $newmax) { - $sliRedundantCount.Value = $newmax - } - $sliRedundantCount.Maximum = $newmax - $sliRedundantCount.Width = ($newmax-1) * 40 - - }) - - $Form.ShowDialog() | out-null - - if ($global:deploy) { - return GenerateConfigData - } -} \ No newline at end of file diff --git a/azure_jumpstart_hcibox/artifacts/SDN/Single-NC.psd1 b/azure_jumpstart_hcibox/artifacts/SDN/Single-NC.psd1 deleted file mode 100644 index a00294138f7744df464a30451d13d98a095ac6b1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6550 zcmeI0NpBlR5QY03ApgNPC4i-HxQ~DUwyDT+5D9{qC>LKi3u7VLAk#|__^&5<U$=(S zGwd0Xp^nC2wq9OUSH148>VN<F)_h}Ln7<A0XZD(!)I69gb8i;r(&YMnufIEUtJ)uR z@0qSSFde<iK9}ai9GP=7Q=fOsc1PyWycGs@(?I)U;a*EZfjg0u2mK$Ik3z}J=USgr z^NU)fR!UVPCuu4<XOeeXllHTET}l5Vy>HZ;??Ps(vRi3=r%~QXGXFOfxu@!JtNRaW zcB7ltm(t{=WW5n)fmF3fsMpkdFp2u-LMVDgCbssB%+QP_KeD#{L1q25TD-QF$jv9c z|7t~y)?#6~=_AGq^PTnWp0ruju4@K0-M;sj;M=&c`){%>Ji>}tuo!#Q_HSj;O!au@ zN<9|p0iWQ6&$W<*sZdi{7xuuy_qsmWp4n1bN2BR@SElc=dc~5OnYsQVT?2jdj%?jX zSoBGC_thqqUt%+ol*G38@e<W1s-3InTvslnj_`VV_thuXU#{}L>WBIQd7%G9^>Et9 za^KxR88toiA1>?A&A+On><E1(t-BggN6%b(3?<LWWh|-6dir<m=C)m?@<ioW!N+#r zjG!#7YhIV1Xq4zU*2vKv3unSk9xXADltelqAAgKh*O5MWbfngG9deBVedlVAe<HPu z^zP}euO~hPJ=HrF+Dw0Q`$dTxd!(|l%0_Ap68eA{3n8+4mgAeNRbuf$?%J=OG(>Kq zUTBL|$3nr+@E}u5Mx5zJ3;YZsHt@MztY_CA_rG$vw0)gRx$KJ#$MVBawr7S!DuX+$ zpLh?};8{F{N0_O20FSI*+i}?;$MSb7>8WH6t>;I2<6U@=NH)wIOBZy5Pr2&RrOxHK zv}Er0RL2?w3uh{UP3Yg(&8+RJ&S5e`K!fv+t#F-HhdGU2XxG=3>ssY9d}RK_wq@7a zsb_5jW+J(Xda-iFdXLm{pc3rN9Dv7>%2?BwSL?X!uhqpa(6svFt@W$_g`~1KoJqdF zmrTsB+LQNHK9R2MqSf6cw6mXR*Sr_rgN;#$02aEPe(ZsJ`pdK%z0*!Y9dS<+>T~t0 zx9@G)zTeXRnelg7M(Jx>Mq)08t44IL%snSIzPZ<4xv(Q&XGh<|KF-ObP3rwOw^&_g zhaQTX-e^xRSQCm!n0rlno@!;C*wr<&(E*V`fyHWYD6SAa9*Oyf=9L&v$wW_TS5d!s zv5xPNQ(5%0<z~sB`UrRTijxArS2c6?+srR*%&cp@i(i`cT<4d4>z94&mwoFON+z1& zZKFSzr(p|`<f^|}&zQr++GH>XS|yw82*xftb_2*w+^NR#1wV@@+@E#3Gw8MXz14!7 z@uzL2dP@F;tXS}|eO|Zmrx);zLp|0S;qt+swC-o((*1I^SY^*(V;oksbcw{u(xzWC zD_>chKaJCFJJgW2U(9oFJ##jADvmY#ZZnRx?Y2+Jv1T^xGXIAgbEBPOo8xT9hEbz_ zyKrnAKy6y}h+&GDaNWtkX0aiNU$dt&$Ejye1I0Mx!({g^gD1u(q9O|>^B~`t+w6jT zl?;U3o&1FCphPadw#%N#V8~s_i^(;}LpYm2FS4dG_ux!~Jeo|NT!tDlegE76{RS!} z<0kVO+JCg<pED{j$Zg2dK<TRmdp|i9xGt9@CLsTJ869QrY=k(26N~bi$x>u-oZWD$ z!6{BxU!3ER8M@4ja~@93$p2zpWPY5o&=*}?t3=;^>_NN{I#rB>RBsnPN36#-9kY6h zh?HuyQN+TlyIVDOqvyHy#yg$ZPL(^%v{U-0n04vZ-Nx_j_O52RtLKaET-U8{%{t(x zwp}%@*fE4z)eO9Fc5tlnV_m*q9NtUW=4`po!#d8dsvf+M4U6pS|HXPfLR})~9GoWj zy7>{L-*=lxxylBI*tD{riyK!u!{_ui7psvI;w-0V2hz5DhB?cr`Lz(!7A$5e@qGCV zV>t%bv(_W&$qCB`$ytc$*SdTQzBU(%xk6*$ROvuAFP|Z~6Jg)$PBn@}<*dF~U7R#$ G(f<Hib2NJZ diff --git a/azure_jumpstart_hcibox/artifacts/Uninstall-AKS.ps1 b/azure_jumpstart_hcibox/artifacts/Uninstall-AKS.ps1 deleted file mode 100644 index f2ab781be7..0000000000 --- a/azure_jumpstart_hcibox/artifacts/Uninstall-AKS.ps1 +++ /dev/null @@ -1,47 +0,0 @@ -# Set paths -$Env:HCIBoxDir = "C:\HCIBox" -$Env:HCIBoxLogsDir = "C:\HCIBox\Logs" -$Env:HCIBoxVMDir = "C:\HCIBox\Virtual Machines" -$Env:HCIBoxKVDir = "C:\HCIBox\KeyVault" -$Env:HCIBoxGitOpsDir = "C:\HCIBox\GitOps" -$Env:HCIBoxIconDir = "C:\HCIBox\Icons" -$Env:HCIBoxVHDDir = "C:\HCIBox\VHD" -$Env:HCIBoxSDNDir = "C:\HCIBox\SDN" -$Env:HCIBoxWACDir = "C:\HCIBox\Windows Admin Center" -$Env:agentScript = "C:\HCIBox\agentScript" -$Env:ToolsDir = "C:\Tools" -$Env:tempDir = "C:\Temp" -$Env:VMPath = "C:\VMs" - -Start-Transcript -Path $Env:HCIBoxLogsDir\Uninstall-AKS.log - -# Import Configuration Module and create Azure login credentials -Write-Header 'Importing config' -$ConfigurationDataFile = 'C:\HCIBox\HCIBox-Config.psd1' -$SDNConfig = Import-PowerShellDataFile -Path $ConfigurationDataFile - -# Generate credential objects -Write-Header 'Creating credentials and connecting to Azure' -$user = "jumpstart.local\administrator" -$password = ConvertTo-SecureString -String $SDNConfig.SDNAdminPassword -AsPlainText -Force -$adcred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $user, $password # Domain credential - -$azureAppCred = (New-Object System.Management.Automation.PSCredential $env:spnClientID, (ConvertTo-SecureString -String $env:spnClientSecret -AsPlainText -Force)) -Connect-AzAccount -ServicePrincipal -Subscription $env:subscriptionId -Tenant $env:spnTenantId -Credential $azureAppCred - -# Uninstall AksHci - only need to perform the following on one of the nodes -$clusterName = $env:AKSClusterName -Write-Header "Removing AKS-HCI workload cluster" -Invoke-Command -VMName $SDNConfig.HostList[0] -Credential $adcred -ScriptBlock { - Disable-AksHciArcConnection -name $using:clusterName - Remove-AksHciCluster -name $using:clusterName -Confirm:$false -} - -Write-Header "Uninstalling AKS-HCI management plane" -Invoke-Command -VMName $SDNConfig.HostList[0] -Credential $adcred -ScriptBlock { - Uninstall-AksHci -Confirm:$false -} -# Set env variable deployAKSHCI to true (in case the script was run manually) -[System.Environment]::SetEnvironmentVariable('deployAKSHCI', 'false',[System.EnvironmentVariableTarget]::Machine) - -Stop-Transcript \ No newline at end of file diff --git a/azure_jumpstart_hcibox/artifacts/Uninstall-ResourceBridge.ps1 b/azure_jumpstart_hcibox/artifacts/Uninstall-ResourceBridge.ps1 deleted file mode 100644 index f4a9ff61e0..0000000000 --- a/azure_jumpstart_hcibox/artifacts/Uninstall-ResourceBridge.ps1 +++ /dev/null @@ -1,46 +0,0 @@ -# Set paths -$Env:HCIBoxDir = "C:\HCIBox" -$Env:HCIBoxLogsDir = "C:\HCIBox\Logs" -$Env:HCIBoxVMDir = "C:\HCIBox\Virtual Machines" -$Env:HCIBoxKVDir = "C:\HCIBox\KeyVault" -$Env:HCIBoxGitOpsDir = "C:\HCIBox\GitOps" -$Env:HCIBoxIconDir = "C:\HCIBox\Icons" -$Env:HCIBoxVHDDir = "C:\HCIBox\VHD" -$Env:HCIBoxSDNDir = "C:\HCIBox\SDN" -$Env:HCIBoxWACDir = "C:\HCIBox\Windows Admin Center" -$Env:agentScript = "C:\HCIBox\agentScript" -$Env:ToolsDir = "C:\Tools" -$Env:tempDir = "C:\Temp" -$Env:VMPath = "C:\VMs" - -# Import Configuration Module -$ConfigurationDataFile = "$Env:HCIBoxDir\HCIBox-Config.psd1" -$SDNConfig = Import-PowerShellDataFile -Path $ConfigurationDataFile - -# Set AD Domain cred -$user = "jumpstart.local\administrator" -$password = ConvertTo-SecureString -String $SDNConfig.SDNAdminPassword -AsPlainText -Force -$adcred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $user, $password - -$csv_path = "C:\ClusterStorage\S2D_vDISK1" -$subId = $env:subscriptionId -$rg = $env:resourceGroup -$spnClientId = $env:spnClientId -$spnSecret = $env:spnClientSecret -$spnTenantId = $env:spnTenantId -$resource_name = "HCIBox-ResourceBridge" -$custom_location_name = "hcibox-rb-cl" - -Invoke-Command -VMName $SDNConfig.HostList[0] -Credential $adcred -ScriptBlock { - Write-Host "Removing Arc Resource Bridge." - $WarningPreference = "SilentlyContinue" - az login --service-principal --username $using:spnClientID --password=$using:spnSecret --tenant $using:spnTenantId - - az azurestackhci virtualnetwork delete --subscription $using:subId --resource-group $using:rg --name "vlan200" --yes - az azurestackhci galleryimage delete --subscription $using:subId --resource-group $using:rg --name "ubuntu20" - az azurestackhci galleryimage delete --subscription $using:subId --resource-group $using:rg --name "win2k22" - az customlocation delete --resource-group $using:rg --name $using:custom_location_name --yes - az k8s-extension delete --cluster-type appliances --cluster-name $using:resource_name --resource-group $using:rg --name vmss-hci --yes - az arcappliance delete hci --config-file $using:csv_path\ResourceBridge\hci-appliance.yaml --yes - Remove-ArcHciConfigFiles -} \ No newline at end of file diff --git a/azure_jumpstart_hcibox/artifacts/dataController.json b/azure_jumpstart_hcibox/artifacts/dataController.json index f7e2969098..6c3a6d1bac 100644 --- a/azure_jumpstart_hcibox/artifacts/dataController.json +++ b/azure_jumpstart_hcibox/artifacts/dataController.json @@ -49,7 +49,7 @@ "type": "string" }, "logAnalyticsPrimaryKey": { - "type": "string" + "type": "securestring" }, "resourceTags": { "type": "object" diff --git a/azure_jumpstart_hcibox/artifacts/hci.json b/azure_jumpstart_hcibox/artifacts/hci.json new file mode 100644 index 0000000000..42933f2ac0 --- /dev/null +++ b/azure_jumpstart_hcibox/artifacts/hci.json @@ -0,0 +1,613 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "deploymentMode": { + "defaultValue": "Validate", + "type": "string", + "allowedValues": [ + "Validate", + "Deploy" + ], + "metadata": { + "description": "First must pass Validate prior running Deploy" + } + }, + "keyVaultName": { + "type": "string", + "metadata": { + "description": "The KeyVault name used to store the secrets." + }, + "defaultValue": "hcibox-kv-[substring(newGuid(),0,4)]" + }, + "softDeleteRetentionDays": { + "type": "int", + "defaultValue": 30 + }, + "diagnosticStorageAccountName": { + "type": "string", + "metadata": { + "description": "The name of the storage account used for KV audit logs" + } + }, + "logsRetentionInDays": { + "type": "int", + "defaultValue": 30, + "minValue": 0, + "maxValue": 365, + "metadata": { + "description": "Specifies the number of days that logs are gonna be kept. If you do not want to apply any retention policy and retain data forever, set value to 0." + } + }, + "storageAccountType": { + "type": "string", + "defaultValue": "Standard_LRS", + "allowedValues": [ + "Premium_LRS", + "Premium_ZRS", + "Standard_GRS", + "Standard_GZRS", + "Standard_LRS", + "Standard_RAGRS", + "Standard_RAGZRS", + "Standard_ZRS" + ], + "metadata": { + "description": "Storage Account type" + } + }, + "secretsLocation": { + "defaultValue": "", + "type": "string", + "metadata": { + "description": "The fqdn of your KeyVault" + } + }, + "ClusterWitnessStorageAccountName": { + "defaultValue": "", + "type": "string", + "metadata": { + "description": "The existing storage account name used for the cluster witness" + } + }, + "clusterName": { + "type": "string", + "minLength": 3, + "maxLength": 24 + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]" + }, + "tenantId": { + "type": "string", + "defaultValue": "[subscription().tenantId]" + }, + "localAdminSecretName": { + "type": "string", + "defaultValue": "LocalAdminCredential", + "allowedValues": [ + "LocalAdminCredential" + ], + "metadata": { + "description": "The name can not be changed" + } + }, + "localAdminSecretValue": { + "type": "securestring" + }, + "domainAdminSecretName": { + "type": "string", + "defaultValue": "AzureStackLCMUserCredential", + "allowedValues": [ + "AzureStackLCMUserCredential" + ], + "metadata": { + "description": "The name can not be changed" + } + }, + "domainAdminSecretValue": { + "type": "securestring" + }, + "arbDeploymentSpnName": { + "type": "string", + "defaultValue": "DefaultARBApplication", + "allowedValues": [ + "DefaultARBApplication" + ], + "metadata": { + "description": "The name can not be changed" + } + }, + "arbDeploymentSpnValue": { + "type": "securestring" + }, + "storageWitnessName": { + "type": "string", + "defaultValue": "WitnessStorageKey", + "allowedValues": [ + "WitnessStorageKey" + ], + "metadata": { + "description": "The name can not be changed" + } + }, + "storageWitnessValue": { + "type": "securestring" + }, + "apiVersion": { + "defaultValue": "", + "type": "string", + "metadata": { + "description": "The api version for deploying a hci cluster" + } + }, + "arcNodeResourceIds": { + "defaultValue": [ + ], + "type": "array", + "metadata": { + "description": "The arc for server node Ids of the hci cluster" + } + }, + "domainFqdn": { + "defaultValue": "", + "type": "string", + "metadata": { + "description": "The domain name of the Active Directory Domain Services" + } + }, + "namingPrefix": { + "defaultValue": "", + "type": "string", + "metadata": { + "description": "The ADFS name prefix" + } + }, + "adouPath": { + "defaultValue": "", + "type": "string", + "metadata": { + "description": "The ADDS OU path" + } + }, + "securityLevel": { + "defaultValue": "Recommended", + "type": "string", + "allowedValues": [ + "Recommended", + "Customized" + ], + "metadata": { + "description": "The security level data for deploying a hci cluster" + } + }, + "driftControlEnforced": { + "defaultValue": true, + "type": "bool", + "allowedValues": [ + true, + false + ], + "metadata": { + "description": "The security setting driftControlEnforced data for deploying a hci cluster" + } + }, + "credentialGuardEnforced": { + "defaultValue": true, + "type": "bool", + "allowedValues": [ + true, + false + ], + "metadata": { + "description": "The security setting credentialGuardEnforced data for deploying a hci cluster" + } + }, + "smbSigningEnforced": { + "defaultValue": true, + "type": "bool", + "allowedValues": [ + true, + false + ], + "metadata": { + "description": "The security setting smbSigningEnforced data for deploying a hci cluster" + } + }, + "smbClusterEncryption": { + "defaultValue": false, + "type": "bool", + "allowedValues": [ + true, + false + ], + "metadata": { + "description": "The security setting smbClusterEncryption data for deploying a hci cluster" + } + }, + "bitlockerBootVolume": { + "defaultValue": true, + "type": "bool", + "allowedValues": [ + true, + false + ], + "metadata": { + "description": "The security setting bitlockerBootVolume data for deploying a hci cluster" + } + }, + "bitlockerDataVolumes": { + "defaultValue": true, + "type": "bool", + "allowedValues": [ + true, + false + ], + "metadata": { + "description": "The security setting bitlockerDataVolumes data for deploying a hci cluster" + } + }, + "wdacEnforced": { + "defaultValue": true, + "type": "bool", + "allowedValues": [ + true, + false + ], + "metadata": { + "description": "The security setting wdacEnforced data for deploying a hci cluster" + } + }, + "streamingDataClient": { + "defaultValue": true, + "type": "bool", + "allowedValues": [ + true, + false + ], + "metadata": { + "description": "The metrics data for deploying a hci cluster" + } + }, + "euLocation": { + "defaultValue": false, + "type": "bool", + "allowedValues": [ + true, + false + ], + "metadata": { + "description": "The location data for deploying a hci cluster" + } + }, + "episodicDataUpload": { + "defaultValue": true, + "type": "bool", + "allowedValues": [ + true, + false + ], + "metadata": { + "description": "The diagnostic data for deploying a hci cluster" + } + }, + "configurationMode": { + "defaultValue": "Express", + "type": "string", + "allowedValues": [ + "Express", + "InfraOnly", + "KeepStorage" + ], + "metadata": { + "description": "The storage volume configuration mode" + } + }, + "subnetMask": { + "defaultValue": "", + "type": "string", + "metadata": { + "description": "The subnet mask for deploying a hci cluster" + } + }, + "defaultGateway": { + "defaultValue": "", + "type": "string", + "metadata": { + "description": "The default gateway for deploying a hci cluster" + } + }, + "startingIPAddress": { + "defaultValue": "", + "type": "string", + "metadata": { + "description": "The starting ip address for deploying a hci cluster" + } + }, + "endingIPAddress": { + "defaultValue": "", + "type": "string", + "metadata": { + "description": "The ending ip address for deploying a hci cluster" + } + }, + "dnsServers": { + "defaultValue": [ + "" + ], + "type": "array", + "metadata": { + "description": "The dns servers for deploying a hci cluster" + } + }, + "physicalNodesSettings": { + "type": "array", + "metadata": { + "description": "The physical nodes settings for deploying a hci cluster" + } + }, + "networkingType": { + "defaultValue": "", + "type": "string", + "allowedValues": [ + "switchedMultiServerDeployment", + "switchlessMultiServerDeployment", + "singleServerDeployment" + ], + "metadata": { + "description": "The networking type for deploying a hci cluster" + } + }, + "intentList": { + "defaultValue": [ + ], + "type": "array", + "metadata": { + "description": "The intent list for deploying a hci cluster" + } + }, + "storageNetworkList": { + "defaultValue": [ + ], + "type": "array", + "metadata": { + "description": "The storage network list for deploying a hci cluster" + } + }, + "storageConnectivitySwitchless": { + "defaultValue": false, + "type": "bool", + "metadata": { + "description": "The storage connectivity switchless value for deploying a hci cluster" + } + }, + "customLocation": { + "defaultValue": "", + "type": "string", + "metadata": { + "description": "The custom location for deploying a hci cluster" + } + } + }, + "resources": [ + { + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2021-01-01", + "name": "[parameters('diagnosticStorageAccountName')]", + "location": "[parameters('location')]", + "sku": { + "name": "[parameters('storageAccountType')]", + "tier": "Standard" + }, + "kind": "StorageV2", + "properties": { + "supportsHttpsTrafficOnly": true + } + }, + { + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2021-06-01-preview", + "name": "[parameters('keyVaultName')]", + "location": "[parameters('location')]", + "dependsOn": [ + "[resourceId('Microsoft.Storage/storageAccounts', parameters('diagnosticStorageAccountName'))]" + ], + "properties": { + "enabledForDeployment": true, + "enabledForTemplateDeployment": true, + "enabledForDiskEncryption": true, + "enableSoftDelete": true, + "softDeleteRetentionInDays": "[parameters('softDeleteRetentionDays')]", + "enableRbacAuthorization": true, + "publicNetworkAccess": "Enabled", + "accessPolicies": [], + "tenantId": "[parameters('tenantId')]", + "sku": { + "name": "standard", + "family": "A" + } + } + }, + { + "type": "Microsoft.KeyVault/vaults/providers/diagnosticsettings", + "name": "[concat(parameters('keyVaultName'), '/Microsoft.Insights/service')]", + "apiVersion": "2016-09-01", + "Location": "[resourceGroup().location]", + "dependsOn": [ + "[concat('Microsoft.KeyVault/vaults/', parameters('keyVaultName'))]", + "[concat('Microsoft.Storage/storageAccounts/', parameters('diagnosticStorageAccountName'))]" + ], + "properties": { + "storageAccountId": "[resourceId('Microsoft.Storage/storageAccounts', parameters('diagnosticStorageAccountName'))]", + "logs": [ + { + "category": "AuditEvent", + "enabled": true, + "retentionPolicy": { + "enabled": true, + "days": "[parameters('LogsRetentionInDays')]" + } + } + ] + } + }, + { + "condition": "[equals(parameters('deploymentMode'), 'Validate')]", + "type": "Microsoft.AzureStackHCI/clusters", + "apiVersion": "2023-08-01-preview", + "name": "[parameters('clusterName')]", + "dependsOn": [ + "[resourceId('Microsoft.KeyVault/vaults', parameters('keyVaultName'))]" + ], + "identity": { + "type": "SystemAssigned" + }, + "location": "[parameters('location')]", + "properties": { + } + }, + { + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2021-06-01-preview", + "name": "[concat(parameters('keyVaultName'), '/', parameters('domainAdminSecretName'))]", + "dependsOn": [ + "[resourceId('Microsoft.KeyVault/vaults', parameters('keyVaultName'))]" + ], + "location": "[parameters('location')]", + "scale": null, + "properties": { + "contentType": "Secret", + "value": "[parameters('domainAdminSecretValue')]", + "attributes": { + "enabled": true + } + } + }, + { + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2021-06-01-preview", + "name": "[concat(parameters('keyVaultName'), '/', parameters('localAdminSecretName'))]", + "dependsOn": [ + "[resourceId('Microsoft.KeyVault/vaults', parameters('keyVaultName'))]" + ], + "location": "[parameters('location')]", + "scale": null, + "properties": { + "contentType": "Secret", + "value": "[parameters('localAdminSecretValue')]", + "attributes": { + "enabled": true + } + } + }, + { + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2021-06-01-preview", + "name": "[concat(parameters('keyVaultName'), '/', parameters('arbDeploymentSpnName'))]", + "dependsOn": [ + "[resourceId('Microsoft.KeyVault/vaults', parameters('keyVaultName'))]" + ], + "location": "[parameters('location')]", + "scale": null, + "properties": { + "contentType": "Secret", + "value": "[parameters('arbDeploymentSpnValue')]", + "attributes": { + "enabled": true + } + } + }, + { + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2021-06-01-preview", + "name": "[concat(parameters('keyVaultName'), '/', parameters('storageWitnessName'))]", + "dependsOn": [ + "[resourceId('Microsoft.KeyVault/vaults', parameters('keyVaultName'))]" + ], + "location": "[parameters('location')]", + "scale": null, + "properties": { + "contentType": "Secret", + "value": "[parameters('storageWitnessValue')]", + "attributes": { + "enabled": true + } + } + }, + { + "type": "microsoft.azurestackhci/clusters/deploymentSettings", + "apiVersion": "[parameters('apiVersion')]", + "name": "[format('{0}/default', parameters('clusterName'))]", + "dependsOn": [ + "[resourceId('Microsoft.AzureStackHCI/clusters', parameters('clusterName'))]" + ], + "properties": { + "arcNodeResourceIds": "[parameters('arcNodeResourceIds')]", + "deploymentMode": "[parameters('deploymentMode')]", + "deploymentConfiguration": { + "version": "10.0.0.0", + "scaleUnits": [ + { + "deploymentData": { + "securitySettings": { + "hvciProtection": true, + "drtmProtection": true, + "driftControlEnforced": "[parameters('driftControlEnforced')]", + "credentialGuardEnforced": "[parameters('credentialGuardEnforced')]", + "smbSigningEnforced": "[parameters('smbSigningEnforced')]", + "smbClusterEncryption": "[parameters('smbClusterEncryption')]", + "sideChannelMitigationEnforced": true, + "bitlockerBootVolume": "[parameters('bitlockerBootVolume')]", + "bitlockerDataVolumes": "[parameters('bitlockerDataVolumes')]", + "wdacEnforced": "[parameters('wdacEnforced')]" + }, + "observability": { + "streamingDataClient": "[parameters('streamingDataClient')]", + "euLocation": "[parameters('euLocation')]", + "episodicDataUpload": "[parameters('episodicDataUpload')]" + }, + "cluster": { + "name": "[parameters('clusterName')]", + "witnessType": "Cloud", + "witnessPath": "", + "cloudAccountName": "[parameters('ClusterWitnessStorageAccountName')]", + "azureServiceEndpoint": "core.windows.net" + }, + "storage": { + "configurationMode": "[parameters('configurationMode')]" + }, + "namingPrefix": "[parameters('namingPrefix')]", + "domainFqdn": "[parameters('domainFqdn')]", + "infrastructureNetwork": [ + { + "subnetMask": "[parameters('subnetMask')]", + "gateway": "[parameters('defaultGateway')]", + "ipPools": [ + { + "startingAddress": "[parameters('startingIPAddress')]", + "endingAddress": "[parameters('endingIPAddress')]" + } + ], + "dnsServers": "[parameters('dnsServers')]" + } + ], + "physicalNodes": "[parameters('physicalNodesSettings')]", + "hostNetwork": { + "intents": "[parameters('intentList')]", + "storageNetworks": "[parameters('storageNetworkList')]", + "storageConnectivitySwitchless": "[parameters('storageConnectivitySwitchless')]" + }, + "adouPath": "[parameters('adouPath')]", + "secretsLocation": "[parameters('secretsLocation')]", + "optionalServices": { + "customLocation": "[parameters('customLocation')]" + } + } + } + ] + } + } + } + ] +} \ No newline at end of file diff --git a/azure_jumpstart_hcibox/artifacts/hci.parameters.json b/azure_jumpstart_hcibox/artifacts/hci.parameters.json new file mode 100644 index 0000000000..49075bc318 --- /dev/null +++ b/azure_jumpstart_hcibox/artifacts/hci.parameters.json @@ -0,0 +1,153 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "apiVersion": { + "value": "2023-08-01-preview" + }, + "clusterName": { + "value": "clusterName-staging" + }, + "arcNodeResourceIds": { + "value": arcNodeResourceIds-staging + }, + "localAdminSecretValue": { + "value": "localAdminSecretValue-staging" + }, + "domainAdminSecretValue": { + "value": "domainAdminSecretValue-staging" + }, + "arbDeploymentSpnValue": { + "value": "arbDeploymentSpnValue-staging" + }, + "storageWitnessValue": { + "value": "storageWitnessValue-staging" + }, + "domainFqdn": { + "value": "domainFqdn-staging" + }, + "namingPrefix": { + "value": "namingPrefix-staging" + }, + "keyVaultName": { + "value": "keyVaultName-staging" + }, + "ClusterWitnessStorageAccountName": { + "value": "ClusterWitnessStorageAccountName-staging" + }, + "diagnosticStorageAccountName": { + "value": "diagnosticStorageAccountName-staging" + }, + "adouPath": { + "value": "adouPath-staging" + }, + "secretsLocation": { + "value": "secretsLocation-staging" + }, + "subnetMask": { + "value": "subnetMask-staging" + }, + "defaultGateway": { + "value": "defaultGateway-staging" + }, + "startingIPAddress": { + "value": "startingIp-staging" + }, + "endingIPAddress": { + "value": "endingIp-staging" + }, + "dnsServers": { + "value": dnsServers-staging + }, + "physicalNodesSettings": { + "value": physicalNodesSettings-staging + }, + "storageConnectivitySwitchless": { + "value": false + }, + "networkingPattern": { + "value": "convergedManagementCompute" + }, + "intentList": { + "value": [ + { + "name": "HCI", + "trafficType": [ + "Management", + "Compute" + ], + "adapter": [ + "FABRIC" + ], + "overrideVirtualSwitchConfiguration": false, + "virtualSwitchConfigurationOverrides": { + "enableIov": "", + "loadBalancingAlgorithm": "" + }, + "overrideQosPolicy": false, + "qosPolicyOverrides": { + "priorityValue8021Action_Cluster": "7", + "priorityValue8021Action_SMB": "3", + "bandwidthPercentage_SMB": "50" + }, + "overrideAdapterProperty": true, + "adapterPropertyOverrides": { + "jumboPacket": "9014", + "networkDirect": "Disabled", + "networkDirectTechnology": "RoCEv2" + } + }, + { + "name": "Storage", + "trafficType": [ + "Storage" + ], + "adapter": [ + "StorageA", + "StorageB" + ], + "overrideVirtualSwitchConfiguration": false, + "virtualSwitchConfigurationOverrides": { + "enableIov": "", + "loadBalancingAlgorithm": "" + }, + "overrideQosPolicy": false, + "qosPolicyOverrides": { + "priorityValue8021Action_Cluster": "7", + "priorityValue8021Action_SMB": "3", + "bandwidthPercentage_SMB": "50" + }, + "overrideAdapterProperty": true, + "adapterPropertyOverrides": { + "jumboPacket": "9014", + "networkDirect": "Disabled", + "networkDirectTechnology": "iWARP" + } + } + ] + }, + "storageNetworkList": { + "value": [ + { + "name": "StorageNetwork1", + "networkAdapterName": "StorageA", + "vlanId": "storageNicAVLAN-staging" + }, + { + "name": "StorageNetwork2", + "networkAdapterName": "StorageB", + "vlanId": "storageNicBVLAN-staging" + } + ] + }, + "networkingType": { + "value": "switchlessMultiServerDeployment" + }, + "customLocation": { + "value": "customLocation-staging" + }, + "deploymentMode": { + "value": "Validate" + } + } +} \ No newline at end of file diff --git a/azure_jumpstart_hcibox/bicep/host/host.bicep b/azure_jumpstart_hcibox/bicep/host/host.bicep index 48d5f7bb90..cdb17ed4e3 100644 --- a/azure_jumpstart_hcibox/bicep/host/host.bicep +++ b/azure_jumpstart_hcibox/bicep/host/host.bicep @@ -33,6 +33,9 @@ param spnClientSecret string @description('Tenant id of the service principal') param spnTenantId string +@description('Azure AD object id for your Microsoft.AzureStackHCI resource provider') +param spnProviderId string + @description('Name for the staging storage account using to hold kubeconfig. This value is passed into the template as an output from mgmtStagingStorage.json') param stagingStorageAccountName string @@ -246,9 +249,9 @@ resource vmBootstrap 'Microsoft.Compute/virtualMachines/extensions@2022-03-01' = autoUpgradeMinorVersion: true protectedSettings: { fileUris: [ - uri(templateBaseUrl, 'artifacts/Bootstrap.ps1') + uri(templateBaseUrl, 'artifacts/PowerShell/Bootstrap.ps1') ] - commandToExecute: 'powershell.exe -ExecutionPolicy Bypass -File Bootstrap.ps1 -adminUsername ${windowsAdminUsername} -adminPassword ${encodedPassword} -spnClientId ${spnClientId} -spnClientSecret ${spnClientSecret} -spnTenantId ${spnTenantId} -subscriptionId ${subscription().subscriptionId} -resourceGroup ${resourceGroup().name} -azureLocation ${location} -stagingStorageAccountName ${stagingStorageAccountName} -workspaceName ${workspaceName} -templateBaseUrl ${templateBaseUrl} -registerCluster ${registerCluster} -deployAKSHCI ${deployAKSHCI} -deployResourceBridge ${deployResourceBridge} -natDNS ${natDNS} -rdpPort ${rdpPort}' + commandToExecute: 'powershell.exe -ExecutionPolicy Bypass -File Bootstrap.ps1 -adminUsername ${windowsAdminUsername} -adminPassword ${encodedPassword} -spnClientId ${spnClientId} -spnClientSecret ${spnClientSecret} -spnTenantId ${spnTenantId} -subscriptionId ${subscription().subscriptionId} -spnProviderId ${spnProviderId} -resourceGroup ${resourceGroup().name} -azureLocation ${location} -stagingStorageAccountName ${stagingStorageAccountName} -workspaceName ${workspaceName} -templateBaseUrl ${templateBaseUrl} -registerCluster ${registerCluster} -deployAKSHCI ${deployAKSHCI} -deployResourceBridge ${deployResourceBridge} -natDNS ${natDNS} -rdpPort ${rdpPort}' } } } diff --git a/azure_jumpstart_hcibox/bicep/main.bicep b/azure_jumpstart_hcibox/bicep/main.bicep index 7b2dc1169f..0285c92b3d 100644 --- a/azure_jumpstart_hcibox/bicep/main.bicep +++ b/azure_jumpstart_hcibox/bicep/main.bicep @@ -8,6 +8,9 @@ param spnClientSecret string @description('Azure AD tenant id for your service principal') param spnTenantId string +@description('Azure AD object id for your Microsoft.AzureStackHCI resource provider') +param spnProviderId string + @description('Username for Windows account') param windowsAdminUsername string @@ -80,6 +83,7 @@ module hostDeployment 'host/host.bicep' = { spnClientId: spnClientId spnClientSecret: spnClientSecret spnTenantId: spnTenantId + spnProviderId: spnProviderId workspaceName: logAnalyticsWorkspaceName stagingStorageAccountName: storageAccountDeployment.outputs.storageAccountName templateBaseUrl: templateBaseUrl diff --git a/azure_jumpstart_hcibox/bicep/main.json b/azure_jumpstart_hcibox/bicep/main.json deleted file mode 100644 index 5837fd8c4c..0000000000 --- a/azure_jumpstart_hcibox/bicep/main.json +++ /dev/null @@ -1,1027 +0,0 @@ -{ - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.12.40.16777", - "templateHash": "5463622317411077072" - } - }, - "parameters": { - "spnClientId": { - "type": "string", - "metadata": { - "description": "Azure service principal client id" - } - }, - "spnClientSecret": { - "type": "secureString", - "metadata": { - "description": "Azure service principal client secret" - } - }, - "spnTenantId": { - "type": "string", - "metadata": { - "description": "Azure AD tenant id for your service principal" - } - }, - "windowsAdminUsername": { - "type": "string", - "metadata": { - "description": "Username for Windows account" - } - }, - "windowsAdminPassword": { - "type": "secureString", - "maxLength": 123, - "minLength": 12, - "metadata": { - "description": "Password for Windows account. Password must have 3 of the following: 1 lower case character, 1 upper case character, 1 number, and 1 special character. The value must be between 12 and 123 characters long" - } - }, - "logAnalyticsWorkspaceName": { - "type": "string", - "metadata": { - "description": "Name for your log analytics workspace" - } - }, - "registerCluster": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Option to disable automatic cluster registration. Setting this to false will also disable deploying AKS and Resource bridge" - } - }, - "deployAKSHCI": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Option to deploy AKS-HCI with HCIBox" - } - }, - "deployResourceBridge": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Option to deploy Resource Bridge with HCIBox" - } - }, - "natDNS": { - "type": "string", - "defaultValue": "8.8.8.8", - "metadata": { - "description": "Public DNS to use for the domain" - } - }, - "githubAccount": { - "type": "string", - "defaultValue": "microsoft", - "metadata": { - "description": "Target GitHub account" - } - }, - "githubBranch": { - "type": "string", - "defaultValue": "main", - "metadata": { - "description": "Target GitHub branch" - } - }, - "deployBastion": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Choice to deploy Bastion to connect to the client VM" - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Location to deploy resources" - } - } - }, - "variables": { - "templateBaseUrl": "[format('https://raw.githubusercontent.com/{0}/azure_arc/{1}/azure_jumpstart_hcibox/', parameters('githubAccount'), parameters('githubBranch'))]" - }, - "resources": [ - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2020-10-01", - "name": "mgmtArtifactsAndPolicyDeployment", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "workspaceName": { - "value": "[parameters('logAnalyticsWorkspaceName')]" - }, - "location": { - "value": "[parameters('location')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.12.40.16777", - "templateHash": "15958021173320564523" - } - }, - "parameters": { - "workspaceName": { - "type": "string", - "metadata": { - "description": "Name for your log analytics workspace" - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Azure Region to deploy the Log Analytics Workspace" - } - }, - "sku": { - "type": "string", - "defaultValue": "pergb2018", - "metadata": { - "description": "SKU, leave default pergb2018" - } - } - }, - "variables": { - "security": { - "name": "[format('Security({0})', parameters('workspaceName'))]", - "galleryName": "Security" - }, - "automationAccountName": "[format('HCIBox-Automation-{0}', uniqueString(resourceGroup().id))]", - "automationAccountLocation": "[if(equals(parameters('location'), 'eastus'), 'eastus2', if(equals(parameters('location'), 'eastus2'), 'eastus', parameters('location')))]" - }, - "resources": [ - { - "type": "Microsoft.OperationalInsights/workspaces", - "apiVersion": "2021-06-01", - "name": "[parameters('workspaceName')]", - "location": "[parameters('location')]", - "properties": { - "sku": { - "name": "[parameters('sku')]" - } - } - }, - { - "type": "Microsoft.OperationsManagement/solutions", - "apiVersion": "2015-11-01-preview", - "name": "[format('VMInsights({0})', split(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspaceName')), '/')[8])]", - "location": "[parameters('location')]", - "properties": { - "workspaceResourceId": "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspaceName'))]" - }, - "plan": { - "name": "[format('VMInsights({0})', split(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspaceName')), '/')[8])]", - "product": "OMSGallery/VMInsights", - "promotionCode": "", - "publisher": "Microsoft" - }, - "dependsOn": [ - "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspaceName'))]" - ] - }, - { - "type": "Microsoft.OperationsManagement/solutions", - "apiVersion": "2015-11-01-preview", - "name": "[variables('security').name]", - "location": "[parameters('location')]", - "properties": { - "workspaceResourceId": "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspaceName'))]" - }, - "plan": { - "name": "[variables('security').name]", - "promotionCode": "", - "product": "[format('OMSGallery/{0}', variables('security').galleryName)]", - "publisher": "Microsoft" - }, - "dependsOn": [ - "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspaceName'))]" - ] - }, - { - "type": "Microsoft.Automation/automationAccounts", - "apiVersion": "2021-06-22", - "name": "[variables('automationAccountName')]", - "location": "[variables('automationAccountLocation')]", - "properties": { - "sku": { - "name": "Basic" - } - }, - "dependsOn": [ - "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspaceName'))]" - ] - }, - { - "type": "Microsoft.OperationalInsights/workspaces/linkedServices", - "apiVersion": "2020-08-01", - "name": "[format('{0}/{1}', parameters('workspaceName'), 'Automation')]", - "properties": { - "resourceId": "[resourceId('Microsoft.Automation/automationAccounts', variables('automationAccountName'))]" - }, - "dependsOn": [ - "[resourceId('Microsoft.Automation/automationAccounts', variables('automationAccountName'))]", - "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspaceName'))]" - ] - } - ] - } - } - }, - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2020-10-01", - "name": "networkDeployment", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "deployBastion": { - "value": "[parameters('deployBastion')]" - }, - "location": { - "value": "[parameters('location')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.12.40.16777", - "templateHash": "12002154451255072834" - } - }, - "parameters": { - "virtualNetworkName": { - "type": "string", - "defaultValue": "HCIBox-VNet", - "metadata": { - "description": "Name of the VNet" - } - }, - "subnetName": { - "type": "string", - "defaultValue": "HCIBox-Subnet", - "metadata": { - "description": "Name of the subnet in the virtual network" - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Azure Region to deploy the Log Analytics Workspace" - } - }, - "deployBastion": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Choice to deploy Bastion to connect to the client VM" - } - }, - "networkSecurityGroupName": { - "type": "string", - "defaultValue": "HCIBox-NSG", - "metadata": { - "description": "Name of the Network Security Group" - } - }, - "bastionNetworkSecurityGroupName": { - "type": "string", - "defaultValue": "HCIBox-Bastion-NSG", - "metadata": { - "description": "Name of the Bastion Network Security Group" - } - } - }, - "variables": { - "addressPrefix": "172.16.0.0/16", - "subnetAddressPrefix": "172.16.1.0/24", - "bastionSubnetName": "AzureBastionSubnet", - "bastionSubnetRef": "[format('{0}/subnets/{1}', resourceId('Microsoft.Network/virtualNetworks', parameters('virtualNetworkName')), variables('bastionSubnetName'))]", - "bastionName": "HCIBox-Bastion", - "bastionSubnetIpPrefix": "172.16.3.64/26", - "bastionPublicIpAddressName": "[format('{0}-PIP', variables('bastionName'))]" - }, - "resources": [ - { - "type": "Microsoft.Network/virtualNetworks", - "apiVersion": "2021-03-01", - "name": "[parameters('virtualNetworkName')]", - "location": "[parameters('location')]", - "properties": { - "addressSpace": { - "addressPrefixes": [ - "[variables('addressPrefix')]" - ] - }, - "subnets": "[if(equals(parameters('deployBastion'), true()), createArray(createObject('name', parameters('subnetName'), 'properties', createObject('addressPrefix', variables('subnetAddressPrefix'), 'privateEndpointNetworkPolicies', 'Enabled', 'privateLinkServiceNetworkPolicies', 'Enabled', 'networkSecurityGroup', createObject('id', resourceId('Microsoft.Network/networkSecurityGroups', parameters('networkSecurityGroupName'))))), createObject('name', 'AzureBastionSubnet', 'properties', createObject('addressPrefix', variables('bastionSubnetIpPrefix'), 'networkSecurityGroup', createObject('id', resourceId('Microsoft.Network/networkSecurityGroups', parameters('bastionNetworkSecurityGroupName')))))), createArray(createObject('name', parameters('subnetName'), 'properties', createObject('addressPrefix', variables('subnetAddressPrefix'), 'privateEndpointNetworkPolicies', 'Enabled', 'privateLinkServiceNetworkPolicies', 'Enabled', 'networkSecurityGroup', createObject('id', resourceId('Microsoft.Network/networkSecurityGroups', parameters('networkSecurityGroupName')))))))]" - }, - "dependsOn": [ - "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('bastionNetworkSecurityGroupName'))]", - "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('networkSecurityGroupName'))]" - ] - }, - { - "type": "Microsoft.Network/networkSecurityGroups", - "apiVersion": "2021-03-01", - "name": "[parameters('networkSecurityGroupName')]", - "location": "[parameters('location')]", - "properties": { - "securityRules": [] - } - }, - { - "condition": "[equals(parameters('deployBastion'), true())]", - "type": "Microsoft.Network/networkSecurityGroups", - "apiVersion": "2021-05-01", - "name": "[parameters('bastionNetworkSecurityGroupName')]", - "location": "[parameters('location')]", - "properties": { - "securityRules": [ - { - "name": "bastion_allow_https_inbound", - "properties": { - "priority": 1010, - "protocol": "Tcp", - "access": "Allow", - "direction": "Inbound", - "sourceAddressPrefix": "Internet", - "sourcePortRange": "*", - "destinationAddressPrefix": "*", - "destinationPortRange": "443" - } - }, - { - "name": "bastion_allow_gateway_manager_inbound", - "properties": { - "priority": 1011, - "protocol": "Tcp", - "access": "Allow", - "direction": "Inbound", - "sourceAddressPrefix": "GatewayManager", - "sourcePortRange": "*", - "destinationAddressPrefix": "*", - "destinationPortRange": "443" - } - }, - { - "name": "bastion_allow_load_balancer_inbound", - "properties": { - "priority": 1012, - "protocol": "Tcp", - "access": "Allow", - "direction": "Inbound", - "sourceAddressPrefix": "AzureLoadBalancer", - "sourcePortRange": "*", - "destinationAddressPrefix": "*", - "destinationPortRange": "443" - } - }, - { - "name": "bastion_allow_host_comms", - "properties": { - "priority": 1013, - "protocol": "*", - "access": "Allow", - "direction": "Inbound", - "sourceAddressPrefix": "VirtualNetwork", - "sourcePortRange": "*", - "destinationAddressPrefix": "VirtualNetwork", - "destinationPortRanges": [ - "8080", - "5701" - ] - } - }, - { - "name": "bastion_allow_ssh_rdp_outbound", - "properties": { - "priority": 1014, - "protocol": "*", - "access": "Allow", - "direction": "Outbound", - "sourceAddressPrefix": "*", - "sourcePortRange": "*", - "destinationAddressPrefix": "VirtualNetwork", - "destinationPortRanges": [ - "22", - "3389" - ] - } - }, - { - "name": "bastion_allow_azure_cloud_outbound", - "properties": { - "priority": 1015, - "protocol": "Tcp", - "access": "Allow", - "direction": "Outbound", - "sourceAddressPrefix": "*", - "sourcePortRange": "*", - "destinationAddressPrefix": "AzureCloud", - "destinationPortRange": "443" - } - }, - { - "name": "bastion_allow_bastion_comms", - "properties": { - "priority": 1016, - "protocol": "*", - "access": "Allow", - "direction": "Outbound", - "sourceAddressPrefix": "VirtualNetwork", - "sourcePortRange": "*", - "destinationAddressPrefix": "VirtualNetwork", - "destinationPortRanges": [ - "8080", - "5701" - ] - } - }, - { - "name": "bastion_allow_get_session_info", - "properties": { - "priority": 1017, - "protocol": "*", - "access": "Allow", - "direction": "Outbound", - "sourceAddressPrefix": "*", - "sourcePortRange": "*", - "destinationAddressPrefix": "Internet", - "destinationPortRanges": [ - "80", - "443" - ] - } - } - ] - } - }, - { - "condition": "[equals(parameters('deployBastion'), true())]", - "type": "Microsoft.Network/publicIPAddresses", - "apiVersion": "2021-05-01", - "name": "[variables('bastionPublicIpAddressName')]", - "location": "[parameters('location')]", - "properties": { - "publicIPAllocationMethod": "Static", - "publicIPAddressVersion": "IPv4", - "idleTimeoutInMinutes": 4 - }, - "sku": { - "name": "Standard" - } - }, - { - "condition": "[equals(parameters('deployBastion'), true())]", - "type": "Microsoft.Network/bastionHosts", - "apiVersion": "2021-05-01", - "name": "[variables('bastionName')]", - "location": "[parameters('location')]", - "properties": { - "ipConfigurations": [ - { - "name": "IpConf", - "properties": { - "publicIPAddress": { - "id": "[resourceId('Microsoft.Network/publicIPAddresses', variables('bastionPublicIpAddressName'))]" - }, - "subnet": { - "id": "[variables('bastionSubnetRef')]" - } - } - } - ] - }, - "dependsOn": [ - "[resourceId('Microsoft.Network/virtualNetworks', parameters('virtualNetworkName'))]", - "[resourceId('Microsoft.Network/publicIPAddresses', variables('bastionPublicIpAddressName'))]" - ] - } - ], - "outputs": { - "vnetId": { - "type": "string", - "value": "[resourceId('Microsoft.Network/virtualNetworks', parameters('virtualNetworkName'))]" - }, - "subnetId": { - "type": "string", - "value": "[reference(resourceId('Microsoft.Network/virtualNetworks', parameters('virtualNetworkName')), '2021-03-01').subnets[0].id]" - } - } - } - } - }, - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2020-10-01", - "name": "stagingStorageAccountDeployment", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "location": { - "value": "[parameters('location')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.12.40.16777", - "templateHash": "8234938478342075972" - } - }, - "parameters": { - "storageAccountType": { - "type": "string", - "defaultValue": "Standard_LRS", - "allowedValues": [ - "Standard_LRS", - "Standard_GRS", - "Standard_ZRS", - "Premium_LRS" - ], - "metadata": { - "description": "Storage Account type" - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Location for all resources." - } - } - }, - "variables": { - "storageAccountName": "[format('hcibox{0}', uniqueString(resourceGroup().id))]" - }, - "resources": [ - { - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2021-06-01", - "name": "[variables('storageAccountName')]", - "location": "[parameters('location')]", - "sku": { - "name": "[parameters('storageAccountType')]" - }, - "kind": "StorageV2", - "properties": { - "supportsHttpsTrafficOnly": true - } - } - ], - "outputs": { - "storageAccountName": { - "type": "string", - "value": "[variables('storageAccountName')]" - } - } - } - } - }, - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2020-10-01", - "name": "hostVmDeployment", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "windowsAdminUsername": { - "value": "[parameters('windowsAdminUsername')]" - }, - "windowsAdminPassword": { - "value": "[parameters('windowsAdminPassword')]" - }, - "spnClientId": { - "value": "[parameters('spnClientId')]" - }, - "spnClientSecret": { - "value": "[parameters('spnClientSecret')]" - }, - "spnTenantId": { - "value": "[parameters('spnTenantId')]" - }, - "workspaceName": { - "value": "[parameters('logAnalyticsWorkspaceName')]" - }, - "stagingStorageAccountName": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', 'stagingStorageAccountDeployment'), '2020-10-01').outputs.storageAccountName.value]" - }, - "templateBaseUrl": { - "value": "[variables('templateBaseUrl')]" - }, - "subnetId": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', 'networkDeployment'), '2020-10-01').outputs.subnetId.value]" - }, - "deployBastion": { - "value": "[parameters('deployBastion')]" - }, - "registerCluster": { - "value": "[parameters('registerCluster')]" - }, - "deployAKSHCI": { - "value": "[parameters('deployAKSHCI')]" - }, - "deployResourceBridge": { - "value": "[parameters('deployResourceBridge')]" - }, - "natDNS": { - "value": "[parameters('natDNS')]" - }, - "location": { - "value": "[parameters('location')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.12.40.16777", - "templateHash": "7350178746438702927" - } - }, - "parameters": { - "vmName": { - "type": "string", - "defaultValue": "HCIBox-Client", - "metadata": { - "description": "The name of your Virtual Machine" - } - }, - "windowsAdminUsername": { - "type": "string", - "defaultValue": "arcdemo", - "metadata": { - "description": "Username for the Virtual Machine" - } - }, - "windowsAdminPassword": { - "type": "secureString", - "maxLength": 123, - "minLength": 12, - "metadata": { - "description": "Password for Windows account. Password must have 3 of the following: 1 lower case character, 1 upper case character, 1 number, and 1 special character. The value must be between 12 and 123 characters long" - } - }, - "windowsOSVersion": { - "type": "string", - "defaultValue": "2022-datacenter-g2", - "metadata": { - "description": "The Windows version for the VM. This will pick a fully patched image of this given Windows version" - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Location for all resources" - } - }, - "subnetId": { - "type": "string", - "metadata": { - "description": "Resource Id of the subnet in the virtual network" - } - }, - "resourceTags": { - "type": "object", - "defaultValue": { - "Project": "jumpstart_HCIBox" - } - }, - "spnClientId": { - "type": "string", - "metadata": { - "description": "Client id of the service principal" - } - }, - "spnClientSecret": { - "type": "secureString", - "metadata": { - "description": "Client secret of the service principal" - } - }, - "spnTenantId": { - "type": "string", - "metadata": { - "description": "Tenant id of the service principal" - } - }, - "stagingStorageAccountName": { - "type": "string", - "metadata": { - "description": "Name for the staging storage account using to hold kubeconfig. This value is passed into the template as an output from mgmtStagingStorage.json" - } - }, - "workspaceName": { - "type": "string", - "metadata": { - "description": "Name for the environment Azure Log Analytics workspace" - } - }, - "templateBaseUrl": { - "type": "string", - "metadata": { - "description": "The base URL used for accessing artifacts and automation artifacts." - } - }, - "registerCluster": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Option to disable automatic cluster registration. Setting this to false will also disable deploying AKS and Resource bridge" - } - }, - "deployBastion": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Choice to deploy Bastion to connect to the client VM" - } - }, - "deployAKSHCI": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Option to deploy AKS-HCI with HCIBox" - } - }, - "deployResourceBridge": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Option to deploy Resource Bridge with HCIBox" - } - }, - "natDNS": { - "type": "string", - "defaultValue": "8.8.8.8", - "metadata": { - "description": "Public DNS to use for the domain" - } - } - }, - "variables": { - "encodedPassword": "[base64(parameters('windowsAdminPassword'))]", - "bastionName": "HCIBox-Bastion", - "publicIpAddressName": "[if(equals(parameters('deployBastion'), false()), format('{0}-PIP', parameters('vmName')), format('{0}-PIP', variables('bastionName')))]", - "networkInterfaceName": "[format('{0}-NIC', parameters('vmName'))]", - "osDiskType": "Premium_LRS", - "PublicIPNoBastion": { - "id": "[resourceId('Microsoft.Network/publicIPAddresses', variables('publicIpAddressName'))]" - } - }, - "resources": [ - { - "type": "Microsoft.Network/networkInterfaces", - "apiVersion": "2021-03-01", - "name": "[variables('networkInterfaceName')]", - "location": "[parameters('location')]", - "properties": { - "ipConfigurations": [ - { - "name": "ipconfig1", - "properties": { - "subnet": { - "id": "[parameters('subnetId')]" - }, - "privateIPAllocationMethod": "Dynamic", - "publicIPAddress": "[if(equals(parameters('deployBastion'), false()), variables('PublicIPNoBastion'), json('null'))]" - } - } - ] - }, - "dependsOn": [ - "[resourceId('Microsoft.Network/publicIPAddresses', variables('publicIpAddressName'))]" - ] - }, - { - "condition": "[equals(parameters('deployBastion'), false())]", - "type": "Microsoft.Network/publicIPAddresses", - "apiVersion": "2021-03-01", - "name": "[variables('publicIpAddressName')]", - "location": "[parameters('location')]", - "properties": { - "publicIPAllocationMethod": "Static", - "publicIPAddressVersion": "IPv4", - "idleTimeoutInMinutes": 4 - }, - "sku": { - "name": "Basic" - } - }, - { - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2022-03-01", - "name": "[parameters('vmName')]", - "location": "[parameters('location')]", - "tags": "[parameters('resourceTags')]", - "properties": { - "hardwareProfile": { - "vmSize": "Standard_D48s_v5" - }, - "storageProfile": { - "osDisk": { - "name": "[format('{0}-OSDisk', parameters('vmName'))]", - "caching": "ReadWrite", - "createOption": "FromImage", - "managedDisk": { - "storageAccountType": "[variables('osDiskType')]" - }, - "diskSizeGB": 1024 - }, - "imageReference": { - "publisher": "MicrosoftWindowsServer", - "offer": "WindowsServer", - "sku": "[parameters('windowsOSVersion')]", - "version": "latest" - }, - "dataDisks": [ - { - "name": "ASHCIHost001_DataDisk_0", - "diskSizeGB": 256, - "createOption": "Empty", - "lun": 0, - "caching": "None", - "writeAcceleratorEnabled": false, - "managedDisk": { - "storageAccountType": "Premium_LRS" - } - }, - { - "name": "ASHCIHost001_DataDisk_1", - "diskSizeGB": 256, - "createOption": "Empty", - "lun": 1, - "caching": "None", - "writeAcceleratorEnabled": false, - "managedDisk": { - "storageAccountType": "Premium_LRS" - } - }, - { - "name": "ASHCIHost001_DataDisk_2", - "diskSizeGB": 256, - "createOption": "Empty", - "lun": 2, - "caching": "None", - "writeAcceleratorEnabled": false, - "managedDisk": { - "storageAccountType": "Premium_LRS" - } - }, - { - "name": "ASHCIHost001_DataDisk_3", - "diskSizeGB": 256, - "createOption": "Empty", - "lun": 3, - "caching": "None", - "writeAcceleratorEnabled": false, - "managedDisk": { - "storageAccountType": "Premium_LRS" - } - }, - { - "name": "ASHCIHost001_DataDisk_4", - "diskSizeGB": 256, - "createOption": "Empty", - "lun": 4, - "caching": "None", - "writeAcceleratorEnabled": false, - "managedDisk": { - "storageAccountType": "Premium_LRS" - } - }, - { - "name": "ASHCIHost001_DataDisk_5", - "diskSizeGB": 256, - "createOption": "Empty", - "lun": 5, - "caching": "None", - "writeAcceleratorEnabled": false, - "managedDisk": { - "storageAccountType": "Premium_LRS" - } - }, - { - "name": "ASHCIHost001_DataDisk_6", - "diskSizeGB": 256, - "createOption": "Empty", - "lun": 6, - "caching": "None", - "writeAcceleratorEnabled": false, - "managedDisk": { - "storageAccountType": "Premium_LRS" - } - }, - { - "name": "ASHCIHost001_DataDisk_7", - "diskSizeGB": 256, - "createOption": "Empty", - "lun": 7, - "caching": "None", - "writeAcceleratorEnabled": false, - "managedDisk": { - "storageAccountType": "Premium_LRS" - } - } - ] - }, - "networkProfile": { - "networkInterfaces": [ - { - "id": "[resourceId('Microsoft.Network/networkInterfaces', variables('networkInterfaceName'))]" - } - ] - }, - "osProfile": { - "computerName": "[parameters('vmName')]", - "adminUsername": "[parameters('windowsAdminUsername')]", - "adminPassword": "[parameters('windowsAdminPassword')]", - "windowsConfiguration": { - "provisionVMAgent": true, - "enableAutomaticUpdates": false - } - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Network/networkInterfaces', variables('networkInterfaceName'))]" - ] - }, - { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2022-03-01", - "name": "[format('{0}/{1}', parameters('vmName'), 'Bootstrap')]", - "location": "[parameters('location')]", - "properties": { - "publisher": "Microsoft.Compute", - "type": "CustomScriptExtension", - "typeHandlerVersion": "1.10", - "autoUpgradeMinorVersion": true, - "settings": { - "fileUris": [ - "[uri(parameters('templateBaseUrl'), 'artifacts/Bootstrap.ps1')]" - ], - "commandToExecute": "[format('powershell.exe -ExecutionPolicy Bypass -File Bootstrap.ps1 -adminUsername {0} -adminPassword {1} -spnClientId {2} -spnClientSecret {3} -spnTenantId {4} -subscriptionId {5} -resourceGroup {6} -azureLocation {7} -stagingStorageAccountName {8} -workspaceName {9} -templateBaseUrl {10} -registerCluster {11} -deployAKSHCI {12} -deployResourceBridge {13} -natDNS {14}', parameters('windowsAdminUsername'), variables('encodedPassword'), parameters('spnClientId'), parameters('spnClientSecret'), parameters('spnTenantId'), subscription().subscriptionId, resourceGroup().name, parameters('location'), parameters('stagingStorageAccountName'), parameters('workspaceName'), parameters('templateBaseUrl'), parameters('registerCluster'), parameters('deployAKSHCI'), parameters('deployResourceBridge'), parameters('natDNS'))]" - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Compute/virtualMachines', parameters('vmName'))]" - ] - } - ], - "outputs": { - "adminUsername": { - "type": "string", - "value": "[parameters('windowsAdminUsername')]" - }, - "publicIP": { - "type": "string", - "value": "[if(equals(parameters('deployBastion'), false()), concat(reference(resourceId('Microsoft.Network/publicIPAddresses', variables('publicIpAddressName')), '2021-03-01').ipAddress), '')]" - }, - "base64Output": { - "type": "string", - "value": "[variables('encodedPassword')]" - } - } - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', 'networkDeployment')]", - "[resourceId('Microsoft.Resources/deployments', 'stagingStorageAccountDeployment')]" - ] - } - ] -} \ No newline at end of file diff --git a/azure_jumpstart_hcibox/bicep/main.parameters.json b/azure_jumpstart_hcibox/bicep/main.parameters.json index 4f90587caf..10f46a1390 100644 --- a/azure_jumpstart_hcibox/bicep/main.parameters.json +++ b/azure_jumpstart_hcibox/bicep/main.parameters.json @@ -11,6 +11,9 @@ "spnTenantId": { "value": "<your service principal tenant id>" }, + "spnProviderId": { + "value": "<your Microsoft.AzureStackHCI resource provider object id" + }, "windowsAdminUsername": { "value": "arcdemo" }, From b122ec65affbee2500d31581d843c172f8214d5b Mon Sep 17 00:00:00 2001 From: saitcho <saitcho@outlook.com> Date: Fri, 19 Jan 2024 14:23:47 -0600 Subject: [PATCH 02/45] azd and log output --- .../PowerShell/New-HCIBoxCluster.ps1 | 136 ++---------------- azure_jumpstart_hcibox/bicep/main.azd.bicep | 9 -- .../bicep/main.azd.parameters.json | 11 +- azure_jumpstart_hcibox/bicep/main.bicep | 9 -- .../bicep/main.parameters.json | 9 -- 5 files changed, 12 insertions(+), 162 deletions(-) diff --git a/azure_jumpstart_hcibox/artifacts/PowerShell/New-HCIBoxCluster.ps1 b/azure_jumpstart_hcibox/artifacts/PowerShell/New-HCIBoxCluster.ps1 index eb5ffa49ba..15ee21dd32 100644 --- a/azure_jumpstart_hcibox/artifacts/PowerShell/New-HCIBoxCluster.ps1 +++ b/azure_jumpstart_hcibox/artifacts/PowerShell/New-HCIBoxCluster.ps1 @@ -1390,113 +1390,6 @@ CertificateTemplate= WebServer } } -function New-HyperConvergedEnvironment { - Param ( - $HCIBoxConfig, - [PSCredential]$domainCred - ) - Invoke-Command -ComputerName $HCIBoxConfig.DCName -Credential $domainCred -ScriptBlock { - $HCIBoxConfig = $using:HCIBoxConfig - $domainCred = $using:domainCred - $localCred = $using:localCred - foreach ($AzSHOST in $HCIBoxConfig.NodeHostConfig) { - Invoke-Command -ComputerName $AzSHOST.Hostname -ArgumentList $AzSHOST, $HCIBoxConfig -Credential $domainCred -ScriptBlock { - $AzSHOST = $args[0] - $HCIBoxconfig = $args[1] - # Check if switch exists already - $switchCheck = Get-VMSwitch | Where-Object { $_.Name -eq $HCIBoxConfig.ClusterVSwitchName } - if ($switchCheck) { - Write-Host "Switch already exists on $env:COMPUTERNAME. Skipping this host." - } - else { - Write-Host "Setting IP Configuration on $($HCIBoxConfig.ClusterVSwitchName) on host $($AzSHOST.Hostname)" - $switchTeamMembers = @("FABRIC", "FABRIC2") - New-VMSwitch -Name $HCIBoxConfig.ClusterVSwitchName -AllowManagementOS $true -NetAdapterName $switchTeamMembers -EnableEmbeddedTeaming $true -MinimumBandwidthMode "Weight" - - Write-Host "Setting IP Configuration on $($HCIBoxConfig.ClusterVSwitchName) on host $($AzSHOST.Hostname)" - $switchNIC = Get-Netadapter | Where-Object { $_.Name -match $HCIBoxConfig.ClusterVSwitchName } - New-NetIPAddress -InterfaceIndex $switchNIC.InterfaceIndex -IpAddress $AzSHOST.IP.Split('/')[0] -PrefixLength 24 -AddressFamily 'IpV4' -DefaultGateway $HCIBoxConfig.BGPRouterIP_MGMT -ErrorAction 'SilentlyContinue' - - Write-Host "Setting DNS configuration on $($HCIBoxConfig.ClusterVSwitchName) on host $($AzSHOST.Hostname)" - Set-DnsClientServerAddress -InterfaceIndex $switchNIC.InterfaceIndex -ServerAddresses $HCIBoxConfig.SDNLABDNS - - Write-Host "Setting vSwitch adapter VLAN $($HCIBoxConfig.mgmtVLAN) on host $($AzSHOST.Hostname)" - Set-VMNetworkAdapterIsolation -IsolationMode 'Vlan' -DefaultIsolationID $HCIBoxConfig.mgmtVLAN -AllowUntaggedTraffic $true -VMNetworkAdapterName $($HCIBoxConfig.ClusterVSwitchName) -ManagementOS - Get-VMSwitchExtension -VMSwitchName $($HCIBoxConfig.ClusterVSwitchName) | Disable-VMSwitchExtension | Out-Null - - Write-Host "Configuring MTU on all adapters on $($AzSHOST.Hostname)" - Get-NetAdapter | Where-Object { $_.Status -eq "Up" } | Set-NetAdapterAdvancedProperty -RegistryValue $HCIBoxConfig.SDNLABMTU -RegistryKeyword "*JumboPacket" - } - } - Start-Sleep -Seconds 60 - } - # Reboot all HCI nodes - foreach ($AzSHOST in $HCIBoxConfig.NodeHostConfig) { - Write-Host "Rebooting HCIBox host $($AzSHOST.Hostname)" - Restart-Computer $AzSHOST.Hostname -Force -Confirm:$false -Credential $domainCred -Protocol WSMan - Start-Sleep -Seconds 10 - Write-Host "Checking to see if $($AzSHOST.Hostname) is up and online" - while ((Invoke-Command -ComputerName $AzSHOST.Hostname -Credential $domainCred { "Test" } -ea SilentlyContinue) -ne "Test") { Start-Sleep -Seconds 10 } - Write-Host "$($AzSHOST.Hostname) is up and online" - } - } -} - -function New-S2DCluster { - param ( - $HCIBoxConfig, - [PSCredential]$domainCred - ) - Invoke-Command -ComputerName $HCIBoxConfig.NodeHostConfig[0].Hostname -Credential $domainCred -ArgumentList $HCIBoxConfig, $domainCred -ScriptBlock { - $HCIBoxConfig = $args[0] - $domainCred = $args[1] - - Import-Module FailoverClusters - Import-Module Storage - $nodes = @() - foreach ($node in $HCIBoxConfig.NodeHostConfig) { - $nodes += $node.Hostname - } - Write-Host "Creating cluster $($HCIBoxConfig.ClusterName) from nodes: $nodes" - Register-PSSessionConfiguration -Name Microsoft.HCIBoxS2D -RunAsCredential $domainCred -MaximumReceivedDataSizePerCommandMB 1000 -MaximumReceivedObjectSizeMB 1000 -WarningAction SilentlyContinue | Out-Null - - Invoke-Command -ComputerName $HCIBoxConfig.NodeHostConfig[0].Hostname -Credential $domainCred -ArgumentList $HCIBoxConfig, $nodes -ConfigurationName Microsoft.HCIBoxS2D -ScriptBlock { - $HCIBoxConfig = $args[0] - $nodes = $args[1] - $ClusterIP = ($HCIBoxConfig.MGMTSubnet.TrimEnd("0/24")) + "252" - - New-Cluster -Name $HCIBoxConfig.ClusterName -Node $nodes -StaticAddress $ClusterIP -NoStorage - Enable-ClusterS2D -Confirm:$false -Verbose - while (!$PerfHistory) { - Write-Host "Waiting for Cluster Performance History volume to come online." - Start-Sleep -Seconds 10 - $PerfHistory = Get-ClusterResource | Where-Object {$_.Name -match 'ClusterPerformanceHistory'} - if ($PerfHistory) { - Write-Host "Cluster Perfomance History volume online." - } - } - - Write-Host "Configuring S2D" - Get-PhysicalDisk | Where-Object { $_.Size -lt 127GB } | Set-PhysicalDisk -MediaType HDD | Out-Null - Start-Sleep -Seconds 10 - New-Volume -FriendlyName "S2D_vDISK1" -FileSystem 'CSVFS_ReFS' -StoragePoolFriendlyName "S2D on $($HCIBoxConfig.ClusterName)" -ResiliencySettingName 'Mirror' -PhysicalDiskRedundancy 1 -AllocationUnitSize 64KB -UseMaximumSize - Get-StorageSubsystem clus* | Set-StorageHealthSetting -name “System.Storage.PhysicalDisk.AutoReplace.Enabled” -value “False” - Set-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Services\spaceport\Parameters -Name HwTimeout -Value 0x00007530 - - Write-Host "Renaming Storage network adapters" - (Get-Cluster -Name $HCIBoxConfig.ClusterName | Get-ClusterNetwork | Where-Object { $_.Address -eq ($HCIBoxConfig.storageAsubnet.Replace('/24', '')) }).Name = 'StorageA' - (Get-Cluster -Name $HCIBoxConfig.ClusterName | Get-ClusterNetwork | Where-Object { $_.Address -eq ($HCIBoxConfig.storageBsubnet.Replace('/24', '')) }).Name = 'StorageB' - (Get-Cluster -Name $HCIBoxConfig.ClusterName | Get-ClusterNetwork | Where-Object { $_.Address -eq ($HCIBoxConfig.MGMTSubnet.Replace('/24', '')) }).Name = 'Public' - - Write-Host "Setting allowed networks for Live Migration" - Get-ClusterResourceType -Name "Virtual Machine" -Cluster $HCIBoxConfig.ClusterName | ` - Set-ClusterParameter -Cluster $HCIBoxConfig.ClusterName -Name MigrationExcludeNetworks -Value ` - ([String]::Join(";", (Get-ClusterNetwork -Cluster $HCIBoxConfig.ClusterName | ` - Where-Object { $_.Name -notmatch "Storage" }).ID)) - } - } -} - function Test-InternetConnect { $testIP = $HCIBoxConfig.natDNS $ErrorActionPreference = "Stop" @@ -1626,7 +1519,7 @@ foreach ($path in $HCIBoxConfig.Paths.GetEnumerator()) { } # Download HCIBox VHDs -Write-Host "[Build cluster - Step 1/12] Downloading HCIBox VHDs. This will take a while..." -ForegroundColor Green +Write-Host "[Build cluster - Step 1/10] Downloading HCIBox VHDs. This will take a while..." -ForegroundColor Green BITSRequest -Params @{'Uri'='https://aka.ms/AAnn1dd'; 'Filename'="$($HCIBoxConfig.Paths.VHDDir)\AZSHCI.vhdx" } BITSRequest -Params @{'Uri'='https://jsvhds.blob.core.windows.net/hcibox23h2/AZSHCI.sha256?sp=r&st=2024-01-16T15:09:53Z&se=2027-01-16T23:09:53Z&spr=https&sv=2022-11-02&sr=b&sig=fM6nSGOUHIB90egY95Oc02NfXxFmh8fPK0bnibjAdQU%3D'; 'Filename'="$($HCIBoxConfig.Paths.VHDDir)\AZSHCI.sha256" } $checksum = Get-FileHash -Path "$($HCIBoxConfig.Paths.VHDDir)\AZSHCI.vhdx" @@ -1661,7 +1554,7 @@ $domainCred = new-object -typename System.Management.Automation.PSCredential ` -argumentlist (($HCIBoxConfig.SDNDomainFQDN.Split(".")[0]) +"\Administrator"), (ConvertTo-SecureString $HCIBoxConfig.SDNAdminPassword -AsPlainText -Force) # Enable PSRemoting -Write-Host "[Build cluster - Step 2/12] Preparing Azure VM virtualization host..." -ForegroundColor Green +Write-Host "[Build cluster - Step 2/10] Preparing Azure VM virtualization host..." -ForegroundColor Green Write-Host "Enabling PS Remoting on client..." Enable-PSRemoting Set-Item WSMan:\localhost\Client\TrustedHosts * -Confirm:$false -Force @@ -1691,19 +1584,19 @@ Copy-Item -Path $HCIBoxConfig.azSHCIVHDXPath -Destination $hcipath -Force | Out- # Create the three nested Virtual Machines ################################################################################ # First create the Management VM (AzSMGMT) -Write-Host "[Build cluster - Step 3/12] Creating Management VM (AzSMGMT)..." -ForegroundColor Green +Write-Host "[Build cluster - Step 3/10] Creating Management VM (AzSMGMT)..." -ForegroundColor Green $mgmtMac = New-ManagementVM -Name $($HCIBoxConfig.MgmtHostConfig.Hostname) -VHDXPath "$HostVMPath\GUI.vhdx" -VMSwitch $InternalSwitch -HCIBoxConfig $HCIBoxConfig Set-MGMTVHDX -VMMac $mgmtMac -HCIBoxConfig $HCIBoxConfig # Create the HCI host node VMs -Write-Host "[Build cluster - Step 4/12] Creating HCI node VMs (AzSHOSTx)..." -ForegroundColor Green +Write-Host "[Build cluster - Step 4/10] Creating HCI node VMs (AzSHOSTx)..." -ForegroundColor Green foreach ($VM in $HCIBoxConfig.NodeHostConfig) { $mac = New-HCINodeVM -Name $VM.Hostname -VHDXPath $hcipath -VMSwitch $InternalSwitch -HCIBoxConfig $HCIBoxConfig Set-HCINodeVHDX -HostName $VM.Hostname -IPAddress $VM.IP -VMMac $mac -HCIBoxConfig $HCIBoxConfig } # Start Virtual Machines -Write-Host "[Build cluster - Step 5/12] Starting VMs..." -ForegroundColor Green +Write-Host "[Build cluster - Step 5/10] Starting VMs..." -ForegroundColor Green Write-Host "Starting VM: $($HCIBoxConfig.MgmtHostConfig.Hostname)" Start-VM -Name $HCIBoxConfig.MgmtHostConfig.Hostname foreach ($VM in $HCIBoxConfig.NodeHostConfig) { @@ -1714,7 +1607,7 @@ foreach ($VM in $HCIBoxConfig.NodeHostConfig) { ####################################################################################### # Prep the virtualization environment ####################################################################################### -Write-Host "[Build cluster - Step 6/12] Configuring host environment..." -ForegroundColor Green +Write-Host "[Build cluster - Step 6/10] Configuring host networking and storage..." -ForegroundColor Green # Wait for AzSHOSTs to come online Test-AllVMsAvailable -HCIBoxConfig $HCIBoxConfig -Credential $localCred Start-Sleep -Seconds 60 @@ -1741,33 +1634,26 @@ Set-FabricNetwork -HCIBoxConfig $HCIBoxConfig -localCred $localCred # Provision the router, domain controller, and WAC VMs and join the hosts to the domain ####################################################################################### # Provision Router VM on AzSMGMT -Write-Host "[Build cluster - Step 7/12] Build BGP router VM..." -ForegroundColor Green +Write-Host "[Build cluster - Step 7/10] Build BGP router VM..." -ForegroundColor Green New-RouterVM -HCIBoxConfig $HCIBoxConfig -localCred $localCred # Provision Domain controller VM on AzSMGMT -Write-Host "[Build cluster - Step 8/12] Building Domain Controller VM..." -ForegroundColor Green +Write-Host "[Build cluster - Step 8/10] Building Domain Controller VM..." -ForegroundColor Green New-DCVM -HCIBoxConfig $HCIBoxConfig -localCred $localCred -domainCred $domainCred -# Join hosts to domain -#Join-HCINodesToDomain -HCIBoxConfig $HCIBoxConfig -localCred $localCred -domainCred $domainCred - # Provision Admincenter VM -Write-Host "[Build cluster - Step 9/12] Building Windows Admin Center gateway server VM... (skipping step)" -ForegroundColor Green +# Write-Host "[Build cluster - Step 9/12] Building Windows Admin Center gateway server VM... (skipping step)" -ForegroundColor Green #New-AdminCenterVM -HCIBoxConfig $HCIBoxConfig -localCred $localCred -domainCred $domainCred -# Provision Hyper-V Logical Switches and Create S2D Cluster on Hosts -# Write-Host "[Build cluster - Step 10/12] Configuring HCI node networking..." -ForegroundColor Green -# New-HyperConvergedEnvironment -HCIBoxConfig $HCIBoxConfig -domainCred $domainCred - ####################################################################################### # Prepare the cluster for deployment ####################################################################################### # New-S2DCluster -HCIBoxConfig $HCIBoxConfig -domainCred $domainCred -Write-Host "[Build cluster - Step 11/12] Preparing HCI cluster Azure deployment..." -ForegroundColor Green +Write-Host "[Build cluster - Step 9/10] Preparing HCI cluster Azure deployment..." -ForegroundColor Green Set-HCIDeployPrereqs -HCIBoxConfig $HCIBoxConfig -localCred $localCred -domainCred $domainCred # Cluster complete. Finish up and add RDP Link to Desktop to WAC machine. -Write-Host "[Build cluster - Step 12/12] Tidying up..." -ForegroundColor Green +Write-Host "[Build cluster - Step 10/10] Tidying up..." -ForegroundColor Green Remove-Item C:\Users\Public\Desktop\AdminCenter.lnk -Force -ErrorAction SilentlyContinue $wshshell = New-Object -ComObject WScript.Shell $lnk = $wshshell.CreateShortcut("C:\Users\Public\Desktop\AdminCenter.lnk") diff --git a/azure_jumpstart_hcibox/bicep/main.azd.bicep b/azure_jumpstart_hcibox/bicep/main.azd.bicep index d52beccddd..2d40c7bf01 100644 --- a/azure_jumpstart_hcibox/bicep/main.azd.bicep +++ b/azure_jumpstart_hcibox/bicep/main.azd.bicep @@ -25,15 +25,6 @@ param windowsAdminPassword string @description('Name for your log analytics workspace') param logAnalyticsWorkspaceName string = 'HCIBox-Workspace' -@description('Option to disable automatic cluster registration. Setting this to false will also disable deploying AKS and Resource bridge') -param registerCluster bool = true - -@description('Option to deploy AKS-HCI with HCIBox') -param deployAKSHCI bool = true - -@description('Option to deploy Resource Bridge with HCIBox') -param deployResourceBridge bool = true - @description('Public DNS to use for the domain') param natDNS string = '8.8.8.8' diff --git a/azure_jumpstart_hcibox/bicep/main.azd.parameters.json b/azure_jumpstart_hcibox/bicep/main.azd.parameters.json index 989eadab2e..5d955a6562 100644 --- a/azure_jumpstart_hcibox/bicep/main.azd.parameters.json +++ b/azure_jumpstart_hcibox/bicep/main.azd.parameters.json @@ -24,16 +24,7 @@ "value": "${JS_RDP_PORT}" }, "deployBastion": { - "value": false - }, - "registerCluster": { - "value": true - }, - "deployResourceBridge": { - "value": true - }, - "deployAKSHCI": { - "value": true + "value": "${JS_DEPLOY_BASTION}" } } } \ No newline at end of file diff --git a/azure_jumpstart_hcibox/bicep/main.bicep b/azure_jumpstart_hcibox/bicep/main.bicep index 0285c92b3d..323b79ce3f 100644 --- a/azure_jumpstart_hcibox/bicep/main.bicep +++ b/azure_jumpstart_hcibox/bicep/main.bicep @@ -23,15 +23,6 @@ param windowsAdminPassword string @description('Name for your log analytics workspace') param logAnalyticsWorkspaceName string -@description('Option to disable automatic cluster registration. Setting this to false will also disable deploying AKS and Resource bridge') -param registerCluster bool = true - -@description('Option to deploy AKS-HCI with HCIBox') -param deployAKSHCI bool = true - -@description('Option to deploy Resource Bridge with HCIBox') -param deployResourceBridge bool = true - @description('Public DNS to use for the domain') param natDNS string = '8.8.8.8' diff --git a/azure_jumpstart_hcibox/bicep/main.parameters.json b/azure_jumpstart_hcibox/bicep/main.parameters.json index 10f46a1390..ef61e3e5c2 100644 --- a/azure_jumpstart_hcibox/bicep/main.parameters.json +++ b/azure_jumpstart_hcibox/bicep/main.parameters.json @@ -25,15 +25,6 @@ }, "deployBastion": { "value": false - }, - "registerCluster": { - "value": true - }, - "deployResourceBridge": { - "value": true - }, - "deployAKSHCI": { - "value": true } } } \ No newline at end of file From 7409059ec2e8a91683dd9a7a38e8c99afcf828ed Mon Sep 17 00:00:00 2001 From: saitcho <saitcho@outlook.com> Date: Fri, 19 Jan 2024 15:19:06 -0600 Subject: [PATCH 03/45] vlan aks --- azure_jumpstart_hcibox/artifacts/PowerShell/Configure-AKS.ps1 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/azure_jumpstart_hcibox/artifacts/PowerShell/Configure-AKS.ps1 b/azure_jumpstart_hcibox/artifacts/PowerShell/Configure-AKS.ps1 index ce3ded1ecb..650029e71f 100644 --- a/azure_jumpstart_hcibox/artifacts/PowerShell/Configure-AKS.ps1 +++ b/azure_jumpstart_hcibox/artifacts/PowerShell/Configure-AKS.ps1 @@ -22,8 +22,9 @@ Invoke-Command -ComputerName $HCIBoxConfig.NodeHostConfig[0].HostName -ArgumentL $tenantId = $args[2] $subId = $args[3] $clustervnetname = $args[4] + $vlanid = "200" Connect-AzAccount -ServicePrincipal -Subscription $subId -Tenant $tenantId -Credential $azureAppCred - New-ArcHciVirtualNetwork -name $clustervnetname -vswitchname "ConvergedSwitch(hci)" -ipaddressprefix "192.168.200.0/24" -gateway $HCIBoxConfig.SDNLABRoute -dnsservers $HCIBoxConfig.SDNLABDNS -vippoolstart "192.168.200.100" -vippoolend "192.168.200.200" -k8snodeippoolstart "192.168.200.201" -k8snodeippoolend "192.168.200.249" -vlanID $vlanid + New-ArcHciVirtualNetwork -name $clustervnetname -vswitchname "ConvergedSwitch(hci)" -ipaddressprefix "192.168.200.0/24" -gateway $HCIBoxConfig.SDNLABRoute -dnsservers $HCIBoxConfig.SDNLABDNS -vippoolstart "192.168.200.150" -vippoolend "192.168.200.200" -k8snodeippoolstart "192.168.200.201" -k8snodeippoolend "192.168.200.249" -vlanID $vlanid } az login --service-principal --username $env:spnClientID --password=$env:spnClientSecret --tenant $env:spnTenantId From bcee7796ba27237bd099682fae8826ae7426b78d Mon Sep 17 00:00:00 2001 From: saitcho <saitcho@outlook.com> Date: Fri, 19 Jan 2024 15:38:01 -0600 Subject: [PATCH 04/45] remove parameters --- azure_jumpstart_hcibox/bicep/main.azd.bicep | 3 --- azure_jumpstart_hcibox/bicep/main.bicep | 3 --- 2 files changed, 6 deletions(-) diff --git a/azure_jumpstart_hcibox/bicep/main.azd.bicep b/azure_jumpstart_hcibox/bicep/main.azd.bicep index 2d40c7bf01..9cc1800d48 100644 --- a/azure_jumpstart_hcibox/bicep/main.azd.bicep +++ b/azure_jumpstart_hcibox/bicep/main.azd.bicep @@ -93,9 +93,6 @@ module hostDeployment 'host/host.bicep' = { templateBaseUrl: templateBaseUrl subnetId: networkDeployment.outputs.subnetId deployBastion: deployBastion - registerCluster: registerCluster - deployAKSHCI: deployAKSHCI - deployResourceBridge: deployResourceBridge natDNS: natDNS location: location rdpPort: rdpPort diff --git a/azure_jumpstart_hcibox/bicep/main.bicep b/azure_jumpstart_hcibox/bicep/main.bicep index 323b79ce3f..cd32561036 100644 --- a/azure_jumpstart_hcibox/bicep/main.bicep +++ b/azure_jumpstart_hcibox/bicep/main.bicep @@ -80,9 +80,6 @@ module hostDeployment 'host/host.bicep' = { templateBaseUrl: templateBaseUrl subnetId: networkDeployment.outputs.subnetId deployBastion: deployBastion - registerCluster: registerCluster - deployAKSHCI: deployAKSHCI - deployResourceBridge: deployResourceBridge natDNS: natDNS location: location rdpPort: rdpPort From 8e2fd89cf2f56eaf6bdffed7275fee6bbe7338e1 Mon Sep 17 00:00:00 2001 From: saitcho <saitcho@outlook.com> Date: Fri, 19 Jan 2024 16:02:13 -0600 Subject: [PATCH 05/45] workaround --- .../artifacts/PowerShell/New-HCIBoxCluster.ps1 | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/azure_jumpstart_hcibox/artifacts/PowerShell/New-HCIBoxCluster.ps1 b/azure_jumpstart_hcibox/artifacts/PowerShell/New-HCIBoxCluster.ps1 index 15ee21dd32..61a16f44f0 100644 --- a/azure_jumpstart_hcibox/artifacts/PowerShell/New-HCIBoxCluster.ps1 +++ b/azure_jumpstart_hcibox/artifacts/PowerShell/New-HCIBoxCluster.ps1 @@ -1488,11 +1488,15 @@ function Set-HCIDeployPrereqs { } } # Workaround for incomplete BITS transfer of LCM files - Start-Sleep -Seconds 60 - Invoke-Command -VMName $HCIBoxconfig.NodeHostConfig[0].Hostname { - Remove-Item -Path "C:\DeploymentPackage" -Recurse -Force - Restart-Computer -Force - } + Start-Sleep -Seconds 15 + foreach ($node in $HCIBoxConfig.NodeHostConfig) { + Invoke-Command -VMName $node.Hostname -Credential $localCred -ScriptBlock { + Remove-Item -Path "C:\DeploymentPackage" -Recurse -Force + } + Start-Sleep -Seconds 3 + Restart-VM -Name $node.Hostname -Force + } + Start-Sleep -Seconds 60 } #endregion From 8168e7e6e3a401cfd69ad88cfb45262cc86409dd Mon Sep 17 00:00:00 2001 From: saitcho <saitcho@outlook.com> Date: Fri, 19 Jan 2024 16:04:46 -0600 Subject: [PATCH 06/45] filenames --- azure_jumpstart_hcibox/artifacts/PowerShell/Bootstrap.ps1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/azure_jumpstart_hcibox/artifacts/PowerShell/Bootstrap.ps1 b/azure_jumpstart_hcibox/artifacts/PowerShell/Bootstrap.ps1 index c4b5432a05..d84f4a0b89 100644 --- a/azure_jumpstart_hcibox/artifacts/PowerShell/Bootstrap.ps1 +++ b/azure_jumpstart_hcibox/artifacts/PowerShell/Bootstrap.ps1 @@ -103,11 +103,11 @@ Invoke-WebRequest "https://raw.githubusercontent.com/microsoft/azure_arc/main/im Invoke-WebRequest https://aka.ms/wacdownload -OutFile "$($HCIBoxConfig.Paths["WACDir"])\WindowsAdminCenter.msi" Invoke-WebRequest ($templateBaseUrl + "artifacts/PowerShell/HCIBoxLogonScript.ps1") -OutFile $HCIPath\HCIBoxLogonScript.ps1 Invoke-WebRequest ($templateBaseUrl + "artifacts/PowerShell/New-HCIBoxCluster.ps1") -OutFile $HCIPath\New-HCIBoxCluster.ps1 -Invoke-WebRequest ($templateBaseUrl + "artifacts/PowerShell/Configure-AKS.ps1") -OutFile $HCIPath\Deploy-AKS.ps1 +Invoke-WebRequest ($templateBaseUrl + "artifacts/PowerShell/Configure-AKS.ps1") -OutFile $HCIPath\Configure-AKS.ps1 Invoke-WebRequest ($templateBaseUrl + "artifacts/PowerShell/Deploy-SQLMI.ps1") -OutFile $HCIPath\Deploy-SQLMI.ps1 -Invoke-WebRequest ($templateBaseUrl + "artifacts/PowerShell/Configure-VMManagement.ps1") -OutFile $HCIPath\Deploy-ArcResourceBridge.ps1 +Invoke-WebRequest ($templateBaseUrl + "artifacts/PowerShell/Configure-VMManagement.ps1") -OutFile $HCIPath\Configure-VMManagement.ps1 Invoke-WebRequest ($templateBaseUrl + "artifacts/PowerShell/Deploy-GitOps.ps1") -OutFile $HCIPath\Deploy-GitOps.ps1 -Invoke-WebRequest ($templateBaseUrl + "artifacts/PowerShell/Cloud-Cluster-Deploy.ps1") -OutFile $HCIPath\Cloud-Cluster-Deploy.ps1 +Invoke-WebRequest ($templateBaseUrl + "artifacts/PowerShell/Generate-ARM-Template.ps1") -OutFile $HCIPath\Generate-ARM-Template.ps1 Invoke-WebRequest ($templateBaseUrl + "artifacts/PowerShell/GetServiceAccountBearerToken.ps1") -OutFile $HCIPath\GetServiceAccountBearerToken.ps1 Invoke-WebRequest ($templateBaseUrl + "artifacts/LogInstructions.txt") -OutFile $HCIBoxConfig.Paths["LogsDir"]\LogInstructions.txt Invoke-WebRequest ($templateBaseUrl + "artifacts/jumpstart-user-secret.yaml") -OutFile $HCIPath\jumpstart-user-secret.yaml From 893158e37e5b4e90ac405f69d4bf25ae4b44e8c3 Mon Sep 17 00:00:00 2001 From: saitcho <saitcho@outlook.com> Date: Fri, 19 Jan 2024 16:34:46 -0600 Subject: [PATCH 07/45] cleanup --- .../artifacts/PowerShell/Configure-AKS.ps1 | 3 +- .../PowerShell/Configure-VMManagement.ps1 | 9 ++-- .../PowerShell/Generate-ARM-Template.ps1 | 2 +- .../artifacts/PowerShell/HCIBox-Config.psd1 | 31 +++++------ .../PowerShell/New-HCIBoxCluster.ps1 | 52 +++++++++---------- azure_jumpstart_hcibox/bicep/main.azd.bicep | 4 ++ .../bicep/main.azd.parameters.json | 3 ++ 7 files changed, 51 insertions(+), 53 deletions(-) diff --git a/azure_jumpstart_hcibox/artifacts/PowerShell/Configure-AKS.ps1 b/azure_jumpstart_hcibox/artifacts/PowerShell/Configure-AKS.ps1 index 650029e71f..aa8cb2bc41 100644 --- a/azure_jumpstart_hcibox/artifacts/PowerShell/Configure-AKS.ps1 +++ b/azure_jumpstart_hcibox/artifacts/PowerShell/Configure-AKS.ps1 @@ -22,9 +22,8 @@ Invoke-Command -ComputerName $HCIBoxConfig.NodeHostConfig[0].HostName -ArgumentL $tenantId = $args[2] $subId = $args[3] $clustervnetname = $args[4] - $vlanid = "200" Connect-AzAccount -ServicePrincipal -Subscription $subId -Tenant $tenantId -Credential $azureAppCred - New-ArcHciVirtualNetwork -name $clustervnetname -vswitchname "ConvergedSwitch(hci)" -ipaddressprefix "192.168.200.0/24" -gateway $HCIBoxConfig.SDNLABRoute -dnsservers $HCIBoxConfig.SDNLABDNS -vippoolstart "192.168.200.150" -vippoolend "192.168.200.200" -k8snodeippoolstart "192.168.200.201" -k8snodeippoolend "192.168.200.249" -vlanID $vlanid + New-ArcHciVirtualNetwork -name $clustervnetname -vswitchname "ConvergedSwitch(hci)" -ipaddressprefix $HCIBoxConfig.AKSIPPrefix -gateway $HCIBoxConfig.AKSGWIP -dnsservers $HCIBoxConfig.AKSDNSIP -vippoolstart $HCIBoxConfig.AKSVIPStartIP -vippoolend $HCIBoxConfig.AKSVIPEndIP -k8snodeippoolstart $HCIBoxConfig.AKSNodeStartIP -k8snodeippoolend $HCIBoxConfig.AKSNodeEndIP -vlanID $HCIBoxConfig.AKSVLAN } az login --service-principal --username $env:spnClientID --password=$env:spnClientSecret --tenant $env:spnTenantId diff --git a/azure_jumpstart_hcibox/artifacts/PowerShell/Configure-VMManagement.ps1 b/azure_jumpstart_hcibox/artifacts/PowerShell/Configure-VMManagement.ps1 index 9d6ef23752..0272269ddd 100644 --- a/azure_jumpstart_hcibox/artifacts/PowerShell/Configure-VMManagement.ps1 +++ b/azure_jumpstart_hcibox/artifacts/PowerShell/Configure-VMManagement.ps1 @@ -25,7 +25,6 @@ $spnClientId = $env:spnClientId $spnSecret = $env:spnClientSecret $spnTenantId = $env:spnTenantId $location = "eastus" -$cloudServiceIP = $HCIBoxConfig.AKSCloudSvcidr.Substring(0, $HCIBoxConfig.AKSCloudSvcidr.IndexOf('/')) $customLocName="Jumpstart" # Copy gallery VHDs to hosts @@ -43,9 +42,9 @@ az stack-hci-vm image create --subscription $env:subscriptionId --resource-group # Create logical networks $switchName='"ConvergedSwitch(hci)"' $lnetName = "myhci-lnet-static" -$addressPrefixes = "192.168.200.0/24" -$gateway = "192.168.1.1" -$dnsServers = "192.168.1.254" -$vlanid = "200" +$addressPrefixes = $HCIBoxConfig.vmIpPrefix +$gateway = $HCIBoxConfig.vmGateway +$dnsServers = $HCIBoxConfig.vmDNS +$vlanid = $HCIBoxConfig.vmVLAN az stack-hci-vm network lnet create --subscription $env:subscriptionId --resource-group $env:resourceGroup --custom-location $customLocationID --location $location --name $lnetName --vm-switch-name $switchName --ip-allocation-method "Static" --address-prefixes $addressPrefixes --gateway $gateway --dns-servers $dnsServers -vlanid $vlanid \ No newline at end of file diff --git a/azure_jumpstart_hcibox/artifacts/PowerShell/Generate-ARM-Template.ps1 b/azure_jumpstart_hcibox/artifacts/PowerShell/Generate-ARM-Template.ps1 index d18ced7028..613908cf9b 100644 --- a/azure_jumpstart_hcibox/artifacts/PowerShell/Generate-ARM-Template.ps1 +++ b/azure_jumpstart_hcibox/artifacts/PowerShell/Generate-ARM-Template.ps1 @@ -63,7 +63,7 @@ foreach ($name in $domainName) { } # Build DNS value -$dns = "[""" + $HCIBoxConfig.rbDNSIP + """]" +$dns = "[""" + $HCIBoxConfig.vmDNS + """]" # Create keyvault name $guid = ([System.Guid]::NewGuid()).ToString().subString(0,5).ToLower() diff --git a/azure_jumpstart_hcibox/artifacts/PowerShell/HCIBox-Config.psd1 b/azure_jumpstart_hcibox/artifacts/PowerShell/HCIBox-Config.psd1 index 2333e1a0df..ebd902accc 100644 --- a/azure_jumpstart_hcibox/artifacts/PowerShell/HCIBox-Config.psd1 +++ b/azure_jumpstart_hcibox/artifacts/PowerShell/HCIBox-Config.psd1 @@ -171,31 +171,24 @@ # AKS and Resource bridge variables AKSworkloadClusterName = "hcibox-aks" # lowercase only AKSvnetname = "akshcivnet" - AKSNodeStartIP = "192.168.200.25" - AKSNodeEndIP = "192.168.200.100" - AKSVIPStartIP = "192.168.200.125" + AKSNodeStartIP = "192.168.200.201" + AKSNodeEndIP = "192.168.200.249" + AKSVIPStartIP = "192.168.200.150" AKSVIPEndIP = "192.168.200.200" AKSIPPrefix = "192.168.200.0/24" AKSGWIP = "192.168.200.1" AKSDNSIP = "192.168.1.254" - AKSCSV = "C:\ClusterStorage\S2D_vDISK1" - AKSImagedir = "C:\ClusterStorage\S2D_vDISK1\aks\Images" - AKSWorkingdir = "C:\ClusterStorage\S2D_vDISK1\aks\Workdir" - AKSCloudConfigdir = "C:\ClusterStorage\S2D_vDISK1\aks\CloudConfig" - AKSCloudSvcidr = "192.168.1.15/24" - AKSVlanID = "200" - rbLocation = "eastus" - rbCustomLocationName = "hcibox-rb-cl" - rbIp = "192.168.200.201" - rbIp2 = "192.168.200.202" - rbCpip = "192.168.200.203" - rbVipStart = "192.168.200.200" - rbVipEnd = "192.168.200.249" - rbDHCPExclusionStart = "192.168.200.200" - rbDHCPExclusionEnd = "192.168.200.209" + AKSVLAN = "200" + # rbVipStart = "192.168.200.200" + # rbVipEnd = "192.168.200.249" + # rbDHCPExclusionStart = "192.168.200.200" + # rbDHCPExclusionEnd = "192.168.200.209" dcVLAN200IP = "192.168.200.205" rbSubnetMask = "255.255.255.0" - rbDNSIP = "192.168.1.254" clusterIpRangeStart = "192.168.1.100" clusterIpRangeEnd = "192.168.1.199" + vmGateway = "192.168.200.1" + vmIpPrefix = "192.168.200.0/24" + vmDNS = "192.168.1.254" + vmVLAN = "200" } \ No newline at end of file diff --git a/azure_jumpstart_hcibox/artifacts/PowerShell/New-HCIBoxCluster.ps1 b/azure_jumpstart_hcibox/artifacts/PowerShell/New-HCIBoxCluster.ps1 index 61a16f44f0..751b82e591 100644 --- a/azure_jumpstart_hcibox/artifacts/PowerShell/New-HCIBoxCluster.ps1 +++ b/azure_jumpstart_hcibox/artifacts/PowerShell/New-HCIBoxCluster.ps1 @@ -913,32 +913,32 @@ function New-DCVM { CMD.exe /c "certutil -SetCATemplates +WebServer" } - Write-Host "Configuring DHCP scope on DHCP server." - # Set up DHCP scope for Arc resource bridge - Invoke-Command -VMName $HCIBoxConfig.DCName -Credential $using:domainCred -ArgumentList $HCIBoxConfig -ScriptBlock { - $HCIBoxConfig = $args[0] - - # Install DHCP feature - Install-WindowsFeature DHCP -IncludeManagementTools - CMD.exe /c "netsh dhcp add securitygroups" - Restart-Service dhcpserver - - # Allow DHCP in domain - $dnsName = $HCIBoxConfig.DCName - $fqdnsName = $HCIBoxConfig.DCName + "." + $HCIBoxConfig.SDNDomainFQDN - Add-DhcpServerInDC -DnsName $fqdnsName -IPAddress $HCIBoxConfig.dcVLAN200IP - Get-DHCPServerInDC - - # Bind DHCP only to VLAN200 NIC - Set-DhcpServerv4Binding -ComputerName $dnsName -InterfaceAlias $dnsName -BindingState $false - Set-DhcpServerv4Binding -ComputerName $dnsName -InterfaceAlias VLAN200 -BindingState $true - - # Add DHCP scope for Resource bridge VMs - Add-DhcpServerv4Scope -name "ResourceBridge" -StartRange $HCIBoxConfig.rbVipStart -EndRange $HCIBoxConfig.rbVipEnd -SubnetMask 255.255.255.0 -State Active - $scope = Get-DhcpServerv4Scope - Add-DhcpServerv4ExclusionRange -ScopeID $scope.ScopeID.IPAddressToString -StartRange $HCIBoxConfig.rbDHCPExclusionStart -EndRange $HCIBoxConfig.rbDHCPExclusionEnd - Set-DhcpServerv4OptionValue -ComputerName $dnsName -ScopeId $scope.ScopeID.IPAddressToString -DnsServer $HCIBoxConfig.SDNLABDNS -Router $HCIBoxConfig.BGPRouterIP_VLAN200.Trim("/24") - } + # Write-Host "Configuring DHCP scope on DHCP server." + # # Set up DHCP scope for Arc resource bridge + # Invoke-Command -VMName $HCIBoxConfig.DCName -Credential $using:domainCred -ArgumentList $HCIBoxConfig -ScriptBlock { + # $HCIBoxConfig = $args[0] + + # # Install DHCP feature + # Install-WindowsFeature DHCP -IncludeManagementTools + # CMD.exe /c "netsh dhcp add securitygroups" + # Restart-Service dhcpserver + + # # Allow DHCP in domain + # $dnsName = $HCIBoxConfig.DCName + # $fqdnsName = $HCIBoxConfig.DCName + "." + $HCIBoxConfig.SDNDomainFQDN + # Add-DhcpServerInDC -DnsName $fqdnsName -IPAddress $HCIBoxConfig.dcVLAN200IP + # Get-DHCPServerInDC + + # # Bind DHCP only to VLAN200 NIC + # Set-DhcpServerv4Binding -ComputerName $dnsName -InterfaceAlias $dnsName -BindingState $false + # Set-DhcpServerv4Binding -ComputerName $dnsName -InterfaceAlias VLAN200 -BindingState $true + + # # Add DHCP scope for Resource bridge VMs + # Add-DhcpServerv4Scope -name "ResourceBridge" -StartRange $HCIBoxConfig.rbVipStart -EndRange $HCIBoxConfig.rbVipEnd -SubnetMask 255.255.255.0 -State Active + # $scope = Get-DhcpServerv4Scope + # Add-DhcpServerv4ExclusionRange -ScopeID $scope.ScopeID.IPAddressToString -StartRange $HCIBoxConfig.rbDHCPExclusionStart -EndRange $HCIBoxConfig.rbDHCPExclusionEnd + # Set-DhcpServerv4OptionValue -ComputerName $dnsName -ScopeId $scope.ScopeID.IPAddressToString -DnsServer $HCIBoxConfig.SDNLABDNS -Router $HCIBoxConfig.BGPRouterIP_VLAN200.Trim("/24") + # } } } diff --git a/azure_jumpstart_hcibox/bicep/main.azd.bicep b/azure_jumpstart_hcibox/bicep/main.azd.bicep index 9cc1800d48..1471e1f7dc 100644 --- a/azure_jumpstart_hcibox/bicep/main.azd.bicep +++ b/azure_jumpstart_hcibox/bicep/main.azd.bicep @@ -13,6 +13,9 @@ param spnClientSecret string @description('Azure AD tenant id for your service principal') param spnTenantId string +@description('Azure AD object id for your Microsoft.AzureStackHCI resource provider') +param spnProviderId string + @description('Username for Windows account') param windowsAdminUsername string @@ -88,6 +91,7 @@ module hostDeployment 'host/host.bicep' = { spnClientId: spnClientId spnClientSecret: spnClientSecret spnTenantId: spnTenantId + spnProviderId: spnProviderId workspaceName: logAnalyticsWorkspaceName stagingStorageAccountName: storageAccountDeployment.outputs.storageAccountName templateBaseUrl: templateBaseUrl diff --git a/azure_jumpstart_hcibox/bicep/main.azd.parameters.json b/azure_jumpstart_hcibox/bicep/main.azd.parameters.json index 5d955a6562..c5d4442177 100644 --- a/azure_jumpstart_hcibox/bicep/main.azd.parameters.json +++ b/azure_jumpstart_hcibox/bicep/main.azd.parameters.json @@ -17,6 +17,9 @@ "spnTenantId": { "value": "${SPN_TENANT_ID}" }, + "spnProviderId": { + "value": "${SPN_PROVIDER_ID}" + }, "windowsAdminUsername": { "value": "${JS_WINDOWS_ADMIN_USERNAME}" }, From 8358e929d740ace088d3bf5a08a31e2f91a04fcb Mon Sep 17 00:00:00 2001 From: saitcho <saitcho@outlook.com> Date: Fri, 19 Jan 2024 17:25:39 -0600 Subject: [PATCH 08/45] preprovision --- .../scripts/preprovision.ps1 | 29 ++++++++++++++----- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/azure_jumpstart_hcibox/scripts/preprovision.ps1 b/azure_jumpstart_hcibox/scripts/preprovision.ps1 index 85f2654f24..2c276d0e79 100644 --- a/azure_jumpstart_hcibox/scripts/preprovision.ps1 +++ b/azure_jumpstart_hcibox/scripts/preprovision.ps1 @@ -17,10 +17,7 @@ if (-not (Get-AzContext)) { Throw "Unable to login to Azure. Please check your credentials and try again." } } - -# Write-Host "Getting Azure Tenant Id..." -$tenantId = (Get-AzSubscription -SubscriptionId $env:AZURE_SUBSCRIPTION_ID).TenantId - +$tenantId = (Get-AzContext).tenant.id # Write-Host "Setting Azure context..." $context = Set-AzContext -SubscriptionId $env:AZURE_SUBSCRIPTION_ID -Tenant $tenantId -ErrorAction Stop @@ -135,6 +132,18 @@ if ($promptOutput = Read-Host "Enter the Windows Admin Username [$JS_WINDOWS_ADM # set the env variable azd env set JS_WINDOWS_ADMIN_USERNAME -- $JS_WINDOWS_ADMIN_USERNAME +######################################################################## +# Use Azure Bastion? +######################################################################## +$promptOutput = Read-Host "Configure Azure Bastion for accessing HCIBox host [Y/N]?" +$JS_DEPLOY_BASTION = $false +if ($promptOutput -like 'y') +{ + $JS_DEPLOY_BASTION = $true +} + +# set the env variable +azd env set JS_DEPLOY_BASTION $JS_DEPLOY_BASTION ######################################################################## # RDP Port @@ -143,7 +152,13 @@ $JS_RDP_PORT = '3389' If ($env:JS_RDP_PORT) { $JS_RDP_PORT = $env:JS_RDP_PORT } -if ($promptOutput = Read-Host "Enter the RDP Port for remote desktop connection [$JS_RDP_PORT]") { $JS_RDP_PORT = $promptOutput } +if ($promptOutput -notlike 'y') { + if ($promptOutput = Read-Host "Enter the RDP Port for remote desktop connection [$JS_RDP_PORT]") + { + $JS_RDP_PORT = $promptOutput + } +} + # set the env variable azd env set JS_RDP_PORT $JS_RDP_PORT @@ -154,7 +169,7 @@ azd env set JS_RDP_PORT $JS_RDP_PORT ######################################################################## Write-Host "Creating Azure Service Principal..." -$user = $context.Account.Id.split("@")[0] +$user = (Get-AzContext).Account.Id.split("@")[0] $uniqueSpnName = "$user-jumpstart-spn-$(Get-Random -Minimum 1000 -Maximum 9999)" try { $spn = New-AzADServicePrincipal -DisplayName $uniqueSpnName -Role "Owner" -Scope "/subscriptions/$($env:AZURE_SUBSCRIPTION_ID)" -ErrorAction Stop @@ -164,7 +179,7 @@ catch { Throw "You do not have permission to create a service principal. Please contact your Azure subscription administrator to grant you the Owner role on the subscription." } elseif ($error[0].ToString() -match "credentials") { - Throw "Please run Connect-AzAccount to sign and run 'azd up' again." + Throw "Please run Connect-AzAccount to sign in and run 'azd up' again." } else { Throw "An error occurred creating the service principal. Please try again." From cf6b5c84a3bd7028bdb503249ff7059478cbeca6 Mon Sep 17 00:00:00 2001 From: saitcho <saitcho@outlook.com> Date: Sat, 20 Jan 2024 08:32:57 -0600 Subject: [PATCH 09/45] fixes --- .../artifacts/PowerShell/Configure-AKS.ps1 | 6 +++--- .../artifacts/PowerShell/Configure-VMManagement.ps1 | 8 +++++--- .../artifacts/PowerShell/New-HCIBoxCluster.ps1 | 1 + 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/azure_jumpstart_hcibox/artifacts/PowerShell/Configure-AKS.ps1 b/azure_jumpstart_hcibox/artifacts/PowerShell/Configure-AKS.ps1 index aa8cb2bc41..69bd8c05c7 100644 --- a/azure_jumpstart_hcibox/artifacts/PowerShell/Configure-AKS.ps1 +++ b/azure_jumpstart_hcibox/artifacts/PowerShell/Configure-AKS.ps1 @@ -16,7 +16,7 @@ $tenantId = $env:spnTenantId $subId = $env:subscriptionId $clustervnetname = "aksvnet1" $azureAppCred = (New-Object System.Management.Automation.PSCredential $env:spnClientID, (ConvertTo-SecureString -String $env:spnClientSecret -AsPlainText -Force)) -Invoke-Command -ComputerName $HCIBoxConfig.NodeHostConfig[0].HostName -ArgumentList $HCIBoxConfig, $azureAppCred, $tenantId, $subId, $clustervnetname -Credential $domainCred -ScriptBlock { +Invoke-Command -ComputerName "$($HCIBoxConfig.NodeHostConfig[0].HostName).jumpstart.local" -Authentication CredSSP -ArgumentList $HCIBoxConfig, $azureAppCred, $tenantId, $subId, $clustervnetname -Credential $domainCred -ScriptBlock { $HCIBoxConfig = $args[0] $azureAppCred = $args[1] $tenantId = $args[2] @@ -27,9 +27,9 @@ Invoke-Command -ComputerName $HCIBoxConfig.NodeHostConfig[0].HostName -ArgumentL } az login --service-principal --username $env:spnClientID --password=$env:spnClientSecret --tenant $env:spnTenantId -$customLocationID=(az customlocation show --resource-group $env:resourceGroup --name "Jumpstart" --query id -o tsv) +$customLocationID=(az customlocation show --resource-group $env:resourceGroup --name $HCIBoxConfig.rbCustomLocationName --query id -o tsv) az akshybrid vnet create -n $HCIBoxConfig.AKSvnetname -g $env:resourceGroup --custom-location $customlocationID --moc-vnet-name $clustervnetname -$vnetId=az hybridaks vnet show --name $HCIBoxConfig.AKSvnetname -g $env:resourceGroup --query id -o tsv +$vnetId="/subscriptions/$subId/resourceGroups/$env:resourceGroup/providers/Microsoft.HybridContainerService/virtualNetworks/$($HCIBoxConfig.AKSvnetname)" $aadgroupID="97d70ef2-db1e-413c-84f5-3159fbf34693" az akshybrid create -n $HCIBoxConfig.AKSworkloadClusterName -g $env:resourceGroup --custom-location $customlocationID --vnet-ids $vnetId --aad-admin-group-object-ids $aadgroupID --generate-ssh-keys --load-balancer-count 1 Stop-Transcript \ No newline at end of file diff --git a/azure_jumpstart_hcibox/artifacts/PowerShell/Configure-VMManagement.ps1 b/azure_jumpstart_hcibox/artifacts/PowerShell/Configure-VMManagement.ps1 index 0272269ddd..835b53969b 100644 --- a/azure_jumpstart_hcibox/artifacts/PowerShell/Configure-VMManagement.ps1 +++ b/azure_jumpstart_hcibox/artifacts/PowerShell/Configure-VMManagement.ps1 @@ -25,7 +25,7 @@ $spnClientId = $env:spnClientId $spnSecret = $env:spnClientSecret $spnTenantId = $env:spnTenantId $location = "eastus" -$customLocName="Jumpstart" +$customLocName = $HCIBoxConfig.rbCustomLocationName # Copy gallery VHDs to hosts # Invoke-Command -VMName $HCIBoxConfig.NodeHostConfig[0].Hostname -Credential $adcred -ScriptBlock { @@ -36,15 +36,17 @@ $customLocName="Jumpstart" # Create VM images az login --service-principal --username $env:spnClientID --password=$env:spnClientSecret --tenant $env:spnTenantId +az config set extension.use_dynamic_install=yes_without_prompt $customLocationID=(az customlocation show --resource-group $env:resourceGroup --name $customLocName --query id -o tsv) -az stack-hci-vm image create --subscription $env:subscriptionId --resource-group $env:resourceGroup --custom-location $customLocationID --location $location --name "Windows Server 2022 Datacenter: Azure Edition Core - Gen2" --os-type "windows" --offer "windowsserver" --publisher "microsoftwindowsserver" --sku "2022-datacenter-azure-edition" --version "20348.2227.240104" # --storage-path-id $storagepathid +az stack-hci-vm image create --subscription $env:subscriptionId --resource-group $env:resourceGroup --custom-location $customLocationID --location $location --name "WinServer2022" --os-type "windows" --offer "windowsserver" --publisher "microsoftwindowsserver" --sku "2022-datacenter-azure-edition" --version "20348.2227.240104" # --storage-path-id $storagepathid # Create logical networks $switchName='"ConvergedSwitch(hci)"' -$lnetName = "myhci-lnet-static" +$lnetName = "hcibox-vm-lnet-static" $addressPrefixes = $HCIBoxConfig.vmIpPrefix $gateway = $HCIBoxConfig.vmGateway $dnsServers = $HCIBoxConfig.vmDNS $vlanid = $HCIBoxConfig.vmVLAN + az stack-hci-vm network lnet create --subscription $env:subscriptionId --resource-group $env:resourceGroup --custom-location $customLocationID --location $location --name $lnetName --vm-switch-name $switchName --ip-allocation-method "Static" --address-prefixes $addressPrefixes --gateway $gateway --dns-servers $dnsServers -vlanid $vlanid \ No newline at end of file diff --git a/azure_jumpstart_hcibox/artifacts/PowerShell/New-HCIBoxCluster.ps1 b/azure_jumpstart_hcibox/artifacts/PowerShell/New-HCIBoxCluster.ps1 index 751b82e591..af26d90828 100644 --- a/azure_jumpstart_hcibox/artifacts/PowerShell/New-HCIBoxCluster.ps1 +++ b/azure_jumpstart_hcibox/artifacts/PowerShell/New-HCIBoxCluster.ps1 @@ -1562,6 +1562,7 @@ Write-Host "[Build cluster - Step 2/10] Preparing Azure VM virtualization host.. Write-Host "Enabling PS Remoting on client..." Enable-PSRemoting Set-Item WSMan:\localhost\Client\TrustedHosts * -Confirm:$false -Force +Enable-WSManCredSSP -Role Client -DelegateComputer "*.$($HCIBoxConfig.SDNDomainFQDN)" -Force ############################################################################### # Configure Hyper-V host From f87db0d8f799c9440b98dd2f23237307c26bd6c4 Mon Sep 17 00:00:00 2001 From: saitcho <saitcho@outlook.com> Date: Sat, 20 Jan 2024 08:44:27 -0600 Subject: [PATCH 10/45] bug --- .../artifacts/PowerShell/Configure-VMManagement.ps1 | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/azure_jumpstart_hcibox/artifacts/PowerShell/Configure-VMManagement.ps1 b/azure_jumpstart_hcibox/artifacts/PowerShell/Configure-VMManagement.ps1 index 835b53969b..c6688ad080 100644 --- a/azure_jumpstart_hcibox/artifacts/PowerShell/Configure-VMManagement.ps1 +++ b/azure_jumpstart_hcibox/artifacts/PowerShell/Configure-VMManagement.ps1 @@ -48,5 +48,4 @@ $gateway = $HCIBoxConfig.vmGateway $dnsServers = $HCIBoxConfig.vmDNS $vlanid = $HCIBoxConfig.vmVLAN - -az stack-hci-vm network lnet create --subscription $env:subscriptionId --resource-group $env:resourceGroup --custom-location $customLocationID --location $location --name $lnetName --vm-switch-name $switchName --ip-allocation-method "Static" --address-prefixes $addressPrefixes --gateway $gateway --dns-servers $dnsServers -vlanid $vlanid \ No newline at end of file +az stack-hci-vm network lnet create --subscription $env:subscriptionId --resource-group $env:resourceGroup --custom-location $customLocationID --location $location --name $lnetName --vm-switch-name $switchName --ip-allocation-method "Static" --address-prefixes $addressPrefixes --gateway $gateway --dns-servers $dnsServers --vlan $vlanid \ No newline at end of file From 3e4a994aa5f4858b012fddf06b1d533b36ed8406 Mon Sep 17 00:00:00 2001 From: saitcho <saitcho@outlook.com> Date: Sat, 20 Jan 2024 10:04:01 -0600 Subject: [PATCH 11/45] wsman --- .../artifacts/PowerShell/New-HCIBoxCluster.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure_jumpstart_hcibox/artifacts/PowerShell/New-HCIBoxCluster.ps1 b/azure_jumpstart_hcibox/artifacts/PowerShell/New-HCIBoxCluster.ps1 index af26d90828..8f2e2a1ffe 100644 --- a/azure_jumpstart_hcibox/artifacts/PowerShell/New-HCIBoxCluster.ps1 +++ b/azure_jumpstart_hcibox/artifacts/PowerShell/New-HCIBoxCluster.ps1 @@ -1561,7 +1561,7 @@ $domainCred = new-object -typename System.Management.Automation.PSCredential ` Write-Host "[Build cluster - Step 2/10] Preparing Azure VM virtualization host..." -ForegroundColor Green Write-Host "Enabling PS Remoting on client..." Enable-PSRemoting -Set-Item WSMan:\localhost\Client\TrustedHosts * -Confirm:$false -Force +set-item WSMan:localhost\client\trustedhosts -value * -Force Enable-WSManCredSSP -Role Client -DelegateComputer "*.$($HCIBoxConfig.SDNDomainFQDN)" -Force ############################################################################### From 1e598a4fd419cbbb4c54a89ac9b0a85299f94393 Mon Sep 17 00:00:00 2001 From: saitcho <saitcho@outlook.com> Date: Sat, 20 Jan 2024 10:39:17 -0600 Subject: [PATCH 12/45] config --- azure_jumpstart_hcibox/artifacts/PowerShell/HCIBox-Config.psd1 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/azure_jumpstart_hcibox/artifacts/PowerShell/HCIBox-Config.psd1 b/azure_jumpstart_hcibox/artifacts/PowerShell/HCIBox-Config.psd1 index ebd902accc..0acfb29260 100644 --- a/azure_jumpstart_hcibox/artifacts/PowerShell/HCIBox-Config.psd1 +++ b/azure_jumpstart_hcibox/artifacts/PowerShell/HCIBox-Config.psd1 @@ -169,6 +169,8 @@ WACport = 443 # AKS and Resource bridge variables + storagePathName = "vms" + storagePath = "C:\ClusterStorage\VMs" AKSworkloadClusterName = "hcibox-aks" # lowercase only AKSvnetname = "akshcivnet" AKSNodeStartIP = "192.168.200.201" From 839b4dd9a475190fb124a92700a8f6b62957a35f Mon Sep 17 00:00:00 2001 From: saitcho <saitcho@outlook.com> Date: Sat, 20 Jan 2024 11:11:40 -0600 Subject: [PATCH 13/45] config --- .../artifacts/PowerShell/HCIBox-Config.psd1 | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/azure_jumpstart_hcibox/artifacts/PowerShell/HCIBox-Config.psd1 b/azure_jumpstart_hcibox/artifacts/PowerShell/HCIBox-Config.psd1 index 0acfb29260..f06dcaeb9c 100644 --- a/azure_jumpstart_hcibox/artifacts/PowerShell/HCIBox-Config.psd1 +++ b/azure_jumpstart_hcibox/artifacts/PowerShell/HCIBox-Config.psd1 @@ -83,7 +83,7 @@ FabricSwitch = "vSwitch-Fabric" FabricNIC = "FABRIC" ClusterVSwitchName = "hciSwitch" - ClusterName = "hciboxcluster3" + ClusterName = "hciboxcluster" WACVMName = "AdminCenter" ClusterSharedVolumePath = "C:\ClusterStorage\S2D_vDISK1" LCMDeployUsername = "HCIBoxDeployUser" @@ -173,11 +173,11 @@ storagePath = "C:\ClusterStorage\VMs" AKSworkloadClusterName = "hcibox-aks" # lowercase only AKSvnetname = "akshcivnet" - AKSNodeStartIP = "192.168.200.201" - AKSNodeEndIP = "192.168.200.249" - AKSVIPStartIP = "192.168.200.150" - AKSVIPEndIP = "192.168.200.200" - AKSIPPrefix = "192.168.200.0/24" + AKSNodeStartIP = "192.168.200.10" + AKSNodeEndIP = "192.168.200.59" + AKSVIPStartIP = "192.168.200.60" + AKSVIPEndIP = "192.168.200.126" + AKSIPPrefix = "192.168.200.0/25" AKSGWIP = "192.168.200.1" AKSDNSIP = "192.168.1.254" AKSVLAN = "200" @@ -190,7 +190,7 @@ clusterIpRangeStart = "192.168.1.100" clusterIpRangeEnd = "192.168.1.199" vmGateway = "192.168.200.1" - vmIpPrefix = "192.168.200.0/24" + vmIpPrefix = "192.168.200.128/26" vmDNS = "192.168.1.254" vmVLAN = "200" } \ No newline at end of file From a6dc3c7e7936992e563ceb008aefad6290c58ed4 Mon Sep 17 00:00:00 2001 From: saitcho <saitcho@outlook.com> Date: Sat, 20 Jan 2024 15:31:02 -0600 Subject: [PATCH 14/45] bug --- .../artifacts/PowerShell/New-HCIBoxCluster.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure_jumpstart_hcibox/artifacts/PowerShell/New-HCIBoxCluster.ps1 b/azure_jumpstart_hcibox/artifacts/PowerShell/New-HCIBoxCluster.ps1 index 8f2e2a1ffe..e0eecf15dc 100644 --- a/azure_jumpstart_hcibox/artifacts/PowerShell/New-HCIBoxCluster.ps1 +++ b/azure_jumpstart_hcibox/artifacts/PowerShell/New-HCIBoxCluster.ps1 @@ -763,7 +763,7 @@ function New-DCVM { # Add NIC for VLAN200 for DHCP server Add-VMNetworkAdapter -VMName $VMName -Name "VLAN200" -SwitchName $HCIBoxConfig.FabricSwitch -DeviceNaming "On" - Get-VMNetworkAdapter -VMName $VMName -Name "VLAN200" | Set-VMNetworkAdapterVLAN -Access -VlanId $HCIBoxConfig.AKSVlanID + Get-VMNetworkAdapter -VMName $VMName -Name "VLAN200" | Set-VMNetworkAdapterVLAN -Access -VlanId $HCIBoxConfig.AKSVLAN # Inject Answer File Write-Host "Mounting and injecting answer file into the $VMName VM." From e4243d39b5cf01d4e437a75bca393f04457364d9 Mon Sep 17 00:00:00 2001 From: saitcho <saitcho@outlook.com> Date: Sat, 20 Jan 2024 18:11:18 -0600 Subject: [PATCH 15/45] name --- azure_jumpstart_hcibox/artifacts/PowerShell/HCIBox-Config.psd1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure_jumpstart_hcibox/artifacts/PowerShell/HCIBox-Config.psd1 b/azure_jumpstart_hcibox/artifacts/PowerShell/HCIBox-Config.psd1 index f06dcaeb9c..cedcddeb75 100644 --- a/azure_jumpstart_hcibox/artifacts/PowerShell/HCIBox-Config.psd1 +++ b/azure_jumpstart_hcibox/artifacts/PowerShell/HCIBox-Config.psd1 @@ -83,7 +83,7 @@ FabricSwitch = "vSwitch-Fabric" FabricNIC = "FABRIC" ClusterVSwitchName = "hciSwitch" - ClusterName = "hciboxcluster" + ClusterName = "hciboxcluster2" WACVMName = "AdminCenter" ClusterSharedVolumePath = "C:\ClusterStorage\S2D_vDISK1" LCMDeployUsername = "HCIBoxDeployUser" From d97251fd17bedb5645a29ea34f7882ae9c8ae3dd Mon Sep 17 00:00:00 2001 From: saitcho <saitcho@outlook.com> Date: Sat, 20 Jan 2024 20:36:52 -0600 Subject: [PATCH 16/45] cleanup --- .../artifacts/PowerShell/HCIBox-Config.psd1 | 2 +- .../PowerShell/New-HCIBoxCluster.ps1 | 67 ++++--------------- 2 files changed, 14 insertions(+), 55 deletions(-) diff --git a/azure_jumpstart_hcibox/artifacts/PowerShell/HCIBox-Config.psd1 b/azure_jumpstart_hcibox/artifacts/PowerShell/HCIBox-Config.psd1 index cedcddeb75..949bf06d6b 100644 --- a/azure_jumpstart_hcibox/artifacts/PowerShell/HCIBox-Config.psd1 +++ b/azure_jumpstart_hcibox/artifacts/PowerShell/HCIBox-Config.psd1 @@ -138,7 +138,7 @@ WACMAC = "10155D010B00" # Router Config - BGPRouterName = "bgp-router" + BGPRouterName = "vm-router" BGPRouterIP_MGMT = "192.168.1.1/24" BGPRouterIP_ProviderNetwork = "172.16.0.1/24" BGPRouterIP_VLAN200 = "192.168.200.1/24" diff --git a/azure_jumpstart_hcibox/artifacts/PowerShell/New-HCIBoxCluster.ps1 b/azure_jumpstart_hcibox/artifacts/PowerShell/New-HCIBoxCluster.ps1 index e0eecf15dc..de80b6d4c9 100644 --- a/azure_jumpstart_hcibox/artifacts/PowerShell/New-HCIBoxCluster.ps1 +++ b/azure_jumpstart_hcibox/artifacts/PowerShell/New-HCIBoxCluster.ps1 @@ -1087,42 +1087,6 @@ function New-RouterVM { } } -function Join-HCINodesToDomain { - Param ( - $HCIBoxConfig, - [PSCredential]$localCred, - [PSCredential]$domainCred - ) - try { - foreach ($node in $HCIBoxConfig.NodeHostConfig) { - # Test connectivity to hosts - $test = Test-Connection $($node.IP).Split("/")[0] - while (!$test) { - Write-Host "Unable to contact $($node.Hostname) at $($node.IP)." -ForegroundColor Red - Start-Sleep -Seconds 2 - $test = Test-Connection $($node.IP).Split("/")[0] - } - - # Join hosts to domain - Write-Host "Joining $($node.Hostname) to domain" - $DomainJoined = "" - while ($DomainJoined -ne $HCIBoxConfig.SDNDomainFQDN) { - $job = Invoke-Command -ComputerName $node.Hostname -Credential $localCred -ArgumentList ($domainCred, $HCIBoxConfig.SDNDomainFQDN) -ScriptBlock { - Add-Computer -DomainName $args[1] -Credential $args[0] - } -AsJob - - while ($job.JobStateInfo.State -ne "Completed") { Start-Sleep -Seconds 5 } - $DomainJoined = (Get-WmiObject -ComputerName $node.Hostname -Credential $localCred -Class win32_computersystem).domain - } - Write-Host "Restarting $($node.Hostname)" - Restart-Computer -ComputerName $node.Hostname -Credential $localCred -Force - } - } - catch { - throw $_ - } -} - function New-AdminCenterVM { Param ( $HCIBoxConfig, @@ -1488,15 +1452,17 @@ function Set-HCIDeployPrereqs { } } # Workaround for incomplete BITS transfer of LCM files - Start-Sleep -Seconds 15 - foreach ($node in $HCIBoxConfig.NodeHostConfig) { - Invoke-Command -VMName $node.Hostname -Credential $localCred -ScriptBlock { - Remove-Item -Path "C:\DeploymentPackage" -Recurse -Force - } - Start-Sleep -Seconds 3 - Restart-VM -Name $node.Hostname -Force - } - Start-Sleep -Seconds 60 + # Start-Sleep -Seconds 15 + # az extension add --name connectedmachine + # az connectedmachine + # foreach ($node in $HCIBoxConfig.NodeHostConfig) { + # Invoke-Command -VMName $node.Hostname -Credential $localCred -ScriptBlock { + # Remove-Item -Path "C:\DeploymentPackage" -Recurse -Force + # } + # Start-Sleep -Seconds 3 + # Restart-VM -Name $node.Hostname -Force + # } + # Start-Sleep -Seconds 60 } #endregion @@ -1639,7 +1605,7 @@ Set-FabricNetwork -HCIBoxConfig $HCIBoxConfig -localCred $localCred # Provision the router, domain controller, and WAC VMs and join the hosts to the domain ####################################################################################### # Provision Router VM on AzSMGMT -Write-Host "[Build cluster - Step 7/10] Build BGP router VM..." -ForegroundColor Green +Write-Host "[Build cluster - Step 7/10] Build router VM..." -ForegroundColor Green New-RouterVM -HCIBoxConfig $HCIBoxConfig -localCred $localCred # Provision Domain controller VM on AzSMGMT @@ -1659,18 +1625,11 @@ Set-HCIDeployPrereqs -HCIBoxConfig $HCIBoxConfig -localCred $localCred -domainCr # Cluster complete. Finish up and add RDP Link to Desktop to WAC machine. Write-Host "[Build cluster - Step 10/10] Tidying up..." -ForegroundColor Green -Remove-Item C:\Users\Public\Desktop\AdminCenter.lnk -Force -ErrorAction SilentlyContinue -$wshshell = New-Object -ComObject WScript.Shell -$lnk = $wshshell.CreateShortcut("C:\Users\Public\Desktop\AdminCenter.lnk") -$lnk.TargetPath = "%windir%\system32\mstsc.exe" -$lnk.Arguments = "/v:$($HCIBoxConfig.WACVMName)" -$lnk.Description = "AdminCenter link for HCIBox." -$lnk.Save() $endtime = Get-Date $timeSpan = New-TimeSpan -Start $starttime -End $endtime Write-Host -Write-Host "Successfully deployed HCIBox Azure Stack HCI cluster." -ForegroundColor Green +Write-Host "Successfully deployed HCIBox infrastructure." -ForegroundColor Green Write-Host "Infrastructure deployment time was $($timeSpan.Hours):$($timeSpan.Minutes) (hh:mm)." -ForegroundColor Green Stop-Transcript From d3fe909250c5425e12f81abe0429489d62698111 Mon Sep 17 00:00:00 2001 From: saitcho <saitcho@outlook.com> Date: Sun, 21 Jan 2024 08:08:43 -0600 Subject: [PATCH 17/45] preprov --- azure_jumpstart_hcibox/scripts/preprovision.ps1 | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/azure_jumpstart_hcibox/scripts/preprovision.ps1 b/azure_jumpstart_hcibox/scripts/preprovision.ps1 index 2c276d0e79..bec723d2d0 100644 --- a/azure_jumpstart_hcibox/scripts/preprovision.ps1 +++ b/azure_jumpstart_hcibox/scripts/preprovision.ps1 @@ -163,6 +163,11 @@ if ($promptOutput -notlike 'y') { # set the env variable azd env set JS_RDP_PORT $JS_RDP_PORT +# Attempt to retrieve provider id for Microsoft.AzureStackHCI +$spnProviderId=$(az ad sp list --display-name "Microsoft.AzureStackHCI") | ConvertFrom-Json +if ($null -ne $spnProviderId.id) { + azd env set SPN_CLIENT_ID -- $($spnProviderId.id) +} ######################################################################## # Create Azure Service Principal From f0ad919e394f6113a283ae767a86452aef4217ac Mon Sep 17 00:00:00 2001 From: saitcho <saitcho@outlook.com> Date: Sun, 21 Jan 2024 08:26:25 -0600 Subject: [PATCH 18/45] preprov change --- azure_jumpstart_hcibox/scripts/preprovision.ps1 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/azure_jumpstart_hcibox/scripts/preprovision.ps1 b/azure_jumpstart_hcibox/scripts/preprovision.ps1 index bec723d2d0..630adb03f7 100644 --- a/azure_jumpstart_hcibox/scripts/preprovision.ps1 +++ b/azure_jumpstart_hcibox/scripts/preprovision.ps1 @@ -164,9 +164,10 @@ if ($promptOutput -notlike 'y') { azd env set JS_RDP_PORT $JS_RDP_PORT # Attempt to retrieve provider id for Microsoft.AzureStackHCI +Write-Host "Attempting to retrieve Microsoft.AzureStackHCI provider id..." $spnProviderId=$(az ad sp list --display-name "Microsoft.AzureStackHCI") | ConvertFrom-Json if ($null -ne $spnProviderId.id) { - azd env set SPN_CLIENT_ID -- $($spnProviderId.id) + azd env set SPN_PROVIDER_ID -- $($spnProviderId.id) } ######################################################################## From 19df22c496dea3546bc0c3ba40d7e0b40690c645 Mon Sep 17 00:00:00 2001 From: saitcho <saitcho@outlook.com> Date: Sun, 21 Jan 2024 14:40:50 -0600 Subject: [PATCH 19/45] workaround change --- .../PowerShell/New-HCIBoxCluster.ps1 | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/azure_jumpstart_hcibox/artifacts/PowerShell/New-HCIBoxCluster.ps1 b/azure_jumpstart_hcibox/artifacts/PowerShell/New-HCIBoxCluster.ps1 index de80b6d4c9..3b66b8dfd3 100644 --- a/azure_jumpstart_hcibox/artifacts/PowerShell/New-HCIBoxCluster.ps1 +++ b/azure_jumpstart_hcibox/artifacts/PowerShell/New-HCIBoxCluster.ps1 @@ -1446,23 +1446,18 @@ function Set-HCIDeployPrereqs { $azureAppCred = (New-Object System.Management.Automation.PSCredential $clientId, (ConvertTo-SecureString -String $clientSecret -AsPlainText -Force)) Connect-AzAccount -ServicePrincipal -SubscriptionId $subId -TenantId $tenantId -Credential $azureAppCred $armtoken = Get-AzAccessToken + + # Workaround for BITS transfer issue + Get-NetAdapter StorageA | Disable-NetAdapter -Confirm:$false | Out-Null + Get-NetAdapter StorageB | Disable-NetAdapter -Confirm:$false | Out-Null #Invoke the registration script. For this preview release, only eastus region is supported. Invoke-AzStackHciArcInitialization -SubscriptionID $subId -ResourceGroup $resourceGroup -TenantID $tenantId -Region eastus -Cloud "AzureCloud" -ArmAccessToken $armtoken.Token -AccountID $clientId + + Get-NetAdapter StorageA | Enable-NetAdapter -Confirm:$false | Out-Null + Get-NetAdapter StorageB | Enable-NetAdapter -Confirm:$false | Out-Null } } - # Workaround for incomplete BITS transfer of LCM files - # Start-Sleep -Seconds 15 - # az extension add --name connectedmachine - # az connectedmachine - # foreach ($node in $HCIBoxConfig.NodeHostConfig) { - # Invoke-Command -VMName $node.Hostname -Credential $localCred -ScriptBlock { - # Remove-Item -Path "C:\DeploymentPackage" -Recurse -Force - # } - # Start-Sleep -Seconds 3 - # Restart-VM -Name $node.Hostname -Force - # } - # Start-Sleep -Seconds 60 } #endregion From 9ee22f7a5e5a34dd46039982b22f7796b5c0eefe Mon Sep 17 00:00:00 2001 From: saitcho <saitcho@outlook.com> Date: Sun, 21 Jan 2024 18:14:34 -0600 Subject: [PATCH 20/45] msg --- .../artifacts/PowerShell/New-HCIBoxCluster.ps1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/azure_jumpstart_hcibox/artifacts/PowerShell/New-HCIBoxCluster.ps1 b/azure_jumpstart_hcibox/artifacts/PowerShell/New-HCIBoxCluster.ps1 index 3b66b8dfd3..fd9b1dbab9 100644 --- a/azure_jumpstart_hcibox/artifacts/PowerShell/New-HCIBoxCluster.ps1 +++ b/azure_jumpstart_hcibox/artifacts/PowerShell/New-HCIBoxCluster.ps1 @@ -1484,7 +1484,7 @@ foreach ($path in $HCIBoxConfig.Paths.GetEnumerator()) { } # Download HCIBox VHDs -Write-Host "[Build cluster - Step 1/10] Downloading HCIBox VHDs. This will take a while..." -ForegroundColor Green +Write-Host "[Build cluster - Step 1/10] Downloading HCIBox VHDs. This will may take some time..." -ForegroundColor Green BITSRequest -Params @{'Uri'='https://aka.ms/AAnn1dd'; 'Filename'="$($HCIBoxConfig.Paths.VHDDir)\AZSHCI.vhdx" } BITSRequest -Params @{'Uri'='https://jsvhds.blob.core.windows.net/hcibox23h2/AZSHCI.sha256?sp=r&st=2024-01-16T15:09:53Z&se=2027-01-16T23:09:53Z&spr=https&sv=2022-11-02&sr=b&sig=fM6nSGOUHIB90egY95Oc02NfXxFmh8fPK0bnibjAdQU%3D'; 'Filename'="$($HCIBoxConfig.Paths.VHDDir)\AZSHCI.sha256" } $checksum = Get-FileHash -Path "$($HCIBoxConfig.Paths.VHDDir)\AZSHCI.vhdx" @@ -1493,7 +1493,7 @@ if ($checksum.Hash -eq $hash) { Write-Host "AZSCHI.vhdx has valid checksum. Continuing..." } else { - Write-Error "AZSCHI.vhdx is corrupt. Abortig..." + Write-Error "AZSCHI.vhdx is corrupt. Aborting deployment. Re-run C:\HCIBox\HCIBoxLogonScript.ps1 to retry" throw } BITSRequest -Params @{'Uri'='https://aka.ms/AAnnebv'; 'Filename'="$($HCIBoxConfig.Paths.VHDDir)\GUI.vhdx"} @@ -1504,7 +1504,7 @@ if ($checksum.Hash -eq $hash) { Write-Host "GUI.vhdx has valid checksum. Continuing..." } else { - Write-Error "GUI.vhdx is corrupt. Aborting..." + Write-Error "GUI.vhdx is corrupt. Aborting deployment. Re-run C:\HCIBox\HCIBoxLogonScript.ps1 to retry" throw } BITSRequest -Params @{'Uri'='https://partner-images.canonical.com/hyper-v/desktop/focal/current/ubuntu-focal-hyperv-amd64-ubuntu-desktop-hyperv.vhdx.zip'; 'Filename'="$($HCIBoxConfig.Paths.VHDDir)\Ubuntu.vhdx.zip"} From cfe0c6a8dae8cf90e4258565ca65faba12edadb8 Mon Sep 17 00:00:00 2001 From: saitcho <saitcho@outlook.com> Date: Mon, 22 Jan 2024 07:40:48 -0600 Subject: [PATCH 21/45] simplify code --- .../artifacts/PowerShell/Generate-ARM-Template.ps1 | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/azure_jumpstart_hcibox/artifacts/PowerShell/Generate-ARM-Template.ps1 b/azure_jumpstart_hcibox/artifacts/PowerShell/Generate-ARM-Template.ps1 index 613908cf9b..45b400055e 100644 --- a/azure_jumpstart_hcibox/artifacts/PowerShell/Generate-ARM-Template.ps1 +++ b/azure_jumpstart_hcibox/artifacts/PowerShell/Generate-ARM-Template.ps1 @@ -32,19 +32,13 @@ New-AzRoleAssignment -ObjectId $env:spnProviderId -RoleDefinitionName "Azure Con $ErrorActionPreference = "Stop" $arcNodes = Get-AzConnectedMachine -ResourceGroup $env:resourceGroup -$arcNodeResourceIds = "[" -$count = 0 +$arcNodeResourceIds = $arcNodes.Id | ConvertTo-Json + foreach ($machine in $arcNodes) { $ErrorActionPreference = "Continue" New-AzRoleAssignment -ObjectId $machine.IdentityPrincipalId -RoleDefinitionName "Key Vault Secrets User" -ResourceGroup $env:resourceGroup $ErrorActionPreference = "Stop" - if ($count -gt 0) { - $arcNodeResourceIds += ", " - } - $arcNodeResourceIds += """" + $machine.id + """" - $count = $count + 1 } -$arcNodeResourceIds += "]" # Get storage account key and convert to base 64 $saKeys = Get-AzStorageAccountKey -ResourceGroupName $env:resourceGroup -Name $env:stagingStorageAccountName From 98878a6ddc1e39cbde9afd05a1bae7bfd5ff6135 Mon Sep 17 00:00:00 2001 From: saitcho <saitcho@outlook.com> Date: Mon, 22 Jan 2024 07:42:00 -0600 Subject: [PATCH 22/45] remove commented code --- .../artifacts/PowerShell/New-HCIBoxCluster.ps1 | 1 - 1 file changed, 1 deletion(-) diff --git a/azure_jumpstart_hcibox/artifacts/PowerShell/New-HCIBoxCluster.ps1 b/azure_jumpstart_hcibox/artifacts/PowerShell/New-HCIBoxCluster.ps1 index fd9b1dbab9..dd9f09e833 100644 --- a/azure_jumpstart_hcibox/artifacts/PowerShell/New-HCIBoxCluster.ps1 +++ b/azure_jumpstart_hcibox/artifacts/PowerShell/New-HCIBoxCluster.ps1 @@ -1205,7 +1205,6 @@ function New-AdminCenterVM { Write-Host "Installing DNS Server RSAT Tools on $VMName" Install-WindowsFeature -Name RSAT-DNS-Server -IncludeAllSubFeature -IncludeManagementTools | Out-Null Install-RemoteAccess -VPNType RoutingOnly | Out-Null - # Install-PackageProvider -Name Nuget -MinimumVersion 2.8.5.201 -Force # Stop Server Manager from starting on boot Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\ServerManager" -Name "DoNotOpenServerManagerAtLogon" -Value 1 From 763809430865b50b2f95faf9dcaf258c7bfe9373 Mon Sep 17 00:00:00 2001 From: saitcho <saitcho@outlook.com> Date: Mon, 22 Jan 2024 07:43:10 -0600 Subject: [PATCH 23/45] remove unneeded code --- .../artifacts/PowerShell/Generate-ARM-Template.ps1 | 2 -- 1 file changed, 2 deletions(-) diff --git a/azure_jumpstart_hcibox/artifacts/PowerShell/Generate-ARM-Template.ps1 b/azure_jumpstart_hcibox/artifacts/PowerShell/Generate-ARM-Template.ps1 index 45b400055e..1e386abc25 100644 --- a/azure_jumpstart_hcibox/artifacts/PowerShell/Generate-ARM-Template.ps1 +++ b/azure_jumpstart_hcibox/artifacts/PowerShell/Generate-ARM-Template.ps1 @@ -76,8 +76,6 @@ foreach ($node in $HCIBoxConfig.NodeHostConfig) { $storageBIPs += ", " } $physicalNodesSettings += "{ ""name"": ""$($node.Hostname)"", ""ipv4Address"": ""$($node.IP.Split("/")[0])"" }" - # $storageAIPs += "{ ""PhysicalNode"": ""$($node.Hostname)"", ""IPv4Address"": ""$($node.StorageAIP)"", ""SubnetMask"": ""$($HCIBoxConfig.storageAsubnet)"" }" - # $storageBIPs += "{ ""PhysicalNode"": ""$($node.Hostname)"", ""IPv4Address"": ""$($node.StorageBIP)"", ""SubnetMask"": ""$($HCIBoxConfig.storageBsubnet)"" }" $count = $count + 1 } $physicalNodesSettings += " ]" From f6e898b096a4ce96e933deaf140d584fb7294e81 Mon Sep 17 00:00:00 2001 From: saitcho <saitcho@outlook.com> Date: Mon, 22 Jan 2024 07:44:59 -0600 Subject: [PATCH 24/45] remove unneeded code --- .../artifacts/PowerShell/Generate-ARM-Template.ps1 | 2 -- 1 file changed, 2 deletions(-) diff --git a/azure_jumpstart_hcibox/artifacts/PowerShell/Generate-ARM-Template.ps1 b/azure_jumpstart_hcibox/artifacts/PowerShell/Generate-ARM-Template.ps1 index 1e386abc25..edbb2661ab 100644 --- a/azure_jumpstart_hcibox/artifacts/PowerShell/Generate-ARM-Template.ps1 +++ b/azure_jumpstart_hcibox/artifacts/PowerShell/Generate-ARM-Template.ps1 @@ -106,8 +106,6 @@ $hciParams = "$env:HCIBoxDir\hci.parameters.json" (Get-Content -Path $hciParams) -replace 'physicalNodesSettings-staging', $physicalNodesSettings | Set-Content -Path $hciParams (Get-Content -Path $hciParams) -replace 'ClusterWitnessStorageAccountName-staging', $env:stagingStorageAccountName | Set-Content -Path $hciParams (Get-Content -Path $hciParams) -replace 'diagnosticStorageAccountName-staging', $diagnosticsStorageName | Set-Content -Path $hciParams -#(Get-Content -Path $hciParams) -replace 'storageNetworkA-staging', $storageAIPs | Set-Content -Path $hciParams -#(Get-Content -Path $hciParams) -replace 'storageNetworkB-staging', $storageBIPs | Set-Content -Path $hciParams (Get-Content -Path $hciParams) -replace 'storageNicAVLAN-staging', $HCIBoxConfig.StorageAVLAN | Set-Content -Path $hciParams (Get-Content -Path $hciParams) -replace 'storageNicBVLAN-staging', $HCIBoxConfig.StorageBVLAN | Set-Content -Path $hciParams (Get-Content -Path $hciParams) -replace 'customLocation-staging', $HCIBoxConfig.rbCustomLocationName | Set-Content -Path $hciParams \ No newline at end of file From ac8dbc70eb008e587e6bdf26e4d559c4fccd431b Mon Sep 17 00:00:00 2001 From: saitcho <saitcho@outlook.com> Date: Mon, 22 Jan 2024 07:46:34 -0600 Subject: [PATCH 25/45] postprov msg --- azure_jumpstart_hcibox/scripts/postprovision.ps1 | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/azure_jumpstart_hcibox/scripts/postprovision.ps1 b/azure_jumpstart_hcibox/scripts/postprovision.ps1 index 2d74453b0e..a355df95ec 100644 --- a/azure_jumpstart_hcibox/scripts/postprovision.ps1 +++ b/azure_jumpstart_hcibox/scripts/postprovision.ps1 @@ -32,7 +32,8 @@ If ($rdpPort -ne "3389") { # Client VM IP address $ip = (Get-AzPublicIpAddress -ResourceGroupName $resourceGroup -Name "HCIBox-Client-PIP").IpAddress - -Write-Host "You can now connect to the client VM using the following command: " -NoNewline -WRite-Host "mstsc /v:$($ip):$($rdpPort)" -ForegroundColor Green -BackgroundColor Black -Write-Host "Remember to use the Windows admin user name [$env:JS_WINDOWS_ADMIN_USERNAME] and the password you specified." \ No newline at end of file +if ($null -ne $ip) { + Write-Host "You can now connect to the client VM using the following command: " -NoNewline + Write-Host "mstsc /v:$($ip):$($rdpPort)" -ForegroundColor Green -BackgroundColor Black + Write-Host "Remember to use the Windows admin user name [$env:JS_WINDOWS_ADMIN_USERNAME] and the password you specified." +} \ No newline at end of file From d1e178b149eea87dc1d8cdf08a9137d39d4197f2 Mon Sep 17 00:00:00 2001 From: saitcho <saitcho@outlook.com> Date: Mon, 22 Jan 2024 08:07:14 -0600 Subject: [PATCH 26/45] custom loc name --- azure_jumpstart_hcibox/artifacts/PowerShell/HCIBox-Config.psd1 | 1 + 1 file changed, 1 insertion(+) diff --git a/azure_jumpstart_hcibox/artifacts/PowerShell/HCIBox-Config.psd1 b/azure_jumpstart_hcibox/artifacts/PowerShell/HCIBox-Config.psd1 index 949bf06d6b..3318aaa083 100644 --- a/azure_jumpstart_hcibox/artifacts/PowerShell/HCIBox-Config.psd1 +++ b/azure_jumpstart_hcibox/artifacts/PowerShell/HCIBox-Config.psd1 @@ -169,6 +169,7 @@ WACport = 443 # AKS and Resource bridge variables + rbCustomLocationName = "jumpstart" storagePathName = "vms" storagePath = "C:\ClusterStorage\VMs" AKSworkloadClusterName = "hcibox-aks" # lowercase only From c0381cd8b83976d18336eb4203c2da00db5cb017 Mon Sep 17 00:00:00 2001 From: saitcho <saitcho@outlook.com> Date: Mon, 22 Jan 2024 08:46:48 -0600 Subject: [PATCH 27/45] update --- .../artifacts/PowerShell/HCIBox-Config.psd1 | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/azure_jumpstart_hcibox/artifacts/PowerShell/HCIBox-Config.psd1 b/azure_jumpstart_hcibox/artifacts/PowerShell/HCIBox-Config.psd1 index 3318aaa083..47e3ce0dbc 100644 --- a/azure_jumpstart_hcibox/artifacts/PowerShell/HCIBox-Config.psd1 +++ b/azure_jumpstart_hcibox/artifacts/PowerShell/HCIBox-Config.psd1 @@ -174,11 +174,11 @@ storagePath = "C:\ClusterStorage\VMs" AKSworkloadClusterName = "hcibox-aks" # lowercase only AKSvnetname = "akshcivnet" - AKSNodeStartIP = "192.168.200.10" - AKSNodeEndIP = "192.168.200.59" - AKSVIPStartIP = "192.168.200.60" - AKSVIPEndIP = "192.168.200.126" - AKSIPPrefix = "192.168.200.0/25" + AKSNodeStartIP = "192.168.200.100" + AKSNodeEndIP = "192.168.200.159" + AKSVIPStartIP = "192.168.200.160" + AKSVIPEndIP = "192.168.200.226" + AKSIPPrefix = "192.168.200.0/24" AKSGWIP = "192.168.200.1" AKSDNSIP = "192.168.1.254" AKSVLAN = "200" @@ -191,7 +191,7 @@ clusterIpRangeStart = "192.168.1.100" clusterIpRangeEnd = "192.168.1.199" vmGateway = "192.168.200.1" - vmIpPrefix = "192.168.200.128/26" + vmIpPrefix = "192.168.200.0/26" vmDNS = "192.168.1.254" vmVLAN = "200" } \ No newline at end of file From 4cbc77ca95d0ad4ab3d77c7c00d4b5b17cedc2ce Mon Sep 17 00:00:00 2001 From: saitcho <saitcho@outlook.com> Date: Mon, 22 Jan 2024 10:24:27 -0600 Subject: [PATCH 28/45] config name --- azure_jumpstart_hcibox/artifacts/PowerShell/HCIBox-Config.psd1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure_jumpstart_hcibox/artifacts/PowerShell/HCIBox-Config.psd1 b/azure_jumpstart_hcibox/artifacts/PowerShell/HCIBox-Config.psd1 index 47e3ce0dbc..88abc7de6f 100644 --- a/azure_jumpstart_hcibox/artifacts/PowerShell/HCIBox-Config.psd1 +++ b/azure_jumpstart_hcibox/artifacts/PowerShell/HCIBox-Config.psd1 @@ -83,7 +83,7 @@ FabricSwitch = "vSwitch-Fabric" FabricNIC = "FABRIC" ClusterVSwitchName = "hciSwitch" - ClusterName = "hciboxcluster2" + ClusterName = "hciboxcluster" WACVMName = "AdminCenter" ClusterSharedVolumePath = "C:\ClusterStorage\S2D_vDISK1" LCMDeployUsername = "HCIBoxDeployUser" From a07009edece2da75e8bd471b8c7d7c8805f3384e Mon Sep 17 00:00:00 2001 From: Dale Kirby <32211549+dkirby-ms@users.noreply.github.com> Date: Mon, 22 Jan 2024 10:27:48 -0600 Subject: [PATCH 29/45] Update azure_jumpstart_hcibox/artifacts/PowerShell/Generate-ARM-Template.ps1 Co-authored-by: Lior Kamrat <46730876+likamrat@users.noreply.github.com> --- .../artifacts/PowerShell/Generate-ARM-Template.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure_jumpstart_hcibox/artifacts/PowerShell/Generate-ARM-Template.ps1 b/azure_jumpstart_hcibox/artifacts/PowerShell/Generate-ARM-Template.ps1 index edbb2661ab..369e751988 100644 --- a/azure_jumpstart_hcibox/artifacts/PowerShell/Generate-ARM-Template.ps1 +++ b/azure_jumpstart_hcibox/artifacts/PowerShell/Generate-ARM-Template.ps1 @@ -44,7 +44,7 @@ foreach ($machine in $arcNodes) { $saKeys = Get-AzStorageAccountKey -ResourceGroupName $env:resourceGroup -Name $env:stagingStorageAccountName $storageAccountAccessKey = [Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($saKeys[0].value)) -# Convert user credentials to base 64 +# Convert user credentials to base64 $AzureStackLCM=[Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes("$($HCIBoxConfig.LCMDeployUsername):$($HCIBoxConfig.SDNAdminPassword)")) $LocalUser=[Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes("Administrator:$($HCIBoxConfig.SDNAdminPassword)")) $AzureSPN=[Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes("$($env:spnClientId):$($env:spnClientSecret)")) From ac49e75912fa68c5ea264c6c5decf69ce8c941f1 Mon Sep 17 00:00:00 2001 From: saitcho <saitcho@outlook.com> Date: Mon, 22 Jan 2024 10:42:54 -0600 Subject: [PATCH 30/45] workspace name --- azure_jumpstart_hcibox/bicep/main.azd.bicep | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure_jumpstart_hcibox/bicep/main.azd.bicep b/azure_jumpstart_hcibox/bicep/main.azd.bicep index 1471e1f7dc..77e55be10a 100644 --- a/azure_jumpstart_hcibox/bicep/main.azd.bicep +++ b/azure_jumpstart_hcibox/bicep/main.azd.bicep @@ -26,7 +26,7 @@ param windowsAdminUsername string param windowsAdminPassword string @description('Name for your log analytics workspace') -param logAnalyticsWorkspaceName string = 'HCIBox-Workspace' +param logAnalyticsWorkspaceName string = 'HCIBox-Workspace1' @description('Public DNS to use for the domain') param natDNS string = '8.8.8.8' From 182c0c6e0ac75f86216c8ef7f6d8b39ef66c8041 Mon Sep 17 00:00:00 2001 From: saitcho <saitcho@outlook.com> Date: Mon, 22 Jan 2024 10:43:11 -0600 Subject: [PATCH 31/45] revert --- azure_jumpstart_hcibox/bicep/main.azd.bicep | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure_jumpstart_hcibox/bicep/main.azd.bicep b/azure_jumpstart_hcibox/bicep/main.azd.bicep index 77e55be10a..1471e1f7dc 100644 --- a/azure_jumpstart_hcibox/bicep/main.azd.bicep +++ b/azure_jumpstart_hcibox/bicep/main.azd.bicep @@ -26,7 +26,7 @@ param windowsAdminUsername string param windowsAdminPassword string @description('Name for your log analytics workspace') -param logAnalyticsWorkspaceName string = 'HCIBox-Workspace1' +param logAnalyticsWorkspaceName string = 'HCIBox-Workspace' @description('Public DNS to use for the domain') param natDNS string = '8.8.8.8' From c6ac96fc1fbaf8bbb642c78668788655b321596c Mon Sep 17 00:00:00 2001 From: saitcho <saitcho@outlook.com> Date: Mon, 22 Jan 2024 11:53:23 -0600 Subject: [PATCH 32/45] postprov cleanup --- azure_jumpstart_hcibox/scripts/postprovision.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure_jumpstart_hcibox/scripts/postprovision.ps1 b/azure_jumpstart_hcibox/scripts/postprovision.ps1 index a355df95ec..339f43e60b 100644 --- a/azure_jumpstart_hcibox/scripts/postprovision.ps1 +++ b/azure_jumpstart_hcibox/scripts/postprovision.ps1 @@ -31,7 +31,7 @@ If ($rdpPort -ne "3389") { # Client VM IP address -$ip = (Get-AzPublicIpAddress -ResourceGroupName $resourceGroup -Name "HCIBox-Client-PIP").IpAddress +$ip = (Get-AzPublicIpAddress -ResourceGroupName $resourceGroup -Name "HCIBox-Client-PIP" -ErrorAction SilentlyContinue).IpAddress | Out-Null if ($null -ne $ip) { Write-Host "You can now connect to the client VM using the following command: " -NoNewline Write-Host "mstsc /v:$($ip):$($rdpPort)" -ForegroundColor Green -BackgroundColor Black From d34928f2eaf23be279490943f45cd7c46f401aa5 Mon Sep 17 00:00:00 2001 From: saitcho <saitcho@outlook.com> Date: Mon, 22 Jan 2024 12:29:16 -0600 Subject: [PATCH 33/45] config --- azure_jumpstart_hcibox/artifacts/PowerShell/HCIBox-Config.psd1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure_jumpstart_hcibox/artifacts/PowerShell/HCIBox-Config.psd1 b/azure_jumpstart_hcibox/artifacts/PowerShell/HCIBox-Config.psd1 index 88abc7de6f..87af23a623 100644 --- a/azure_jumpstart_hcibox/artifacts/PowerShell/HCIBox-Config.psd1 +++ b/azure_jumpstart_hcibox/artifacts/PowerShell/HCIBox-Config.psd1 @@ -191,7 +191,7 @@ clusterIpRangeStart = "192.168.1.100" clusterIpRangeEnd = "192.168.1.199" vmGateway = "192.168.200.1" - vmIpPrefix = "192.168.200.0/26" + vmIpPrefix = "192.168.200.0/24" vmDNS = "192.168.1.254" vmVLAN = "200" } \ No newline at end of file From 84ee83fe882adfa687be7b7d0504a4e4ee8df980 Mon Sep 17 00:00:00 2001 From: saitcho <saitcho@outlook.com> Date: Mon, 22 Jan 2024 18:13:05 -0600 Subject: [PATCH 34/45] fix --- .../PowerShell/Configure-VMManagement.ps1 | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/azure_jumpstart_hcibox/artifacts/PowerShell/Configure-VMManagement.ps1 b/azure_jumpstart_hcibox/artifacts/PowerShell/Configure-VMManagement.ps1 index c6688ad080..ff6fed2842 100644 --- a/azure_jumpstart_hcibox/artifacts/PowerShell/Configure-VMManagement.ps1 +++ b/azure_jumpstart_hcibox/artifacts/PowerShell/Configure-VMManagement.ps1 @@ -9,8 +9,6 @@ $Env:HCIBoxDir = "C:\HCIBox" $HCIBoxConfig = Import-PowerShellDataFile -Path $Env:HCIBoxConfigFile Start-Transcript -Path "$($HCIBoxConfig.Paths.LogsDir)\Configure-VMManagement.log" -#$csv_path = $HCIBoxConfig.ClusterSharedVolumePath - # Generate credential objects $user = "$($HCIBoxConfig.SDNDomainFQDN)\administrator" $password = ConvertTo-SecureString -String $HCIBoxConfig.SDNAdminPassword -AsPlainText -Force @@ -27,25 +25,16 @@ $spnTenantId = $env:spnTenantId $location = "eastus" $customLocName = $HCIBoxConfig.rbCustomLocationName -# Copy gallery VHDs to hosts -# Invoke-Command -VMName $HCIBoxConfig.NodeHostConfig[0].Hostname -Credential $adcred -ScriptBlock { -# New-Item -Name "VHD" -Path $using:csv_path -ItemType Directory -Force -# Move-Item -Path "C:\VHD\GUI.vhdx" -Destination "$using:csv_path\VHD\GUI.vhdx" -Force -# Move-Item -Path "C:\VHD\Ubuntu.vhdx" -Destination "$using:csv_path\VHD\Ubuntu.vhdx" -Force -# } - -# Create VM images +# Create logical networks az login --service-principal --username $env:spnClientID --password=$env:spnClientSecret --tenant $env:spnTenantId az config set extension.use_dynamic_install=yes_without_prompt $customLocationID=(az customlocation show --resource-group $env:resourceGroup --name $customLocName --query id -o tsv) -az stack-hci-vm image create --subscription $env:subscriptionId --resource-group $env:resourceGroup --custom-location $customLocationID --location $location --name "WinServer2022" --os-type "windows" --offer "windowsserver" --publisher "microsoftwindowsserver" --sku "2022-datacenter-azure-edition" --version "20348.2227.240104" # --storage-path-id $storagepathid -# Create logical networks $switchName='"ConvergedSwitch(hci)"' $lnetName = "hcibox-vm-lnet-static" $addressPrefixes = $HCIBoxConfig.vmIpPrefix $gateway = $HCIBoxConfig.vmGateway $dnsServers = $HCIBoxConfig.vmDNS $vlanid = $HCIBoxConfig.vmVLAN - -az stack-hci-vm network lnet create --subscription $env:subscriptionId --resource-group $env:resourceGroup --custom-location $customLocationID --location $location --name $lnetName --vm-switch-name $switchName --ip-allocation-method "Static" --address-prefixes $addressPrefixes --gateway $gateway --dns-servers $dnsServers --vlan $vlanid \ No newline at end of file +Start-Sleep -Seconds 10 +az stack-hci-vm network lnet create --subscription $env:subscriptionId --resource-group $env:resourceGroup --custom-location $customLocationID --location $location --name $lnetName --vm-switch-name $switchName --ip-allocation-method "static" --address-prefixes $addressPrefixes --gateway $gateway --dns-servers $dnsServers --vlan $vlanid \ No newline at end of file From ab43b470f6be44b18556558a9ae0b323e2c5b699 Mon Sep 17 00:00:00 2001 From: saitcho <saitcho@outlook.com> Date: Mon, 22 Jan 2024 18:13:50 -0600 Subject: [PATCH 35/45] rename files --- .../{Configure-AKS.ps1 => Configure-AKSWorkloadCluster.ps1} | 0 ...{Configure-VMManagement.ps1 => Configure-VMLogicalNetwork.ps1} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename azure_jumpstart_hcibox/artifacts/PowerShell/{Configure-AKS.ps1 => Configure-AKSWorkloadCluster.ps1} (100%) rename azure_jumpstart_hcibox/artifacts/PowerShell/{Configure-VMManagement.ps1 => Configure-VMLogicalNetwork.ps1} (100%) diff --git a/azure_jumpstart_hcibox/artifacts/PowerShell/Configure-AKS.ps1 b/azure_jumpstart_hcibox/artifacts/PowerShell/Configure-AKSWorkloadCluster.ps1 similarity index 100% rename from azure_jumpstart_hcibox/artifacts/PowerShell/Configure-AKS.ps1 rename to azure_jumpstart_hcibox/artifacts/PowerShell/Configure-AKSWorkloadCluster.ps1 diff --git a/azure_jumpstart_hcibox/artifacts/PowerShell/Configure-VMManagement.ps1 b/azure_jumpstart_hcibox/artifacts/PowerShell/Configure-VMLogicalNetwork.ps1 similarity index 100% rename from azure_jumpstart_hcibox/artifacts/PowerShell/Configure-VMManagement.ps1 rename to azure_jumpstart_hcibox/artifacts/PowerShell/Configure-VMLogicalNetwork.ps1 From af5b9dbade0472d015b39abf7a6803d196759262 Mon Sep 17 00:00:00 2001 From: saitcho <saitcho@outlook.com> Date: Tue, 23 Jan 2024 08:30:33 -0600 Subject: [PATCH 36/45] updates to AKS and VM networking --- .../PowerShell/Configure-VMLogicalNetwork.ps1 | 7 +------ .../artifacts/PowerShell/HCIBox-Config.psd1 | 14 ++++++-------- 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/azure_jumpstart_hcibox/artifacts/PowerShell/Configure-VMLogicalNetwork.ps1 b/azure_jumpstart_hcibox/artifacts/PowerShell/Configure-VMLogicalNetwork.ps1 index ff6fed2842..6c04e47e9b 100644 --- a/azure_jumpstart_hcibox/artifacts/PowerShell/Configure-VMLogicalNetwork.ps1 +++ b/azure_jumpstart_hcibox/artifacts/PowerShell/Configure-VMLogicalNetwork.ps1 @@ -9,11 +9,6 @@ $Env:HCIBoxDir = "C:\HCIBox" $HCIBoxConfig = Import-PowerShellDataFile -Path $Env:HCIBoxConfigFile Start-Transcript -Path "$($HCIBoxConfig.Paths.LogsDir)\Configure-VMManagement.log" -# Generate credential objects -$user = "$($HCIBoxConfig.SDNDomainFQDN)\administrator" -$password = ConvertTo-SecureString -String $HCIBoxConfig.SDNAdminPassword -AsPlainText -Force -$adcred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $user, $password - # Install AZ Resource Bridge and prerequisites Write-Host "Now Preparing to configure guest VM management" @@ -36,5 +31,5 @@ $addressPrefixes = $HCIBoxConfig.vmIpPrefix $gateway = $HCIBoxConfig.vmGateway $dnsServers = $HCIBoxConfig.vmDNS $vlanid = $HCIBoxConfig.vmVLAN -Start-Sleep -Seconds 10 + az stack-hci-vm network lnet create --subscription $env:subscriptionId --resource-group $env:resourceGroup --custom-location $customLocationID --location $location --name $lnetName --vm-switch-name $switchName --ip-allocation-method "static" --address-prefixes $addressPrefixes --gateway $gateway --dns-servers $dnsServers --vlan $vlanid \ No newline at end of file diff --git a/azure_jumpstart_hcibox/artifacts/PowerShell/HCIBox-Config.psd1 b/azure_jumpstart_hcibox/artifacts/PowerShell/HCIBox-Config.psd1 index 87af23a623..1254263505 100644 --- a/azure_jumpstart_hcibox/artifacts/PowerShell/HCIBox-Config.psd1 +++ b/azure_jumpstart_hcibox/artifacts/PowerShell/HCIBox-Config.psd1 @@ -170,16 +170,14 @@ # AKS and Resource bridge variables rbCustomLocationName = "jumpstart" - storagePathName = "vms" - storagePath = "C:\ClusterStorage\VMs" AKSworkloadClusterName = "hcibox-aks" # lowercase only AKSvnetname = "akshcivnet" - AKSNodeStartIP = "192.168.200.100" - AKSNodeEndIP = "192.168.200.159" - AKSVIPStartIP = "192.168.200.160" - AKSVIPEndIP = "192.168.200.226" - AKSIPPrefix = "192.168.200.0/24" - AKSGWIP = "192.168.200.1" + AKSNodeStartIP = "10.10.0.101" + AKSNodeEndIP = "10.10.0.199" + AKSVIPStartIP = "10.10.0.10" + AKSVIPEndIP = "10.10.0.100" + AKSIPPrefix = "10.10.0.0/24" + AKSGWIP = "10.10.0.1" AKSDNSIP = "192.168.1.254" AKSVLAN = "200" # rbVipStart = "192.168.200.200" From 5f3a6aa6c0695229066609a1a84ff2cf9f4a94d5 Mon Sep 17 00:00:00 2001 From: saitcho <saitcho@outlook.com> Date: Tue, 23 Jan 2024 08:48:19 -0600 Subject: [PATCH 37/45] add new vlan for AKS --- .../artifacts/PowerShell/HCIBox-Config.psd1 | 4 +- .../PowerShell/New-HCIBoxCluster.ps1 | 99 ++++++++++++------- 2 files changed, 68 insertions(+), 35 deletions(-) diff --git a/azure_jumpstart_hcibox/artifacts/PowerShell/HCIBox-Config.psd1 b/azure_jumpstart_hcibox/artifacts/PowerShell/HCIBox-Config.psd1 index 1254263505..18f5dd05c2 100644 --- a/azure_jumpstart_hcibox/artifacts/PowerShell/HCIBox-Config.psd1 +++ b/azure_jumpstart_hcibox/artifacts/PowerShell/HCIBox-Config.psd1 @@ -141,12 +141,14 @@ BGPRouterName = "vm-router" BGPRouterIP_MGMT = "192.168.1.1/24" BGPRouterIP_ProviderNetwork = "172.16.0.1/24" + BGPRouterIP_VLAN110 = "10.10.0.1/24" BGPRouterIP_VLAN200 = "192.168.200.1/24" BGPRouterIP_SimulatedInternet = "131.127.0.1/24" BGPRouterASN = "65534" # VLANs providerVLAN = 12 + vlan110VLAN = 110 vlan200VLAN = 200 mgmtVLAN = 0 simInternetVLAN = 131 @@ -179,7 +181,7 @@ AKSIPPrefix = "10.10.0.0/24" AKSGWIP = "10.10.0.1" AKSDNSIP = "192.168.1.254" - AKSVLAN = "200" + AKSVLAN = "110" # rbVipStart = "192.168.200.200" # rbVipEnd = "192.168.200.249" # rbDHCPExclusionStart = "192.168.200.200" diff --git a/azure_jumpstart_hcibox/artifacts/PowerShell/New-HCIBoxCluster.ps1 b/azure_jumpstart_hcibox/artifacts/PowerShell/New-HCIBoxCluster.ps1 index dd9f09e833..6b9ddd15af 100644 --- a/azure_jumpstart_hcibox/artifacts/PowerShell/New-HCIBoxCluster.ps1 +++ b/azure_jumpstart_hcibox/artifacts/PowerShell/New-HCIBoxCluster.ps1 @@ -562,12 +562,17 @@ function New-NATSwitch { Add-VMNetworkAdapter -VMName $HCIBoxConfig.MgmtHostConfig.Hostname -Name PROVIDER -DeviceNaming On -SwitchName $HCIBoxConfig.InternalSwitch Get-VMNetworkAdapter -VMName $HCIBoxConfig.MgmtHostConfig.Hostname -Name PROVIDER | Set-VMNetworkAdapter -MacAddressSpoofing On Get-VMNetworkAdapter -VMName $HCIBoxConfig.MgmtHostConfig.Hostname -Name PROVIDER | Set-VMNetworkAdapterVlan -Access -VlanId $HCIBoxConfig.providerVLAN | Out-Null - + + #Create VLAN 110 NIC in order for NAT to work from L3 Connections + Add-VMNetworkAdapter -VMName $HCIBoxConfig.MgmtHostConfig.Hostname -Name VLAN110 -DeviceNaming On -SwitchName $HCIBoxConfig.InternalSwitch + Get-VMNetworkAdapter -VMName $HCIBoxConfig.MgmtHostConfig.Hostname -Name VLAN110 | Set-VMNetworkAdapter -MacAddressSpoofing On + Get-VMNetworkAdapter -VMName $HCIBoxConfig.MgmtHostConfig.Hostname -Name VLAN110 | Set-VMNetworkAdapterVlan -Access -VlanId $HCIBoxConfig.vlan110VLAN | Out-Null + #Create VLAN 200 NIC in order for NAT to work from L3 Connections Add-VMNetworkAdapter -VMName $HCIBoxConfig.MgmtHostConfig.Hostname -Name VLAN200 -DeviceNaming On -SwitchName $HCIBoxConfig.InternalSwitch Get-VMNetworkAdapter -VMName $HCIBoxConfig.MgmtHostConfig.Hostname -Name VLAN200 | Set-VMNetworkAdapter -MacAddressSpoofing On Get-VMNetworkAdapter -VMName $HCIBoxConfig.MgmtHostConfig.Hostname -Name VLAN200 | Set-VMNetworkAdapterVlan -Access -VlanId $HCIBoxConfig.vlan200VLAN | Out-Null - + #Create Simulated Internet NIC in order for NAT to work from L3 Connections Add-VMNetworkAdapter -VMName $HCIBoxConfig.MgmtHostConfig.Hostname -Name simInternet -DeviceNaming On -SwitchName $HCIBoxConfig.InternalSwitch Get-VMNetworkAdapter -VMName $HCIBoxConfig.MgmtHostConfig.Hostname -Name simInternet | Set-VMNetworkAdapter -MacAddressSpoofing On @@ -674,9 +679,11 @@ function Set-FabricNetwork { $natIP = ($HCIBoxConfig.natSubnet.TrimEnd("0./$Prefix")) + (".1") $provIP = $HCIBoxConfig.BGPRouterIP_ProviderNetwork.TrimEnd("1/24") + "254" $vlan200IP = $HCIBoxConfig.BGPRouterIP_VLAN200.TrimEnd("1/24") + "250" + $vlan110IP = $HCIBoxConfig.BGPRouterIP_VLAN110.TrimEnd("1/24") + "250" $provGW = $HCIBoxConfig.BGPRouterIP_ProviderNetwork.TrimEnd("/24") $provpfx = $HCIBoxConfig.BGPRouterIP_ProviderNetwork.Split("/")[1] - $vlanpfx = $HCIBoxConfig.BGPRouterIP_VLAN200.Split("/")[1] + $vlan200pfx = $HCIBoxConfig.BGPRouterIP_VLAN200.Split("/")[1] + $vlan110pfx = $HCIBoxConfig.BGPRouterIP_VLAN110.Split("/")[1] $simInternetIP = $HCIBoxConfig.BGPRouterIP_SimulatedInternet.TrimEnd("1/24") + "254" $simInternetPFX = $HCIBoxConfig.BGPRouterIP_SimulatedInternet.Split("/")[1] New-VMSwitch -SwitchName NAT -SwitchType Internal -MinimumBandwidthMode None | Out-Null @@ -691,7 +698,12 @@ function Set-FabricNetwork { Write-Host "Configuring VLAN200 NIC on $env:COMPUTERNAME" $NIC = Get-NetAdapterAdvancedProperty -RegistryKeyWord "HyperVNetworkAdapterName" | Where-Object { $_.RegistryValue -eq "VLAN200" } Rename-NetAdapter -name $NIC.name -newname "VLAN200" | Out-Null - New-NetIPAddress -InterfaceAlias "VLAN200" -IPAddress $vlan200IP -PrefixLength $vlanpfx | Out-Null + New-NetIPAddress -InterfaceAlias "VLAN200" -IPAddress $vlan200IP -PrefixLength $vlan200pfx | Out-Null + + Write-Host "Configuring VLAN110 NIC on $env:COMPUTERNAME" + $NIC = Get-NetAdapterAdvancedProperty -RegistryKeyWord "HyperVNetworkAdapterName" | Where-Object { $_.RegistryValue -eq "VLAN110" } + Rename-NetAdapter -name $NIC.name -newname "VLAN110" | Out-Null + New-NetIPAddress -InterfaceAlias "VLAN110" -IPAddress $vlan110IP -PrefixLength $vlan110pfx | Out-Null Write-Host "Configuring simulatedInternet NIC on $env:COMPUTERNAME" $NIC = Get-NetAdapterAdvancedProperty -RegistryKeyWord "HyperVNetworkAdapterName" | Where-Object { $_.RegistryValue -eq "simInternet" } @@ -761,10 +773,6 @@ function New-DCVM { Set-VMProcessor -VMName $VMName -Count 2 | Out-Null Set-VM -Name $VMName -AutomaticStartAction Start -AutomaticStopAction ShutDown | Out-Null - # Add NIC for VLAN200 for DHCP server - Add-VMNetworkAdapter -VMName $VMName -Name "VLAN200" -SwitchName $HCIBoxConfig.FabricSwitch -DeviceNaming "On" - Get-VMNetworkAdapter -VMName $VMName -Name "VLAN200" | Set-VMNetworkAdapterVLAN -Access -VlanId $HCIBoxConfig.AKSVLAN - # Inject Answer File Write-Host "Mounting and injecting answer file into the $VMName VM." New-Item -Path "C:\TempMount" -ItemType Directory | Out-Null @@ -912,33 +920,45 @@ function New-DCVM { #Issue Certificate Template CMD.exe /c "certutil -SetCATemplates +WebServer" } + } +} - # Write-Host "Configuring DHCP scope on DHCP server." - # # Set up DHCP scope for Arc resource bridge - # Invoke-Command -VMName $HCIBoxConfig.DCName -Credential $using:domainCred -ArgumentList $HCIBoxConfig -ScriptBlock { - # $HCIBoxConfig = $args[0] - - # # Install DHCP feature - # Install-WindowsFeature DHCP -IncludeManagementTools - # CMD.exe /c "netsh dhcp add securitygroups" - # Restart-Service dhcpserver - - # # Allow DHCP in domain - # $dnsName = $HCIBoxConfig.DCName - # $fqdnsName = $HCIBoxConfig.DCName + "." + $HCIBoxConfig.SDNDomainFQDN - # Add-DhcpServerInDC -DnsName $fqdnsName -IPAddress $HCIBoxConfig.dcVLAN200IP - # Get-DHCPServerInDC - - # # Bind DHCP only to VLAN200 NIC - # Set-DhcpServerv4Binding -ComputerName $dnsName -InterfaceAlias $dnsName -BindingState $false - # Set-DhcpServerv4Binding -ComputerName $dnsName -InterfaceAlias VLAN200 -BindingState $true - - # # Add DHCP scope for Resource bridge VMs - # Add-DhcpServerv4Scope -name "ResourceBridge" -StartRange $HCIBoxConfig.rbVipStart -EndRange $HCIBoxConfig.rbVipEnd -SubnetMask 255.255.255.0 -State Active - # $scope = Get-DhcpServerv4Scope - # Add-DhcpServerv4ExclusionRange -ScopeID $scope.ScopeID.IPAddressToString -StartRange $HCIBoxConfig.rbDHCPExclusionStart -EndRange $HCIBoxConfig.rbDHCPExclusionEnd - # Set-DhcpServerv4OptionValue -ComputerName $dnsName -ScopeId $scope.ScopeID.IPAddressToString -DnsServer $HCIBoxConfig.SDNLABDNS -Router $HCIBoxConfig.BGPRouterIP_VLAN200.Trim("/24") - # } +function Set-DHCPServerOnDC { + Param ( + $HCIBoxConfig, + [PSCredential]$domainCred, + [PSCredential]$localCred + ) + Invoke-Command -VMName $HCIBoxConfig.MgmtHostConfig.Hostname -Credential $localCred -ScriptBlock { + # Add NIC for VLAN200 for DHCP server (for use with Arc-enabled VMs) + Add-VMNetworkAdapter -VMName $VMName -Name "VLAN200" -SwitchName $HCIBoxConfig.FabricSwitch -DeviceNaming "On" + Get-VMNetworkAdapter -VMName $VMName -Name "VLAN200" | Set-VMNetworkAdapterVLAN -Access -VlanId $HCIBoxConfig.AKSVLAN + } + Write-Host "Configuring DHCP scope on DHCP server." + # Set up DHCP scope for Arc resource bridge + Invoke-Command -VMName $HCIBoxConfig.DCName -Credential $using:domainCred -ArgumentList $HCIBoxConfig -ScriptBlock { + $HCIBoxConfig = $args[0] + + # Install DHCP feature + Install-WindowsFeature DHCP -IncludeManagementTools + CMD.exe /c "netsh dhcp add securitygroups" + Restart-Service dhcpserver + + # Allow DHCP in domain + $dnsName = $HCIBoxConfig.DCName + $fqdnsName = $HCIBoxConfig.DCName + "." + $HCIBoxConfig.SDNDomainFQDN + Add-DhcpServerInDC -DnsName $fqdnsName -IPAddress $HCIBoxConfig.dcVLAN200IP + Get-DHCPServerInDC + + # Bind DHCP only to VLAN200 NIC + Set-DhcpServerv4Binding -ComputerName $dnsName -InterfaceAlias $dnsName -BindingState $false + Set-DhcpServerv4Binding -ComputerName $dnsName -InterfaceAlias VLAN200 -BindingState $true + + # Add DHCP scope for Resource bridge VMs + Add-DhcpServerv4Scope -name "ResourceBridge" -StartRange $HCIBoxConfig.rbVipStart -EndRange $HCIBoxConfig.rbVipEnd -SubnetMask 255.255.255.0 -State Active + $scope = Get-DhcpServerv4Scope + Add-DhcpServerv4ExclusionRange -ScopeID $scope.ScopeID.IPAddressToString -StartRange $HCIBoxConfig.rbDHCPExclusionStart -EndRange $HCIBoxConfig.rbDHCPExclusionEnd + Set-DhcpServerv4OptionValue -ComputerName $dnsName -ScopeId $scope.ScopeID.IPAddressToString -DnsServer $HCIBoxConfig.SDNLABDNS -Router $HCIBoxConfig.BGPRouterIP_VLAN200.Trim("/24") } } @@ -974,9 +994,11 @@ function New-RouterVM { Write-Host "Configuring $VMName's Networking" Add-VMNetworkAdapter -VMName $VMName -Name Mgmt -SwitchName $HCIBoxConfig.FabricSwitch -DeviceNaming On Add-VMNetworkAdapter -VMName $VMName -Name Provider -SwitchName $HCIBoxConfig.FabricSwitch -DeviceNaming On + Add-VMNetworkAdapter -VMName $VMName -Name VLAN110 -SwitchName $HCIBoxConfig.FabricSwitch -DeviceNaming On Add-VMNetworkAdapter -VMName $VMName -Name VLAN200 -SwitchName $HCIBoxConfig.FabricSwitch -DeviceNaming On Add-VMNetworkAdapter -VMName $VMName -Name SIMInternet -SwitchName $HCIBoxConfig.FabricSwitch -DeviceNaming On Set-VMNetworkAdapterVlan -VMName $VMName -VMNetworkAdapterName Provider -Access -VlanId $HCIBoxConfig.providerVLAN + Set-VMNetworkAdapterVlan -VMName $VMName -VMNetworkAdapterName VLAN110 -Access -VlanId $HCIBoxConfig.vlan110VLAN Set-VMNetworkAdapterVlan -VMName $VMName -VMNetworkAdapterName VLAN200 -Access -VlanId $HCIBoxConfig.vlan200VLAN Set-VMNetworkAdapterVlan -VMName $VMName -VMNetworkAdapterName SIMInternet -Access -VlanId $HCIBoxConfig.simInternetVLAN Add-VMNetworkAdapter -VMName $VMName -Name NAT -SwitchName NAT -DeviceNaming On @@ -1015,6 +1037,8 @@ function New-RouterVM { $PNVPFX = $HCIBoxConfig.BGPRouterIP_ProviderNetwork.Split("/")[1] $VLANIP = $HCIBoxConfig.BGPRouterIP_VLAN200.Split("/")[0] $VLANPFX = $HCIBoxConfig.BGPRouterIP_VLAN200.Split("/")[1] + $VLAN110IP = $HCIBoxConfig.BGPRouterIP_VLAN110.Split("/")[0] + $VLAN110PFX = $HCIBoxConfig.BGPRouterIP_VLAN110.Split("/")[1] $simInternetIP = $HCIBoxConfig.BGPRouterIP_SimulatedInternet.Split("/")[0] $simInternetPFX = $HCIBoxConfig.BGPRouterIP_SimulatedInternet.Split("/")[1] @@ -1024,12 +1048,19 @@ function New-RouterVM { Rename-NetAdapter -name $NIC.name -newname "Mgmt" | Out-Null New-NetIPAddress -InterfaceAlias "Mgmt" -IPAddress $MGMTIP -PrefixLength $MGMTPFX | Out-Null Set-DnsClientServerAddress -InterfaceAlias “Mgmt” -ServerAddresses $DNS | Out-Null + $NIC = Get-NetAdapterAdvancedProperty -RegistryKeyWord "HyperVNetworkAdapterName" | Where-Object { $_.RegistryValue -eq "PROVIDER" } Rename-NetAdapter -name $NIC.name -newname "PROVIDER" | Out-Null New-NetIPAddress -InterfaceAlias "PROVIDER" -IPAddress $PNVIP -PrefixLength $PNVPFX | Out-Null + $NIC = Get-NetAdapterAdvancedProperty -RegistryKeyWord "HyperVNetworkAdapterName" | Where-Object { $_.RegistryValue -eq "VLAN200" } Rename-NetAdapter -name $NIC.name -newname "VLAN200" | Out-Null New-NetIPAddress -InterfaceAlias "VLAN200" -IPAddress $VLANIP -PrefixLength $VLANPFX | Out-Null + + $NIC = Get-NetAdapterAdvancedProperty -RegistryKeyWord "HyperVNetworkAdapterName" | Where-Object { $_.RegistryValue -eq "VLAN110" } + Rename-NetAdapter -name $NIC.name -newname "VLAN110" | Out-Null + New-NetIPAddress -InterfaceAlias "VLAN110" -IPAddress $VLAN110IP -PrefixLength $VLAN110PFX | Out-Null + $NIC = Get-NetAdapterAdvancedProperty -RegistryKeyWord "HyperVNetworkAdapterName" | Where-Object { $_.RegistryValue -eq "SIMInternet" } Rename-NetAdapter -name $NIC.name -newname "SIMInternet" | Out-Null New-NetIPAddress -InterfaceAlias "SIMInternet" -IPAddress $simInternetIP -PrefixLength $simInternetPFX | Out-Null From b795f4e5355376bb4e2c04e445a826a4ddfa65ac Mon Sep 17 00:00:00 2001 From: saitcho <saitcho@outlook.com> Date: Tue, 23 Jan 2024 10:42:37 -0600 Subject: [PATCH 38/45] vm logical network --- .../PowerShell/Configure-VMLogicalNetwork.ps1 | 29 ++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/azure_jumpstart_hcibox/artifacts/PowerShell/Configure-VMLogicalNetwork.ps1 b/azure_jumpstart_hcibox/artifacts/PowerShell/Configure-VMLogicalNetwork.ps1 index 6c04e47e9b..c90b033128 100644 --- a/azure_jumpstart_hcibox/artifacts/PowerShell/Configure-VMLogicalNetwork.ps1 +++ b/azure_jumpstart_hcibox/artifacts/PowerShell/Configure-VMLogicalNetwork.ps1 @@ -7,10 +7,10 @@ $Env:HCIBoxDir = "C:\HCIBox" # Import Configuration Module $HCIBoxConfig = Import-PowerShellDataFile -Path $Env:HCIBoxConfigFile -Start-Transcript -Path "$($HCIBoxConfig.Paths.LogsDir)\Configure-VMManagement.log" +Start-Transcript -Path "$($HCIBoxConfig.Paths.LogsDir)\Configure-VMLogicalNetwork.log" -# Install AZ Resource Bridge and prerequisites -Write-Host "Now Preparing to configure guest VM management" +$domainCred = new-object -typename System.Management.Automation.PSCredential ` + -argumentlist (($HCIBoxConfig.SDNDomainFQDN.Split(".")[0]) +"\Administrator"), (ConvertTo-SecureString $HCIBoxConfig.SDNAdminPassword -AsPlainText -Force) $subId = $env:subscriptionId $rg = $env:resourceGroup @@ -21,15 +21,18 @@ $location = "eastus" $customLocName = $HCIBoxConfig.rbCustomLocationName # Create logical networks -az login --service-principal --username $env:spnClientID --password=$env:spnClientSecret --tenant $env:spnTenantId -az config set extension.use_dynamic_install=yes_without_prompt -$customLocationID=(az customlocation show --resource-group $env:resourceGroup --name $customLocName --query id -o tsv) +Invoke-Command -ComputerName "$($HCIBoxConfig.NodeHostConfig[0].Hostname).$($HCIBoxConfig.SDNDomainFQDN)" -Credential $domainCred -Authentication CredSSP -ArgumentList $HCIBoxConfig -ScriptBlock { + $HCIBoxConfig = $args[0] + az login --service-principal --username $using:spnClientID --password=$using:spnSecret --tenant $using:spnTenantId + az config set extension.use_dynamic_install=yes_without_prompt + $customLocationID=(az customlocation show --resource-group $using:rg --name $using:customLocName --query id -o tsv) -$switchName='"ConvergedSwitch(hci)"' -$lnetName = "hcibox-vm-lnet-static" -$addressPrefixes = $HCIBoxConfig.vmIpPrefix -$gateway = $HCIBoxConfig.vmGateway -$dnsServers = $HCIBoxConfig.vmDNS -$vlanid = $HCIBoxConfig.vmVLAN + $switchName='"ConvergedSwitch(hci)"' + $lnetName = "hcibox-vm-lnet-vlan200" + $addressPrefixes = $HCIBoxConfig.vmIpPrefix + $gateway = $HCIBoxConfig.vmGateway + $dnsServers = $HCIBoxConfig.vmDNS + $vlanid = $HCIBoxConfig.vmVLAN -az stack-hci-vm network lnet create --subscription $env:subscriptionId --resource-group $env:resourceGroup --custom-location $customLocationID --location $location --name $lnetName --vm-switch-name $switchName --ip-allocation-method "static" --address-prefixes $addressPrefixes --gateway $gateway --dns-servers $dnsServers --vlan $vlanid \ No newline at end of file + az stack-hci-vm network lnet create --subscription $using:subId --resource-group $using:rg --custom-location $customLocationID --location $using:location --name $lnetName --vm-switch-name $switchName --ip-allocation-method "static" --address-prefixes $addressPrefixes --gateway $gateway --dns-servers $dnsServers --vlan $vlanid +} \ No newline at end of file From 8057ae01b62851dbfaac9f5964f1f201d943e2cd Mon Sep 17 00:00:00 2001 From: saitcho <saitcho@outlook.com> Date: Tue, 23 Jan 2024 14:41:36 -0600 Subject: [PATCH 39/45] decouple dhcp from main function --- .../artifacts/PowerShell/New-HCIBoxCluster.ps1 | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/azure_jumpstart_hcibox/artifacts/PowerShell/New-HCIBoxCluster.ps1 b/azure_jumpstart_hcibox/artifacts/PowerShell/New-HCIBoxCluster.ps1 index 6b9ddd15af..92631b82f8 100644 --- a/azure_jumpstart_hcibox/artifacts/PowerShell/New-HCIBoxCluster.ps1 +++ b/azure_jumpstart_hcibox/artifacts/PowerShell/New-HCIBoxCluster.ps1 @@ -808,11 +808,6 @@ function New-DCVM { Set-DnsClientServerAddress -InterfaceAlias $DCName -ServerAddresses $IP | Out-Null Install-WindowsFeature -name AD-Domain-Services -IncludeManagementTools | Out-Null - Write-Host "Configuring NIC settings for $DCName VLAN200" - $NIC = Get-NetAdapterAdvancedProperty -RegistryKeyWord "HyperVNetworkAdapterName" | Where-Object { $_.RegistryValue -eq "VLAN200" } - Rename-NetAdapter -name $NIC.name -newname VLAN200 | Out-Null - New-NetIPAddress -InterfaceAlias VLAN200 -IPAddress $HCIBoxConfig.dcVLAN200IP -PrefixLength ($HCIBoxConfig.AKSIPPrefix.split("/"))[1] -DefaultGateway $HCIBoxConfig.AKSGWIP | Out-Null - Write-Host "Configuring Trusted Hosts on $DCName" Set-Item WSMan:\localhost\Client\TrustedHosts * -Confirm:$false -Force @@ -938,6 +933,11 @@ function Set-DHCPServerOnDC { # Set up DHCP scope for Arc resource bridge Invoke-Command -VMName $HCIBoxConfig.DCName -Credential $using:domainCred -ArgumentList $HCIBoxConfig -ScriptBlock { $HCIBoxConfig = $args[0] + + Write-Host "Configuring NIC settings for $DCName VLAN200" + $NIC = Get-NetAdapterAdvancedProperty -RegistryKeyWord "HyperVNetworkAdapterName" | Where-Object { $_.RegistryValue -eq "VLAN200" } + Rename-NetAdapter -name $NIC.name -newname VLAN200 | Out-Null + New-NetIPAddress -InterfaceAlias VLAN200 -IPAddress $HCIBoxConfig.dcVLAN200IP -PrefixLength ($HCIBoxConfig.AKSIPPrefix.split("/"))[1] -DefaultGateway $HCIBoxConfig.AKSGWIP | Out-Null # Install DHCP feature Install-WindowsFeature DHCP -IncludeManagementTools From 63bdc9593b0fd6b434e2e1a5d95dd6d3ded137aa Mon Sep 17 00:00:00 2001 From: saitcho <saitcho@outlook.com> Date: Tue, 23 Jan 2024 18:47:46 -0600 Subject: [PATCH 40/45] aks --- .../artifacts/PowerShell/Bootstrap.ps1 | 4 ++-- .../PowerShell/Configure-AKSWorkloadCluster.ps1 | 9 +++++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/azure_jumpstart_hcibox/artifacts/PowerShell/Bootstrap.ps1 b/azure_jumpstart_hcibox/artifacts/PowerShell/Bootstrap.ps1 index d84f4a0b89..4fd94b0f46 100644 --- a/azure_jumpstart_hcibox/artifacts/PowerShell/Bootstrap.ps1 +++ b/azure_jumpstart_hcibox/artifacts/PowerShell/Bootstrap.ps1 @@ -103,9 +103,9 @@ Invoke-WebRequest "https://raw.githubusercontent.com/microsoft/azure_arc/main/im Invoke-WebRequest https://aka.ms/wacdownload -OutFile "$($HCIBoxConfig.Paths["WACDir"])\WindowsAdminCenter.msi" Invoke-WebRequest ($templateBaseUrl + "artifacts/PowerShell/HCIBoxLogonScript.ps1") -OutFile $HCIPath\HCIBoxLogonScript.ps1 Invoke-WebRequest ($templateBaseUrl + "artifacts/PowerShell/New-HCIBoxCluster.ps1") -OutFile $HCIPath\New-HCIBoxCluster.ps1 -Invoke-WebRequest ($templateBaseUrl + "artifacts/PowerShell/Configure-AKS.ps1") -OutFile $HCIPath\Configure-AKS.ps1 +Invoke-WebRequest ($templateBaseUrl + "artifacts/PowerShell/Configure-AKSWorkloadCluster.ps1") -OutFile $HCIPath\Configure-AKSWorkloadCluster.ps1 Invoke-WebRequest ($templateBaseUrl + "artifacts/PowerShell/Deploy-SQLMI.ps1") -OutFile $HCIPath\Deploy-SQLMI.ps1 -Invoke-WebRequest ($templateBaseUrl + "artifacts/PowerShell/Configure-VMManagement.ps1") -OutFile $HCIPath\Configure-VMManagement.ps1 +Invoke-WebRequest ($templateBaseUrl + "artifacts/PowerShell/Configure-VMLogicalNetwork.ps1") -OutFile $HCIPath\Configure-VMLogicalNetwork.ps1 Invoke-WebRequest ($templateBaseUrl + "artifacts/PowerShell/Deploy-GitOps.ps1") -OutFile $HCIPath\Deploy-GitOps.ps1 Invoke-WebRequest ($templateBaseUrl + "artifacts/PowerShell/Generate-ARM-Template.ps1") -OutFile $HCIPath\Generate-ARM-Template.ps1 Invoke-WebRequest ($templateBaseUrl + "artifacts/PowerShell/GetServiceAccountBearerToken.ps1") -OutFile $HCIPath\GetServiceAccountBearerToken.ps1 diff --git a/azure_jumpstart_hcibox/artifacts/PowerShell/Configure-AKSWorkloadCluster.ps1 b/azure_jumpstart_hcibox/artifacts/PowerShell/Configure-AKSWorkloadCluster.ps1 index 69bd8c05c7..eeda048ee2 100644 --- a/azure_jumpstart_hcibox/artifacts/PowerShell/Configure-AKSWorkloadCluster.ps1 +++ b/azure_jumpstart_hcibox/artifacts/PowerShell/Configure-AKSWorkloadCluster.ps1 @@ -7,7 +7,10 @@ $Env:HCIBoxDir = "C:\HCIBox" # Import Configuration Module $HCIBoxConfig = Import-PowerShellDataFile -Path $Env:HCIBoxConfigFile -Start-Transcript -Path "$($HCIBoxConfig.Paths.LogsDir)\Configure-AKS.log" +Start-Transcript -Path "$($HCIBoxConfig.Paths.LogsDir)\Configure-AKSWorkloadCluster.log" + +$domainCred = new-object -typename System.Management.Automation.PSCredential ` + -argumentlist (($HCIBoxConfig.SDNDomainFQDN.Split(".")[0]) +"\Administrator"), (ConvertTo-SecureString $HCIBoxConfig.SDNAdminPassword -AsPlainText -Force) # Generate credential objects Write-Host 'Creating credentials and connecting to Azure' @@ -16,7 +19,7 @@ $tenantId = $env:spnTenantId $subId = $env:subscriptionId $clustervnetname = "aksvnet1" $azureAppCred = (New-Object System.Management.Automation.PSCredential $env:spnClientID, (ConvertTo-SecureString -String $env:spnClientSecret -AsPlainText -Force)) -Invoke-Command -ComputerName "$($HCIBoxConfig.NodeHostConfig[0].HostName).jumpstart.local" -Authentication CredSSP -ArgumentList $HCIBoxConfig, $azureAppCred, $tenantId, $subId, $clustervnetname -Credential $domainCred -ScriptBlock { +Invoke-Command -ComputerName "$($HCIBoxConfig.NodeHostConfig[0].Hostname).$($HCIBoxConfig.SDNDomainFQDN)" -Authentication CredSSP -ArgumentList $HCIBoxConfig, $azureAppCred, $tenantId, $subId, $clustervnetname -Credential $domainCred -ScriptBlock { $HCIBoxConfig = $args[0] $azureAppCred = $args[1] $tenantId = $args[2] @@ -27,6 +30,8 @@ Invoke-Command -ComputerName "$($HCIBoxConfig.NodeHostConfig[0].HostName).jumpst } az login --service-principal --username $env:spnClientID --password=$env:spnClientSecret --tenant $env:spnTenantId +az extension add --name customlocation +az extension add --name akshybrid $customLocationID=(az customlocation show --resource-group $env:resourceGroup --name $HCIBoxConfig.rbCustomLocationName --query id -o tsv) az akshybrid vnet create -n $HCIBoxConfig.AKSvnetname -g $env:resourceGroup --custom-location $customlocationID --moc-vnet-name $clustervnetname $vnetId="/subscriptions/$subId/resourceGroups/$env:resourceGroup/providers/Microsoft.HybridContainerService/virtualNetworks/$($HCIBoxConfig.AKSvnetname)" From ec65bc8f8be3a9e2a2aaa374b7162d41c86fab98 Mon Sep 17 00:00:00 2001 From: saitcho <saitcho@outlook.com> Date: Tue, 23 Jan 2024 21:20:24 -0600 Subject: [PATCH 41/45] optimize --- .../artifacts/PowerShell/Bootstrap.ps1 | 2 - .../artifacts/PowerShell/Deploy-GitOps.ps1 | 210 ------ .../artifacts/PowerShell/Deploy-SQLMI.ps1 | 610 ------------------ 3 files changed, 822 deletions(-) delete mode 100644 azure_jumpstart_hcibox/artifacts/PowerShell/Deploy-GitOps.ps1 delete mode 100644 azure_jumpstart_hcibox/artifacts/PowerShell/Deploy-SQLMI.ps1 diff --git a/azure_jumpstart_hcibox/artifacts/PowerShell/Bootstrap.ps1 b/azure_jumpstart_hcibox/artifacts/PowerShell/Bootstrap.ps1 index 4fd94b0f46..c9b68f4560 100644 --- a/azure_jumpstart_hcibox/artifacts/PowerShell/Bootstrap.ps1 +++ b/azure_jumpstart_hcibox/artifacts/PowerShell/Bootstrap.ps1 @@ -104,9 +104,7 @@ Invoke-WebRequest https://aka.ms/wacdownload -OutFile "$($HCIBoxConfig.Paths["WA Invoke-WebRequest ($templateBaseUrl + "artifacts/PowerShell/HCIBoxLogonScript.ps1") -OutFile $HCIPath\HCIBoxLogonScript.ps1 Invoke-WebRequest ($templateBaseUrl + "artifacts/PowerShell/New-HCIBoxCluster.ps1") -OutFile $HCIPath\New-HCIBoxCluster.ps1 Invoke-WebRequest ($templateBaseUrl + "artifacts/PowerShell/Configure-AKSWorkloadCluster.ps1") -OutFile $HCIPath\Configure-AKSWorkloadCluster.ps1 -Invoke-WebRequest ($templateBaseUrl + "artifacts/PowerShell/Deploy-SQLMI.ps1") -OutFile $HCIPath\Deploy-SQLMI.ps1 Invoke-WebRequest ($templateBaseUrl + "artifacts/PowerShell/Configure-VMLogicalNetwork.ps1") -OutFile $HCIPath\Configure-VMLogicalNetwork.ps1 -Invoke-WebRequest ($templateBaseUrl + "artifacts/PowerShell/Deploy-GitOps.ps1") -OutFile $HCIPath\Deploy-GitOps.ps1 Invoke-WebRequest ($templateBaseUrl + "artifacts/PowerShell/Generate-ARM-Template.ps1") -OutFile $HCIPath\Generate-ARM-Template.ps1 Invoke-WebRequest ($templateBaseUrl + "artifacts/PowerShell/GetServiceAccountBearerToken.ps1") -OutFile $HCIPath\GetServiceAccountBearerToken.ps1 Invoke-WebRequest ($templateBaseUrl + "artifacts/LogInstructions.txt") -OutFile $HCIBoxConfig.Paths["LogsDir"]\LogInstructions.txt diff --git a/azure_jumpstart_hcibox/artifacts/PowerShell/Deploy-GitOps.ps1 b/azure_jumpstart_hcibox/artifacts/PowerShell/Deploy-GitOps.ps1 deleted file mode 100644 index 02e55e83e9..0000000000 --- a/azure_jumpstart_hcibox/artifacts/PowerShell/Deploy-GitOps.ps1 +++ /dev/null @@ -1,210 +0,0 @@ -$WarningPreference = "SilentlyContinue" -$ErrorActionPreference = "Stop" -$ProgressPreference = 'SilentlyContinue' -# Set paths -$Env:HCIBoxDir = "C:\HCIBox" -$Env:HCIBoxLogsDir = "C:\HCIBox\Logs" -$Env:HCIBoxVMDir = "C:\HCIBox\Virtual Machines" -$Env:HCIBoxKVDir = "C:\HCIBox\KeyVault" -$Env:HCIBoxGitOpsDir = "C:\HCIBox\GitOps" -$Env:HCIBoxIconDir = "C:\HCIBox\Icons" -$Env:HCIBoxVHDDir = "C:\HCIBox\VHD" -$Env:HCIBoxSDNDir = "C:\HCIBox\SDN" -$Env:HCIBoxWACDir = "C:\HCIBox\Windows Admin Center" -$Env:agentScript = "C:\HCIBox\agentScript" -$Env:ToolsDir = "C:\Tools" -$Env:tempDir = "C:\Temp" -$Env:VMPath = "C:\VMs" - -$ingressNamespace = "ingress-nginx" - -$certname = "ingress-cert" -$certdns = "hcibox.devops.com" - -$appClonedRepo = "https://github.com/microsoft/azure-arc-jumpstart-apps" - -if ($host.Name -match 'ISE') {throw "Running this script in PowerShell ISE is not supported"} - -try { - Start-Transcript -Path $Env:HCIBoxLogsDir\Deploy-GitOps.log -} -catch { - Start-Transcript -Path $Env:HCIBoxLogsDir\Deploy-GitOps.log -} - -# Import Configuration Module -$ConfigurationDataFile = "$Env:HCIBoxDir\HCIBox-Config.psd1" -$HCIBoxConfig = Import-PowerShellDataFile -Path $ConfigurationDataFile -$user = "jumpstart.local\administrator" -$password = ConvertTo-SecureString -String $HCIBoxConfig.SDNAdminPassword -AsPlainText -Force -$adcred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $user, $password - -$Env:AZURE_CONFIG_DIR = $cliDir.FullName - -# Required for CLI commands -Write-Header "Az CLI Login" -az login --service-principal --username $Env:spnClientID --password=$Env:spnClientSecret --tenant $Env:spnTenantId -az config set extension.use_dynamic_install=yes_without_prompt - -# Required for azcopy -$azurePassword = ConvertTo-SecureString $Env:spnClientSecret -AsPlainText -Force -$psCred = New-Object System.Management.Automation.PSCredential($Env:spnClientID , $azurePassword) -Connect-AzAccount -Credential $psCred -TenantId $Env:spnTenantId -ServicePrincipal - -# Setting kubeconfig -$clusterName = az connectedk8s list --resource-group $Env:resourceGroup --query "[].{Name:name} | [? contains(Name,'hcibox')]" --output tsv -Invoke-Command -VMName $HCIBoxConfig.HostList[0] -Credential $adcred -ScriptBlock { - Get-AksHciCredential -name $using:clusterName -Confirm:$false - kubectl get nodes - foreach ($namespace in @('hello-arc')) { - kubectl create namespace $namespace - } -} - -# Create random 13 character string for Key Vault name -$strLen = 13 -$randStr = (-join ((0x30..0x39) + (0x61..0x7A) | Get-Random -Count $strLen | ForEach-Object {[char]$_})) -$keyVaultName = "HCIBox-KV-$randStr" - -[System.Environment]::SetEnvironmentVariable('keyVaultName', $keyVaultName, [System.EnvironmentVariableTarget]::Machine) - -# Create Azure Key Vault -Write-Header "Creating Azure KeyVault" -az keyvault create --name $keyVaultName --resource-group $Env:resourceGroup --location $Env:azureLocation - -# Allow SPN to import certificates into Key Vault -Write-Header "Setting KeyVault Access Policies" -az keyvault set-policy --name $keyVaultName --spn $Env:spnClientID --key-permissions --secret-permissions get --certificate-permissions get list import - -# Making extension install dynamic -az config set extension.use_dynamic_install=yes_without_prompt -Write-Host "`n" -az -v - -############################# -# - Apply GitOps Configs -############################# - -Write-Header "Applying GitOps Configs" - -# Create GitOps config for NGINX Ingress Controller -Write-Host "Creating GitOps config for NGINX Ingress Controller" -az k8s-configuration flux create ` - --cluster-name $clusterName ` - --resource-group $Env:resourceGroup ` - --name config-nginx ` - --namespace $ingressNamespace ` - --cluster-type connectedClusters ` - --scope cluster ` - --url $appClonedRepo ` - --branch main --sync-interval 3s ` - --kustomization name=nginx path=./nginx/release - -# Create GitOps config for Hello-Arc application -Write-Host "Creating GitOps config for Hello-Arc application" -az k8s-configuration flux create ` - --cluster-name $clusterName ` - --resource-group $Env:resourceGroup ` - --name config-helloarc ` - --namespace hello-arc ` - --cluster-type connectedClusters ` - --scope namespace ` - --url $appClonedRepo ` - --branch main --sync-interval 3s ` - --kustomization name=helloarc path=./hello-arc/yaml - -################################################ -# - Install Key Vault Extension / Create Ingress -################################################ - -Write-Header "Installing KeyVault Extension" - -Write-Host "Generating a TLS Certificate" -$cert = New-SelfSignedCertificate -DnsName $certdns -KeyAlgorithm RSA -KeyLength 2048 -NotAfter (Get-Date).AddYears(1) -CertStoreLocation "Cert:\CurrentUser\My" -$certPassword = ConvertTo-SecureString -String "arcbox" -Force -AsPlainText -Export-PfxCertificate -Cert "cert:\CurrentUser\My\$($cert.Thumbprint)" -FilePath "$Env:TempDir\$certname.pfx" -Password $certPassword -Copy-VMFile AzSMGMT -SourcePath "$Env:TempDir\$certname.pfx" -DestinationPath "C:\VMConfigs\$certname.pfx" -FileSource Host -$localCred = new-object -typename System.Management.Automation.PSCredential -argumentlist "Administrator", (ConvertTo-SecureString $HCIBoxConfig.SDNAdminPassword -AsPlainText -Force) -Invoke-Command -VMName AzSMGMT -Credential $localcred -ScriptBlock { - Enable-VMIntegrationService -VMName AdminCenter -Name "Guest Service Interface" -} -Start-Sleep 20 -Invoke-Command -VMName AzSMGMT -Credential $localcred -ScriptBlock { - Copy-VMFile AdminCenter -SourcePath "C:\VMConfigs\$using:certname.pfx" -DestinationPath "C:\VHDs\$using:certname.pfx" -FileSource Host -} -Invoke-Command -ComputerName AdminCenter -Credential $adcred -ScriptBlock { - Import-PfxCertificate -FilePath "C:\VHDs\$using:certname.pfx" -CertStoreLocation Cert:\LocalMachine\Root -Password $using:certPassword -} - -Write-Host "Importing the TLS certificate to Key Vault" -az keyvault certificate import ` - --vault-name $keyVaultName ` - --password "arcbox" ` - --name $certname ` - --file "$Env:TempDir\$certname.pfx" - -Write-Host "Installing Azure Key Vault Kubernetes extension instance" -az k8s-extension create --name 'akvsecretsprovider' ` - --extension-type Microsoft.AzureKeyVaultSecretsProvider ` - --scope cluster ` - --cluster-name $clusterName ` - --resource-group $Env:resourceGroup ` - --cluster-type connectedClusters ` - --release-namespace kube-system ` - --configuration-settings 'secrets-store-csi-driver.enableSecretRotation=true' 'secrets-store-csi-driver.syncSecret.enabled=true' - -# Replace Variable values -Invoke-WebRequest ($env:templateBaseUrl + "artifacts/devops_ingress/hello-arc.yaml") -OutFile $Env:HCIBoxKVDir\hello-arc.yaml -Get-ChildItem -Path $Env:HCIBoxKVDir | - ForEach-Object { - (Get-Content -path $_.FullName -Raw) -Replace '\{JS_CERTNAME}', $certname | Set-Content -Path $_.FullName - (Get-Content -path $_.FullName -Raw) -Replace '\{JS_KEYVAULTNAME}', $keyVaultName | Set-Content -Path $_.FullName - (Get-Content -path $_.FullName -Raw) -Replace '\{JS_HOST}', $certdns | Set-Content -Path $_.FullName - (Get-Content -path $_.FullName -Raw) -Replace '\{JS_TENANTID}', $Env:spnTenantId | Set-Content -Path $_.FullName - } - -Write-Header "Creating Ingress Controller" - -# Deploy Ingress resources for Bookstore and Hello-Arc App -Copy-VMFile $HCIBoxConfig.HostList[0] -SourcePath "$Env:HCIBoxKVDir\hello-arc.yaml" -DestinationPath "C:\VHD\hello-arc.yaml" -FileSource Host -$clientId = $env:spnClientID -$clientSecret = $env:spnClientSecret -Invoke-Command -VMName $HCIBoxConfig.HostList[0] -Credential $adcred -ScriptBlock { - foreach ($namespace in @('hello-arc')) { - # Create the Kubernetes secret with the service principal credentials - kubectl create secret generic secrets-store-creds --namespace $namespace --from-literal clientid=$using:clientId --from-literal clientsecret=$using:clientSecret - kubectl --namespace $namespace label secret secrets-store-creds secrets-store.csi.k8s.io/used=true - - # Deploy Key Vault resources and Ingress for Book Store and Hello-Arc App - kubectl --namespace $namespace apply -f "C:\VHD\hello-arc.yaml" - } -} -[string]$ip = Invoke-Command -VMName $HCIBoxConfig.HostList[0] -Credential $adcred -ScriptBlock { - $ip = kubectl get service/ingress-nginx-controller --namespace $using:ingressNamespace --output=jsonpath='{.status.loadBalancer.ingress[0].ip}' - return $ip -} -# Insert into HOSTS file -Invoke-Command -ComputerName AdminCenter -Credential $adcred -ScriptBlock { - Add-Content -Path $Env:windir\System32\drivers\etc\hosts -Value "`n`t$using:ip`t$using:certdns" -Force -} - -Write-Header "Creating Desktop Icons" - -# # Creating CAPI Hello Arc Icon on Desktop -Invoke-WebRequest ($env:templateBaseUrl + "artifacts/icons/arc.ico") -OutFile $Env:HCIBoxIconDir\arc.ico -Copy-VMFile AzSMGMT -SourcePath "$Env:HCIBoxIconDir\arc.ico" -DestinationPath "C:\VMConfigs\arc.ico" -FileSource Host -Invoke-Command -VMName AzSMGMT -Credential $localcred -ScriptBlock { - Copy-VMFile AdminCenter -SourcePath "C:\VMConfigs\arc.ico" -DestinationPath "C:\VHDs\arc.ico" -FileSource Host -} - -Invoke-Command -ComputerName AdminCenter -Credential $adcred -ScriptBlock { - $shortcutLocation = "$Env:Public\Desktop\Hello-Arc.lnk" - $wScriptShell = New-Object -ComObject WScript.Shell - $shortcut = $wScriptShell.CreateShortcut($shortcutLocation) - $shortcut.TargetPath = "https://$using:certdns" - $shortcut.IconLocation="C:\VHDs\arc.ico, 0" - $shortcut.WindowStyle = 3 - $shortcut.Save() -} - -Stop-Transcript diff --git a/azure_jumpstart_hcibox/artifacts/PowerShell/Deploy-SQLMI.ps1 b/azure_jumpstart_hcibox/artifacts/PowerShell/Deploy-SQLMI.ps1 deleted file mode 100644 index 95d8ec33c4..0000000000 --- a/azure_jumpstart_hcibox/artifacts/PowerShell/Deploy-SQLMI.ps1 +++ /dev/null @@ -1,610 +0,0 @@ -$WarningPreference = 'SilentlyContinue' -$ProgressPreference = 'SilentlyContinue' - -# Set paths -$Env:HCIBoxDir = "C:\HCIBox" -$Env:HCIBoxLogsDir = "C:\HCIBox\Logs" -$Env:HCIBoxVMDir = "C:\HCIBox\Virtual Machines" -$Env:HCIBoxKVDir = "C:\HCIBox\KeyVault" -$Env:HCIBoxIconDir = "C:\HCIBox\Icons" -$Env:HCIBoxVHDDir = "C:\HCIBox\VHD" -$Env:HCIBoxSDNDir = "C:\HCIBox\SDN" -$Env:HCIBoxWACDir = "C:\HCIBox\Windows Admin Center" -$Env:agentScript = "C:\HCIBox\agentScript" -$Env:ToolsDir = "C:\Tools" -$Env:tempDir = "C:\Temp" -$Env:VMPath = "C:\VMs" - -Start-Transcript -Path $Env:HCIBoxLogsDir\Deploy-SQLMI.log - -# Capture Custom Location ObjectID -do { - $customLocationObjectId = Read-Host -Prompt "Custom Location Object Id" - if ($customLocationObjectId -eq "" -or $customLocationObjectId.Length -ne 36) { write-host "Please enter a valid Custom Location Object Id to proceed!" } -} -until ($customLocationObjectId -ne "" -and $customLocationObjectId.Length -eq 36) - -# Import Configuration Module and create Azure login credentials -Write-Header 'Importing config' -$ConfigurationDataFile = 'C:\HCIBox\HCIBox-Config.psd1' -$HCIBoxConfig = Import-PowerShellDataFile -Path $ConfigurationDataFile - -# Generate credential objects -Write-Header 'Creating credentials and connecting to Azure' -$user = "jumpstart.local\administrator" -$password = ConvertTo-SecureString -String $HCIBoxConfig.SDNAdminPassword -AsPlainText -Force -$adcred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $user, $password # Domain credential - -$azureAppCred = (New-Object System.Management.Automation.PSCredential $env:spnClientID, (ConvertTo-SecureString -String $env:spnClientSecret -AsPlainText -Force)) -Connect-AzAccount -ServicePrincipal -Subscription $env:subscriptionId -Tenant $env:spnTenantId -Credential $azureAppCred -$context = Get-AzContext # Azure credential - -Register-AzResourceProvider -ProviderNamespace Microsoft.Kubernetes -Confirm:$false -Register-AzResourceProvider -ProviderNamespace Microsoft.KubernetesConfiguration -Confirm:$false - -# Install latest versions of Nuget and PowershellGet -Write-Header "Install latest versions of Nuget and PowershellGet" -Invoke-Command -VMName $HCIBoxConfig.HostList -Credential $adcred -ScriptBlock { - Enable-PSRemoting -Force - $ProgressPreference = "SilentlyContinue" - Install-PackageProvider -Name NuGet -Force - Set-PSRepository -Name "PSGallery" -InstallationPolicy Trusted - Install-Module -Name PowershellGet -Force - $ProgressPreference = "Continue" -} - -# Install necessary AZ modules and initialize akshci on each node -Write-Header "Install necessary AZ modules, AZ CLI extensions, plus AksHCI module and initialize akshci on each node" - -Invoke-Command -VMName $HCIBoxConfig.HostList -Credential $adcred -ScriptBlock { - Write-Host "Installing Required Modules" - [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 - $ProgressPreference = "SilentlyContinue" - Install-Module -Name AksHci -Force -AcceptLicense - Import-Module Az.Accounts -DisableNameChecking - Import-Module Az.Resources -DisableNameChecking - Import-Module AzureAD -DisableNameChecking - Import-Module AksHci -DisableNameChecking - Initialize-AksHciNode - $ProgressPreference = "Continue" -} - -# Downloading artifacts for Azure Arc Data services -Write-Header "Downloading artifacts for Azure Arc Data services" -Invoke-WebRequest ($env:templateBaseUrl + "artifacts/dataController.json") -OutFile $Env:HCIBoxDir\dataController.json -Invoke-WebRequest ($env:templateBaseUrl + "artifacts/dataController.parameters.json") -OutFile $Env:HCIBoxDir\dataController.parameters.json -Invoke-WebRequest ($env:templateBaseUrl + "artifacts/adConnector.json") -OutFile $Env:HCIBoxDir\adConnector.json -Invoke-WebRequest ($env:templateBaseUrl + "artifacts/adConnector.parameters.json") -OutFile $Env:HCIBoxDir\adConnector.parameters.json -Invoke-WebRequest ($env:templateBaseUrl + "artifacts/sqlmiAD.json") -OutFile $Env:HCIBoxDir\sqlmiAD.json -Invoke-WebRequest ($env:templateBaseUrl + "artifacts/sqlmiAD.parameters.json") -OutFile $Env:HCIBoxDir\sqlmiAD.parameters.json -Invoke-WebRequest ($env:templateBaseUrl + "artifacts/settingsTemplate.json") -OutFile $Env:HCIBoxDir\settingsTemplate.json -Invoke-WebRequest ("https://azuredatastudio-update.azurewebsites.net/latest/win32-x64-archive/stable") -OutFile $Env:HCIBoxDir\azuredatastudio.zip -Invoke-WebRequest "https://aka.ms/azdata-msi" -OutFile $Env:HCIBoxDir\AZDataCLI.msi -Invoke-WebRequest "https://github.com/ErikEJ/SqlQueryStress/releases/download/102/SqlQueryStressNet6.zip" -OutFile $Env:HCIBoxDir\SqlQueryStress.zip - -Copy-VMFile $HCIBoxConfig.HostList[0] -SourcePath "$Env:HCIBoxDir\dataController.json" -DestinationPath "C:\VHD\dataController.json" -FileSource Host -Force -Copy-VMFile $HCIBoxConfig.HostList[0] -SourcePath "$Env:HCIBoxDir\dataController.parameters.json" -DestinationPath "C:\VHD\dataController.parameters.json" -FileSource Host -Force -Copy-VMFile $HCIBoxConfig.HostList[0] -SourcePath "$Env:HCIBoxDir\adConnector.json" -DestinationPath "C:\VHD\adConnector.json" -FileSource Host -Force -Copy-VMFile $HCIBoxConfig.HostList[0] -SourcePath "$Env:HCIBoxDir\adConnector.parameters.json" -DestinationPath "C:\VHD\adConnector.parameters.json" -FileSource Host -Force -Copy-VMFile $HCIBoxConfig.HostList[0] -SourcePath "$Env:HCIBoxDir\sqlmiAD.json" -DestinationPath "C:\VHD\sqlmiAD.json" -FileSource Host -Force -Copy-VMFile $HCIBoxConfig.HostList[0] -SourcePath "$Env:HCIBoxDir\sqlmiAD.parameters.json" -DestinationPath "C:\VHD\sqlmiAD.parameters.json" -FileSource Host -Force -Copy-VMFile $HCIBoxConfig.HostList[0] -SourcePath "$Env:HCIBoxDir\settingsTemplate.json" -DestinationPath "C:\VHD\settingsTemplate.json" -FileSource Host -Force -Copy-VMFile $HCIBoxConfig.HostList[0] -SourcePath "$Env:HCIBoxDir\azuredatastudio.zip" -DestinationPath "C:\VHD\azuredatastudio.zip" -FileSource Host -Force -Copy-VMFile $HCIBoxConfig.HostList[0] -SourcePath "$Env:HCIBoxDir\AZDataCLI.msi" -DestinationPath "C:\VHD\AZDataCLI.msi" -FileSource Host -Force -$adminCenterSession = New-PSSession -ComputerName "admincenter" -Credential $adcred -Copy-Item $Env:HCIBoxDir\azuredatastudio.zip -Destination "C:\VHDs\azuredatastudio.zip" -ToSession $adminCenterSession -Force -Copy-Item $Env:HCIBoxDir\SqlQueryStress.zip -Destination "C:\VHDs\SqlQueryStress.zip" -ToSession $adminCenterSession -Force - -# Generate unique name for workload cluster -$rand = New-Object System.Random -$prefixLen = 5 -[string]$namingPrefix = '' -for ($i = 0; $i -lt $prefixLen; $i++) { - $namingPrefix += [char]$rand.Next(97, 122) -} -# Get cluster name -$clusterName = $env:AKSClusterName -[System.Environment]::SetEnvironmentVariable('AKS-sqlmi-ClusterName', $clusterName, [System.EnvironmentVariableTarget]::Machine) - -# Initializing variables -$subId = $env:subscriptionId -$rg = $env:resourceGroup -$spnClientId = $env:spnClientId -$spnSecret = $env:spnClientSecret -$spnTenantId = $env:spnTenantId -$adminUsername = $env:adminUsername -$adminPassword = $HCIBoxConfig.SDNAdminPassword -$workspaceName = $env:workspaceName -$dataController = "jumpstart-dc-$namingPrefix" -$sqlMI = "jumpstart-sql" -$customLocation = "jumpstart-cl-$namingPrefix" -$domainName = "jumpstart" -$defaultDomainPartition = "DC=$domainName,DC=local" - -# Deploying the Arc Data Controller -Write-Header "Deploying the Arc Data extension" -Invoke-Command -VMName $HCIBoxConfig.HostList[0] -Credential $adcred -ScriptBlock { - [System.Environment]::SetEnvironmentVariable('Path', $env:Path + ";C:\Program Files (x86)\Microsoft SDKs\Azure\CLI2\wbin", [System.EnvironmentVariableTarget]::Machine) - $Env:Path = [System.Environment]::GetEnvironmentVariable("Path", "Machine") - az config set extension.use_dynamic_install=yes_without_prompt --only-show-errors - az login --service-principal --username $using:spnClientID --password=$using:spnSecret --tenant $using:spnTenantId - az extension add --name arcdata --system --only-show-errors - Get-AksHciCredential -name $using:clusterName -Confirm:$false - Write-Host "Installing the Arc Data extension" - Write-Host "`n" - az k8s-extension create --name arc-data-services ` - --extension-type microsoft.arcdataservices ` - --cluster-type connectedClusters ` - --cluster-name $using:clusterName ` - --resource-group $using:rg ` - --auto-upgrade false ` - --scope cluster ` - --version 1.26.0 ` - --release-namespace arc ` - --config Microsoft.CustomLocation.ServiceAccount=sa-bootstrapper ` - --only-show-errors - - Write-Host "`n" - - Do { - Write-Host "Waiting for bootstrapper pod, hold tight..." - Write-Host "`n" - kubectl get pods -n arc - Write-Host "`n" - Start-Sleep -Seconds 20 - $podStatus = $(if (kubectl get pods -n arc | Select-String "bootstrapper" | Select-String "Running" -Quiet) { "Ready!" }Else { "Nope" }) - } while ($podStatus -eq "Nope") - Write-Host "Bootstrapper pod is ready!" - Write-Host "`n" -} - -# Configuring Azure Arc Custom Location on the cluster -Write-Header "Deploying the Azure Arc Data Controller and Custom Location" -Invoke-Command -VMName $HCIBoxConfig.HostList[0] -Credential $adcred -ScriptBlock { - Get-AksHciCredential -name $using:clusterName -Confirm:$false - Write-Host "Creating the Azure Arc Custom Location" - Write-Host "`n" - $connectedClusterId = az connectedk8s show --name $using:clusterName --resource-group $using:rg --query id -o tsv --only-show-errors - az connectedk8s enable-features -n $using:clusterName -g $using:rg --custom-locations-oid $using:customLocationObjectId --features cluster-connect custom-locations --only-show-errors - $extensionId = az k8s-extension show --name arc-data-services --cluster-type connectedClusters --cluster-name $using:clusterName --resource-group $using:rg --query id -o tsv - Start-Sleep -Seconds 20 - az customlocation create --name $using:customLocation --resource-group $using:rg --namespace arc --host-resource-id $connectedClusterId --cluster-extension-ids $extensionId --only-show-errors --location eastus - - $customLocationId = $(az customlocation show --name $using:customLocation --resource-group $using:rg --query id -o tsv) - - $workspaceId = $(az resource show --resource-group $using:rg --name $using:workspaceName --resource-type "Microsoft.OperationalInsights/workspaces" --query properties.customerId -o tsv) - $workspaceKey = $(az monitor log-analytics workspace get-shared-keys --resource-group $using:rg --workspace-name $using:workspaceName --query primarySharedKey -o tsv) - - Write-Host "Deploying the Azure Arc Data Controller" - Write-Host "`n" - $dataControllerParams = "C:\VHD\dataController.parameters.json" - - (Get-Content -Path $dataControllerParams) -replace 'dataControllerName-stage', $using:dataController | Set-Content -Path $dataControllerParams - (Get-Content -Path $dataControllerParams) -replace 'resourceGroup-stage', $using:rg | Set-Content -Path $dataControllerParams - (Get-Content -Path $dataControllerParams) -replace 'azdataUsername-stage', $using:adminUsername | Set-Content -Path $dataControllerParams - (Get-Content -Path $dataControllerParams) -replace 'azdataPassword-stage', $using:adminPassword | Set-Content -Path $dataControllerParams - (Get-Content -Path $dataControllerParams) -replace 'customLocation-stage', $customLocationId | Set-Content -Path $dataControllerParams - (Get-Content -Path $dataControllerParams) -replace 'subscriptionId-stage', $using:subId | Set-Content -Path $dataControllerParams - (Get-Content -Path $dataControllerParams) -replace 'spnClientId-stage', $using:spnClientId | Set-Content -Path $dataControllerParams - (Get-Content -Path $dataControllerParams) -replace 'spnTenantId-stage', $using:spnTenantId | Set-Content -Path $dataControllerParams - (Get-Content -Path $dataControllerParams) -replace 'spnClientSecret-stage', $using:spnSecret | Set-Content -Path $dataControllerParams - (Get-Content -Path $dataControllerParams) -replace 'logAnalyticsWorkspaceId-stage', $workspaceId | Set-Content -Path $dataControllerParams - (Get-Content -Path $dataControllerParams) -replace 'logAnalyticsPrimaryKey-stage', $workspaceKey | Set-Content -Path $dataControllerParams - - az deployment group create --resource-group $using:rg --template-file "C:\VHD\dataController.json" --parameters "C:\VHD\dataController.parameters.json" - Write-Host "`n" - - Do { - Write-Host "Waiting for data controller. Hold tight, this might take a few minutes..." - Start-Sleep -Seconds 50 - Write-Host "`n" - kubectl get pods -n arc - Write-Host "`n" - Start-Sleep -Seconds 10 - $dcStatus = $(if (kubectl get datacontroller -n arc | Select-String "Ready" -Quiet) { "Ready!" }Else { "Nope" }) - } while ($dcStatus -eq "Nope") - Write-Host "Azure Arc data controller is ready!" - Write-Host "`n" -} - -# Preparing AD for SQL MI AD authenticaion -Write-Header "Deploying the Azure Arc-enabled SQL Managed Instance" -Invoke-Command -VMName $HCIBoxConfig.HostList[0] -Credential $adcred -ScriptBlock { - $ErrorActionPreference = 'SilentlyContinue' - $WarningPreference = 'SilentlyContinue' - Add-WindowsFeature -Name "RSAT-AD-PowerShell" -IncludeAllSubFeature - Add-WindowsFeature -Name "RSAT-DNS-Server" -IncludeAllSubFeature - Get-AksHciCredential -name $using:clusterName -Confirm:$false - $dcInfo = Get-ADDomainController -discover -domain $using:domainName - $sqlmiouName = "ArcSQLMI" - $sqlmiOUDN = "OU=" + $sqlmiouName + "," + $using:defaultDomainPartition - $sqlmi_port = 31433 - $adminUsername = $using:adminUsername - $adminPassword = $using:adminPassword - $dcIPv4 = ([System.Net.IPAddress]$dcInfo.IPv4Address).GetAddressBytes() - $dcIpv4Secondary = ([System.Net.IPAddress]$using:HCIBoxConfig.dcVLAN200IP).GetAddressBytes() - $reverseLookupCidr = [System.String]::Concat($dcIPv4[0], '.', $dcIPv4[1], '.', $dcIPv4[2], '.0/24') - $reverseLookupSecondaryCidr = [System.String]::Concat($dcIpv4Secondary[0], '.', $dcIpv4Secondary[1], '.', $dcIpv4Secondary[2], '.0/24') - - Write-Host "Reverse lookup zone CIDR $reverseLookupCidr" - # Setup reverse lookup zone - # check if reverse DNS already setup - $ReverseDnsZone = Get-DnsServerZone -ComputerName $dcInfo.HostName | Where-Object { $_.IsAutoCreated -eq $false -and $_.IsReverseLookupZone -eq $true } - if ($null -eq $ReverseDnsZone) { - try { - Add-DnsServerPrimaryZone -NetworkId $reverseLookupCidr -ReplicationScope Domain -ComputerName $dcInfo.HostName - Add-DnsServerPrimaryZone -NetworkId $reverseLookupSecondaryCidr -ReplicationScope Domain -ComputerName $dcInfo.HostName - Write-Host "Successfully created reverse DNS Zone." - - $ReverseDnsZone = Get-DnsServerZone -ComputerName $dcInfo.HostName | Where-Object { $_.IsAutoCreated -eq $false -and $_.IsReverseLookupZone -eq $true } - } - catch { - # Reverse DNS already setup - Write-Host "Failed to create Reverse DNS Zone." - Exit - } - } - else { - Write-Host "Reverse DNS Zone ${ReverseDnsZone.Name} already exists for this domain controller." - } - - # Create reverse DNS for domain controller - if ($null -ne $ReverseDnsZone) { - try { - Add-DNSServerResourceRecordPTR -ZoneName $ReverseDnsZone[0].ZoneName -Name $dcIPv4[3] -PTRDomainName $dcInfo.HostName -ComputerName $dcInfo.HostName - Add-DNSServerResourceRecordPTR -ZoneName $ReverseDnsZone[1].ZoneName -Name $dcIpv4Secondary[3] -PTRDomainName $dcInfo.HostName -ComputerName $dcInfo.HostName - Write-Host "Created PTR record for domain controller." - } - catch { - Write-Host "Failed to create domain controller PTR record or PTR record already exists." - } - } - else { - Write-Host "Failed to create reverse DNS lookup zone or zone does not exist." - Exit - } - - # Create ArcSQLMI OU - Write-Host "Creating the SQL MI OU in Active directory" - Write-Host "`n" - try { - $ou = Get-ADOrganizationalUnit -Identity $sqlmiOUDN - if ($null -ne $ou -and $ou.Name.Length -gt 0) { - Write-Host "Organization Unit $sqlmiouName already exist. Skipping this step." - } - else { - Write-Host "Organization Unit $sqlmiouName does not exist. Creating new OU." - New-ADOrganizationalUnit -Name $sqlmiouName -Path $using:defaultDomainPartition -ProtectedFromAccidentalDeletion $False - } - } - catch { - Write-Host "Organization Unit $sqlmiOu does not exist. Creating new OU." - New-ADOrganizationalUnit -Name $sqlmiouName -Path $using:defaultDomainPartition -ProtectedFromAccidentalDeletion $False - } - - # Creating endpoints file - Write-Host "Creating endpoints file" - Write-Host "`n" - $filename = "SQLMIEndpoints.txt" - $file = New-Item -Path "C:\VHD" -Name $filename -ItemType "file" - $Endpoints = $file.FullName - - $sqlMIName = $using:sqlMI - $sqlmi_fqdn_name = $sqlMIName + "." + $dcInfo.domain - $sqlmi_secondary_fqdn_name = $sqlMIName + "-secondary." + $dcInfo.domain - - # Create dedicated service account for AD connector - Write-Host "Creating dedicated service account for AD connector" - Write-Host "`n" - $arcsaname = "sa-$sqlMIName" - $arcsapass = "ArcDSA#Pwd123$" - $arcsasecpass = $arcsapass | ConvertTo-SecureString -AsPlainText -Force - $sqlmisaupn = $arcsaname + "@" + $dcInfo.domain - - $samaccountname = $arcsaname - $domain_netbios_name = $dcInfo.domain.split('.')[0].ToUpper(); - $domain_name = $dcInfo.domain.ToUpper() - - try { - New-ADUser -Name $arcsaname ` - -UserPrincipalName $sqlmisaupn ` - -Path $sqlmiOUDN ` - -AccountPassword $arcsasecpass ` - -Enabled $true ` - -ChangePasswordAtLogon $false ` - -PasswordNeverExpires $true - } - catch { - # User already exists - Write-Host "User $arcsaname already existings in the directory." - } - - Start-Sleep -Seconds 10 - # Geneate key tab - Write-Host "Gerating key tab for primary and secondary SQL MI instance" - Write-Host "`n" - try { - setspn -A MSSQLSvc/${sqlmi_fqdn_name} ${domain_netbios_name}\${samaccountname} - setspn -A MSSQLSvc/${sqlmi_fqdn_name}:${sqlmi_port} ${domain_netbios_name}\${samaccountname} - - # Secondary instance spn - setspn -A MSSQLSvc/${sqlmi_secondary_fqdn_name} ${domain_netbios_name}\${samaccountname} - setspn -A MSSQLSvc/${sqlmi_secondary_fqdn_name}:${sqlmi_port} ${domain_netbios_name}\${samaccountname} - - $keytab_file = "C:\VHD\$sqlMIName.keytab" - ktpass /princ MSSQLSvc/${sqlmi_fqdn_name}@${domain_name} /ptype KRB5_NT_PRINCIPAL /crypto aes256-sha1 /mapuser ${domain_netbios_name}\${samaccountname} /out $keytab_file -setpass -setupn /pass $arcsapass - ktpass /princ MSSQLSvc/${sqlmi_fqdn_name}@${domain_name} /ptype KRB5_NT_PRINCIPAL /crypto rc4-hmac-nt /mapuser ${domain_netbios_name}\${samaccountname} /in $keytab_file /out $keytab_file -setpass -setupn /pass $arcsapass - ktpass /princ MSSQLSvc/${sqlmi_fqdn_name}:${sqlmi_port}@${domain_name} /ptype KRB5_NT_PRINCIPAL /crypto aes256-sha1 /mapuser ${domain_netbios_name}\${samaccountname} /in $keytab_file /out $keytab_file -setpass -setupn /pass $arcsapass - ktpass /princ MSSQLSvc/${sqlmi_fqdn_name}:${sqlmi_port}@${domain_name} /ptype KRB5_NT_PRINCIPAL /crypto rc4-hmac-nt /mapuser ${domain_netbios_name}\${samaccountname} /in $keytab_file /out $keytab_file -setpass -setupn /pass $arcsapass - - # Generate Keytab for secondary - ktpass /princ MSSQLSvc/${sqlmi_secondary_fqdn_name}@${domain_name} /ptype KRB5_NT_PRINCIPAL /crypto aes256-sha1 /mapuser ${domain_netbios_name}\${samaccountname} /in $keytab_file /out $keytab_file -setpass -setupn /pass $arcsapass - ktpass /princ MSSQLSvc/${sqlmi_secondary_fqdn_name}@${domain_name} /ptype KRB5_NT_PRINCIPAL /crypto rc4-hmac-nt /mapuser ${domain_netbios_name}\${samaccountname} /in $keytab_file /out $keytab_file -setpass -setupn /pass $arcsapass - ktpass /princ MSSQLSvc/${sqlmi_secondary_fqdn_name}:${sqlmi_port}@${domain_name} /ptype KRB5_NT_PRINCIPAL /crypto aes256-sha1 /mapuser ${domain_netbios_name}\${samaccountname} /in $keytab_file /out $keytab_file -setpass -setupn /pass $arcsapass - ktpass /princ MSSQLSvc/${sqlmi_secondary_fqdn_name}:${sqlmi_port}@${domain_name} /ptype KRB5_NT_PRINCIPAL /crypto rc4-hmac-nt /mapuser ${domain_netbios_name}\${samaccountname} /in $keytab_file /out $keytab_file -setpass -setupn /pass $arcsapass - - ktpass /princ ${samaccountname}@${domain_name} /ptype KRB5_NT_PRINCIPAL /crypto aes256-sha1 /mapuser ${domain_netbios_name}\${samaccountname} /in $keytab_file /out $keytab_file -setpass -setupn /pass $arcsapass - ktpass /princ ${samaccountname}@${domain_name} /ptype KRB5_NT_PRINCIPAL /crypto rc4-hmac-nt /mapuser ${domain_netbios_name}\${samaccountname} /in $keytab_file /out $keytab_file -setpass -setupn /pass $arcsapass - # Convert key tab file into base64 data - $keytabrawdata = Get-Content $keytab_file -Encoding byte - $b64keytabtext = [System.Convert]::ToBase64String($keytabrawdata) - # Grant permission to DSA account on SQLMI OU - } - catch { - - } - - Start-Sleep -Seconds 10 - - Write-Host "Deploying Azure Arc AD connecter" - Write-Host "`n" - $adConnectorParams = "C:\VHD\adConnector.parameters.json" - $adConnectorName = $using:dataController + "/adarc" - $serviceAccountProvisioning = "manual" - (Get-Content -Path $adConnectorParams) -replace 'connectorName-stage', $adConnectorName | Set-Content -Path $adConnectorParams - (Get-Content -Path $adConnectorParams) -replace 'domainController-stage', $dcInfo.HostName | Set-Content -Path $adConnectorParams - (Get-Content -Path $adConnectorParams) -replace 'netbiosDomainName-stage', $domain_netbios_name | Set-Content -Path $adConnectorParams - (Get-Content -Path $adConnectorParams) -replace 'realm-stage', $dcInfo.domain.ToUpper() | Set-Content -Path $adConnectorParams - (Get-Content -Path $adConnectorParams) -replace 'serviceAccountProvisioning-stage', $serviceAccountProvisioning | Set-Content -Path $adConnectorParams - (Get-Content -Path $adConnectorParams) -replace 'domainName-stage', $dcInfo.domain.Tolower() | Set-Content -Path $adConnectorParams - - az deployment group create --resource-group $using:rg --name "AD-Connector" --template-file "C:\VHD\adConnector.json" --parameters "C:\VHD\adConnector.parameters.json" - Write-Host "`n" - Do { - Write-Host "Waiting for AD connector deployment. Hold tight, this might take a few minutes...(30s sleeping loop)" - Write-Host "`n" - Start-Sleep -Seconds 15 - kubectl get pods -n arc - Start-Sleep -Seconds 5 - Write-Host "`n" - $adcStatus = $(if (kubectl get adc adarc -n arc | Select-String "Ready" -Quiet) { "Ready!" }Else { "Nope" }) - } while ($adcStatus -eq "Nope") - - Write-Host "`n" - Write-Host "Azure Arc AD connector ready!" - Write-Host "`n" - - # Deploying the Azure Arc-enabled SQL Managed Instance - Write-Host "Deploying the Azure Arc-enabled SQL Managed Instance" - Write-Host "`n" - - $dataControllerId = $(az resource show --resource-group $using:rg --name $using:dataController --resource-type "Microsoft.AzureArcData/dataControllers" --query id -o tsv) - $customLocationId = $(az customlocation show --name $using:customLocation --resource-group $using:rg --query id -o tsv) - - ################################################ - # Localize ARM template - ################################################ - $ServiceType = "LoadBalancer" - $readableSecondaries = $ServiceType - - # Resource Requests - $vCoresRequest = "2" - $memoryRequest = "4Gi" - $vCoresLimit = "4" - $memoryLimit = "8Gi" - - # Storage - $StorageClassName = "default" - $dataStorageSize = "5Gi" - $logsStorageSize = "5Gi" - $dataLogsStorageSize = "5Gi" - - # High Availability - $replicas = 2 # Deploy SQL MI "Business Critical" tier - ####################################################### - - $SQLParams = "C:\VHD\sqlmiAD.parameters.json" - -(Get-Content -Path $SQLParams) -replace 'resourceGroup-stage', $using:rg | Set-Content -Path $SQLParams -(Get-Content -Path $SQLParams) -replace 'dataControllerId-stage', $dataControllerId | Set-Content -Path $SQLParams -(Get-Content -Path $SQLParams) -replace 'customLocation-stage', $customLocationId | Set-Content -Path $SQLParams -(Get-Content -Path $SQLParams) -replace 'subscriptionId-stage', $using:subId | Set-Content -Path $SQLParams -(Get-Content -Path $SQLParams) -replace 'azdataUsername-stage', $using:adminUsername | Set-Content -Path $SQLParams -(Get-Content -Path $SQLParams) -replace 'azdataPassword-stage', $using:adminPassword | Set-Content -Path $SQLParams -(Get-Content -Path $SQLParams) -replace 'serviceType-stage', $ServiceType | Set-Content -Path $SQLParams -(Get-Content -Path $SQLParams) -replace 'readableSecondaries-stage', $readableSecondaries | Set-Content -Path $SQLParams -(Get-Content -Path $SQLParams) -replace 'vCoresRequest-stage', $vCoresRequest | Set-Content -Path $SQLParams -(Get-Content -Path $SQLParams) -replace 'memoryRequest-stage', $memoryRequest | Set-Content -Path $SQLParams -(Get-Content -Path $SQLParams) -replace 'vCoresLimit-stage', $vCoresLimit | Set-Content -Path $SQLParams -(Get-Content -Path $SQLParams) -replace 'memoryLimit-stage', $memoryLimit | Set-Content -Path $SQLParams -(Get-Content -Path $SQLParams) -replace 'dataStorageClassName-stage', $StorageClassName | Set-Content -Path $SQLParams -(Get-Content -Path $SQLParams) -replace 'logsStorageClassName-stage', $StorageClassName | Set-Content -Path $SQLParams -(Get-Content -Path $SQLParams) -replace 'dataLogStorageClassName-stage', $StorageClassName | Set-Content -Path $SQLParams -(Get-Content -Path $SQLParams) -replace 'dataSize-stage', $dataStorageSize | Set-Content -Path $SQLParams -(Get-Content -Path $SQLParams) -replace 'logsSize-stage', $logsStorageSize | Set-Content -Path $SQLParams -(Get-Content -Path $SQLParams) -replace 'dataLogSize-stage', $dataLogsStorageSize | Set-Content -Path $SQLParams -(Get-Content -Path $SQLParams) -replace 'replicasStage' , $replicas | Set-Content -Path $SQLParams -(Get-Content -Path $SQLParams) -replace 'sqlInstanceName-stage' , $using:sqlMI | Set-Content -Path $SQLParams -(Get-Content -Path $SQLParams) -replace 'keyTab-stage' , $b64keytabtext | Set-Content -Path $SQLParams -(Get-Content -Path $SQLParams) -replace 'adAccountName-stage' , $arcsaname | Set-Content -Path $SQLParams -(Get-Content -Path $SQLParams) -replace 'adConnectorName-stage' , "adarc" | Set-Content -Path $SQLParams -(Get-Content -Path $SQLParams) -replace 'dnsName-stage' , $sqlmi_fqdn_name | Set-Content -Path $SQLParams -(Get-Content -Path $SQLParams) -replace 'dnsNameSecondary-stage' , $sqlmi_secondary_fqdn_name | Set-Content -Path $SQLParams -(Get-Content -Path $SQLParams) -replace 'port-stage' , $sqlmi_port | Set-Content -Path $SQLParams -(Get-Content -Path $SQLParams) -replace 'licenseType-stage' , "LicenseIncluded" | Set-Content -Path $SQLParams - - az deployment group create --resource-group $using:rg --name $using:sqlMI --template-file "C:\VHD\sqlmiAD.json" --parameters "C:\VHD\sqlmiAD.parameters.json" - Write-Host "`n" - - Do { - Write-Host "Waiting for SQL Managed Instance. Hold tight, this might take a few minutes...(45s sleeping loop)" - Write-Host "`n" - Start-Sleep -Seconds 50 - kubectl get pods -n arc - Write-Host "`n" - Start-Sleep -Seconds 10 - $dcStatus = $(if (kubectl get sqlmanagedinstances -n arc | Select-String "Ready" -Quiet) { "Ready!" }Else { "Nope" }) - } while ($dcStatus -eq "Nope") - Write-Host "Azure Arc SQL Managed Instance is ready!" - Write-Host "`n" - - # Create windows account in SQLMI to support AD authentication and grant sysadmin role - $podname = "${sqlMIName}-0" - kubectl exec $podname -c arc-sqlmi -n arc -- /opt/mssql-tools/bin/sqlcmd -S localhost -U $adminUsername -P "$adminPassword" -Q "CREATE LOGIN [${domain_netbios_name}\$adminUsername] FROM WINDOWS" - Write-Host "Created Windows user account ${domain_netbios_name}\$adminUsername in SQLMI instance." - - kubectl exec $podname -c arc-sqlmi -n arc -- /opt/mssql-tools/bin/sqlcmd -S localhost -U $adminUsername -P "$adminPassword" -Q "EXEC master..sp_addsrvrolemember @loginame = N'${domain_netbios_name}\$adminUsername', @rolename = N'sysadmin'" - Write-Host "Granted sysadmin role to user account ${domain_netbios_name}\$adminUsername in SQLMI instance." - - # Downloading demo database and restoring onto SQL MI - Write-Host "`n" - Write-Host "Downloading AdventureWorks database for MS SQL... (1/2)" - kubectl exec $podname -n arc -c arc-sqlmi -- wget https://github.com/Microsoft/sql-server-samples/releases/download/adventureworks/AdventureWorks2019.bak -O /var/opt/mssql/data/AdventureWorks2019.bak 2>&1 | Out-Null - Write-Host "Restoring AdventureWorks database for MS SQL. (2/2)" - kubectl exec $podname -n arc -c arc-sqlmi -- /opt/mssql-tools/bin/sqlcmd -S localhost -U $adminUsername -P "$adminPassword" -Q "RESTORE DATABASE AdventureWorks2019 FROM DISK = N'/var/opt/mssql/data/AdventureWorks2019.bak' WITH MOVE 'AdventureWorks2019' TO '/var/opt/mssql/data/AdventureWorks2019.mdf', MOVE 'AdventureWorks2019_Log' TO '/var/opt/mssql/data/AdventureWorks2019_Log.ldf'" 2>&1 $null - Write-Host "Restoring AdventureWorks database completed." -} - -# Install Azure Data Studio -Invoke-Command -ComputerName admincenter -Credential $adcred -ScriptBlock { - $adminUsername = $using:adminUsername - Write-Host "Installing Azure Data Studio" - Expand-Archive "C:\VHDs\azuredatastudio.zip" -DestinationPath 'C:\Program Files\Azure Data Studio' - Start-Process msiexec.exe -Wait -ArgumentList "/I C:\VHD\AZDataCLI.msi /quiet" - Write-Host "Installing Azure Data Studio extensions" - $Env:argument1 = "--install-extension" - $Env:argument2 = "microsoft.azcli" - $Env:argument3 = "Microsoft.arc" - - & "C:\Program Files\Azure Data Studio\bin\azuredatastudio.cmd" $Env:argument1 $Env:argument2 - & "C:\Program Files\Azure Data Studio\bin\azuredatastudio.cmd" $Env:argument1 $Env:argument3 - - # Create Azure Data Studio desktop shortcut - Write-Host "Creating Azure Data Studio Desktop Shortcut" - $TargetFile = "C:\Program Files\Azure Data Studio\azuredatastudio.exe" - $ShortcutFile = "C:\Users\$adminUsername\Desktop\Azure Data Studio.lnk" - $WScriptShell = New-Object -ComObject WScript.Shell - $Shortcut = $WScriptShell.CreateShortcut($ShortcutFile) - $Shortcut.TargetPath = $TargetFile - $Shortcut.Save() - - -} - -Write-Header "Configure ADS" -Invoke-Command -VMName $HCIBoxConfig.HostList[0] -Credential $adcred -ScriptBlock { - $WarningPreference = 'SilentlyContinue' - $ErrorActionPreference = 'silentlycontinue' - $adminUsername = $using:adminUsername - $adminCenterSession = New-PSSession -ComputerName "admincenter" -Credential $using:adcred - Write-Host "Generating endpoints file" - Write-host "`n" - - # Retrieving SQL MI connection endpoint - $sqlMIName = $using:sqlMI - $dcInfo = Get-ADDomainController -discover -domain $using:domainName - Get-AksHciCredential -name $using:clusterName -Confirm:$false - $sqlmiEndPoint = kubectl get SqlManagedInstance $sqlMIName -n arc -o=jsonpath='{.status.endpoints.primary}' - $sqlmiSecondaryEndPoint = kubectl get SqlManagedInstance $sqlMIName -n arc -o=jsonpath='{.status.endpoints.secondary}' - Write-host "`n" - - # Get public ip of the SQLMI endpoint - $sqlmiIpaddress = kubectl get svc -n arc "$sqlMIName-external-svc" -o jsonpath='{.status.loadBalancer.ingress[0].ip}' - Add-DnsServerResourceRecord -ComputerName $dcInfo.HostName -ZoneName $dcInfo.Domain -A -Name $sqlMIName -AllowUpdateAny -IPv4Address $sqlmiIpaddress -TimeToLive 01:00:00 -AgeRecord - - # Get public ip of the secondary SQLMI endpoint - $sqlmiSecondaryIpaddress = kubectl get svc -n arc "$sqlMIName-secondary-external-svc" -o jsonpath='{.status.loadBalancer.ingress[0].ip}' - Add-DnsServerResourceRecord -ComputerName $dcInfo.HostName -ZoneName $dcInfo.Domain -A -Name "$sqlMIName-secondary" -AllowUpdateAny -IPv4Address $sqlmiSecondaryIpaddress -TimeToLive 01:00:00 -AgeRecord - - # Write endpoint information in the file - - Start-Sleep -Seconds 5 - $filename = "SQLMIEndpoints.txt" - $Endpoints = "c:\vhd\$filename.txt" - - Add-Content $Endpoints "======================================================================" - Add-Content $Endpoints "" - Add-Content $Endpoints "$sqlMIName external endpoint DNS name for AD Authentication:" - $sqlmiEndPoint | Add-Content $Endpoints - - Add-Content $Endpoints "" - Add-Content $Endpoints "$sqlMIName secondary external endpoint DNS name for AD Authentication:" - $sqlmiSecondaryEndPoint | Add-Content $Endpoints - - Add-Content $Endpoints "" - Add-Content $Endpoints "SQL Managed Instance SQL login username:" - $using:adminUsername | Add-Content $Endpoints - - Add-Content $Endpoints "" - Add-Content $Endpoints "SQL Managed Instance SQL login password:" - $using:adminPassword | Add-Content $Endpoints - Add-Content $Endpoints "" - - Add-Content $Endpoints "======================================================================" - Add-Content $Endpoints "" - - Copy-Item "c:\VHD\$filename.txt" -Destination "C:\users\$adminUsername\desktop\SQLMI endpoints.txt" -ToSession $adminCenterSession -Force - - write-host "Configuring ADS" - - $settingsTemplate = "c:\VHD\settingsTemplate.json" - $ADSConnections = @" -{ - "options": { - "connectionName": "SQLMI", - "server": "$sqlmiEndPoint", - "database": "", - "authenticationType": "Integrated", - "applicationName": "azdata", - "groupId": "C777F06B-202E-4480-B475-FA416154D458", - "databaseDisplayName": "" - }, - "groupId": "C777F06B-202E-4480-B475-FA416154D458", - "providerName": "MSSQL", - "savePassword": true, - "id": "ac333479-a04b-436b-88ab-3b314a201295" -} -"@ - - $settingsTemplateJson = Get-Content $settingsTemplate | ConvertFrom-Json - $settingsTemplateJson.'datasource.connections'[0] = ConvertFrom-Json -InputObject $ADSConnections - ConvertTo-Json -InputObject $settingsTemplateJson -Depth 3 | Set-Content -Path $settingsTemplate - - New-Item -Path "\\admincenter\c$\users\$adminUsername\AppData\Roaming\azuredatastudio\" -Name "User" -ItemType "directory" -Force - Copy-Item -Path $settingsTemplate -Destination "\\admincenter\c$\users\$adminUsername\AppData\Roaming\azuredatastudio\User\settings.json" - -} - -Write-Header "Configure SQL Query Stress" -# Unzip SqlQueryStress -Invoke-Command -ComputerName admincenter -Credential $adcred -ScriptBlock { - Expand-Archive -Path C:\VHDs\SqlQueryStress.zip -DestinationPath C:\VHDs\SqlQueryStress - - # Create SQLQueryStress desktop shortcut - Write-Host "Installing dotnet sdk" - choco install dotnet-sdk -y -r --no-progress - Write-Host "`n" - Write-Host "Creating SQLQueryStress Desktop shortcut" - Write-Host "`n" - $TargetFile = "C:\VHDs\SqlQueryStress\SqlQueryStress.exe" - $ShortcutFile = "C:\Users\$using:adminUsername\Desktop\SqlQueryStress.lnk" - $WScriptShell = New-Object -ComObject WScript.Shell - $Shortcut = $WScriptShell.CreateShortcut($ShortcutFile) - $Shortcut.TargetPath = $TargetFile - $Shortcut.Save() -} - -# Set env variable deployAKSHCI to true (in case the script was run manually) -[System.Environment]::SetEnvironmentVariable('deploySQLMI', 'true', [System.EnvironmentVariableTarget]::Machine) - -Stop-Transcript \ No newline at end of file From 96b71aa3bd556617936ec9546533693535c3332c Mon Sep 17 00:00:00 2001 From: saitcho <saitcho@outlook.com> Date: Thu, 25 Jan 2024 11:58:09 -0600 Subject: [PATCH 42/45] AKS update --- .../artifacts/PowerShell/Configure-AKSWorkloadCluster.ps1 | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/azure_jumpstart_hcibox/artifacts/PowerShell/Configure-AKSWorkloadCluster.ps1 b/azure_jumpstart_hcibox/artifacts/PowerShell/Configure-AKSWorkloadCluster.ps1 index eeda048ee2..af29a54a23 100644 --- a/azure_jumpstart_hcibox/artifacts/PowerShell/Configure-AKSWorkloadCluster.ps1 +++ b/azure_jumpstart_hcibox/artifacts/PowerShell/Configure-AKSWorkloadCluster.ps1 @@ -2,6 +2,9 @@ $WarningPreference = "SilentlyContinue" $ErrorActionPreference = "Stop" $ProgressPreference = 'SilentlyContinue' +# Set aadgroupID to the object ID of the Microsoft Entra group that will be granted access to the AKS workload cluster. +#aadgroupID="xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx" + # Set paths $Env:HCIBoxDir = "C:\HCIBox" @@ -35,6 +38,5 @@ az extension add --name akshybrid $customLocationID=(az customlocation show --resource-group $env:resourceGroup --name $HCIBoxConfig.rbCustomLocationName --query id -o tsv) az akshybrid vnet create -n $HCIBoxConfig.AKSvnetname -g $env:resourceGroup --custom-location $customlocationID --moc-vnet-name $clustervnetname $vnetId="/subscriptions/$subId/resourceGroups/$env:resourceGroup/providers/Microsoft.HybridContainerService/virtualNetworks/$($HCIBoxConfig.AKSvnetname)" -$aadgroupID="97d70ef2-db1e-413c-84f5-3159fbf34693" az akshybrid create -n $HCIBoxConfig.AKSworkloadClusterName -g $env:resourceGroup --custom-location $customlocationID --vnet-ids $vnetId --aad-admin-group-object-ids $aadgroupID --generate-ssh-keys --load-balancer-count 1 Stop-Transcript \ No newline at end of file From 506ad27ce8fbd66bee5a5089d59bba830f17cf80 Mon Sep 17 00:00:00 2001 From: saitcho <saitcho@outlook.com> Date: Thu, 25 Jan 2024 12:19:51 -0600 Subject: [PATCH 43/45] dont create SPN if it already exists --- .../scripts/preprovision.ps1 | 53 ++++++++++--------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/azure_jumpstart_hcibox/scripts/preprovision.ps1 b/azure_jumpstart_hcibox/scripts/preprovision.ps1 index 630adb03f7..fefa2bd052 100644 --- a/azure_jumpstart_hcibox/scripts/preprovision.ps1 +++ b/azure_jumpstart_hcibox/scripts/preprovision.ps1 @@ -173,30 +173,33 @@ if ($null -ne $spnProviderId.id) { ######################################################################## # Create Azure Service Principal ######################################################################## -Write-Host "Creating Azure Service Principal..." - -$user = (Get-AzContext).Account.Id.split("@")[0] -$uniqueSpnName = "$user-jumpstart-spn-$(Get-Random -Minimum 1000 -Maximum 9999)" -try { - $spn = New-AzADServicePrincipal -DisplayName $uniqueSpnName -Role "Owner" -Scope "/subscriptions/$($env:AZURE_SUBSCRIPTION_ID)" -ErrorAction Stop -} -catch { - If ($error[0].ToString() -match "Forbidden"){ - Throw "You do not have permission to create a service principal. Please contact your Azure subscription administrator to grant you the Owner role on the subscription." - } - elseif ($error[0].ToString() -match "credentials") { - Throw "Please run Connect-AzAccount to sign in and run 'azd up' again." +Write-Host "Checking for existing stored Azure service principal..." +if ($null -ne $env:SPN_CLIENT_ID) { + Write-Host "Re-using existing service principal..." +} else { + Write-Host "Attempting to create new service principal..." + $user = (Get-AzContext).Account.Id.split("@")[0] + $uniqueSpnName = "$user-jumpstart-spn-$(Get-Random -Minimum 1000 -Maximum 9999)" + try { + $spn = New-AzADServicePrincipal -DisplayName $uniqueSpnName -Role "Owner" -Scope "/subscriptions/$($env:AZURE_SUBSCRIPTION_ID)" -ErrorAction Stop + $SPN_CLIENT_ID = $spn.AppId + $SPN_CLIENT_SECRET = $spn.PasswordCredentials.SecretText + $SPN_TENANT_ID = (Get-AzContext).Tenant.Id + # Set environment variables + azd env set SPN_CLIENT_ID -- $SPN_CLIENT_ID + azd env set SPN_CLIENT_SECRET -- $SPN_CLIENT_SECRET + azd env set SPN_TENANT_ID -- $SPN_TENANT_ID } - else { - Throw "An error occurred creating the service principal. Please try again." + catch { + If ($error[0].ToString() -match "Forbidden"){ + Throw "You do not have permission to create a service principal. Please contact your Azure subscription administrator to grant you the Owner role on the subscription." + } + elseif ($error[0].ToString() -match "credentials") { + Throw "Please run Connect-AzAccount to sign in and run 'azd up' again." + } + else { + Throw "An error occurred creating the service principal. Please try again." + } } -} - -$SPN_CLIENT_ID = $spn.AppId -$SPN_CLIENT_SECRET = $spn.PasswordCredentials.SecretText -$SPN_TENANT_ID = (Get-AzContext).Tenant.Id - -# Set environment variables -azd env set SPN_CLIENT_ID -- $SPN_CLIENT_ID -azd env set SPN_CLIENT_SECRET -- $SPN_CLIENT_SECRET -azd env set SPN_TENANT_ID -- $SPN_TENANT_ID + +} From 83329a415443e81af70fce0823ce1c6a6e830e7e Mon Sep 17 00:00:00 2001 From: saitcho <saitcho@outlook.com> Date: Thu, 25 Jan 2024 15:10:35 -0600 Subject: [PATCH 44/45] no need to download ubuntu vhd --- .../artifacts/PowerShell/New-HCIBoxCluster.ps1 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/azure_jumpstart_hcibox/artifacts/PowerShell/New-HCIBoxCluster.ps1 b/azure_jumpstart_hcibox/artifacts/PowerShell/New-HCIBoxCluster.ps1 index 92631b82f8..c3d697a4c6 100644 --- a/azure_jumpstart_hcibox/artifacts/PowerShell/New-HCIBoxCluster.ps1 +++ b/azure_jumpstart_hcibox/artifacts/PowerShell/New-HCIBoxCluster.ps1 @@ -489,7 +489,7 @@ function Set-HCINodeVHDX { New-Item -Path ($MountedDrive + ":\VHD") -ItemType Directory -Force | Out-Null Copy-Item -Path "$($HCIBoxConfig.Paths.VHDDir)" -Destination ($MountedDrive + ":\VHD") -Recurse -Force - Copy-Item -Path "$($HCIBoxConfig.Paths.VHDDir)\Ubuntu.vhdx" -Destination ($MountedDrive + ":\VHD") -Recurse -Force + # Copy-Item -Path "$($HCIBoxConfig.Paths.VHDDir)\Ubuntu.vhdx" -Destination ($MountedDrive + ":\VHD") -Recurse -Force # Dismount VHDX Write-Host "Dismounting VHDX File at path $path" @@ -1537,9 +1537,9 @@ else { Write-Error "GUI.vhdx is corrupt. Aborting deployment. Re-run C:\HCIBox\HCIBoxLogonScript.ps1 to retry" throw } -BITSRequest -Params @{'Uri'='https://partner-images.canonical.com/hyper-v/desktop/focal/current/ubuntu-focal-hyperv-amd64-ubuntu-desktop-hyperv.vhdx.zip'; 'Filename'="$($HCIBoxConfig.Paths.VHDDir)\Ubuntu.vhdx.zip"} -Expand-Archive -Path "$($HCIBoxConfig.Paths.VHDDir)\Ubuntu.vhdx.zip" -DestinationPath $($HCIBoxConfig.Paths.VHDDir) -Move-Item -Path "$($HCIBoxConfig.Paths.VHDDir)\livecd.ubuntu-desktop-hyperv.vhdx" -Destination "$($HCIBoxConfig.Paths.VHDDir)\Ubuntu.vhdx" +# BITSRequest -Params @{'Uri'='https://partner-images.canonical.com/hyper-v/desktop/focal/current/ubuntu-focal-hyperv-amd64-ubuntu-desktop-hyperv.vhdx.zip'; 'Filename'="$($HCIBoxConfig.Paths.VHDDir)\Ubuntu.vhdx.zip"} +# Expand-Archive -Path "$($HCIBoxConfig.Paths.VHDDir)\Ubuntu.vhdx.zip" -DestinationPath $($HCIBoxConfig.Paths.VHDDir) +# Move-Item -Path "$($HCIBoxConfig.Paths.VHDDir)\livecd.ubuntu-desktop-hyperv.vhdx" -Destination "$($HCIBoxConfig.Paths.VHDDir)\Ubuntu.vhdx" # Set credentials $localCred = new-object -typename System.Management.Automation.PSCredential ` From d411b94d08577b8c552c5c3bab689f6dbd62f02f Mon Sep 17 00:00:00 2001 From: saitcho <saitcho@outlook.com> Date: Thu, 25 Jan 2024 17:55:01 -0600 Subject: [PATCH 45/45] deprecate GetServiceAccountBearerToken.ps1 --- .../artifacts/PowerShell/Bootstrap.ps1 | 1 - .../GetServiceAccountBearerToken.ps1 | 38 ------------------- 2 files changed, 39 deletions(-) delete mode 100644 azure_jumpstart_hcibox/artifacts/PowerShell/GetServiceAccountBearerToken.ps1 diff --git a/azure_jumpstart_hcibox/artifacts/PowerShell/Bootstrap.ps1 b/azure_jumpstart_hcibox/artifacts/PowerShell/Bootstrap.ps1 index c9b68f4560..6c8ec7ab1d 100644 --- a/azure_jumpstart_hcibox/artifacts/PowerShell/Bootstrap.ps1 +++ b/azure_jumpstart_hcibox/artifacts/PowerShell/Bootstrap.ps1 @@ -106,7 +106,6 @@ Invoke-WebRequest ($templateBaseUrl + "artifacts/PowerShell/New-HCIBoxCluster.ps Invoke-WebRequest ($templateBaseUrl + "artifacts/PowerShell/Configure-AKSWorkloadCluster.ps1") -OutFile $HCIPath\Configure-AKSWorkloadCluster.ps1 Invoke-WebRequest ($templateBaseUrl + "artifacts/PowerShell/Configure-VMLogicalNetwork.ps1") -OutFile $HCIPath\Configure-VMLogicalNetwork.ps1 Invoke-WebRequest ($templateBaseUrl + "artifacts/PowerShell/Generate-ARM-Template.ps1") -OutFile $HCIPath\Generate-ARM-Template.ps1 -Invoke-WebRequest ($templateBaseUrl + "artifacts/PowerShell/GetServiceAccountBearerToken.ps1") -OutFile $HCIPath\GetServiceAccountBearerToken.ps1 Invoke-WebRequest ($templateBaseUrl + "artifacts/LogInstructions.txt") -OutFile $HCIBoxConfig.Paths["LogsDir"]\LogInstructions.txt Invoke-WebRequest ($templateBaseUrl + "artifacts/jumpstart-user-secret.yaml") -OutFile $HCIPath\jumpstart-user-secret.yaml Invoke-WebRequest ($templateBaseUrl + "artifacts/hci.json") -OutFile $HCIPath\hci.json diff --git a/azure_jumpstart_hcibox/artifacts/PowerShell/GetServiceAccountBearerToken.ps1 b/azure_jumpstart_hcibox/artifacts/PowerShell/GetServiceAccountBearerToken.ps1 deleted file mode 100644 index cf2ffe2d8b..0000000000 --- a/azure_jumpstart_hcibox/artifacts/PowerShell/GetServiceAccountBearerToken.ps1 +++ /dev/null @@ -1,38 +0,0 @@ -# Set paths -$Env:HCIBoxDir = "C:\HCIBox" -$Env:HCIBoxLogsDir = "C:\HCIBox\Logs" -$Env:HCIBoxVMDir = "C:\HCIBox\Virtual Machines" -$Env:HCIBoxKVDir = "C:\HCIBox\KeyVault" -$Env:HCIBoxGitOpsDir = "C:\HCIBox\GitOps" -$Env:HCIBoxIconDir = "C:\HCIBox\Icons" -$Env:HCIBoxVHDDir = "C:\HCIBox\VHD" -$Env:HCIBoxSDNDir = "C:\HCIBox\SDN" -$Env:HCIBoxWACDir = "C:\HCIBox\Windows Admin Center" -$Env:agentScript = "C:\HCIBox\agentScript" -$Env:ToolsDir = "C:\Tools" -$Env:tempDir = "C:\Temp" -$Env:VMPath = "C:\VMs" - -# Import Configuration Module and create Azure login credentials -Write-Header 'Importing config' -$ConfigurationDataFile = 'C:\HCIBox\HCIBox-Config.psd1' -$HCIBoxConfig = Import-PowerShellDataFile -Path $ConfigurationDataFile - -# Generate credential objects -$user = "jumpstart.local\administrator" -$password = ConvertTo-SecureString -String $HCIBoxConfig.SDNAdminPassword -AsPlainText -Force -$adcred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $user, $password # Domain credential -$clusterName = $env:AKSClusterName -Copy-VMFile -Name $HCIBoxConfig.HostList[0] -SourcePath $env:HCIBoxDir\jumpstart-user-secret.yaml -DestinationPath C:\AksHci\jumpstart-user-secret.yaml -FileSource Host -Force -$TOKEN = Invoke-Command -VMName $HCIBoxConfig.HostList[0] -Credential $adcred -ScriptBlock { - Get-AksHciCredential -name $using:clusterName -Confirm:$false - kubectl create serviceaccount jumpstart-user - kubectl create clusterrolebinding jumpstart-user-binding --clusterrole cluster-admin --serviceaccount default:jumpstart-user - kubectl apply -f C:\AksHci\jumpstart-user-secret.yaml - $TOKEN = ([System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String((kubectl get secret jumpstart-user-secret -o jsonpath='{$.data.token}')))) - return $TOKEN -} - -Write-Output "The service account bearer token below can be used to view Kubernetes resources inside the Azure portal. Copy the code starting after the dashed line (do not include the dashed line)." -Write-Output "----------------------------------" -Write-Output $TOKEN \ No newline at end of file