Merge pull request #562 from microsoft/dev

Dev
This commit is contained in:
Jaromir Kaspar 2023-07-29 23:50:37 +02:00 коммит произвёл GitHub
Родитель 414a2d2bde e2c432b23f
Коммит b6c6ff73e8
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
16 изменённых файлов: 1895 добавлений и 1861 удалений

Просмотреть файл

@ -1,6 +1,6 @@
$LabConfig=@{AllowedVLANs="1-10,711-719" ; DomainAdminName='LabAdmin'; AdminPassword='LS1setup!' ; DCEdition='4'; Internet=$true ; TelemetryLevel='Full' ; TelemetryNickname='' ; AdditionalNetworksConfig=@(); VMs=@()}
#Azure Stack HCI 21H2
#Azure Stack HCI 22H2
1..4 | ForEach-Object {$LABConfig.VMs += @{ VMName = "AzSHCI$_" ; Configuration = 'S2D' ; ParentVHD = 'AzSHCI22H2_G2.vhdx' ; HDDNumber = 4 ; HDDSize= 2TB ; MemoryStartupBytes= 1GB; VMProcessorCount=4 ; vTPM=$true}}
#Or with nested virtualization enabled
#1..4 | ForEach-Object {$LABConfig.VMs += @{ VMName = "AzSHCI$_" ; Configuration = 'S2D' ; ParentVHD = 'AzSHCI22H2_G2.vhdx' ; HDDNumber = 4 ; HDDSize= 2TB ; MemoryStartupBytes= 4GB; VMProcessorCount=4 ; vTPM=$true ; NestedVirt=$true}}

Просмотреть файл

@ -171,9 +171,9 @@
}
}
#define and install other features
$features="Failover-Clustering","RSAT-Clustering-PowerShell","Hyper-V-PowerShell","NetworkATC","NetworkHUD","Data-Center-Bridging","RSAT-DataCenterBridging-LLDP-Tools","FS-SMBBW"
#optional - affects perf even if not enabled on volumes as filter driver is attached (Bitlocker,SR,Dedup)
#$features+="RSAT-Feature-Tools-BitLocker","Storage-Replica","RSAT-Storage-Replica","FS-Data-Deduplication","System-Insights","RSAT-System-Insights"
$features="Failover-Clustering","RSAT-Clustering-PowerShell","Hyper-V-PowerShell","NetworkATC","NetworkHUD","Data-Center-Bridging","RSAT-DataCenterBridging-LLDP-Tools","FS-SMBBW","System-Insights","RSAT-System-Insights"
#optional - affects perf even if not enabled on volumes as filter driver is attached (SR,Dedup) and also Bitlocker, that affects a little bit
#$features+="Storage-Replica","RSAT-Storage-Replica","FS-Data-Deduplication","BitLocker","RSAT-Feature-Tools-BitLocker"
Invoke-Command -ComputerName $servers -ScriptBlock {Install-WindowsFeature -Name $using:features}
#endregion
@ -823,6 +823,10 @@ if ($NetATC){
#check number of live migrations
get-vmhost -CimSession $Servers | Select-Object Name,MaximumVirtualMachineMigrations
#check it in cluster (is only 1 - expected)
get-cluster -Name $ClusterName | Select-Object Name,MaximumParallelMigrations
#endregion
#remove net intent global overrides if necessary

Просмотреть файл

@ -392,7 +392,7 @@
#Copy agent and bootloader to VMs
#create sessions
$sessions=New-PSSession -ComputerName $VMs.VMName
#copy ARC agent
#copy AVD agent
foreach ($session in $sessions){
Copy-Item -Path "$env:USERPROFILE\Downloads\AVDAgent.msi" -Destination "$env:USERPROFILE\Downloads\" -tosession $session -force
Copy-Item -Path "$env:USERPROFILE\Downloads\AVDAgentBootloader.msi" -Destination "$env:USERPROFILE\Downloads\" -tosession $session -force

Просмотреть файл

@ -1,14 +0,0 @@
$LabConfig=@{ DomainAdminName='LabAdmin'; AdminPassword='LS1setup!' ; Prefix = 'MSLab-' ; DCEdition='4'; Internet=$true ; TelemetryLevel='Full' ; TelemetryNickname='' ; AdditionalNetworksConfig=@(); VMs=@()}
#2 nodes for AzSHCI Cluster
1..2 | ForEach-Object {$VMNames="ArcVMs" ; $LABConfig.VMs += @{ VMName = "$VMNames$_" ; Configuration = 'S2D' ; ParentVHD = 'AzSHCI21H2_G2.vhdx' ; HDDNumber = 4 ; HDDSize= 4TB ; MemoryStartupBytes= 14GB; VMProcessorCount="Max" ; NestedVirt=$true ; VirtualTPM=$true}}
#or 2 nodes for Windows Server 2022
#1..2 | ForEach-Object {$VMNames="ArcVMs" ; $LABConfig.VMs += @{ VMName = "$VMNames$_" ; Configuration = 'S2D' ; ParentVHD = 'Win2022Core_G2.vhdx' ; HDDNumber = 4 ; HDDSize= 4TB ; MemoryStartupBytes= 14GB; VMProcessorCount="Max" ; NestedVirt=$true ; VirtualTPM=$true}}
#optional Windows Admin Center gateway
#$LabConfig.VMs += @{ VMName = 'WACGW' ; ParentVHD = 'Win2022Core_G2.vhdx' ; MGMTNICs=1 }
#optional Windows Management machine
#$LabConfig.VMs += @{ VMName = 'Management' ; ParentVHD = 'Win2022_G2.vhdx' ; MGMTNICs=1 }

Просмотреть файл

@ -1,592 +0,0 @@
#https://aka.ms/ArcEnabledHCI
#https://aka.ms/AzureArcVM
###################
### Run from DC ###
###################
#region Variables
$ClusterNodeNames="ArcVMs1","ArcVMs2"
$ClusterName="ArcVMs-Cluster"
$vswitchName="vSwitch"
$controlPlaneIP="10.0.0.111"
$VolumeName="MOC"
$VolumePath="c:\ClusterStorage\$VolumeName"
$CredSSPUserName="CORP\LabAdmin"
$CredSSPPassword="LS1setup!"
$CustomLocationName="$ClusterName-cl"
$LibraryVolumeName="Library" #volume for Gallery images for VMs
$AzureImages=@()
$AzureImages+=@{PublisherName = "microsoftwindowsserver";Offer="windowsserver";SKU="2022-datacenter-azure-edition-smalldisk";OSType="Windows"} #OS TYpe can be "Windows" or "Linux" - first letter has to be capital!
$AzureImages+=@{PublisherName = "microsoftwindowsserver";Offer="windowsserver";SKU="2022-datacenter-azure-edition-core-smalldisk";OSType="Windows"} #OS TYpe can be "Windows" or "Linux" - first letter has to be capital!
#Install or update Azure packages
Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force
$ModuleNames="Az.Accounts","Az.Compute","Az.Resources","Az.StackHCI"
foreach ($ModuleName in $ModuleNames){
$Module=Get-InstalledModule -Name $ModuleName -ErrorAction Ignore
if ($Module){$LatestVersion=(Find-Module -Name $ModuleName).Version}
if (-not($Module) -or ($Module.Version -lt $LatestVersion)){
Install-Module -Name $ModuleName -Force
}
}
#login to Azure
if (-not (Get-AzContext)){
Login-AzAccount -UseDeviceAuthentication
}
$ResourceGroupName="$ClusterName-rg"
$SubscriptionID=(Get-AzContext).Subscription.ID
#select context
$context=Get-AzContext -ListAvailable
if (($context).count -gt 1){
$context=$context | Out-GridView -OutputMode Single
$context | Set-AzContext
}
#I did only test same for all (EastUS)
$VMImageLocation="eastus"
$ArcResourceBridgeLocation="eastus"
$AzureStackLocation="eastus"
<#or populate by choosing your own
#grab region where to grab VMs from
$VMImageLocation = (Get-AzLocation | Where-Object Providers -Contains "Microsoft.Compute" | Out-GridView -OutputMode Single -Title "Choose location where to grab VMs from").Location
#grab location for Arc Resource Bridge and Custom location
$ArcResourceBridgeLocation=(Get-AzLocation | Where-Object Providers -Contains "Microsoft.ResourceConnector" | Out-GridView -OutputMode Single -Title "Choose location for Arc Resource Bridge and Custom location").Location
#grab location for Azure Stack
$AzureStackLocation=(Get-AzLocation | Where-Object Providers -Contains "Microsoft.AzureStackHCI" | Out-GridView -OutputMode Single -Title "Choose location for Azure Stack HCI - where it should be registered").Location
#>
#virtual network name
$vnetName=$vswitchName
#endregion
#region Create 2 node cluster (just simple. Not for prod - follow hyperconverged scenario for real clusters https://github.com/microsoft/MSLab/tree/master/Scenarios/AzSHCI%20Deployment)
# Install features for management on server
Install-WindowsFeature -Name RSAT-Clustering,RSAT-Clustering-Mgmt,RSAT-Clustering-PowerShell,RSAT-Hyper-V-Tools
# Update servers (optional)
<#
Invoke-Command -ComputerName $ClusterNodeNames -ScriptBlock {
New-PSSessionConfigurationFile -RunAsVirtualAccount -Path $env:TEMP\VirtualAccount.pssc
Register-PSSessionConfiguration -Name 'VirtualAccount' -Path $env:TEMP\VirtualAccount.pssc -Force
} -ErrorAction Ignore
# Run Windows Update via ComObject.
Invoke-Command -ComputerName $ClusterNodeNames -ConfigurationName 'VirtualAccount' {
$Searcher = New-Object -ComObject Microsoft.Update.Searcher
$SearchCriteriaAllUpdates = "IsInstalled=0 and DeploymentAction='Installation' or
IsPresent=1 and DeploymentAction='Uninstallation' or
IsInstalled=1 and DeploymentAction='Installation' and RebootRequired=1 or
IsInstalled=0 and DeploymentAction='Uninstallation' and RebootRequired=1"
$SearchResult = $Searcher.Search($SearchCriteriaAllUpdates).Updates
$Session = New-Object -ComObject Microsoft.Update.Session
$Downloader = $Session.CreateUpdateDownloader()
$Downloader.Updates = $SearchResult
$Downloader.Download()
$Installer = New-Object -ComObject Microsoft.Update.Installer
$Installer.Updates = $SearchResult
$Result = $Installer.Install()
$Result
}
#remove temporary PSsession config
Invoke-Command -ComputerName $ClusterNodeNames -ScriptBlock {
Unregister-PSSessionConfiguration -Name 'VirtualAccount'
Remove-Item -Path $env:TEMP\VirtualAccount.pssc
}
#>
# Install features on servers
Invoke-Command -computername $ClusterNodeNames -ScriptBlock {
Enable-WindowsOptionalFeature -FeatureName Microsoft-Hyper-V -Online -NoRestart
Install-WindowsFeature -Name "Failover-Clustering","RSAT-Clustering-Powershell","Hyper-V-PowerShell"
}
# restart servers
Restart-Computer -ComputerName $ClusterNodeNames -Protocol WSMan -Wait -For PowerShell
#failsafe - sometimes it evaluates, that servers completed restart after first restart (hyper-v needs 2)
Start-sleep 20
# create vSwitch (sometimes happens, that I need to restart servers again and then it will create vSwitch...)
Invoke-Command -ComputerName $ClusterNodeNames -ScriptBlock {New-VMSwitch -Name $using:vswitchName -EnableEmbeddedTeaming $TRUE -NetAdapterName (Get-NetIPAddress -IPAddress 10.* ).InterfaceAlias}
#create cluster
New-Cluster -Name $ClusterName -Node $ClusterNodeNames
Start-Sleep 5
Clear-DNSClientCache
#add file share witness
#Create new directory
$WitnessName=$ClusterName+"Witness"
Invoke-Command -ComputerName DC -ScriptBlock {new-item -Path c:\Shares -Name $using:WitnessName -ItemType Directory}
$accounts=@()
$accounts+="corp\$($ClusterName)$"
$accounts+="corp\Domain Admins"
New-SmbShare -Name $WitnessName -Path "c:\Shares\$WitnessName" -FullAccess $accounts -CimSession DC
#Set NTFS permissions
Invoke-Command -ComputerName DC -ScriptBlock {(Get-SmbShare $using:WitnessName).PresetPathAcl | Set-Acl}
#Set Quorum
Set-ClusterQuorum -Cluster $ClusterName -FileShareWitness "\\DC\$WitnessName"
#Enable S2D
Enable-ClusterS2D -CimSession $ClusterName -Verbose -Confirm:0
#configure thin volumes a default if available (because why not :)
$OSInfo=Invoke-Command -ComputerName $ClusterName -ScriptBlock {
Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\'
}
if ($OSInfo.productname -eq "Azure Stack HCI" -and $OSInfo.CurrentBuild -ge 20348){
Get-StoragePool -CimSession $ClusterName -FriendlyName S2D* | Set-StoragePool -ProvisioningTypeDefault Thin
}
#endregion
#region Register Azure Stack HCI to Azure - if not registered, VMs are not added as cluster resources = AKS script will fail
#download Azure module
Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force
if (!(Get-InstalledModule -Name Az.StackHCI -ErrorAction Ignore)){
Install-Module -Name Az.StackHCI -Force
}
#login to azure
#download Azure module
if (!(Get-InstalledModule -Name az.accounts -ErrorAction Ignore)){
Install-Module -Name Az.Accounts -Force
}
Connect-AzAccount -UseDeviceAuthentication
#select subscription if more available
$subscription=Get-AzSubscription
if (($subscription).count -gt 1){
$subscription | Out-GridView -OutputMode Single | Set-AzContext
}
#grab subscription ID
$subscriptionID=(Get-AzContext).Subscription.id
<# Register AZSHCi without prompting for creds,
Notes: As Dec. 2021, in Azure Stack HCI 21H2, if you Register-AzStackHCI the cluster multiple times in same ResourceGroup (e.g. default
resource group name is AzSHCI-Cluster-rg) without run UnRegister-AzStackHCI first, although you may succeed in cluster registration, but
sever node Arc integration will fail, even if you have deleted the ResourceGroup in Azure Portal before running Register-AzStackHCI #>
$armTokenItemResource = "https://management.core.windows.net/"
$graphTokenItemResource = "https://graph.windows.net/"
$azContext = Get-AzContext
$authFactory = [Microsoft.Azure.Commands.Common.Authentication.AzureSession]::Instance.AuthenticationFactory
$graphToken = $authFactory.Authenticate($azContext.Account, $azContext.Environment, $azContext.Tenant.Id, $null, [Microsoft.Azure.Commands.Common.Authentication.ShowDialog]::Never, $null, $graphTokenItemResource).AccessToken
$armToken = $authFactory.Authenticate($azContext.Account, $azContext.Environment, $azContext.Tenant.Id, $null, [Microsoft.Azure.Commands.Common.Authentication.ShowDialog]::Never, $null, $armTokenItemResource).AccessToken
$id = $azContext.Account.Id
#grab location
if (!(Get-InstalledModule -Name Az.Resources -ErrorAction Ignore)){
Install-Module -Name Az.Resources -Force
}
#register
Register-AzStackHCI -SubscriptionID $subscriptionID -Region $AzureStackLocation -ComputerName $ClusterName -GraphAccessToken $graphToken -ArmAccessToken $armToken -AccountId $id
#Install Azure Stack HCI RSAT Tools to all nodes
Invoke-Command -ComputerName $ClusterNodeNames -ScriptBlock {
Install-WindowsFeature -Name RSAT-Azure-Stack-HCI
}
#Validate registration (query on just one node is needed)
Invoke-Command -ComputerName $ClusterName -ScriptBlock {
Get-AzureStackHCI
}
#endregion
#region Install modules and create MOC agent Service
#Install required modules
Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force
Install-Module -Name PowershellGet -Force -Confirm:$false -SkipPublisherCheck
Update-Module -Name PowerShellGet
#to be able to install ArcHci and MOC, powershellget 2.2.5 needs to be used - to this posh restart is needed
Start-Process -Wait -FilePath PowerShell -ArgumentList {
Install-Module -Name MOC -Repository PSGallery -Force -AcceptLicense
Install-Module -Name ArcHci -Force -Confirm:$false -SkipPublisherCheck -AcceptLicense
}
#Increase MaxEvenlope and create session to copy files to
Invoke-Command -ComputerName $ClusterNodeNames -ScriptBlock {Set-Item -Path WSMan:\localhost\MaxEnvelopeSizekb -Value 4096}
#distribute modules to cluster nodes
$ModuleNames="ArcHci","Moc","DownloadSDK"
$PSSessions=New-PSSession -ComputerName $ClusterNodeNames
Foreach ($PSSession in $PSSessions){
Foreach ($ModuleName in $ModuleNames){
Copy-Item -Path $env:ProgramFiles\windowspowershell\modules\$ModuleName -Destination $env:ProgramFiles\windowspowershell\modules -ToSession $PSSession -Recurse -Force
}
Foreach ($ModuleName in $RequiredModules.ModuleName){
Copy-Item -Path $env:ProgramFiles\windowspowershell\modules\$ModuleName -Destination $env:ProgramFiles\windowspowershell\modules -ToSession $PSSession -Recurse -Force
}
}
#Enable CredSSP
# Temporarily enable CredSSP delegation to avoid double-hop issue
foreach ($ClusterNodeName in $ClusterNodeNames){
Enable-WSManCredSSP -Role "Client" -DelegateComputer $ClusterNodeName -Force
}
Invoke-Command -ComputerName $ClusterNodeNames -ScriptBlock { Enable-WSManCredSSP Server -Force }
$SecureStringPassword = ConvertTo-SecureString $CredSSPPassword -AsPlainText -Force
$Credentials = New-Object System.Management.Automation.PSCredential ($CredSSPUserName, $SecureStringPassword)
#initialize MOC
Invoke-Command -ComputerName $ClusterNodeNames -Credential $Credentials -Authentication Credssp -ScriptBlock {
Initialize-MocNode
}
#Create volume for MOC if does not exist
if (-not (Get-Volume -FriendlyName $VolumeName -CimSession $ClusterName -ErrorAction SilentlyContinue)) {
New-Volume -FriendlyName $VolumeName -CimSession $ClusterName -Size 1TB -StoragePoolFriendlyName S2D*
}
#prepare arc resource bridge
#Configure MOC
Invoke-Command -ComputerName $ClusterNodeNames[0] -Credential $Credentials -Authentication Credssp -ScriptBlock {
$Vnet=New-MocNetworkSetting -Name hcirb-vnet -vswitchName $using:vswitchName -vipPoolStart $using:controlPlaneIP -vipPoolEnd $using:controlPlaneIP
Set-MocConfig -workingDir "\\$using:ClusterName\ClusterStorage$\$using:VolumeName\workingDir" -vnet $vnet -imageDir $using:VolumePath\imageStore -skipHostLimitChecks -cloudConfigLocation $using:VolumePath\cloudStore -catalog aks-hci-stable-catalogs-ext -ring stable
}
#Install MOC Cloud Agent Service
Invoke-Command -ComputerName $ClusterNodeNames[0] -Credential $Credentials -Authentication Credssp -ScriptBlock {
Install-moc
}
# Disable CredSSP
Disable-WSManCredSSP -Role Client
Invoke-Command -ComputerName $ClusterNodeNames -ScriptBlock { Disable-WSManCredSSP Server }
#endregion
#region Create custom location and install Arc Resource Bridge
#Login to azure
if (!(Get-AzContext)){
Connect-AzAccount -UseDeviceAuthentication
}
#generate variables
#Grab registration info
$RegistrationInfo=Invoke-Command -ComputerName $CLusterName -ScriptBlock {Get-AzureStackHCI}
$AzureResourceUri= $RegistrationInfo.AzureResourceUri
$HCIResourceGroupName=$AzureResourceUri.split("/")[4]
$HCISubscriptionID=$AzureResourceUri.split("/")[2]
#create bridge resource name
$BridgeResourceName=("$($RegistrationInfo.AzureResourceName)-arcbridge").ToLower()
#install Az CLI
#download
Start-BitsTransfer -Source https://aka.ms/installazurecliwindows -Destination $env:userprofile\Downloads\AzureCLI.msi
#install
Start-Process msiexec.exe -Wait -ArgumentList "/I $env:userprofile\Downloads\AzureCLI.msi /quiet"
#add az to enviromental variables so no posh restart is needed
[System.Environment]::SetEnvironmentVariable('PATH',$Env:PATH+';C:\Program Files (x86)\Microsoft SDKs\Azure\CLI2\wbin')
#add Az extensions
az extension add --name customlocation
az extension add --name azurestackhci
az extension add --name arcappliance
az extension add --name k8s-extension
az extension add --name connectedk8s
#register namespaces
#register
$Providers="Microsoft.ExtendedLocation","Microsoft.ResourceConnector"
foreach ($Provider in $Providers){
Register-AzResourceProvider -ProviderNamespace $Provider
}
#wait until resource providers are registered
foreach ($Provider in $Providers){
do {
$Status=Get-AzResourceProvider -ProviderNamespace $Provider
Write-Output "Registration Status - $Provider : $(($status.RegistrationState -match 'Registered').Count)/$($Status.Count)"
Start-Sleep 1
} while (($status.RegistrationState -match "Registered").Count -ne ($Status.Count))
}
#login with device authentication
az login --use-device-code
$allSubscriptions = (az account list | ConvertFrom-Json).ForEach({$_ | Select-Object -Property Name, id, tenantId })
if (($allSubscriptions).Count -gt 1){
$subscription = ($allSubscriptions | Out-GridView -OutputMode Single)
az account set --subscription $subscription.id
}
#create arc appliance
#generate config files
#Enable CredSSP
# Temporarily enable CredSSP delegation to avoid double-hop issue
foreach ($ClusterNodeName in $ClusterNodeNames){
Enable-WSManCredSSP -Role "Client" -DelegateComputer $ClusterNodeName -Force
}
Invoke-Command -ComputerName $ClusterNodeNames -ScriptBlock { Enable-WSManCredSSP Server -Force }
$SecureStringPassword = ConvertTo-SecureString $CredSSPPassword -AsPlainText -Force
$Credentials = New-Object System.Management.Automation.PSCredential ($CredSSPUserName, $SecureStringPassword)
Invoke-Command -ComputerName $ClusterNodeNames[0] -Credential $Credentials -Authentication Credssp -ScriptBlock {
New-ArcHciConfigFiles -subscriptionID $using:HCISubscriptionID -location $using:ArcResourceBridgeLocation -resourceGroup $using:HCIResourceGroupName -resourceName $using:BridgeResourceName -workDirectory "\\$using:ClusterName\ClusterStorage$\$using:VolumeName\workingDir"
}
# Disable CredSSP
Disable-WSManCredSSP -Role Client
Invoke-Command -ComputerName $ClusterNodeNames -ScriptBlock { Disable-WSManCredSSP Server }
#prepare
az arcappliance prepare hci --config-file \\$ClusterName\ClusterStorage$\$VolumeName\workingDir\hci-appliance.yaml
#Create folder for config
New-Item -Path $env:USERPROFILE\.kube -ItemType Directory -ErrorAction Ignore
#deploy control plane and export kube config
az arcappliance deploy hci --config-file \\$ClusterName\ClusterStorage$\$VolumeName\workingDir\hci-appliance.yaml --outfile $env:USERPROFILE\.kube\config
#create connection to Azure (might throw error, dont worry! It's being deployed on background)
az arcappliance create hci --config-file \\$ClusterName\ClusterStorage$\$VolumeName\workingDir\hci-appliance.yaml --kubeconfig $env:USERPROFILE\.kube\config
#wait until appliance is running
do {
$Status=az arcappliance show --only-show-errors --resource-group $HCIResourceGroupName --name $BridgeResourceName | ConvertFrom-Json
Write-Host -NoNewline -Object "."
Start-Sleep 2
} until ($status.status -match "Running")
#verify if appliance is running
az arcappliance show --resource-group $HCIResourceGroupName --name $BridgeResourceName | ConvertFrom-Json
#Add K8s extension
#create
az k8s-extension create --cluster-type appliances --cluster-name $BridgeResourceName --resource-group $HCIResourceGroupName --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 \\$ClusterName\ClusterStorage$\$VolumeName\workingDir\hci-config.json --configuration-settings HCIClusterID=$AzureResourceUri --auto-upgrade true
#validate
az k8s-extension show --cluster-type appliances --cluster-name $BridgeResourceName --resource-group $HCIResourceGroupName --name hci-vmoperator
#Create custom location (has to be created after arcappliance deployment)
az customlocation create --resource-group $HCIResourceGroupName --name $CustomLocationName --cluster-extension-ids "/subscriptions/$HCISubscriptionID/resourceGroups/$HCIResourceGroupName/providers/Microsoft.ResourceConnector/appliances/$BridgeResourceName/providers/Microsoft.KubernetesConfiguration/extensions/hci-vmoperator" --namespace hci-vmoperator --host-resource-id "/subscriptions/$HCISubscriptionID/resourceGroups/$HCIResourceGroupName/providers/Microsoft.ResourceConnector/appliances/$BridgeResourceName" --location $ArcResourceBridgeLocation
<# Or with PowerShell
#install Az.CustomLocation module
if (!(Get-InstalledModule -Name az.CustomLocation -ErrorAction Ignore)){
Install-Module -Name Az.CustomLocation -Force
}
New-AzCustomLocation -ResourceGroupName $ResourceGroupName -Name $CustomLocationName -ClusterExtensionID "/subscriptions/$SubscriptionID/resourceGroups/$ResourceGroupName/providers/Microsoft.ResourceConnector/appliances/$BridgeResourceName/providers/Microsoft.KubernetesConfiguration/extensions/hci-vmoperator" -NameSpace hci-vmoperator -HostResourceID "/subscriptions/$SubscriptionID/resourceGroups/$ResourceGroupName/providers/Microsoft.ResourceConnector/appliances/$BridgeResourceName" -Location $ArcResourceBridgeLocation
#>
#endregion
#region Copy kube config to nodes to have it available there
$Sessions=New-PSSession -ComputerName $ClusterNodeNames
#copy kube to cluster nodes
Foreach ($Session in $Sessions){
Copy-Item -Path "$env:userprofile\.kube" -Destination $env:userprofile -ToSession $Session -Recurse -Force
}
$Sessions | Remove-PSSession
#endregion
#region create virtual network
#Grab registration info
$RegistrationInfo=Invoke-Command -ComputerName $CLusterName -ScriptBlock {Get-AzureStackHCI}
$AzureResourceUri= $RegistrationInfo.AzureResourceUri
$HCIResourceGroupName=$AzureResourceUri.split("/")[4]
$HCISubscriptionID=$AzureResourceUri.split("/")[2]
#create network
az azurestackhci virtualnetwork create --subscription $HCISubscriptionID --resource-group $HCIResourceGroupName --extended-location name="/subscriptions/$HCISubscriptionID/resourceGroups/$HCIResourceGroupName/providers/Microsoft.ExtendedLocation/customLocations/$CustomLocationName" type="CustomLocation" --location $ArcResourceBridgeLocation --network-type "Transparent" --name $vnetName
#endregion
#region create images
#Create library volume
if (-not (Get-VirtualDisk -CimSession $ClusterName -FriendlyName $LibraryVolumeName -ErrorAction Ignore)){
New-Volume -StoragePoolFriendlyName "S2D*" -FriendlyName $LibraryVolumeName -FileSystem CSVFS_ReFS -Size 500GB -ResiliencySettingName Mirror -CimSession $ClusterName
}
#region download Azure images to library
#list windows server Offers
Get-AzVMImageSku -Location $VMImageLocation -PublisherName "microsoftwindowsserver" -Offer "WindowsServer"
#Create managed disks with azure images
foreach ($AzureImage in $AzureImages){
$image=Get-AzVMImage -Location $VMImageLocation -PublisherName $AzureImage.PublisherName -Offer $AzureImage.Offer -SKU $AzureImage.SKU | Sort-Object Version -Descending |Select-Object -First 1
$ImageVersionID = $image.id
# Export the OS disk
$imageOSDisk = @{Id = $ImageVersionID}
$OSDiskConfig = New-AzDiskConfig -Location $VMImageLocation -CreateOption "FromImage" -ImageReference $imageOSDisk
New-AzDisk -ResourceGroupName $ResourceGroupName -DiskName $AzureImage.SKU -Disk $OSDiskConfig
}
#Download AZCopy
# Download the package
Start-BitsTransfer -Source "https://aka.ms/downloadazcopy-v10-windows" -Destination "$env:UserProfile\Downloads\AzCopy.zip"
Expand-Archive -Path "$env:UserProfile\Downloads\AzCopy.zip" -DestinationPath "$env:UserProfile\Downloads\AZCopy" -Force
$item=Get-ChildItem -Name azcopy.exe -Recurse -Path "$env:UserProfile\Downloads\AZCopy"
Move-Item -Path "$env:UserProfile\Downloads\AZCopy\$item" -Destination "$env:UserProfile\Downloads\" -Force
Remove-Item -Path "$env:UserProfile\Downloads\AZCopy\" -Recurse
Remove-Item -Path "$env:UserProfile\Downloads\AzCopy.zip"
#Download Images
foreach ($AzureImage in $AzureImages){
#Grant Access https://docs.microsoft.com/en-us/azure/storage/common/storage-sas-overview
$output=Grant-AzDiskAccess -ResourceGroupName $ResourceGroupName -DiskName $AzureImage.SKU -Access 'Read' -DurationInSecond 3600
#Grab shared access signature
$SAS=$output.accesssas
#Download
& $env:UserProfile\Downloads\azcopy.exe copy $sas "\\$ClusterName\ClusterStorage$\$LibraryVolumeName\$($AzureImage.SKU).vhd" --check-md5 NoCheck --cap-mbps 500
#once disk is downloaded, disk access can be revoked
Revoke-AzDiskAccess -ResourceGroupName $ResourceGroupName -Name $AzureImage.SKU
#and disk itself can be removed
Remove-AzDisk -ResourceGroupName $ResourceGroupName -DiskName $AzureImage.SKU -Force
#and disk itself can be converted to VHDx and compacted
Invoke-Command -ComputerName $ClusterName -ScriptBlock {
Convert-VHD -Path "c:\clusterstorage\$using:LibraryVolumeName\$($using:AzureImage.sku).vhd" -DestinationPath "c:\clusterstorage\$using:LibraryVolumeName\$($using:AzureImage.sku).vhdx" -VHDType Dynamic -DeleteSource
Optimize-VHD -Path "c:\clusterstorage\$using:LibraryVolumeName\$($using:AzureImage.sku).vhdx" -Mode Full
}
if ($AzureImage.SKU -like "*-smalldisk*"){
#and it can be also expanded from default 32GB (since image is small to safe some space)
Invoke-Command -ComputerName $ClusterName -ScriptBlock {
Resize-VHD -Path "c:\clusterstorage\$using:LibraryVolumeName\$($using:AzureImage.sku).vhdx" -SizeBytes 127GB
#mount VHD
$VHDMount=Mount-VHD "c:\clusterstorage\$using:LibraryVolumeName\$($using:AzureImage.sku).vhdx" -Passthru
$partition = $vhdmount | Get-Disk | Get-Partition | Where-Object PartitionNumber -Eq 4
$partition | Resize-Partition -Size ($Partition | Get-PartitionSupportedSize).SizeMax
$VHDMount| Dismount-VHD
}
#and since it's no longer smalldisk, it can be renamed
Invoke-Command -ComputerName $ClusterName -ScriptBlock {
$NewName=($using:AzureImage.SKU).replace("-smalldisk","")
Rename-Item -Path "c:\clusterstorage\$using:LibraryVolumeName\$($using:AzureImage.sku).vhdx" -NewName "$NewName.vhdx"
}
}
}
#endregion
#region create gallery image offer
$RegistrationInfo=Invoke-Command -ComputerName $CLusterName -ScriptBlock {Get-AzureStackHCI}
$AzureResourceUri= $RegistrationInfo.AzureResourceUri
$HCIResourceGroupName=$AzureResourceUri.split("/")[4]
$HCISubscriptionID=$AzureResourceUri.split("/")[2]
foreach ($AzureImage in $AzureImages){
#Since disk was expandend, -smalldisk can be removed from name
$NewName=($AzureImage.SKU).replace("-smalldisk","")
$galleryImageName=$NewName
$galleryImageSourcePath="c:\ClusterStorage\$LibraryVolumeName\$galleryImageName.vhdx"
$osType=$AzureImage.OSType
az azurestackhci galleryimage create --subscription $HCISubscriptionID --resource-group $HCIResourceGroupName --extended-location name="/subscriptions/$HCISubscriptionID/resourceGroups/$HCIResourceGroupName/providers/Microsoft.ExtendedLocation/customLocations/$CustomLocationName" type="CustomLocation" --location $ArcResourceBridgeLocation --image-path $galleryImageSourcePath --name $galleryImageName --os-type $osType
}
#endregion
#endregion
#now you can navigate to https://aka.ms/AzureArcVM to create VMs!
#region collect logs
#Enable CredSSP
# Temporarily enable CredSSP delegation to avoid double-hop issue
foreach ($ClusterNodeName in $ClusterNodeNames){
Enable-WSManCredSSP -Role "Client" -DelegateComputer $ClusterNodeName -Force
}
Invoke-Command -ComputerName $ClusterNodeNames -ScriptBlock { Enable-WSManCredSSP Server -Force }
$SecureStringPassword = ConvertTo-SecureString $CredSSPPassword -AsPlainText -Force
$Credentials = New-Object System.Management.Automation.PSCredential ($CredSSPUserName, $SecureStringPassword)
#generate logs
Invoke-Command -ComputerName $ClusterNodeNames[0] -Credential $Credentials -Authentication Credssp -ScriptBlock {
get-archcilogs
}
# Disable CredSSP
Disable-WSManCredSSP -Role Client
Invoke-Command -ComputerName $ClusterNodeNames -ScriptBlock { Disable-WSManCredSSP Server }
#copy logs to downloads
$Session=New-PSSession -ComputerName $ClusterNodeNames[0]
Copy-Item -Path $env:userprofile\Documents\archcilogs.zip -Destination $env:userprofile\Downloads -FromSession $Sessions
$Session | Remove-PSSession
#endregion
#region cleanup
#unregister Azure Stack HCI
#Grab registration info
$RegistrationInfo=Invoke-Command -ComputerName $CLusterName -ScriptBlock {Get-AzureStackHCI}
$AzureResourceUri= $RegistrationInfo.AzureResourceUri
$HCIResourceGroupName=$AzureResourceUri.split("/")[4]
$HCISubscriptionID=$AzureResourceUri.split("/")[2]
#login to Azure
if (-not (Get-AzContext)){
Login-AzAccount -UseDeviceAuthentication
}
$subscriptionID=(Get-AzContext).Subscription.id
$armTokenItemResource = "https://management.core.windows.net/"
$graphTokenItemResource = "https://graph.windows.net/"
$azContext = Get-AzContext
$authFactory = [Microsoft.Azure.Commands.Common.Authentication.AzureSession]::Instance.AuthenticationFactory
$graphToken = $authFactory.Authenticate($azContext.Account, $azContext.Environment, $azContext.Tenant.Id, $null, [Microsoft.Azure.Commands.Common.Authentication.ShowDialog]::Never, $null, $graphTokenItemResource).AccessToken
$armToken = $authFactory.Authenticate($azContext.Account, $azContext.Environment, $azContext.Tenant.Id, $null, [Microsoft.Azure.Commands.Common.Authentication.ShowDialog]::Never, $null, $armTokenItemResource).AccessToken
$id = $azContext.Account.Id
UnRegister-AzStackHCI -SubscriptionID $subscriptionID -ComputerName $ClusterName -GraphAccessToken $graphToken -ArmAccessToken $armToken -AccountId $id -Confirm:0
#login to Azure
if (-not (Get-AzContext)){
Login-AzAccount -UseDeviceAuthentication
}
#remove virtual network
az azurestackhci virtualnetwork delete --subscription $HCISubscriptionID --resource-group $HCIResourceGroupName --name $vnetName --yes
#remove gallery images
foreach ($AzureImage in $AzureImages){
az azurestackhci galleryimage delete --subscription $HCISubscriptionID --resource-group $HCIResourceGroupName --name $AzureImage.SKU
}
#remove custom location
az customlocation delete --resource-group $HCIResourceGroupName --name $customLocationName --yes
#remove Kubernetes Extension
$BridgeResourceName=("$($RegistrationInfo.AzureResourceName)-arcbridge").ToLower()
az k8s-extension delete --cluster-type appliances --cluster-name $BridgeResourceName --resource-group $HCIResourceGroupName --name hci-vmoperator --yes
#remove appliance
az arcappliance delete hci --config-file \\$ClusterName\clusterstorage$\MOC\workingDir\hci-appliance.yaml --yes
#remove configfiles
Invoke-Command -ComputerName $ClusterName -ScriptBlock {
Remove-ArcHciConfigFiles
}
#remove resource group
#login to Azure
if (-not (Get-AzContext)){
Login-AzAccount -UseDeviceAuthentication
}
Remove-AzResourceGroup -Name $ResourceGroupName -Force
#uninstall MOC
#Enable CredSSP
# Temporarily enable CredSSP delegation to avoid double-hop issue
foreach ($ClusterNodeName in $ClusterNodeNames){
Enable-WSManCredSSP -Role "Client" -DelegateComputer $ClusterNodeName -Force
}
Invoke-Command -ComputerName $ClusterNodeNames -ScriptBlock { Enable-WSManCredSSP Server -Force }
$SecureStringPassword = ConvertTo-SecureString $CredSSPPassword -AsPlainText -Force
$Credentials = New-Object System.Management.Automation.PSCredential ($CredSSPUserName, $SecureStringPassword)
#uninstall MOC
Invoke-Command -ComputerName $ClusterNodeNames[0] -Credential $Credentials -Authentication Credssp -ScriptBlock {
Uninstall-Moc
}
# Disable CredSSP
Disable-WSManCredSSP -Role Client
Invoke-Command -ComputerName $ClusterNodeNames -ScriptBlock { Disable-WSManCredSSP Server }
#remove volume for MOC
Remove-VirtualDisk -FriendlyName $VolumeName -CimSession $ClusterName -Confirm:0
#remove volume for MOC
Remove-VirtualDisk -FriendlyName $LibraryVolumeName -CimSession $ClusterName -Confirm:0
#endregion

Просмотреть файл

@ -279,9 +279,17 @@ if ($offline){
#region apply updates on nodes
foreach ($Node in $Nodes){
#make sure there is no maintenance mode
Write-Output "$(get-date -Format 'yyyy/MM/dd hh:mm:ss tt') $($Node): Disabling maintenance mode - if there is any"
Get-StorageFaultDomain -Type StorageScaleUnit -CimSession $ClusterName | Disable-StorageMaintenanceMode -CimSession $ClusterName
#make sure all nodes are up
Write-Output "$(get-date -Format 'yyyy/MM/dd hh:mm:ss tt') Make sure all nodes are up"
$NodesNotUp=Get-ClusterNode -Cluster $ClusterName | Where-Object state -ne up
if ($NodesNotUp){
Write-Output "$(get-date -Format 'yyyy/MM/dd hh:mm:ss tt') Some nodes were not up, resuming : $($NodesNotUp.Name)"
$NodesNotUp | Resume-ClusterNode -Failback Immediate | Out-Null
if (Get-ClusterNode -Cluster $ClusterName | Where-Object state -ne up){
Write-Output "$(get-date -Format 'yyyy/MM/dd hh:mm:ss tt') Resuming nodes failed. Interrupting"
break
}
}
#check for repair jobs, if found, wait until finished
Write-Output "$(get-date -Format 'yyyy/MM/dd hh:mm:ss tt') $($Node): Waiting for Storage jobs to finish"
@ -368,11 +376,13 @@ if ($offline){
$MSUpdateInstallResult=$Null
}
}
}else{
Write-Output "$(get-date -Format 'yyyy/MM/dd hh:mm:ss tt') $($Node): Skipping Microsoft Updates as requested"
}
#Suspend node
Write-Output "$(get-date -Format 'yyyy/MM/dd hh:mm:ss tt') $($Node): Suspending Cluster Node"
Suspend-ClusterNode -Name "$Node" -Cluster $ClusterName -Drain -Wait | Out-Null
Suspend-ClusterNode -Name "$Node" -Cluster $ClusterName -Drain -Wait -ErrorAction Ignore | Out-Null
if (Get-ClusterResource -Cluster $ClusterName | Where-Object OwnerNode -eq $Node | Where-Object State -eq "Online"){
Write-Output "$(get-date -Format 'yyyy/MM/dd hh:mm:ss tt') $($Node): Suspending Cluster Node Failed. Resuming and terminating patch run"
@ -380,9 +390,9 @@ if ($offline){
break
}
#enable storage maintenance mode
Write-Output "$(get-date -Format 'yyyy/MM/dd hh:mm:ss tt') $($Node): Enabling Storage Maintenance mode"
Get-StorageFaultDomain -CimSession $ClusterName -FriendlyName $Node | Enable-StorageMaintenanceMode -CimSession $ClusterName
#enable storage maintenance mode (not needed as node goes to maintenance mode when suspended)
#Write-Output "$(get-date -Format 'yyyy/MM/dd hh:mm:ss tt') $($Node): Enabling Storage Maintenance mode"
#Get-StorageFaultDomain -CimSession $ClusterName -FriendlyName $Node | Enable-StorageMaintenanceMode -CimSession $ClusterName
#Install Dell updates https://dl.dell.com/content/manual36290092-dell-emc-system-update-version-1-9-3-0-user-s-guide.pdf?language=en-us&ps=true
#assuming dell updates might interrupt server, therefore it's done during maintenance mode
@ -401,11 +411,13 @@ if ($offline){
}
}
}
}else{
Write-Output "$(get-date -Format 'yyyy/MM/dd hh:mm:ss tt') $($Node): Skipping Dell Updates as requested"
}
#Check if reboot is required and reboot
if (($Compliance | Where-Object {$_.NodeName -eq $Node -and $_.rebootrequired -eq $True}) -or ($Scanresult | Where-Object ($_.ComputerName -eq $node -and $_.MicrosoftUpdateRequired -eq $True)) -or ($ForceReboot -eq $True)){
Write-Output "$(get-date -Format 'yyyy/MM/dd hh:mm:ss tt') $($Node): Reboot is required"
Write-Output "$(get-date -Format 'yyyy/MM/dd hh:mm:ss tt') $($Node): Reboot is requested"
#restart node and wait for PowerShell to come up (with powershell 7 you need to wait for WINRM :)
Write-Output "$(get-date -Format 'yyyy/MM/dd hh:mm:ss tt') $($Node): Restarting Cluster Node"
Restart-Computer -ComputerName $Node -Protocol WSMan -Wait -For PowerShell -Force | Out-Null
@ -417,9 +429,9 @@ if ($offline){
Start-Sleep 5
}while($state -ne "Paused")
#disable storage maintenance mode
Write-Output "$(get-date -Format 'yyyy/MM/dd hh:mm:ss tt') $($Node): Disabling Storage Maintenance mode"
Get-StorageFaultDomain -Type StorageScaleUnit -CimSession $Node | Where-Object FriendlyName -eq $Node | Disable-StorageMaintenanceMode -CimSession $Node
#disable storage maintenance mode (not needed as node resumes from maintenance mode when resumed)
#Write-Output "$(get-date -Format 'yyyy/MM/dd hh:mm:ss tt') $($Node): Disabling Storage Maintenance mode"
#Get-StorageFaultDomain -Type StorageScaleUnit -CimSession $Node | Where-Object FriendlyName -eq $Node | Disable-StorageMaintenanceMode -CimSession $Node
#resume cluster node
Write-Output "$(get-date -Format 'yyyy/MM/dd hh:mm:ss tt') $($Node): Resuming Cluster Node"
@ -430,6 +442,12 @@ if ($offline){
do {Start-Sleep 5}while(
Get-CimInstance -CimSession $Nodes -Namespace root\virtualization\v2 -ClassName Msvm_MigrationJob | Where-Object StatusDescriptions -eq "Job is running"
)
#wait for node to resume from maintenance mode
Write-Output "$(get-date -Format 'yyyy/MM/dd hh:mm:ss tt') $($Node): Waiting for node to resume from Maintenance mode"
do {Start-Sleep 5}while(
Get-StorageFaultDomain -CimSession $Node | Where-Object OperationalStatus -eq "In Maintenance Mode"
)
}
#cleanup updates folder on nodes

Просмотреть файл

@ -2,9 +2,9 @@ $LabConfig=@{AllowedVLANs="1-10,711-719" ; DomainAdminName='LabAdmin'; AdminPass
#Azure Stack HCI 22H2
#labconfig will not domain join VMs, will add "Tools disk" and will also execute powershell command to make this tools disk online.
1..4 | ForEach-Object {$LABConfig.VMs += @{ VMName = "ASNode$_" ; Configuration = 'S2D' ; ParentVHD = 'AzSHCI22H2_G2.vhdx' ; HDDNumber = 4 ; HDDSize= 2TB ; MemoryStartupBytes= 1GB; VMProcessorCount=4 ; vTPM=$true ; AddToolsVHD=$True ; Unattend="NoDjoin" }}
1..4 | ForEach-Object {$LABConfig.VMs += @{ VMName = "ASNode$_" ; Configuration = 'S2D' ; ParentVHD = 'AzSHCI23H2_G2.vhdx' ; HDDNumber = 4 ; HDDSize= 2TB ; MemoryStartupBytes= 1GB; VMProcessorCount=4 ; vTPM=$true ; Unattend="NoDjoin" }}
#labconfig for nested virtualization
#1..4 | ForEach-Object {$LABConfig.VMs += @{ VMName = "ASNode$_" ; Configuration = 'S2D' ; ParentVHD = 'AzSHCI22H2_G2.vhdx' ; HDDNumber = 4 ; HDDSize= 2TB ; MemoryStartupBytes= 6GB; VMProcessorCount=4 ; vTPM=$true ; AddToolsVHD=$True ; Unattend="NoDjoin" ; NestedVirt=$true }}
#1..4 | ForEach-Object {$LABConfig.VMs += @{ VMName = "ASNode$_" ; Configuration = 'S2D' ; ParentVHD = 'AzSHCI23H2_G2.vhdx' ; HDDNumber = 4 ; HDDSize= 2TB ; MemoryStartupBytes= 6GB; VMProcessorCount=4 ; vTPM=$true ; Unattend="NoDjoin" ; NestedVirt=$true }}
#Windows Admin Center in GW mode
$LabConfig.VMs += @{ VMName = 'WACGW' ; ParentVHD = 'Win2022Core_G2.vhdx'; MGMTNICs=1}

Просмотреть файл

@ -23,77 +23,75 @@
Install-WindowsFeature -Name RSAT-AD-PowerShell,GPMC
#populate objects
New-HciAdObjectsPreCreation -Deploy -AsHciDeploymentUserCredential $Credentials -AsHciOUName $AsHCIOUName -AsHciPhysicalNodeList $Servers -DomainFQDN $DomainFQDN -AsHciClusterName $ClusterName -AsHciDeploymentPrefix $Prefix
New-HciAdObjectsPreCreation -Deploy -AzureStackLCMUserCredential $Credentials -AsHciOUName $AsHCIOUName -AsHciPhysicalNodeList $Servers -DomainFQDN $DomainFQDN -AsHciClusterName $ClusterName -AsHciDeploymentPrefix $Prefix
#install management features to explore cluster,settings...
Install-WindowsFeature -Name "RSAT-ADDS","RSAT-Clustering"
#endregion
#region Deploy - run from ASNode1!
#make D drives online
$Servers="ASNode1","ASNode2","ASNode3","ASNode4"
#add $Servers into trustedhosts
Set-Item WSMan:\localhost\Client\TrustedHosts -Value $($Servers -join ',') -Force
#invoke command
Invoke-Command -ComputerName $Servers -ScriptBlock {
get-disk -Number 1 | Set-Disk -IsReadOnly $false
get-disk -Number 1 | Set-Disk -IsOffline $false
}
#region prepare azure prerequisites - run from ASNode1 or Management (you can run from Management, just copy the resulting variables and use it in next region)
#variables
$StorageAccountName="asclus01$(Get-Random -Minimum 100000 -Maximum 999999)"
$ServicePrincipal=$True #or false if you want to use MFA (and skip SP creation)
$ServicePrincipalName="Azure-Stack-Registration"
$ResourceGroupName="ASClus01-RG"
$Location="EastUS"
#Download files
$downloadfolder="D:"
$files=@()
$Files+=@{Uri="https://go.microsoft.com/fwlink/?linkid=2210545" ; FileName="BootstrapCloudDeploymentTool.ps1" ; Description="Bootstrap PowerShell"}
$Files+=@{Uri="https://go.microsoft.com/fwlink/?linkid=2210546" ; FileName="CloudDeployment_10.2303.0.36.zip" ; Description="Cloud Deployment Package"}
$Files+=@{Uri="https://go.microsoft.com/fwlink/?linkid=2210608" ; FileName="Verify-CloudDeployment.zip_Hash.ps1" ; Description="Verify Cloud Deployment PowerShell"}
#login to azure
#download Azure module
if (!(Get-InstalledModule -Name az.accounts -ErrorAction Ignore)){
Install-Module -Name Az.Accounts -Force
}
if (-not (Get-AzContext)){
Connect-AzAccount -UseDeviceAuthentication
}
foreach ($file in $files){
if (-not (Test-Path "$downloadfolder\$($file.filename)")){
Start-BitsTransfer -Source $file.uri -Destination "$downloadfolder\$($file.filename)" -DisplayName "Downloading: $($file.filename)"
}
}
#select subscription if more available
$subscriptions=Get-AzSubscription
#list subscriptions
$subscriptions
if (($subscriptions).count -gt 1){
$SubscriptionID=Read-Host "Please give me subscription ID"
}else{
$SubscriptionID=$subscriptions.id
}
#Start bootstrap (script is looking for file "CloudDeployment_*.zip"
& D:\BootstrapCloudDeploymentTool.ps1
#make sure resource providers are registered
if (!(Get-InstalledModule -Name "az.resources" -ErrorAction Ignore)){
Install-Module -Name "az.resources" -Force
}
$Providers="Microsoft.ResourceConnector","Microsoft.Authorization","Microsoft.AzureStackHCI","Microsoft.HybridCompute","Microsoft.GuestConfiguration"
foreach ($Provider in $Providers){
Register-AzResourceProvider -ProviderNamespace $Provider
#wait for provider to finish registration
do {
$Status=Get-AzResourceProvider -ProviderNamespace $Provider
Write-Output "Registration Status - $Provider : $(($status.RegistrationState -match 'Registered').Count)/$($Status.Count)"
Start-Sleep 1
} while (($status.RegistrationState -match "Registered").Count -ne ($Status.Count))
}
#Create Storage Account
if (!(Get-InstalledModule -Name "az.storage"-ErrorAction Ignore)){
Install-Module -Name "az.storage" -Force
}
#create deployment credentials
$UserName="ASClus01-DeployUser"
$Password="LS1setup!"
$SecuredPassword = ConvertTo-SecureString $password -AsPlainText -Force
$AzureStackLCMUserCredential = New-Object System.Management.Automation.PSCredential ($UserName,$SecuredPassword)
#create resource group first
if (-not(Get-AzResourceGroup -Name $ResourceGroupName -ErrorAction Ignore)){
New-AzResourceGroup -Name $ResourceGroupName -Location $location
}
#create Storage Account
If (-not(Get-AzStorageAccountKey -Name $StorageAccountName -ResourceGroupName $ResourceGroupName -ErrorAction Ignore)){
New-AzStorageAccount -ResourceGroupName $ResourceGroupName -Name $StorageAccountName -SkuName Standard_LRS -Location $location -Kind StorageV2 -AccessTier Cool
}
$StorageAccountAccessKey=(Get-AzStorageAccountKey -Name $StorageAccountName -ResourceGroupName $ResourceGroupName | Select-Object -First 1).Value
$UserName="Administrator"
$Password="LS1setup!"
$SecuredPassword = ConvertTo-SecureString $password -AsPlainText -Force
$LocalAdminCred = New-Object System.Management.Automation.PSCredential ($UserName,$SecuredPassword)
$CloudName="AzureCloud"
$ServicePrincipalName="Azure-Stack-Registration"
#login to azure
#download Azure module
if (!(Get-InstalledModule -Name az.accounts -ErrorAction Ignore)){
Install-Module -Name Az.Accounts -Force
}
if (-not (Get-AzContext)){
Connect-AzAccount -UseDeviceAuthentication
}
#select subscription if more available
$subscriptions=Get-AzSubscription
#list subscriptions
$subscriptions
if (($subscriptions).count -gt 1){
$SubscriptionID=Read-Host "Please give me subscription ID"
}else{
$SubscriptionID=$subscriptions.id
}
if (!(Get-InstalledModule -Name az.Resources -ErrorAction Ignore)){
Install-Module -Name Az.Resources -Force
}
#Create Azure Stack HCI registration role https://learn.microsoft.com/en-us/azure-stack/hci/deploy/register-with-azure#assign-permissions-from-azure-portal
if (-not (Get-AzRoleDefinition -Name "Azure Stack HCI registration role - Custom")){
$Content=@"
#create service principal if requested
if ($ServicePrincipal){
#Create Azure Stack HCI registration role https://learn.microsoft.com/en-us/azure-stack/hci/deploy/register-with-azure#assign-permissions-from-azure-portal
#https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles#azure-connected-machine-onboarding
if (-not (Get-AzRoleDefinition -Name "Azure Stack HCI registration role - Custom" -ErrorAction Ignore)){
$Content=@"
{
"Name": "Azure Stack HCI registration role - Custom",
"Id": null,
@ -110,7 +108,13 @@
"Microsoft.Authorization/roleAssignments/read",
"Microsoft.HybridCompute/register/action",
"Microsoft.GuestConfiguration/register/action",
"Microsoft.HybridConnectivity/register/action"
"Microsoft.HybridConnectivity/register/action",
"Microsoft.HybridCompute/machines/extensions/write",
"Microsoft.HybridCompute/machines/extensions/read",
"Microsoft.HybridCompute/machines/read",
"Microsoft.HybridCompute/machines/write",
"Microsoft.HybridCompute/privateLinkScopes/read",
"Microsoft.GuestConfiguration/guestConfigurationAssignments/read"
],
"NotActions": [
],
@ -119,50 +123,119 @@
]
}
"@
$Content | Out-File "$env:USERPROFILE\Downloads\customHCIRole.json"
New-AzRoleDefinition -InputFile "$env:USERPROFILE\Downloads\customHCIRole.json"
}
#Create AzADServicePrincipal for Azure Stack HCI registration
$SP=Get-AZADServicePrincipal -DisplayName $ServicePrincipalName
if (-not $SP){
$SP=New-AzADServicePrincipal -DisplayName $ServicePrincipalName -Role "Azure Stack HCI registration role - Custom"
#remove default cred
Remove-AzADAppCredential -ApplicationId $SP.AppId
}
$Content | Out-File "$env:USERPROFILE\Downloads\customHCIRole.json"
New-AzRoleDefinition -InputFile "$env:USERPROFILE\Downloads\customHCIRole.json"
}
#Create new SPN password
$credential = New-Object -TypeName "Microsoft.Azure.PowerShell.Cmdlets.Resources.MSGraph.Models.ApiV10.MicrosoftGraphPasswordCredential" -Property @{
"KeyID" = (new-guid).Guid ;
"EndDateTime" = [DateTime]::UtcNow.AddYears(10)
#Create AzADServicePrincipal for Azure Stack HCI registration (if it does not exist)
$SP=Get-AZADServicePrincipal -DisplayName $ServicePrincipalName
if (-not $SP){
$SP=New-AzADServicePrincipal -DisplayName $ServicePrincipalName -Role "Azure Stack HCI registration role - Custom"
#remove default cred
Remove-AzADAppCredential -ApplicationId $SP.AppId
}
#Create new SPN password
$credential = New-Object -TypeName "Microsoft.Azure.PowerShell.Cmdlets.Resources.MSGraph.Models.ApiV10.MicrosoftGraphPasswordCredential" -Property @{
"KeyID" = (new-guid).Guid ;
"EndDateTime" = [DateTime]::UtcNow.AddYears(1)
}
$Creds=New-AzADAppCredential -PasswordCredentials $credential -ApplicationID $SP.AppID
$SPNSecret=$Creds.SecretText
$SPAppID=$SP.AppID
}
Disconnect-AzAccount
#output variables
Write-Host -ForegroundColor Cyan @"
#Variables to copy
`$SubscriptionID=`"$SubscriptionID`"
`$SPAppID=`"$SPAppID`"
`$SPNSecret=`"$SPNSecret`"
`$ResourceGroupName=`"$ResourceGroupName`"
`$StorageAccountName=`"$StorageAccountName`"
`$StorageAccountAccessKey=`"$StorageAccountAccessKey`"
`$Location=`"$Location`"
"@
#endregion
#region Deploy - run from ASNode1!
#variables
#create deployment credentials
$UserName="ASClus01-DeployUser"
$Password="LS1setup!"
$SecuredPassword = ConvertTo-SecureString $password -AsPlainText -Force
$AzureStackLCMUserCredential = New-Object System.Management.Automation.PSCredential ($UserName,$SecuredPassword)
$UserName="Administrator"
$Password="LS1setup!"
$SecuredPassword = ConvertTo-SecureString $password -AsPlainText -Force
$LocalAdminCred = New-Object System.Management.Automation.PSCredential ($UserName,$SecuredPassword)
#the one you have to populate if you did not run above region from Seed node
<#
$SubscriptionID=""
$SPAppID="" #not needed if you use MFA
$SPNSecret="" #not needed if you use MFA
$ResourceGroupName=""
$StorageAccountName=""
$StorageAccountAccessKey=""
$Location=""
#>
#download folder
$downloadfolder="c:\temp"
$Servers="ASNode1","ASNode2","ASNode3","ASNode4"
#Download files
#create folder
if (-not (Test-Path $downloadfolder)){New-Item -Path $downloadfolder -ItemType Directory}
$files=@()
$Files+=@{Uri="https://go.microsoft.com/fwlink/?linkid=2210545" ; FileName="BootstrapCloudDeploymentTool.ps1" ; Description="Bootstrap PowerShell"}
$Files+=@{Uri="https://go.microsoft.com/fwlink/?linkid=2210546" ; FileName="CloudDeployment_10.2306.0.47.zip" ; Description="Cloud Deployment Package"}
$Files+=@{Uri="https://go.microsoft.com/fwlink/?linkid=2210608" ; FileName="Verify-CloudDeployment.zip_Hash.ps1" ; Description="Verify Cloud Deployment PowerShell"}
foreach ($file in $files){
if (-not (Test-Path "$downloadfolder\$($file.filename)")){
Start-BitsTransfer -Source $file.uri -Destination "$downloadfolder\$($file.filename)" -DisplayName "Downloading: $($file.filename)"
}
}
#Start bootstrap (script is looking for file "CloudDeployment_*.zip"
& $downloadfolder\BootstrapCloudDeploymentTool.ps1
#create authentication token (Service Principal or MFA)
if ($SPAppID){
$SPNsecStringPassword = ConvertTo-SecureString $SPNSecret -AsPlainText -Force
$SPNCred=New-Object System.Management.Automation.PSCredential ($SPAppID, $SPNsecStringPassword)
}else{
Set-AuthenticationToken -RegistrationCloudName AzureCloud -RegistrationSubscriptionID $SubscriptionID
}
$Creds=New-AzADAppCredential -PasswordCredentials $credential -ApplicationID $SP.AppID
$SPNSecret=$Creds.SecretText
Write-Host "Your Password is: " -NoNewLine ; Write-Host $SPNSecret -ForegroundColor Cyan
$SPNsecStringPassword = ConvertTo-SecureString $SPNSecret -AsPlainText -Force
$SPNCred=New-Object System.Management.Automation.PSCredential ($SP.AppID, $SPNsecStringPassword)
#create config.json
#add servers to trusted hosts so you can query IP address dynamically (in the lab we dont exactly now which adapter is first and what IP was assigned
$TrustedHosts=@()
$TrustedHosts+=$Servers
Set-Item WSMan:\localhost\Client\TrustedHosts -Value $($TrustedHosts -join ',') -Force
$Content=@"
{
"Version": "3.0.0.0",
"Version": "10.0.0.0",
"ScaleUnits": [
{
"DeploymentData": {
"SecuritySettings": {
"SecurityModeSealed": true,
"SecuredCoreEnforced": true,
"VBSProtection": true,
"HVCIProtection": true,
"DRTMProtection": true,
"KernelDMAProtection": true,
"DriftControlEnforced": true,
"CredentialGuardEnforced": false,
"CredentialGuardEnforced": true,
"SMBSigningEnforced": true,
"SMBClusterEncryption": false,
"SideChannelMitigationEnforced": true,
"BitlockerBootVolume": true,
"BitlockerDataVolumes": true,
"SEDProtectionEnforced": true,
"BitlockerDataVolumes": false,
"WDACEnforced": true
},
"Observability": {
@ -172,6 +245,10 @@
},
"Cluster": {
"Name": "ASClus01",
"WitnessType": "Cloud",
"WitnessPath": "",
"CloudAccountName": "$StorageAccountName",
"AzureServiceEndpoint": "core.windows.net",
"StaticAddress": [
""
]
@ -179,15 +256,9 @@
"Storage": {
"ConfigurationMode": "Express"
},
"OptionalServices": {
"VirtualSwitchName": "",
"CSVPath": "",
"ARBRegion": "westeurope"
},
"TimeZone": "Pacific Standard Time",
"NamingPrefix": "ASClus01",
"DomainFQDN": "corp.contoso.com",
"ExternalDomainFQDN": "corp.contoso.com",
"InfrastructureNetwork": [
{
"VlanId": "0",
@ -196,7 +267,7 @@
"IPPools": [
{
"StartingAddress": "10.0.0.100",
"EndingAddress": "10.0.0.199"
"EndingAddress": "10.0.0.110"
}
],
"DNSServers": [
@ -276,10 +347,14 @@
]
}
"@
$Content | Out-File -FilePath d:\config.json
$Content | Out-File -FilePath c:\config.json
#set trusted hosts back
Set-Item WSMan:\localhost\Client\TrustedHosts -Value "" -Force
#start deployment
#make sure some prereqs (that will be fixed in future) are set
<#
#Make sure Windows Update is disabled and ping enabled (https://learn.microsoft.com/en-us/azure-stack/hci/hci-known-issues-2303)
Microsoft.PowerShell.Core\Invoke-Command -ComputerName $Servers -ScriptBlock {
reg add HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU /v NoAutoUpdate /t REG_DWORD /d 1 /f
@ -290,19 +365,25 @@ $Content | Out-File -FilePath d:\config.json
}
#add hostnames and IPs to trusted hosts (bug that in BareMetal.psm1 is invoke-command with IP that is not in trusted hosts)
$TrustedHosts=@()
$TrustedHosts+=(Get-NetIPAddress -CimSession $Servers -InterfaceAlias Ethernet* -AddressFamily IPv4).IPAddress
$TrustedHosts+=$Servers
Set-Item WSMan:\localhost\Client\TrustedHosts -Value $($TrustedHosts -join ',') -Force
#>
#create secured storage access key
$StorageAccountAccessKeySecured = ConvertTo-SecureString $StorageAccountAccessKey -AsPlainText -Force
#deploy
.\Invoke-CloudDeployment -JSONFilePath D:\config.json -AzureStackLCMUserCredential $AzureStackLCMUserCredential -LocalAdminCredential $LocalAdminCred -RegistrationSPCredential $SPNCred -RegistrationCloudName $CloudName -RegistrationSubscriptionID $SubscriptionID
if ($SPAppID){
.\Invoke-CloudDeployment -JSONFilePath c:\config.json -AzureStackLCMUserCredential $AzureStackLCMUserCredential -LocalAdminCredential $LocalAdminCred -RegistrationSPCredential $SPNCred -RegistrationCloudName AzureCloud -RegistrationSubscriptionID $SubscriptionID -RegistrationResourceGroupName $ResourceGroupName -WitnessStorageKey $StorageAccountAccessKeySecured -RegistrationRegion $Location
}else{
.\Invoke-CloudDeployment -JSONFilePath c:\config.json -AzureStackLCMUserCredential $AzureStackLCMUserCredential -LocalAdminCredential $LocalAdminCred -RegistrationCloudName AzureCloud -RegistrationSubscriptionID $SubscriptionID -RegistrationResourceGroupName $ResourceGroupName -WitnessStorageKey $StorageAccountAccessKeySecured -RegistrationRegion $Location
}
#endregion
#region Validate deployment - run from management VM!
$SeedNode="ASNode1"
Invoke-Command -ComputerName $SeedNode -ScriptBlock {
([xml](Get-Content C:\ecestore\efb61d70-47ed-8f44-5d63-bed6adc0fb0f\086a22e3-ef1a-7b3a-dc9d-f407953b0f84)) | Select-Xml -XPath "//Action/Steps/Step" | ForEach-Object { $_.Node } | Select-Object FullStepIndex, Status, Name, StartTimeUtc, EndTimeUtc, @{Name="Duration";Expression={new-timespan -Start $_.StartTimeUtc -End $_.EndTimeUtc } } | ft -AutoSize
([xml](Get-Content C:\ecestore\efb61d70-47ed-8f44-5d63-bed6adc0fb0f\086a22e3-ef1a-7b3a-dc9d-f407953b0f84)) | Select-Xml -XPath "//Action/Steps/Step" | ForEach-Object { $_.Node } | Select-Object FullStepIndex, Status, Name, StartTimeUtc, EndTimeUtc, @{Name="Duration";Expression={new-timespan -Start $_.StartTimeUtc -End $_.EndTimeUtc } } | Format-Table -AutoSize
}
#endregion

Просмотреть файл

@ -276,16 +276,17 @@ Foreach ($PSSession in $PSSessions){
$VolumeName="AKS"
$Servers=(Get-ClusterNode -Cluster $ClusterName).Name
$DHCPServer="DC"
$DHCPScopeID="10.0.0.0"
$VIPPoolStart="10.0.1.2"
$VIPPoolEnd="10.0.1.100"
$VLANID=11
$resourcegroupname="$ClusterName-rg"
#if dhcp is disabled:
$k8sNodeIpPoolStart="10.0.1.101"
$k8sNodeIpPoolEnd="10.0.1.254"
$IPAddressPrefix="10.0.1.0/24"
$DNSServers="10.0.1.1"
$Gateway="10.0.1.1"
$VLANID=11
$resourcegroupname="$ClusterName-rg"
#JaromirK note: it would be great if I could simply run "Initialize-AksHciNode -ComputerName $ClusterName". I could simply skip credssp. Same applies for AksHciConfig and AksHciRegistration
@ -323,11 +324,13 @@ Foreach ($PSSession in $PSSessions){
#configure aks
#note: I'm assigning larger control plane VM than default as I saw IP disapperaring IP address if it was smaller in virtual environment (I tested manually incresed size to 8cores and 8GB RAM)
Invoke-Command -ComputerName $servers[0] -Credential $Credentials -Authentication Credssp -ScriptBlock {
#install nuget first
Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force
#DHCP
#$vnet = New-AksHciNetworkSetting -Name $using:vNetName -vSwitchName $using:vSwitchName -vippoolstart $using:vippoolstart -vippoolend $using:vippoolend
$vnet = New-AksHciNetworkSetting -Name $using:vNetName -vSwitchName $using:vSwitchName -vippoolstart $using:vippoolstart -vippoolend $using:vippoolend -vlanID $using:VLANID
#Static
$vnet = New-AksHciNetworkSetting -Name $using:vNetName -ipAddressPrefix $using:IPAddressPrefix -vSwitchName $using:vSwitchName -vippoolstart $using:vippoolstart -vippoolend $using:vippoolend -k8sNodeIpPoolStart $using:k8sNodeIpPoolStart -k8sNodeIpPoolEnd $using:k8sNodeIpPoolEnd -vlanID $using:VLANID -DNSServers $using:DNSServers -gateway $Using:Gateway
Set-AksHciConfig -vnet $vnet -workingDir c:\clusterstorage\$using:VolumeName\ImagesStore -imageDir c:\clusterstorage\$using:VolumeName\Images -cloudConfigLocation c:\clusterstorage\$using:VolumeName\Config -ClusterRoleName "$($using:ClusterName)_AKS" -controlPlaneVmSize 'Standard_A4_v2' # Get-AksHciVmSize
#$vnet = New-AksHciNetworkSetting -Name $using:vNetName -ipAddressPrefix $using:IPAddressPrefix -vSwitchName $using:vSwitchName -vippoolstart $using:vippoolstart -vippoolend $using:vippoolend -k8sNodeIpPoolStart $using:k8sNodeIpPoolStart -k8sNodeIpPoolEnd $using:k8sNodeIpPoolEnd -vlanID $using:VLANID -DNSServers $using:DNSServers -gateway $Using:Gateway
Set-AksHciConfig -vnet $vnet -workingDir c:\clusterstorage\$using:VolumeName\WorkDir -imageDir c:\clusterstorage\$using:VolumeName\Images -cloudConfigLocation c:\clusterstorage\$using:VolumeName\Config -ClusterRoleName "$($using:ClusterName)_AKS" -controlPlaneVmSize 'Standard_A4_v2' # Get-AksHciVmSize
}
#validate config
@ -518,7 +521,7 @@ $password="" #if blank, password will be created
#create credentials
$ClientID=$sp.AppId
$SecureSecret= ConvertTo-SecureString $password -AsPlainText -Force
$Credentials = New-Object System.Management.Automation.PSCredential ($ClientID , $SecureSecret)
$SPCredentials = New-Object System.Management.Automation.PSCredential ($ClientID , $SecureSecret)
#register namespace Microsoft.KubernetesConfiguration and Microsoft.Kubernetes
Register-AzResourceProvider -ProviderNamespace Microsoft.Kubernetes
@ -529,7 +532,7 @@ Invoke-Command -ComputerName $ClusterName -ScriptBlock {
#Generate kubeconfig
Get-AksHciCredential -Name $using:KubernetesClusterName -confirm:0
#onboard
Enable-AksHciArcConnection -Name $using:KubernetesClusterName -tenantId $using:tenantID -subscriptionId $using:subscriptionID -resourcegroup $using:resourcegroup -Location $using:location -credential $using:Credentials
Enable-AksHciArcConnection -Name $using:KubernetesClusterName -tenantId $using:tenantID -subscriptionId $using:subscriptionID -resourcegroup $using:resourcegroup -Location $using:location -credential $using:SPCredentials
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -163,6 +163,7 @@
$DestinationClusterName="AzSHCI-Cluster"
$SourceStoragePath="C:\ClusterStorage\CSV1"
$DestinationStoragePath="C:\ClusterStorage\CSV1"
$DestinationSwitchName=(Get-VMSwitch -CimSession ((Get-ClusterNode -Cluster $ClusterName).Name | Select-Object -First 1)).Name
$VMNames=(Get-VM -cimsession (get-clusternode -cluster $SourceClusterName).Name | Where-Object Path -Like "$SourceStoragePath*").Name
# Temporarily enable CredSSP delegation to avoid double-hop issue
@ -178,27 +179,42 @@
#do the move
foreach ($VMName in $VMNames){
#remove VM from HA Resources
Write-Output "$(get-date -Format 'yyyy/MM/dd hh:mm:ss tt') : Removing VM $($VM.VMName) From Cluster resources"
Get-ClusterResource -Cluster $SourceClusterName -name "Virtual Machine $VMName" -ErrorAction Ignore | Remove-ClusterResource -force
Get-ClusterGroup -Cluster $SourceClusterName -Name $VMName -ErrorAction Ignore | Remove-ClusterGroup -force
#Grab random node in cluster $DestinationClusterName
#Grab random node in cluster $DestinationClusterName (does not have to be random of course)
$VM=Get-VM -Cimsession (get-clusternode -cluster $SourceClusterName).Name -Name $VMName
$VM | Stop-VM -Save
Write-Output "$(get-date -Format 'yyyy/MM/dd hh:mm:ss tt') : Stopping VM $($VM.VMName)"
$VM | Stop-VM
#or just save it, but we need to update version anyway
#$VM | Stop-VM -Save
#If there is different switch name in destination node, you should consider disconnecting vNICs before removing VM and saving config
$VM | Get-VMNetworkAdapter | Disconnect-VMNetworkAdapter
#Backup config
Write-Output "$(get-date -Format 'yyyy/MM/dd hh:mm:ss tt') : Backing up VM config"
Invoke-Command -ComputerName $SourceClusterName -ScriptBlock {Copy-Item -Path "$($using:VM.Path)\Virtual Machines" -Destination "$($using:VM.Path)\Virtual Machines Bak" -Recurse}
#If there is different switch name in destination node, you should consider disconnecting vNICs first
#$VM | Get-VMNetworkAdapter | Disconnect-VMNetworkAdapter
#Remove VM
$VM | Remove-VM -Force
#Remove VM (Just making sure hyper-v command is used, because SCVMM Remove-VM also removes VHDs)
Write-Output "$(get-date -Format 'yyyy/MM/dd hh:mm:ss tt') : Removing VM"
$VM | Hyper-V\Remove-VM -Force
#Restore Config
#Invoke-Command -ComputerName $SourceClusterName -ScriptBlock {Copy-Item -Path "$($using:VM.Path)\Virtual Machines Bak\*" -Destination "$($using:VM.Path)\Virtual Machines" -Recurse}
Invoke-Command -ComputerName $SourceClusterName -ScriptBlock {Move-Item -Path "$($using:VM.Path)\Virtual Machines Bak\*" -Destination "$($using:VM.Path)\Virtual Machines"}
Invoke-Command -ComputerName $SourceClusterName -ScriptBlock {Remove-Item -Path "$($using:VM.Path)\Virtual Machines Bak\"}
#zip config to have a backup (in case something goes wrong with updating VM version)
Invoke-Command -ComputerName $SourceClusterName -ScriptBlock {Compress-Archive -Path "$($using:VM.Path)\Virtual Machines\" -DestinationPath "$($using:VM.Path)\Virtual Machines.zip"}
#Copy machine to destination node using CredSSP
$VolumeName=$DestinationStoragePath | Split-Path -Leaf
Write-Output "$(get-date -Format 'yyyy/MM/dd hh:mm:ss tt') : Copying VM $($VM.VMName) to \\$DestinationClusterName\ClusterStorage$\$VolumeName\"
Invoke-Command -ComputerName ($Servers | Get-Random) -Credential $Credentials -Authentication Credssp -ScriptBlock {Copy-Item -Path "$($using:VM.Path)" -Destination "\\$using:DestinationClusterName\ClusterStorage$\$using:VolumeName\" -Recurse}
Write-Output "$(get-date -Format 'yyyy/MM/dd hh:mm:ss tt') : Copying VM $($VM.VMName) Finished"
#Import VM and Start
Write-Output "$(get-date -Format 'yyyy/MM/dd hh:mm:ss tt') : Importing VM $($VM.VMName) And Starting"
$DestinationHost=(get-clusternode -cluster $DestinationClusterName | get-random).Name
$NewVM=Import-VM -Path "$DestinationStoragePath\$($VM.Name)\Virtual Machines\$($VM.ID.GUID).vmcx" -CimSession $DestinationHost
$NewVM | Update-VMVersion -Force
$NewVM | Get-VMNetworkAdapter | Connect-VMNetworkAdapter -SwitchName $DestinationSwitchName
$NewVM | Start-VM
}
@ -213,6 +229,7 @@
$DestinationClusterName="AzSHCI-Cluster"
$SourceClusterVolumes=(Get-ClusterSharedVolume -Cluster $SourceClusterName).sharedvolumeinfo.Friendlyvolumename
$DestinationClusterVolumes=(Get-ClusterSharedVolume -Cluster $DestinationClusterName).sharedvolumeinfo.Friendlyvolumename
$DestinationSwitchName=(Get-VMSwitch -CimSession ((Get-ClusterNode -Cluster $ClusterName).Name | Select-Object -First 1)).Name
# Temporarily enable CredSSP delegation to avoid double-hop issue
$Servers=(get-clusternode -cluster $SourceClusterName).Name
@ -234,27 +251,45 @@
}
$VMNames=(Get-VM -cimsession (get-clusternode -cluster $SourceClusterName).Name | Where-Object Path -Like "$SourceClusterVolume*").Name
foreach ($VMName in $VMNames){
#remove VM from HA Resources
Write-Output "$(get-date -Format 'yyyy/MM/dd hh:mm:ss tt') : Removing VM $($VM.VMName) From Cluster resources"
Get-ClusterResource -Cluster $SourceClusterName -name "Virtual Machine $VMName" -ErrorAction Ignore | Remove-ClusterResource -force
Get-ClusterGroup -Cluster $SourceClusterName -Name $VMName -ErrorAction Ignore | Remove-ClusterGroup -force
#Grab random node in cluster $DestinationClusterName (does not have to be random of course)
$VM=Get-VM -Cimsession (get-clusternode -cluster $SourceClusterName).Name -Name $VMName
$VM | Stop-VM -Save
Write-Output "$(get-date -Format 'yyyy/MM/dd hh:mm:ss tt') : Stopping VM $($VM.VMName)"
$VM | Stop-VM
#or just save it, but we need to update version anyway
#$VM | Stop-VM -Save
#If there is different switch name in destination node, you should consider disconnecting vNICs before removing VM and saving config
$VM | Get-VMNetworkAdapter | Disconnect-VMNetworkAdapter
#Backup config
Write-Output "$(get-date -Format 'yyyy/MM/dd hh:mm:ss tt') : Backing up VM config"
Invoke-Command -ComputerName $SourceClusterName -ScriptBlock {Copy-Item -Path "$($using:VM.Path)\Virtual Machines" -Destination "$($using:VM.Path)\Virtual Machines Bak" -Recurse}
#If there is different switch name in destination node, you should consider disconnecting vNICs first
#$VM | Get-VMNetworkAdapter | Disconnect-VMNetworkAdapter
#Backup config
Invoke-Command -ComputerName $SourceClusterName -ScriptBlock {Copy-Item -Path "$($using:VM.Path)\Virtual Machines" -Destination "$($using:VM.Path)\Virtual Machines Bak" -Recurse}
#Remove VM
$VM | Remove-VM -Force
#Remove VM (Just making sure hyper-v command is used, because SCVMM Remove-VM also removes VHDs)
Write-Output "$(get-date -Format 'yyyy/MM/dd hh:mm:ss tt') : Removing VM"
$VM | Hyper-V\Remove-VM -Force
#Restore Config
#Invoke-Command -ComputerName $SourceClusterName -ScriptBlock {Copy-Item -Path "$($using:VM.Path)\Virtual Machines Bak\*" -Destination "$($using:VM.Path)\Virtual Machines" -Recurse}
Invoke-Command -ComputerName $SourceClusterName -ScriptBlock {Move-Item -Path "$($using:VM.Path)\Virtual Machines Bak\*" -Destination "$($using:VM.Path)\Virtual Machines"}
Invoke-Command -ComputerName $SourceClusterName -ScriptBlock {Remove-Item -Path "$($using:VM.Path)\Virtual Machines Bak\"}
#zip config to have a backup (in case something goes wrong with updating VM version)
Invoke-Command -ComputerName $SourceClusterName -ScriptBlock {Compress-Archive -Path "$($using:VM.Path)\Virtual Machines\" -DestinationPath "$($using:VM.Path)\Virtual Machines.zip"}
#Copy machine to destination node using CredSSP
$VolumeName=$DestinationClusterVolumes[$index] | Split-Path -Leaf
$VolumeName=$DestinationStoragePath | Split-Path -Leaf
Write-Output "$(get-date -Format 'yyyy/MM/dd hh:mm:ss tt') : Copying VM $($VM.VMName) to \\$DestinationClusterName\ClusterStorage$\$VolumeName\"
Invoke-Command -ComputerName ($Servers | Get-Random) -Credential $Credentials -Authentication Credssp -ScriptBlock {Copy-Item -Path "$($using:VM.Path)" -Destination "\\$using:DestinationClusterName\ClusterStorage$\$using:VolumeName\" -Recurse}
Write-Output "$(get-date -Format 'yyyy/MM/dd hh:mm:ss tt') : Copying VM $($VM.VMName) Finished"
#Import VM and Start
Write-Output "$(get-date -Format 'yyyy/MM/dd hh:mm:ss tt') : Importing VM $($VM.VMName) And Starting"
$DestinationHost=(get-clusternode -cluster $DestinationClusterName | get-random).Name
$NewVM=Import-VM -Path "$($DestinationClusterVolumes[$index])\$($VM.Name)\Virtual Machines\$($VM.ID.GUID).vmcx" -CimSession $DestinationHost
$NewVM=Import-VM -Path "$DestinationStoragePath\$($VM.Name)\Virtual Machines\$($VM.ID.GUID).vmcx" -CimSession $DestinationHost
$NewVM | Update-VMVersion -Force
$NewVM | Get-VMNetworkAdapter | Connect-VMNetworkAdapter -SwitchName $DestinationSwitchName
$NewVM | Start-VM
}
}

Просмотреть файл

@ -0,0 +1,14 @@
$LabConfig=@{ManagementSubnetIDs=0..1 ;DomainAdminName='LabAdmin'; AdminPassword='LS1setup!' ; <#Prefix = 'MSLab-'#> ; DCEdition='4'; Internet=$true ; TelemetryLevel='Full' ; TelemetryNickname='JaromiK' ; CustomDnsForwarders="10.8.8.8","10.7.7.7" ; AdditionalNetworksConfig=@(); VMs=@()}
#2 nodes for AzSHCI Cluster
1..2 | ForEach-Object {$VMNames="ASHCIRB" ; $LABConfig.VMs += @{ VMName = "$VMNames$_" ; Configuration = 'S2D' ; ParentVHD = 'AzSHCI22H2_G2.vhdx' ; HDDNumber = 4 ; HDDSize= 4TB ; MemoryStartupBytes= 14GB; VMProcessorCount="Max" ; NestedVirt=$true ; VirtualTPM=$true}}
#or small just when host is limited
#1..2 | ForEach-Object {$LABConfig.VMs += @{ VMName = "AzSHCI$_" ; Configuration = 'S2D' ; ParentVHD = 'AzSHCI21H2_G2.vhdx' ; HDDNumber = 10 ; HDDSize= 10TB ; MemoryStartupBytes= 1GB; VMProcessorCount="Max" ; vTPM=$true}}
#Optional Windows Admin Center in GW mode
$LabConfig.VMs += @{ VMName = 'WACGW' ; ParentVHD = 'Win2022Core_G2.vhdx'; MGMTNICs=1}
#Management machine
$LabConfig.VMs += @{ VMName = 'Management' ; ParentVHD = 'Win2022_G2.vhdx' ; MGMTNICs=1 }

Просмотреть файл

@ -0,0 +1,487 @@
#https://learn.microsoft.com/en-us/azure/aks/hybrid/deploy-aks-service-hci?tabs=powershell#step-2-install-the-aks-hybrid-extension-on-the-azure-arc-resource-bridge
#https://aka.ms/ArcEnabledHCI
#region Variables
$ClusterNodeNames="ASHCIRB1","ASHCIRB2"
$ClusterName="ASHCIRB-Cluster"
$vswitchName="vSwitch"
$controlPlaneIP="10.0.0.101"
$VolumeName="MOC"
$VolumePath="c:\ClusterStorage\$VolumeName"
$CredSSPUserName="CORP\LabAdmin"
$CredSSPPassword="LS1setup!"
$CustomLocationName="$ClusterName"
$CustomLocationNameSpace="customlocation-ns"
#ARC VMs virtual network name (the one that is visible in portal when you create a VM)
$vnetName="management"
#AKS config
$AKSvnetName="AKSvnet"
$VIPPoolStart="10.0.1.2"
$VIPPoolEnd="10.0.1.50"
$DHCPServer="DC"
$DHCPScopeID="10.0.1.0"
$VLANID=11
#for static aks deployment
$IPAddressPrefix="10.0.1.0/24"
$Gateway="10.0.1.1"
$dnsservers="10.0.1.1"
$k8snodeippoolstart="10.0.1.51"
$k8snodeippoolend="10.0.1.254"
#if you want custom images to add
$LibraryVolumeName="Library" #volume for Gallery images for VMs
$AzureImages=@()
$AzureImages+=@{PublisherName = "microsoftwindowsserver";Offer="windowsserver";SKU="2022-datacenter-azure-edition-smalldisk";OSType="Windows"} #OS TYpe can be "Windows" or "Linux" - first letter has to be capital!
$AzureImages+=@{PublisherName = "microsoftwindowsserver";Offer="windowsserver";SKU="2022-datacenter-azure-edition-core-smalldisk";OSType="Windows"} #OS TYpe can be "Windows" or "Linux" - first letter has to be capital!
#Install or update Azure packages
Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force
$ModuleNames="Az.Accounts","Az.Compute","Az.Resources","Az.StackHCI"
foreach ($ModuleName in $ModuleNames){
$Module=Get-InstalledModule -Name $ModuleName -ErrorAction Ignore
if ($Module){$LatestVersion=(Find-Module -Name $ModuleName).Version}
if (-not($Module) -or ($Module.Version -lt $LatestVersion)){
Install-Module -Name $ModuleName -Force
}
}
#login to Azure
if (-not (Get-AzContext)){
Login-AzAccount -UseDeviceAuthentication
}
$ResourceGroupName="$ClusterName-rg"
$SubscriptionID=(Get-AzContext).Subscription.ID
#select context
$context=Get-AzContext -ListAvailable
if (($context).count -gt 1){
$context=$context | Out-GridView -OutputMode Single
$context | Set-AzContext
}
#I did only test same for all (EastUS)
$VMImageLocation="eastus"
$ArcResourceBridgeLocation="eastus"
$AzureStackLocation="eastus"
<#or populate by choosing your own
#grab region where to grab VMs from
$VMImageLocation = (Get-AzLocation | Where-Object Providers -Contains "Microsoft.Compute" | Out-GridView -OutputMode Single -Title "Choose location where to grab VMs from").Location
#grab location for Arc Resource Bridge and Custom location
$ArcResourceBridgeLocation=(Get-AzLocation | Where-Object Providers -Contains "Microsoft.ResourceConnector" | Out-GridView -OutputMode Single -Title "Choose location for Arc Resource Bridge and Custom location").Location
#grab location for Azure Stack
$AzureStackLocation=(Get-AzResourceProvider -ProviderNamespace Microsoft.AzureStackHCI).Where{($_.ResourceTypes.ResourceTypeName -eq 'clusters' -and $_.RegistrationState -eq 'Registered')}.Locations | Out-GridView -OutputMode Single -Title "Please select Location for AzureStackHCI metadata"
$AzureStackLocation = $region -replace '\s',''
$AzureStackLocation = $region.ToLower()
#>
#endregion
#region Create 2 node cluster (just simple. Not for prod - follow hyperconverged scenario for real clusters https://github.com/microsoft/MSLab/tree/master/Scenarios/AzSHCI%20Deployment%2022H2%20Edition)
# Install features for management on server
Install-WindowsFeature -Name RSAT-Clustering,RSAT-Clustering-Mgmt,RSAT-Clustering-PowerShell,RSAT-Hyper-V-Tools
# Update servers (optional)
Invoke-Command -ComputerName $ClusterNodeNames -ScriptBlock {
New-PSSessionConfigurationFile -RunAsVirtualAccount -Path $env:TEMP\VirtualAccount.pssc
Register-PSSessionConfiguration -Name 'VirtualAccount' -Path $env:TEMP\VirtualAccount.pssc -Force
} -ErrorAction Ignore
# Run Windows Update via ComObject.
Invoke-Command -ComputerName $ClusterNodeNames -ConfigurationName 'VirtualAccount' {
$Searcher = New-Object -ComObject Microsoft.Update.Searcher
$SearchCriteriaAllUpdates = "IsInstalled=0 and DeploymentAction='Installation' or
IsPresent=1 and DeploymentAction='Uninstallation' or
IsInstalled=1 and DeploymentAction='Installation' and RebootRequired=1 or
IsInstalled=0 and DeploymentAction='Uninstallation' and RebootRequired=1"
$SearchResult = $Searcher.Search($SearchCriteriaAllUpdates).Updates
$Session = New-Object -ComObject Microsoft.Update.Session
$Downloader = $Session.CreateUpdateDownloader()
$Downloader.Updates = $SearchResult
$Downloader.Download()
$Installer = New-Object -ComObject Microsoft.Update.Installer
$Installer.Updates = $SearchResult
$Result = $Installer.Install()
$Result
}
#remove temporary PSsession config
Invoke-Command -ComputerName $ClusterNodeNames -ScriptBlock {
Unregister-PSSessionConfiguration -Name 'VirtualAccount'
Remove-Item -Path $env:TEMP\VirtualAccount.pssc
}
# Install features on servers
Invoke-Command -computername $ClusterNodeNames -ScriptBlock {
Enable-WindowsOptionalFeature -FeatureName Microsoft-Hyper-V -Online -NoRestart
Install-WindowsFeature -Name "Failover-Clustering","RSAT-Clustering-Powershell","Hyper-V-PowerShell"
}
# restart servers
Restart-Computer -ComputerName $ClusterNodeNames -Protocol WSMan -Wait -For PowerShell
#failsafe - sometimes it evaluates, that servers completed restart after first restart (hyper-v needs 2)
Start-sleep 20
# create vSwitch (sometimes happens, that I need to restart servers again and then it will create vSwitch...)
Invoke-Command -ComputerName $ClusterNodeNames -ScriptBlock {New-VMSwitch -Name $using:vswitchName -EnableEmbeddedTeaming $TRUE -NetAdapterName (Get-NetIPAddress -IPAddress 10.* ).InterfaceAlias}
#create cluster
New-Cluster -Name $ClusterName -Node $ClusterNodeNames
Start-Sleep 5
Clear-DNSClientCache
#add file share witness
#Create new directory
$WitnessName=$ClusterName+"Witness"
Invoke-Command -ComputerName DC -ScriptBlock {new-item -Path c:\Shares -Name $using:WitnessName -ItemType Directory}
$accounts=@()
$accounts+="corp\$($ClusterName)$"
$accounts+="corp\Domain Admins"
New-SmbShare -Name $WitnessName -Path "c:\Shares\$WitnessName" -FullAccess $accounts -CimSession DC
#Set NTFS permissions
Invoke-Command -ComputerName DC -ScriptBlock {(Get-SmbShare $using:WitnessName).PresetPathAcl | Set-Acl}
#Set Quorum
Set-ClusterQuorum -Cluster $ClusterName -FileShareWitness "\\DC\$WitnessName"
#Enable S2D
Enable-ClusterS2D -CimSession $ClusterName -Verbose -Confirm:0
#configure thin volumes a default if available (because why not :)
$OSInfo=Invoke-Command -ComputerName $ClusterName -ScriptBlock {
Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\'
}
if ($OSInfo.productname -eq "Azure Stack HCI" -and $OSInfo.CurrentBuild -ge 20348){
Get-StoragePool -CimSession $ClusterName -FriendlyName S2D* | Set-StoragePool -ProvisioningTypeDefault Thin
}
#endregion
#region Register Azure Stack HCI to Azure - if not registered, VMs are not added as cluster resources = AKS script will fail
#download Azure module
Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force
if (!(Get-InstalledModule -Name Az.StackHCI -ErrorAction Ignore)){
Install-Module -Name Az.StackHCI -Force
}
#login to azure
#download Azure module
if (!(Get-InstalledModule -Name az.accounts -ErrorAction Ignore)){
Install-Module -Name Az.Accounts -Force
}
Connect-AzAccount -UseDeviceAuthentication
#select subscription if more available
$subscription=Get-AzSubscription
if (($subscription).count -gt 1){
$subscription | Out-GridView -OutputMode Single | Set-AzContext
}
#grab subscription ID
$subscriptionID=(Get-AzContext).Subscription.id
<# Register AZSHCi without prompting for creds,
Notes: As Dec. 2021, in Azure Stack HCI 21H2, if you Register-AzStackHCI the cluster multiple times in same ResourceGroup (e.g. default
resource group name is AzSHCI-Cluster-rg) without run UnRegister-AzStackHCI first, although you may succeed in cluster registration, but
sever node Arc integration will fail, even if you have deleted the ResourceGroup in Azure Portal before running Register-AzStackHCI #>
$armTokenItemResource = "https://management.core.windows.net/"
$graphTokenItemResource = "https://graph.windows.net/"
$azContext = Get-AzContext
$authFactory = [Microsoft.Azure.Commands.Common.Authentication.AzureSession]::Instance.AuthenticationFactory
$armToken = $authFactory.Authenticate($azContext.Account, $azContext.Environment, $azContext.Tenant.Id, $null, [Microsoft.Azure.Commands.Common.Authentication.ShowDialog]::Never, $null, $armTokenItemResource).AccessToken
$id = $azContext.Account.Id
#register
Register-AzStackHCI -SubscriptionID $subscriptionID -Region $AzureStackLocation -ComputerName $ClusterName -ArmAccessToken $armToken -AccountId $id
#Install Azure Stack HCI RSAT Tools to all nodes
Invoke-Command -ComputerName $ClusterNodeNames -ScriptBlock {
Install-WindowsFeature -Name RSAT-Azure-Stack-HCI
}
#Validate registration (query on just one node is needed)
Invoke-Command -ComputerName $ClusterName -ScriptBlock {
Get-AzureStackHCI
}
#endregion
#region Install modules and create MOC agent Service
#Install required modules
Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force
Install-Module -Name PowershellGet -Force -Confirm:$false -SkipPublisherCheck
Update-Module -Name PowerShellGet
#to be able to install ArcHci and MOC, powershellget 2.2.5 needs to be used - to this posh restart is needed
Start-Process -Wait -FilePath PowerShell -ArgumentList {
Install-Module -Name MOC -Repository PSGallery -Force -AcceptLicense
Install-Module -Name ArcHci -Force -Confirm:$false -SkipPublisherCheck -AcceptLicense
}
#Increase MaxEvenlope and create session to copy files to
Invoke-Command -ComputerName $ClusterNodeNames -ScriptBlock {Set-Item -Path WSMan:\localhost\MaxEnvelopeSizekb -Value 4096}
#distribute modules to cluster nodes
$ModuleNames="ArcHci","Moc","DownloadSDK"
$PSSessions=New-PSSession -ComputerName $ClusterNodeNames
Foreach ($PSSession in $PSSessions){
Foreach ($ModuleName in $ModuleNames){
Copy-Item -Path $env:ProgramFiles\windowspowershell\modules\$ModuleName -Destination $env:ProgramFiles\windowspowershell\modules -ToSession $PSSession -Recurse -Force
}
Foreach ($ModuleName in $RequiredModules.ModuleName){
Copy-Item -Path $env:ProgramFiles\windowspowershell\modules\$ModuleName -Destination $env:ProgramFiles\windowspowershell\modules -ToSession $PSSession -Recurse -Force
}
}
#Enable CredSSP
# Temporarily enable CredSSP delegation to avoid double-hop issue
foreach ($ClusterNodeName in $ClusterNodeNames){
Enable-WSManCredSSP -Role "Client" -DelegateComputer $ClusterNodeName -Force
}
Invoke-Command -ComputerName $ClusterNodeNames -ScriptBlock { Enable-WSManCredSSP Server -Force }
$SecureStringPassword = ConvertTo-SecureString $CredSSPPassword -AsPlainText -Force
$Credentials = New-Object System.Management.Automation.PSCredential ($CredSSPUserName, $SecureStringPassword)
#initialize MOC
Invoke-Command -ComputerName $ClusterNodeNames -Credential $Credentials -Authentication Credssp -ScriptBlock {
Initialize-MocNode
}
#Create volume for MOC if does not exist
if (-not (Get-Volume -FriendlyName $VolumeName -CimSession $ClusterName -ErrorAction SilentlyContinue)) {
New-Volume -FriendlyName $VolumeName -CimSession $ClusterName -Size 1TB -StoragePoolFriendlyName S2D*
}
#prepare arc resource bridge
#Configure MOC
Invoke-Command -ComputerName $ClusterNodeNames[0] -Credential $Credentials -Authentication Credssp -ScriptBlock {
Set-MocConfig -workingDir $using:VolumePath\workingDir -imageDir $using:VolumePath\imageStore -skipHostLimitChecks -cloudConfigLocation $using:VolumePath\cloudStore -catalog aks-hci-stable-catalogs-ext -ring stable -createAutoConfigContainers $false
}
#Install MOC Cloud Agent Service
Invoke-Command -ComputerName $ClusterNodeNames[0] -Credential $Credentials -Authentication Credssp -ScriptBlock {
Install-moc
}
# Disable CredSSP
Disable-WSManCredSSP -Role Client
Invoke-Command -ComputerName $ClusterNodeNames -ScriptBlock { Disable-WSManCredSSP Server }
#endregion
#region Create custom location and install Arc Resource Bridge
#Login to azure
if (!(Get-AzContext)){
Connect-AzAccount -UseDeviceAuthentication
}
#generate variables
#Grab registration info
$RegistrationInfo=Invoke-Command -ComputerName $CLusterName -ScriptBlock {Get-AzureStackHCI}
$AzureResourceUri= $RegistrationInfo.AzureResourceUri
$HCIResourceGroupName=$AzureResourceUri.split("/")[4]
$HCISubscriptionID=$AzureResourceUri.split("/")[2]
#create bridge resource name
$BridgeResourceName=("$($RegistrationInfo.AzureResourceName)-arcbridge").ToLower()
#install Az CLI
#download
Start-BitsTransfer -Source https://aka.ms/installazurecliwindows -Destination $env:userprofile\Downloads\AzureCLI.msi
#install
Start-Process msiexec.exe -Wait -ArgumentList "/I $env:userprofile\Downloads\AzureCLI.msi /quiet"
#add az to enviromental variables so no posh restart is needed
[System.Environment]::SetEnvironmentVariable('PATH',$Env:PATH+';C:\Program Files (x86)\Microsoft SDKs\Azure\CLI2\wbin')
#add Az extensions
az extension add --name customlocation
az extension add --name azurestackhci
az extension add --name arcappliance
az extension add --name k8s-extension
az extension add --name connectedk8s
#register namespaces
#register
$Providers="Microsoft.ExtendedLocation","Microsoft.ResourceConnector"
foreach ($Provider in $Providers){
Register-AzResourceProvider -ProviderNamespace $Provider
}
#wait until resource providers are registered
foreach ($Provider in $Providers){
do {
$Status=Get-AzResourceProvider -ProviderNamespace $Provider
Write-Output "Registration Status - $Provider : $(($status.RegistrationState -match 'Registered').Count)/$($Status.Count)"
Start-Sleep 1
} while (($status.RegistrationState -match "Registered").Count -ne ($Status.Count))
}
#login with device authentication
az login --use-device-code
$allSubscriptions = (az account list | ConvertFrom-Json).ForEach({$_ | Select-Object -Property Name, id, tenantId })
if (($allSubscriptions).Count -gt 1){
$subscription = ($allSubscriptions | Out-GridView -OutputMode Single)
az account set --subscription $subscription.id
}
#create arc appliance
#generate config files
#Enable CredSSP
# Temporarily enable CredSSP delegation to avoid double-hop issue
foreach ($ClusterNodeName in $ClusterNodeNames){
Enable-WSManCredSSP -Role "Client" -DelegateComputer $ClusterNodeName -Force
}
Invoke-Command -ComputerName $ClusterNodeNames -ScriptBlock { Enable-WSManCredSSP Server -Force }
$SecureStringPassword = ConvertTo-SecureString $CredSSPPassword -AsPlainText -Force
$Credentials = New-Object System.Management.Automation.PSCredential ($CredSSPUserName, $SecureStringPassword)
Invoke-Command -ComputerName $ClusterNodeNames[0] -Credential $Credentials -Authentication Credssp -ScriptBlock {
New-ArcHciConfigFiles -subscriptionID $using:HCISubscriptionID -location $using:ArcResourceBridgeLocation -resourceGroup $using:HCIResourceGroupName -resourceName $using:BridgeResourceName -workDirectory "\\$using:ClusterName\ClusterStorage$\$using:VolumeName\workingDir" -controlPlaneIP $using:controlPlaneIP -vipPoolStart $using:controlPlaneIP -vipPoolEnd $using:controlPlaneIP -vswitchName $using:vswitchName #-vLanID $vlanID
}
# Disable CredSSP
Disable-WSManCredSSP -Role Client
Invoke-Command -ComputerName $ClusterNodeNames -ScriptBlock { Disable-WSManCredSSP Server }
#prepare
az arcappliance prepare hci --config-file \\$ClusterName\ClusterStorage$\$VolumeName\workingDir\hci-appliance.yaml
#Create folder for config
New-Item -Path $env:USERPROFILE\.kube -ItemType Directory -ErrorAction Ignore
#deploy control plane and export kube config
az arcappliance deploy hci --config-file \\$ClusterName\ClusterStorage$\$VolumeName\workingDir\hci-appliance.yaml --outfile $env:USERPROFILE\.kube\config
#create connection to Azure (might throw error, dont worry! It's being deployed on background)
az arcappliance create hci --config-file \\$ClusterName\ClusterStorage$\$VolumeName\workingDir\hci-appliance.yaml --kubeconfig $env:USERPROFILE\.kube\config
#wait until appliance is running
do {
$Status=az arcappliance show --only-show-errors --resource-group $HCIResourceGroupName --name $BridgeResourceName | ConvertFrom-Json
Write-Host -NoNewline -Object "."
Start-Sleep 2
} until ($status.status -match "Running")
#verify if appliance is running
az arcappliance show --resource-group $HCIResourceGroupName --name $BridgeResourceName | ConvertFrom-Json
#Add hci-vmoperator extension
#create
az k8s-extension create --cluster-type appliances --cluster-name $BridgeResourceName --resource-group $HCIResourceGroupName --name hci-vmoperator --extension-type Microsoft.AZStackHCI.Operator --scope cluster --release-namespace helm-operator2 --configuration-settings Microsoft.CustomLocation.ServiceAccount=hci-vmoperator --config-protected-file \\$ClusterName\ClusterStorage$\$VolumeName\workingDir\hci-config.json --configuration-settings HCIClusterID=$AzureResourceUri --auto-upgrade true
#validate
az k8s-extension show --cluster-type appliances --cluster-name $BridgeResourceName --resource-group $HCIResourceGroupName --name hci-vmoperator
#Create custom location (has to be created after arcappliance deployment)
az customlocation create --resource-group $HCIResourceGroupName --name $CustomLocationName --cluster-extension-ids "/subscriptions/$HCISubscriptionID/resourceGroups/$HCIResourceGroupName/providers/Microsoft.ResourceConnector/appliances/$BridgeResourceName/providers/Microsoft.KubernetesConfiguration/extensions/hci-vmoperator" --namespace $CustomLocationNameSpace --host-resource-id "/subscriptions/$HCISubscriptionID/resourceGroups/$HCIResourceGroupName/providers/Microsoft.ResourceConnector/appliances/$BridgeResourceName" --location $ArcResourceBridgeLocation
<# Or with PowerShell
#install Az.CustomLocation module
if (!(Get-InstalledModule -Name az.CustomLocation -ErrorAction Ignore)){
Install-Module -Name Az.CustomLocation -Force
}
New-AzCustomLocation -ResourceGroupName $ResourceGroupName -Name $CustomLocationName -ClusterExtensionID "/subscriptions/$SubscriptionID/resourceGroups/$ResourceGroupName/providers/Microsoft.ResourceConnector/appliances/$BridgeResourceName/providers/Microsoft.KubernetesConfiguration/extensions/hci-vmoperator" -NameSpace hci-vmoperator -HostResourceID "/subscriptions/$SubscriptionID/resourceGroups/$ResourceGroupName/providers/Microsoft.ResourceConnector/appliances/$BridgeResourceName" -Location $ArcResourceBridgeLocation
#>
#endregion
#region create virtual network for arcVMs
#Grab registration info
$RegistrationInfo=Invoke-Command -ComputerName $CLusterName -ScriptBlock {Get-AzureStackHCI}
$AzureResourceUri= $RegistrationInfo.AzureResourceUri
$HCIResourceGroupName=$AzureResourceUri.split("/")[4]
$HCISubscriptionID=$AzureResourceUri.split("/")[2]
#create network
az azurestackhci virtualnetwork create --subscription $HCISubscriptionID --resource-group $HCIResourceGroupName --extended-location name="/subscriptions/$HCISubscriptionID/resourceGroups/$HCIResourceGroupName/providers/Microsoft.ExtendedLocation/customLocations/$CustomLocationName" type="CustomLocation" --location $ArcResourceBridgeLocation --network-type "Transparent" --name $vnetName
#endregion
#region Copy kube config to nodes to have it available there
$Sessions=New-PSSession -ComputerName $ClusterNodeNames
#copy kube to cluster nodes
Foreach ($Session in $Sessions){
Copy-Item -Path "$env:userprofile\.kube" -Destination $env:userprofile -ToSession $Session -Recurse -Force
}
$Sessions | Remove-PSSession
#endregion
#region add aks hybrid extension to the custom location
#https://learn.microsoft.com/en-us/azure/aks/hybrid/deploy-aks-service-hci?tabs=powershell#step-2-install-the-aks-hybrid-extension-on-the-azure-arc-resource-bridge
#add extension
$aksHybridExtnName = "aks-hybrid-extn"
az k8s-extension create --resource-group $HCIResourceGroupName --cluster-name $BridgeResourceName --cluster-type appliances --name $aksHybridExtnName --extension-type Microsoft.HybridAKSOperator --config Microsoft.CustomLocation.ServiceAccount=$CustomLocationNameSpace
#Patch your existing custom location to support AKS hybrid alongside Arc VMs
$ArcResourceBridgeId=az arcappliance show -g $HCIResourceGroupName --name $BridgeResourceName --query id -o tsv
$VMClusterExtensionResourceId=az k8s-extension list -g $HCIResourceGroupName --cluster-name $BridgeResourceName --cluster-type appliances --query "[?extensionType == ``microsoft.azstackhci.operator``].id" -o tsv
$AKSClusterExtensionResourceId=az k8s-extension show -g $HCIResourceGroupName --cluster-name $BridgeResourceName --cluster-type appliances --name $aksHybridExtnName --query id -o tsv
az customlocation patch --name $customLocationName --namespace $CustomLocationNameSpace --host-resource-id $ArcResourceBridgeId --cluster-extension-ids $VMClusterExtensionResourceId $AKSClusterExtensionResourceId --resource-group $HCIResourceGroupName
#check
az customlocation show --name $customLocationName --resource-group $HCIResourceGroupName --query "clusterExtensionIds" -o tsv
#endregion
#region create virtual network for AKS
#https://learn.microsoft.com/en-us/azure/aks/hybrid/create-aks-hybrid-preview-networks?tabs=dhcp%2Clinux-vhd
#make sure latest module is installed (note required version)
Start-Process -Wait -FilePath PowerShell -ArgumentList {
Install-Module -Name MOC -Repository PSGallery -Force -AcceptLicense
Install-Module -Name ArcHci -Force -Confirm:$false -SkipPublisherCheck -AcceptLicense -RequiredVersion 0.2.24
}
#distribute new module to cluster nodes
$ModuleNames="ArcHci"
$PSSessions=New-PSSession -ComputerName $ClusterNodeNames
Foreach ($PSSession in $PSSessions){
Foreach ($ModuleName in $ModuleNames){
Copy-Item -Path $env:ProgramFiles\windowspowershell\modules\$ModuleName -Destination $env:ProgramFiles\windowspowershell\modules -ToSession $PSSession -Recurse -Force
}
Foreach ($ModuleName in $RequiredModules.ModuleName){
Copy-Item -Path $env:ProgramFiles\windowspowershell\modules\$ModuleName -Destination $env:ProgramFiles\windowspowershell\modules -ToSession $PSSession -Recurse -Force
}
}
#since there was a subnet configured for AKS (note the labconfig), let's exclude VIP pool from dhcp
#make sure dhcp tools are installed
install-windowsfeature -name RSAT-DHCP
#exclude
Add-DhcpServerv4ExclusionRange -StartRange $VIPPoolStart -EndRange $VIPPoolEnd -ScopeId $DHCPScopeID -ComputerName $DHCPServer
#
Invoke-Command -ComputerName $ClusterName -ScriptBlock {
#dhcp does not work as it keeps asking for gw, dns servers...
#New-ArcHciVirtualNetwork -name AKSvnet -vswitchname $using:vswitchname -vippoolstart $using:vipPoolStart -vippoolend $using:vipPoolEnd -vlanid $using:vlanid
#without dhcp
New-ArcHciVirtualNetwork -name $using:AKSVnetName -vswitchname $using:vswitchname -vippoolstart $using:vipPoolStart -vippoolend $using:vipPoolEnd -vlanid $using:vlanid -ipAddressPrefix $Using:ipaddressprefix -gateway $using:gateway -dnsservers $using:DNSServers -k8sNodeIpPoolStart $using:k8sNodeIpPoolStart -k8sNodeIpPoolEnd $using:k8sNodeIpPoolend
}
#Connect your on-premises AKS hybrid network to Azure
az extension add --name hybridaks
#register namespace provider
$Providers="Microsoft.HybridContainerService"
foreach ($Provider in $Providers){
Register-AzResourceProvider -ProviderNamespace $Provider
}
#wait until resource providers are registered
foreach ($Provider in $Providers){
do {
$Status=Get-AzResourceProvider -ProviderNamespace $Provider
Write-Output "Registration Status - $Provider : $(($status.RegistrationState -match 'Registered').Count)/$($Status.Count)"
Start-Sleep 1
} while (($status.RegistrationState -match "Registered").Count -ne ($Status.Count))
}
#add network
az hybridaks vnet create -n $AKSVnetName -g $HCIResourceGroupName --custom-location $customLocationName --moc-vnet-name $AKSVnetName
#endregion
#region add image for aks
Invoke-Command -ComputerName $ClusterName -ScriptBlock {
Add-ArcHciK8sGalleryImage -k8sVersion 1.22.11 -version 1.0.16.10113
}
#endregion

Просмотреть файл

@ -178,7 +178,7 @@ function Get-WindowsBuildNumber {
$downloadurl = $webcontent.BaseResponse.ResponseUri.AbsoluteUri.Substring(0,$webcontent.BaseResponse.ResponseUri.AbsoluteUri.LastIndexOf('/'))+($webcontent.Links | where-object { $_.'data-url' -match '/Diskspd.*zip$' }|Select-Object -ExpandProperty "data-url")
}
#>
$downloadurl="https://github.com/microsoft/diskspd/releases/download/v2.0.21a/DiskSpd.zip"
$downloadurl="https://github.com/microsoft/diskspd/releases/download/v2.1/DiskSpd.ZIP"
Invoke-WebRequest -Uri $downloadurl -OutFile "$PSScriptRoot\Temp\ToolsVHD\DiskSpd\diskspd.zip"
}catch{
WriteError "`t Failed to download Diskspd!"

Просмотреть файл

@ -354,13 +354,13 @@ If (-not $isAdmin) {
Kind = "Full"
Edition="4"
VHDName="Win2016_G2.vhdx"
Size=60GB
Size=127GB
}
$ServerVHDs += @{
Kind = "Core"
Edition="3"
VHDName="Win2016Core_G2.vhdx"
Size=30GB
Size=127GB
}
<# Removed since it does not work with newer than 14393.2724
$ServerVHDs += @{
@ -376,13 +376,13 @@ If (-not $isAdmin) {
Kind = "Full"
Edition="4"
VHDName="Win2019_G2.vhdx"
Size=60GB
Size=127GB
}
$ServerVHDs += @{
Kind = "Core"
Edition="3"
VHDName="Win2019Core_G2.vhdx"
Size=30GB
Size=127GB
}
}elseif ($BuildNumber -eq 20348){
#Windows Server 2022
@ -390,20 +390,20 @@ If (-not $isAdmin) {
Kind = "Full"
Edition="4"
VHDName="Win2022_G2.vhdx"
Size=60GB
Size=127GB
}
$ServerVHDs += @{
Kind = "Core"
Edition="3"
VHDName="Win2022Core_G2.vhdx"
Size=30GB
Size=127GB
}
}elseif ($BuildNumber -gt 20348 -and $SAC){
$ServerVHDs += @{
Kind = "Core"
Edition="2"
VHDName="WinSrvInsiderCore_$BuildNumber.vhdx"
Size=30GB
Size=127GB
}
#DCEdition fix
if ($LabConfig.DCEdition -gt 2){
@ -415,13 +415,13 @@ If (-not $isAdmin) {
Kind = "Full"
Edition="4"
VHDName="WinSrvInsider_$BuildNumber.vhdx"
Size=60GB
Size=127GB
}
$ServerVHDs += @{
Kind = "Core"
Edition="3"
VHDName="WinSrvInsiderCore_$BuildNumber.vhdx"
Size=30GB
Size=127GB
}
}else{
$ISOServer | Dismount-DiskImage

Просмотреть файл

@ -168,11 +168,14 @@ If (-not $isAdmin) {
20348 {
"AzSHCI21H2_G2.vhdx"
}
22621 {
20349 {
"AzSHCI22H2_G2.vhdx"
}
25398 {
"AzSHCI23H2_G2.vhdx"
}
}
if ($BuildNumber -GT 20348){
if ($BuildNumber -GT 25398){
$tempvhdname="AzSHCIInsider_$BuildNumber.vhdx"
}
}elseif (($Edition -like "*Server*Core*") -or ($Edition -like "Windows Server * Datacenter") -or ($Edition -like "Windows Server * Standard")){
@ -321,9 +324,9 @@ If (-not $isAdmin) {
if(!$vhdname){$vhdname=$tempvhdname}
#ask for size
[int64]$size=(Read-Host -Prompt "Please type size of the Image in GB. If nothing specified, 60 is used")
[int64]$size=(Read-Host -Prompt "Please type size of the Image in GB. If nothing specified, 127 is used")
$size=$size*1GB
if (!$size){$size=60GB}
if (!$size){$size=127GB}
#Create VHD
if ($nanoserver -eq "y"){