framework/Resources/Scripts/add_servers.ps1


Param(
    [Parameter(Mandatory)]
    $VmCounts,
    [Parameter(Mandatory)]
    $ResourceName,
    [Parameter(Mandatory)]
    $Password,
    [Parameter(Mandatory)]
    [string]$LicenseDuration,
    [string]$ArmTemplatePath = ".\AddServer.json",
    [int]$Port = 8250,
    [string]$UserProvidedKey,

    [string]$ScriptsFolderPath = ".\Resources\Scripts"
)

. "$ScriptsFolderPath\dashboard_common.ps1"

$vms = [System.Collections.ArrayList]@()
$newVmsList = [System.Collections.ArrayList]@()
$maxServerCount = 0
$userName = ""
$resource = $null
$resourceGroupName = $null

function Enable-SystemAssignedIdentity {
    param(
        [Parameter(Mandatory)][string]$VmName
    )

    Write-Host "$((Get-Date).ToString()) - Enabling system-assigned managed identity on $VmName"
    $vm = Get-AzVM -ResourceGroupName $resourceGroupName -Name $VmName -ErrorAction Stop 
    Update-AzVM -ResourceGroupName $resourceGroupName -VM $vm -IdentityType SystemAssigned -ErrorAction Stop 
}

function GetUploadedVms {
    param(
        [string]$ResourceGroup
    )
    $vms = @(Get-AzVM -ErrorAction Stop -ResourceGroupName $ResourceGroup | Where-Object { $_.Tags.ContainsKey("ServerType") -and $_.Tags["ServerType"] -eq "NCache" } | ForEach-Object {
            $nicId = $_.NetworkProfile.NetworkInterfaces[0].Id
            $nicName = ($nicId -split "/")[-1]
            $nic = Get-AzNetworkInterface -ResourceGroupName $resourceGroupName -Name $nicName -ErrorAction Stop 
            $privateIp = $nic.IpConfigurations[0].PrivateIpAddress
            [PSCustomObject]@{
                Name               = $_.Name
                Location           = $_.Location
                VmSize             = $_.HardwareProfile.VmSize
                OsType             = $_.StorageProfile.OsDisk.OsType
                Zone               = ($_.Zones[0])
                Publisher          = $_.StorageProfile.ImageReference.Publisher
                Offer              = $_.StorageProfile.ImageReference.Offer
                Sku                = $_.StorageProfile.ImageReference.Sku
                Version            = $_.StorageProfile.ImageReference.Version
                NIC                = $_.NetworkProfile.NetworkInterfaces.id
                StorageAccountType = $_.StorageProfile.OsDisk.ManagedDisk.StorageAccountType
                Disk               = $_.StorageProfile.OsDisk.Name
                Tags               = $_.Tags
                PrivateIp          = $privateIp
            }
        }  )

    return , $vms
}

function RemoveResources {
    param(
        [string]$VmName,
        [string]$DiskName,
        [string]$NetworkInterfaceName,
        [string]$PublicIpName,
        [string]$ResourceGroup,
        [bool]$UseForce
    )
    if ($UseForce) {
        Remove-AzVM -ResourceGroupName $ResourceGroup -Name $VmName -Force -ErrorAction SilentlyContinue
        Remove-AzDisk -ResourceGroupName $ResourceGroup -DiskName $DiskName -Force -ErrorAction SilentlyContinue
        Remove-AzNetworkInterface -Name $NetworkInterfaceName -ResourceGroupName $ResourceGroup -Force -ErrorAction SilentlyContinue
        Remove-AzPublicIpAddress -Name $PublicIpName -ResourceGroupName $ResourceGroup -Force -ErrorAction SilentlyContinue
    }
    else {
        Remove-AzVM -ResourceGroupName $ResourceGroup -Name $VmName -ErrorAction SilentlyContinue
        Remove-AzDisk -ResourceGroupName $ResourceGroup -DiskName $DiskName -ErrorAction SilentlyContinue
        Remove-AzNetworkInterface -Name $NetworkInterfaceName -ResourceGroupName $ResourceGroup -ErrorAction SilentlyContinue
        Remove-AzPublicIpAddress -Name $PublicIpName -ResourceGroupName $ResourceGroup -ErrorAction SilentlyContinue
    }

}


function CreateStartupCommand {
    param(
        [string]$Key,
        [string]$firstName,
        [string]$lastName,
        [string]$email,
        [string]$company,
        [string]$environment,
        [bool]$evalFlag,
        $OS
    )
    $PrivateIps = @()
    $evalFlagCasted = [int]$evalFlag 
    $cloudType = "azs"
    $StartupScriptUrl = "https://ncachedeployments.s3.us-east-1.amazonaws.com/5.3.6-tools/StartupScriptLinux.sh"
    $paramStr = "-InstallType $cloudType -Key $Key -FirstName $FirstName -LastName $LastName -Email $Email -Environment $ResourceName -IsEvalKey $evalFlagCasted "

    if (-not $evalFlag) {
        $paramStr += "-LicenseDuration $LicenseDuration "
    }

    if (![string]::IsNullOrWhiteSpace($company)) {
        $paramStr += "-Company $company"
    }

    if ($OS -eq "Windows") {
        $paramStr += " -Username $script:userName -Password $Password "
        return ("Invoke-WebRequest -Uri https://ncachedeployments.s3.us-east-1.amazonaws.com/5.3.6-tools/StartupScriptWin_v6.ps1 -OutFile C:/StartupScriptWin_v6.ps1;Unblock-File -Path C:/StartupScriptWin_v6.ps1;
        C:/StartupScriptWin_v6.ps1 $paramStr"
)
    }
    return ("#!/bin/sh
sleep 30; wget -O /tmp/StartupScriptLinux.sh $StartupScriptUrl; chmod +x /tmp/StartupScriptLinux.sh; /tmp/StartupScriptLinux.sh $paramStr"
 -replace "`r`n", "`n")
}
 
 

function EncryptStartupCommand {
    param(
        [string]$StartupCommand
    )
    $bytes = [System.Text.Encoding]::UTF8.GetBytes($StartupCommand)
    $encoded = [Convert]::ToBase64String($bytes)
    return $encoded
}

function EnableCacheServerPublicIp {
    param(
        [string]$RuleType
    )
    if ($RuleType -eq "Data" -or $RuleType -eq "All") {
        return $true
    }
    return $false
}

function InvokeCommandOnServerWindows {

    $LogFile = "C:\Temp\InstallLog.txt"
    $evalKey = $resource.Tags['EvaluationKey']
    $firstName = $resource.Tags['FirstName']
    $lastName = $resource.Tags['LastName']
    $company = $resource.Tags['Company']
    $email = $resource.Tags['Email']
    $setupUrl = $resource.Tags['SetupUrl']
    $licenseKey = $resource.Tags["LicenseKey"]
    $licenseDuration = $resource.Tags["LicenseDuration"]
    $ruleType = $resource.Tags["RuleType"]
    $enableCacheServerIp = EnableCacheServerPublicIp -RuleType $ruleType

    if (![string]::IsNullOrWhiteSpace($UserProvidedKey)) {
        $licenseKey = $UserProvidedKey
    }

    $script = @"
New-Item -ItemType Directory -Force -Path "C:\Temp" | Out-Null
wget "https://ncachedeployments.s3.us-east-1.amazonaws.com/5.3.6-tools/InstallScript_Win_Server.ps1" -OutFile "C:\Temp\InstallScript_Win_Server.ps1"
C:\Temp\InstallScript_Win_Server.ps1 -Key $evalKey -UserName $script:userName -Company $company -FirstName $FirstName -LastName $LastName -Password $Password -Email $Email -SetupUrl $SetupUrl -LicenseKey '$licenseKey' -EnableCacheServerPublicIp `$$enableCacheServerIp -Environment '$ResourceName' -LicenseDuration '$licenseDuration'
"@


    foreach ($server in $newVmsList) {
        Write-Host "$((Get-Date).ToString()) - Downloading and Installing NCache on $server"
    }

    $jobs = foreach ($server in $newVmsList) {
        Start-Job -ScriptBlock {
            param($rg, $vm, $script)
            Invoke-AzVMRunCommand -ResourceGroupName $rg -VMName $vm -CommandId 'RunPowerShellScript' -ScriptString $script
            Write-Host "$((Get-Date).ToString()) - Installed NCache on server $server"
        } -ArgumentList $resourceGroupName, $server, $script
    }

    
    # while (@($jobs | Where-Object { $_.State -eq "Running" }).Count -gt 0) {
    # BlastFromThePast;
    # Start-Sleep -Milliseconds 100
    # }
    # BlastFromThePast -Finished;
    $dots = ""
    while (@($jobs | Where-Object { $_.State -eq "Running" }).Count -gt 0) {
        $dots += "."
        Write-Host -NoNewline "`r$dots"
        Start-Sleep -Seconds 5
        $jobs = $jobs | Get-Job
    }

    # Clear dots line
    $clearLine = " " * $dots.Length
    Write-Host -NoNewline "`r$clearLine`r"
    $jobs | Wait-Job
    $jobs | Receive-Job

}


function BlastFromThePast([switch]$EndOfLine, [switch]$Finished) {
    $EscChar = "`r"
    if ($EndOfLine) { $EscChar = "`b" }
    if (!$tickcounter) { Set-Variable -Name "tickcounter" -Scope global -Value 0 -Force -Option AllScope }
    if (!$tickoption) { Set-Variable -Name "tickoption" -Scope global -Value 0 -Force -Option AllScope }
    $chance = Get-Random -Minimum 1 -Maximum 10
    if ($chance -eq 5) { if ($tickoption -eq 1) { $tickoption = 0 }else { $tickoption = 1 } }
    switch ($tickoption) {
        0 {
            switch ($tickcounter) {
                0 { Write-Host "$EscChar|" -NoNewline }
                1 { Write-Host "$EscChar/" -NoNewline }
                2 { Write-Host "$EscChar-" -NoNewline }
                3 { Write-Host "$EscChar\" -NoNewline }
            }
            break;
        }
        1 {
            switch ($tickcounter) {
                0 { Write-Host "$EscChar|" -NoNewline }
                1 { Write-Host "$EscChar\" -NoNewline }
                2 { Write-Host "$EscChar-" -NoNewline }
                3 { Write-Host "$EscChar/" -NoNewline }
            }
            break;
        }
    }
    if ($tickcounter -eq 3) { $tickcounter = 0 }
    else { $tickcounter++ }
}

function InvokeCommandOnServerLinux {

    foreach ($server in $newVmsList) {
        Write-Host "$((Get-Date).ToString()) - Downloading and Installing NCache on $server"
    }

    $command = CreateScriptBlockLinux
    $jobs = foreach ($server in $newVmsList) {
        Start-Job -ScriptBlock {
            param($rg, $vm, $script)
            Invoke-AzVMRunCommand -ResourceGroupName $rg -VMName $vm -CommandId 'RunShellScript' -ScriptString $script
            Write-Host "$((Get-Date).ToString()) - Installed NCache on server $vm" 
        } -ArgumentList $resourceGroupName, $server, $command
    }

    while (@($jobs | Where-Object { $_.State -eq "Running" }).Count -gt 0) {
        BlastFromThePast -Finished; 
        Start-Sleep -Milliseconds 100
    }

    $jobs | Wait-Job
    $jobs | Receive-Job
}


function CreateScriptBlockLinux {
    $evalKey = $resource.Tags['EvaluationKey']
    $firstName = $resource.Tags['FirstName']
    $lastName = $resource.Tags['LastName']
    $company = $resource.Tags['Company']
    $email = $resource.Tags['Email']
    $setupUrl = $resource.Tags['SetupUrl']
    $licenseKey = $resource.Tags["LicenseKey"]
    $licenseDuration = $resource.Tags["LicenseDuration"]

    if (![string]::IsNullOrWhiteSpace($UserProvidedKey)) {
        $licenseKey = $UserProvidedKey
    }

    $ruleType = $resource.Tags["RuleType"]
    $enableCacheServerIp = EnableCacheServerPublicIp -RuleType $ruleType
    return "sudo wget -O /tmp/InstallScript_Lin_Server.sh https://ncachedeployments.s3.us-east-1.amazonaws.com/5.3.6-tools/InstallScript_Lin_Server.sh;
    chmod +x /tmp/InstallScript_Lin_Server.sh;
    /tmp/InstallScript_Lin_Server.sh -FirstName $FirstName -LastName $LastName -Email $Email -Key $evalKey -Company $company -SetupUrl $SetupUrl -PrivateIps '' -LicenseKey '$licenseKey' -Environment '$ResourceName' -EnableCacheServerPublicIp $enableCacheServerIp -LicenseDuration '$LicenseDuration'"

}

function DownloadAndInstallNCache {
    param(
        [Parameter(Mandatory)][string]$OS
    )

    if ($OS -eq "Windows") {
        InvokeCommandOnServerWindows
    }
    else {
        InvokeCommandOnServerLinux
    }
}




function CreateScript {
    $firstName = $resource.Tags['FirstName']
    $lastName = $resource.Tags['LastName']
    $email = $resource.Tags['Email']
    $company = $resource.Tags['Company']
    $licenseKey = $resource.Tags['LicenseKey']
    $script:userName = $resource.Tags['UserName']
    $isEvalKey = $resource.Tags["IsEvalKey"]
    $licenseDuration = $resource.Tags["LicenseDuration"]
    $os = $resource.Tags["OsType"]
    $IsEval = [System.Convert]::ToBoolean($isEvalKey)
    $scriptCode = CreateStartupCommand -key $LicenseKey -firstName $FirstName -lastname $LastName -email $Email -company $company -environment $ResourceName -evalFlag $IsEval -OS $os
    $encodedScript = EncryptStartupCommand -StartupCommand $scriptCode
    return $encodedScript
}




function ExtractVmData {
    return [PSCustomObject]@{
        Location           = $resource.Tags['Location']
        VmSize             = $resource.Tags['VmSize']
        Zone               = $resource.Tags['Zone']
        Publisher          = $resource.Tags['Publisher']
        Offer              = $resource.Tags['Offer']
        Sku                = $resource.Tags['Sku']
        Version            = $resource.Tags['Version']
        StorageAccountType = $resource.Tags['StorageAccountType']
        OsType             = $resource.Tags['OsType']
        CreatePublicIp     = $resource.Tags["CreatePublicIp"]
        ImageVersion       = $resource.Tags["ImageVersion"]
        UseNCacheImage     = [System.Convert]::ToBoolean($resource.Tags["UseNCacheImage"])
    }
}

function CreatePublicIp {
    param(
        [string]$MachineName
    )
    return "NC-PUBLIC_IP-$($ResourceName)-$($MachineName)"
}
function ExtractAndCreateNIC() {
    param(
        [string]$MachineName
    )
    return "NC-NIC-$($ResourceName)-$($MachineName)"
}

function CreateNewServersList {
    for ($i = 1; $i -le $VmCounts; $i++) {
        $newVmsList.Add("NC-Server-$($maxServerCount+$i)") | Out-Null
    }
}

function FindMaxServerCount {
    for ($i = 0; $i -lt $($vms | Measure-Object).Count; $i++) {
        $currentVmCount = $vms[$i].Name -split '-'
        if ([int]$currentVmCount[2] -gt $maxServerCount) {
            $maxServerCount = [int]$currentVmCount[2]
        }
    }
    return $maxServerCount
}



function PerformRollback {
    if ($resourceGroupName) {
        $uploadedVms = GetUploadedVms -ResourceGroup $nc_resource_group

        $disks = Get-AzDisk -ResourceGroupName $nc_resource_group | Select-Object -ExpandProperty Name

        for ($i = 0 ; $i -lt $newVmsList.Count; $i++) {
            for ($j = 0; $j -lt $uploadedVms.Count; $j++) {
                if ($newVmsList[$i] -ne $uploadedVms[$j].Name ) {
                    $matchingDisks = $disks | Where-Object { $_ -like "*$($newVmsList[$i])*" }
                    if (  $null -ne $matchingDisks -and $matchingDisks -ne "") {
                        $publicIpName = CreatePublicIp -MachineName $newVmsList[$i]
                        $nicName = ExtractAndCreateNIC -MachineName $newVmsList[$i] 
                        RemoveResources -VmName $newVmsList[$i] -DiskName $matchingDisks -NetworkInterfaceName $nicName -PublicIpName $publicIpName -ResourceGroup $nc_resource_group -UseForce $true 
                    }
                }
                break;
            }
        }
    }
}

function CheckQuota {
    param(
        [string]$Location,
        [string]$VmSizeName
    )
    

    (Get-AzComputeResourceSku -Location $Location |
    Where-Object { $_.ResourceType -eq "virtualMachines" -and $_.Name -eq $VmSizeName }).Capabilities |
    Where-Object { $_.Name -eq "vCPUs" } |
    Select-Object -ExpandProperty Value

    $sku = Get-AzComputeResourceSku -Location $Location `
    | Where-Object { $_.ResourceType -eq "virtualMachines" -and $_.Name -eq $VmSizeName }

    $family = $sku.Family
    $vcpus = ($sku.Capabilities | Where-Object { $_.Name -eq "vCPUs" }).Value

    $info = [PSCustomObject]@{
        Name   = $sku.Name
        Family = $family
        vCPUs  = $vcpus
    }
    $Usage = Get-AzVMUsage -Location $Location | Where-Object { $_.Name.Value -eq $family }

    ValidateQuota -currentQuota $($Usage.CurrentValue) -limitQuota $($Usage.Limit) -vCpus $vcpus
}

function ValidateQuota() {
    param(
        [int]$currentQuota,
        [int]$limitQuota,
        [int]$vCpus
    )
    $myQuota = $VmCounts * $vCpus
    $total = $myQuota + $currentQuota
    if ($total -gt $limitQuota) {
        throw "Quota limit exceeded"
    }
}

function ShowDeployedEvs {


    $vms = Get-AzVM -ResourceGroupName $resourceGroupName -Status -ErrorAction Stop 

    $results = foreach ($vm in $vms) {
        $nicId = $vm.NetworkProfile.NetworkInterfaces[0].Id
        $nicName = ($nicId -split '/')[8]
        $nic = Get-AzNetworkInterface -ResourceGroupName $resourceGroupName -Name $nicName -ErrorAction Stop 

        $privateIp = $nic.IpConfigurations[0].PrivateIpAddress
        $publicIp = $null
        $managementLink = $null

        if ($nic.IpConfigurations[0].PublicIpAddress) {
            $publicIpId = $nic.IpConfigurations[0].PublicIpAddress.Id
            $publicIpName = ($publicIpId -split '/')[8]
            $publicIpObj = Get-AzPublicIpAddress -ResourceGroupName $resourceGroupName -Name $publicIpName -ErrorAction Stop 
            $publicIp = $publicIpObj.IpAddress

            if ($publicIp) {
                $managementLink = "http://$publicIp`:8251"
            }
        }

        [PSCustomObject]@{
            VMName         = $vm.Name
            PrivateIP      = $privateIp
            PublicIP       = $publicIp
            ManagementLink = $managementLink
        }
    }

    $results | Format-Table -AutoSize
}



function ExecuteCommands {
    $resource = Get-AzResourceGroup | Where-Object { $_.Tags -and $_.Tags.Contains("EnvironmentName") -and $_.Tags["EnvironmentName"] -eq $ResourceName } -ErrorAction Stop 
    if (-not $resource) {
        throw "No such environment exists"
    }
    $resourceGroupName = $resource | Select-Object -ExpandProperty resourceGroupName
    $vms = GetUploadedVms -ResourceGroup $resourceGroupName
    $maxServerCount = FindMaxServerCount
    CreateNewServersList
    $vmData = ExtractVmData
    $encodedScript = CreateScript
    # CheckQuota -Location $($vmData.Location) -VmSizeName $($vmData.VmSize)
    $CreatePublicIp = [System.Convert]::ToBoolean($vmData.CreatePublicIp)
    New-AzResourceGroupDeployment -ResourceGroupName $resourceGroupName -TemplateFile $ArmTemplatePath -location $($vmData.location) -resource_group_name $ResourceName -vm_names $newVmsList -zone_name $($vmData.zone) -publisher_name $($vmData.publisher) -offer_name $($vmData.offer) -sku_name $($vmData.sku) -version_name $($vmData.version) -os_name $($vmData.osType) -storage_account_type $($vmData.storageAccountType) -vm_size $($vmData.VmSize) -userName $script:userName -password $Password -create_public_ip $CreatePublicIp -image_version $($vmData.ImageVersion) -custom_data $encodedScript -use_ncache_image $($vmData.UseNCacheImage) -Verbose -ErrorVariable MyError | Out-Null
    if ($MyError) {
        throw "Exception $($MyError.Exception.Message)"
    }
    InstallNCache
    AddnewServersToCaches
    ShowDeployedEvs
}

function InstallNCache {
    foreach ($server in $newVmsList) {
        Enable-SystemAssignedIdentity -VmName $server
    }
    
    $os = $resource.Tags['OsType']
    $UseNCacheImage = [System.Convert]::ToBoolean($resource.Tags["UseNCacheImage"])
    if (-not $UseNCacheImage) {
        DownloadAndInstallNCache -OS $os
    }
}
function AddCacheTagsToNewServers {
    param(
        $NewVm,
        [string]$caches
    )
    $NewVm.Tags["Caches"] = $caches
    Update-AzTag -ResourceId $NewVm.Id -Tag $NewVm.Tags -Operation Merge | Out-Null

    $cacheList = $caches -split ',' | ForEach-Object { $_.Trim() }
    foreach ($cacheName in $cacheList) {
        if (-not [string]::IsNullOrWhiteSpace($cacheName)) {
            Update-NcAzDashboards -ScriptsFolderPath $ScriptsFolderPath -ResourceGroupName $NewVm.ResourceGroupName -CacheName $cacheName -SkipClient
        }
    }
}

function AddToCachesWindows {
    param(
        [string]$NewVmPrivateIp,
        [string]$NewVmName,
        $NewVm
    )
    $cmd = ""
    $cachesValue = ""
    $caches = @()

    if ($vms -and $vms.Count -gt 0) {
        $vm = $null
        $cacheVMs = $vms | Where-Object { $_.Tags.ContainsKey("Caches") -and $_.Tags.ContainsKey("InstallMode") }
        if ($cacheVMs -and $cacheVMs.Count -gt 0) {
            $vm = $cacheVMs[0]
            $caches += $vm.Tags["Caches"].Split(",") | ForEach-Object { $_.Trim() }
            $cachesList = $vm.Tags["Caches"].Split(",")
            $uniqueCaches = $caches | Sort-Object -Unique
            $cachesValue = ($uniqueCaches -join ",")
            if ($cachesList.count -gt 0) {
                foreach ($cache in $cachesList) {
                    $cmd += "Add-Node -CacheName $cache -NewServer $NewVmPrivateIp -Port $Port -ExistingServer $($vm.PrivateIp)"
                    $cmd += "`n"
                }
            }
            AddCacheTagsToNewServers -NewVm $NewVm -caches $cachesValue
            $result = Invoke-AzVMRunCommand -ResourceGroupName $resourceGroupName -VMName $NewVmName -CommandId 'RunPowerShellScript' -ScriptString $cmd
            foreach ($val in $result.Value) {
                Write-Host $val.Message
            }
        }
    }
}


function AddToCachesLinux {
    param(
        [string]$NewVmPrivateIp,
        [string]$NewVmName,
        $NewVm
    )
    $cmd = ""
    $cachesValue = ""
    $caches = @()
    if ($vms -and $vms.Count -gt 0) {
        $vm = $null
        if ($vms -and $vms.Count -gt 0) {
            $vm = $null
            $cacheVMs = $vms | Where-Object { $_.Tags.ContainsKey("Caches") -and $_.Tags.ContainsKey("InstallMode") }
            if ($cacheVMs -and $cacheVMs.Count -gt 0) {
                $vm = $cacheVMs[0]
                $caches += $vm.Tags["Caches"].Split(",") | ForEach-Object { $_.Trim() }
                $cachesList = $vm.Tags["Caches"].Split(",")
                $uniqueCaches = $caches | Sort-Object -Unique
                $cachesValue = ($uniqueCaches -join ",")
                if ($cachesList.count -gt 0) {
                    foreach ($cache in $cachesList) {
                        $cmd += "/opt/ncache/bin/tools/add-node -cacheName $cache -newserver $NewVmPrivateIp -port $Port -existingserver $($vm.PrivateIp)"
                        if ($cmd) { $cmd += "; " }  
                    }
                }
            }
            AddCacheTagsToNewServers -NewVm $NewVm -caches $cachesValue
            $result = Invoke-AzVMRunCommand -ResourceGroupName $resourceGroupName -VMName $NewVmName -CommandId 'RunShellScript' -ScriptString $cmd
            foreach ($val in $result.Value) {
                Write-Host $val.Message
            }
        }
    }
}
function GetNewServersPrivateIp {
    foreach ($server in $newVmsList) {
        $vm = Get-AzVM -ResourceGroupName $resourceGroupName -Name $server -ErrorAction Stop 
        $nicId = $vm.NetworkProfile.NetworkInterfaces[0].Id
        $nicName = ($nicId -split "/")[-1]
        $nic = Get-AzNetworkInterface -ResourceGroupName $resourceGroupName -Name $nicName -ErrorAction Stop 
        $privateIp = $nic.IpConfigurations[0].PrivateIpAddress

        if ($resource.Tags["OsType"] -eq "Windows") {
            AddToCachesWindows -NewVmName $server -NewVmPrivateIp $privateIp -NewVm $vm
        }
        else {
            AddToCachesLinux -NewVmName $server -NewVmPrivateIp $privateIp -NewVm $vm
        }
    }
}

function AddnewServersToCaches {
    GetNewServersPrivateIp
}

try {
    if (-not (Get-AzContext)) {
        Connect-AzAccount
        if (Get-AzContext) {
            Write-Host "Deploying resources..."
            ExecuteCommands
        }
    }
    else {
        Write-Host "Deploying resources..."
        ExecuteCommands
    }
}
catch {
    Write-Error $($_.Exception.Message)

    Write-Error "Machine(s) deployment failed"
    Write-Warning "Rolling back changes..."
    
    PerformRollback
}