connect.ps1 (169 lines of code) (raw):
param(
$userName,
$password,
$authType,
$ip, $port,
$subscriptionId, $resourceGroupName, $region, $tenant, $servicePrincipalId, $servicePrincipalSecret, $expandC
)
$script:ErrorActionPreference = 'Stop'
echo "Start to connect Arc server!"
$count = 0
$retryCount = 3
if ($authType -eq "CredSSP") {
try {
echo "set trusted hosts"
Set-Item wsman:localhost\client\trustedhosts -value * -Force
echo "enable client CredSSP"
Enable-WSManCredSSP -Role Client -DelegateComputer * -Force
echo "Allow fresh credentials"
$key = 'hklm:\SOFTWARE\Policies\Microsoft\Windows\CredentialsDelegation'
if (!(Test-Path $key)) {
md $key
}
New-ItemProperty -Path $key -Name AllowFreshCredentials -Value 1 -PropertyType Dword -Force
$allowFreshCredentialsKey = Join-Path $key 'AllowFreshCredentials'
if (!(Test-Path $allowFreshCredentialsKey)) {
md $allowFreshCredentialsKey
}
if (!(Get-ItemProperty -Path $allowFreshCredentialsKey -Name 'AzureArcIaCAutomation' -ErrorAction SilentlyContinue)) {
New-ItemProperty -Path $allowFreshCredentialsKey -Name 'AzureArcIaCAutomation' -Value 'WSMAN/*' -PropertyType String -Force
}
echo "Allow fresh credentials when NTLM only"
New-ItemProperty -Path $key -Name AllowFreshCredentialsWhenNTLMOnly -Value 1 -PropertyType Dword -Force
$allowFreshCredentialsWhenNTLMOnlyKey = Join-Path $key 'AllowFreshCredentialsWhenNTLMOnly'
if (!(Test-Path $allowFreshCredentialsWhenNTLMOnlyKey)) {
md $allowFreshCredentialsWhenNTLMOnlyKey
}
if (!(Get-ItemProperty -Path $allowFreshCredentialsWhenNTLMOnlyKey -Name 1 -ErrorAction SilentlyContinue)) {
New-ItemProperty -Path $allowFreshCredentialsWhenNTLMOnlyKey -Name 1 -Value 'WSMAN/*' -PropertyType String -Force
}
}
catch {
echo "Enable-WSManCredSSP failed: $_"
}
}
for ($count = 0; $count -lt $retryCount; $count++) {
try {
$secpasswd = ConvertTo-SecureString $password -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential -ArgumentList ".\$username", $secpasswd
$session = New-PSSession -ComputerName $ip -Port $port -Authentication $authType -Credential $cred
Invoke-Command -Session $session -ScriptBlock {
Param ($subscriptionId, $resourceGroupName, $region, $tenant, $servicePrincipalId, $servicePrincipalSecret)
$script:ErrorActionPreference = 'Stop'
function Install-ModuleIfMissing {
param(
[Parameter(Mandatory = $true)]
[string]$Name,
[string]$Repository = 'PSGallery',
[switch]$Force,
[switch]$AllowClobber
)
$script:ErrorActionPreference = 'Stop'
$module = Get-Module -Name $Name -ListAvailable
if (!$module) {
Write-Host "Installing module $Name"
Install-Module -Name $Name -Repository $Repository -Force:$Force -AllowClobber:$AllowClobber
}
}
if ($expandC) {
# Expand C volume as much as possible
$drive_letter = "C"
$size = (Get-PartitionSupportedSize -DriveLetter $drive_letter)
if ($size.SizeMax -gt (Get-Partition -DriveLetter $drive_letter).Size) {
echo "Resizing volume"
Resize-Partition -DriveLetter $drive_letter -Size $size.SizeMax
}
}
echo "Validate BITS is working"
$job = Start-BitsTransfer -Source https://aka.ms -Destination $env:TEMP -TransferType Download -Asynchronous
$bitsRetry = 0
while ($job.JobState -ne "Transferred" -and $bitsRetry -lt 30) {
if ($job.JobState -eq "TransientError") {
throw "BITS transfer failed"
}
sleep 6
$bitsRetry++
}
if ($bitsRetry -ge 30) {
throw "BITS transfer failed after 3 minutes. Job state: $job.JobState"
}
echo "Install modules"
Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force -Confirm:$false
Install-ModuleIfMissing -Name Az -Repository PSGallery -Force
Install-ModuleIfMissing Az.Accounts -Force -AllowClobber
Install-ModuleIfMissing Az.ConnectedMachine -Force -AllowClobber
Install-ModuleIfMissing Az.Resources -Force -AllowClobber
echo "login to Azure"
$creds = [System.Management.Automation.PSCredential]::new($servicePrincipalId, (ConvertTo-SecureString $servicePrincipalSecret -AsPlainText -Force))
Connect-AzAccount -Subscription $subscriptionId -Tenant $tenant -Credential $creds -ServicePrincipal
$tenantId = (Get-AzContext).Tenant.Id
$token = (Get-AzAccessToken).Token
$machineName = [System.Net.Dns]::GetHostName()
$correlationID = New-Guid
$azcmagentPath = "$env:ProgramW6432\AzureConnectedMachineAgent\azcmagent.exe"
if (!(Test-Path $azcmagentPath)) {
wget -Uri "https://aka.ms/AzureConnectedMachineAgent" -OutFile "$env:TEMP\AzureConnectedMachineAgent.msi"
msiexec /i "$env:TEMP\AzureConnectedMachineAgent.msi" /l*v "$env:TEMP\AzureConnectedMachineAgentInstall.log" /qn
}
& "$azcmagentPath" connect --resource-group "$resourceGroupName" --resource-name "$machineName" --tenant-id "$tenantId" --location "$region" --subscription-id "$subscriptionId" --cloud "AzureCloud" --correlation-id "$correlationID" --access-token "$token";
$exitCode = $LASTEXITCODE
if ($exitCode -eq 0) {
echo "Arc server connected!"
}
else {
throw "Arc server connection failed"
}
echo "PUT edge device resource to install mandatory extensions"
$uri = "https://management.azure.com/subscriptions/$subscriptionId/resourceGroups/$resourceGroupName/providers/Microsoft.HybridCompute/machines/$machineName/providers/Microsoft.AzureStackHCI/edgeDevices/default?api-version=2024-04-01"
$body = @{
"kind" = "HCI";
"properties" = @{};
}
$headers = @{
"Authorization" = "Bearer $token";
}
Invoke-RestMethod -Uri $uri -Method Put -Headers $headers -Body ($body | ConvertTo-Json) -ContentType "application/json"
echo "Waiting for Edge device resource to be ready"
sleep 600
$waitCount = 0
$waitLimit = 60
$ready = $false
while (!$ready -and $waitCount -lt $waitLimit) {
Connect-AzAccount -Subscription $subscriptionId -Tenant $tenant -Credential $creds -ServicePrincipal | Out-Null
$token = (Get-AzAccessToken).Token
$headers = @{
"Authorization" = "Bearer $token";
}
try {
$resp = Invoke-RestMethod -Uri $uri -Method Get -Headers $headers
if ($resp.properties.provisioningState -eq "Succeeded") {
$ready = $true
}
} catch {
echo "Failed to get Edge device resource: $_"
} finally {
echo "Waiting for Edge device resource to be ready"
$waitCount++
Start-Sleep -Seconds 30
}
}
if ($waitCount -ge $waitLimit) {
throw "Edge device resource is not ready after 30 minutes."
}
} -ArgumentList $subscriptionId, $resourceGroupName, $region, $tenant, $servicePrincipalId, $servicePrincipalSecret
echo "Arc server connected and all mandatory extensions are ready!"
break
}
catch {
echo "Error in retry ${count}:`n$_"
}
finally {
if ($session) {
Remove-PSSession -Session $session
}
}
}
if ($count -ge $retryCount) {
echo "Failed to connect Arc server after $retryCount retries."
throw "Arc server connection failed"
}