install_utils.ps1

Function Get-ZertoOVAFile {
    param (
        [Parameter(Mandatory=$true, HelpMessage = "My Zerto Zoken")]
        [string]$MyZertoToken
    )

    process {
        $LocalFolderPath = Get-Location

        try {
            Write-Host "Getting Zerto download links"
            $ZertoUrlsJson = Get-ZertoDownloadLinksFromMyZerto -Token $MyZertoToken
        
            Write-Host "Parsing download links for file names"
            $OvaPresignedUrl = $ZertoUrlsJson.data.files.ova_file
            $OvaSignaturePresignedUrl = $ZertoUrlsJson.data.files.ova_signature

            $OvaFileName = Get-FileNameFromDownloadLink -Url $OvaPresignedUrl
            $OvaSignatureFileName = Get-FileNameFromDownloadLink -Url $OvaSignaturePresignedUrl
            
            $OvaFilePath = Join-Path -Path "$LocalFolderPath" -ChildPath "$OvaFileName"
            $OvaSignatureFilePath = Join-Path -Path "$LocalFolderPath" -ChildPath "$OvaSignatureFileName"
            
            Write-Host "Downloading OVA file $OvaFileName, this process might take a while, please wait ..."
            Download-File -FileUrl $OvaPresignedUrl -LocalFilePath $OvaFilePath

            Write-Host "Downloading OVA signature file $OvaSignatureFileName"
            Download-File -FileUrl $OvaSignaturePresignedUrl -LocalFilePath $OvaSignatureFilePath
        }
        catch {
            Write-Error "Failed download Zerto OVA file, exception = $_"  -ErrorAction Stop
        }
        
        if ((Validate-FileBySignature -FilePath $OvaFilePath -SignatureFilePath $OvaSignatureFilePath) -ne $true){
            Write-Error "OVA or signature file validation failed." -ErrorAction Stop
        }
        
        return $OvaFilePath
    }
}

Function Get-ZertoDownloadLinksFromMyZerto {
     param (
        [Parameter(Mandatory=$true, HelpMessage = "My Zerto Zoken")]
        [string]$Token
    )

    Process{
        
        Write-Host "Starting $($MyInvocation.MyCommand)"
        
        try {
            $Url = "https://www.zerto.com/myzerto/wp-json/services/zerto/s3-ova?key=" + $Token
            $Response = Invoke-WebRequest -Uri $Url -SkipCertificateCheck -ErrorAction Stop  -TimeoutSec 1800 | ConvertFrom-Json 
        }
        catch {
            $ErrorMessage = $_

            if ($ErrorMessage -match "invalid_key") {
                Write-Error "Failed to retrieve download files for the ZVM Appliance, invalid token" -ErrorAction Stop
            }
            else {
                Write-Host $ErrorMessage
                Write-Error "Failed to retrieve download files for the ZVM Appliance" -ErrorAction Stop
            }
        }
        
        Write-Host "Download JSON file with URLs completed successfully"
        
        return $Response
    }
}

Function Download-File {
     param (
        [Parameter(Mandatory=$true, HelpMessage = "file url to download from")]
        [string]$FileUrl,
        [Parameter(Mandatory=$true, HelpMessage = "local file path")]
        [string]$LocalFilePath
     )

     Process {
        
        Write-Host "Starting $($MyInvocation.MyCommand)"
        
        if (Test-Path "$LocalFilePath"){
            Write-Host "$LocalFilePath already exists. Skipping download"
            return
        }

        try
        {
            $start_time = Get-Date
            
            Invoke-WebRequest $FileUrl -OutFile $LocalFilePath -ErrorAction Stop -TimeoutSec 10800 -Resume -SkipCertificateCheck
        }
        catch{
            Write-Error "Failed download $FileUrl, exception = $_" -ErrorAction Stop
        }
        
        Write-Host "Zerto download was completed successfully, duration: $((Get-Date).Subtract($start_time).TotalSeconds) second(s)"
     }
}

Function Get-FileNameFromDownloadLink {
    param (
        [Parameter(Mandatory=$true, HelpMessage = "file url to download from")]
        [string]
        $Url
    )
    
    Process {
        try {
            $uri = New-Object System.Uri($url)
            $FileName = [System.IO.Path]::GetFileName($uri.LocalPath)
            return $FileName
        }
        catch {
            throw "Failed getting file name from $Url, exception = $_"
        }
    }
}

Function Deploy-Vm {
    param(
        [Parameter(Mandatory=$true, HelpMessage = "Path for the OVA file")]
        [ValidateNotNullOrEmpty()][string]
        $OvaPath,

        [Parameter(Mandatory=$true, HelpMessage = "Host Name")]
        [ValidateNotNullOrEmpty()][string]
        $VMHostName,

        [Parameter(Mandatory=$true, HelpMessage = "Datastore Name")]
        [ValidateNotNullOrEmpty()][string]
        $DatastoreName,

        [Parameter(Mandatory = $true, HelpMessage = "Zvm IP address")]
        [ValidateNotNullOrEmpty()][string]
        $ZVMLIp,

        [Parameter(Mandatory=$true, HelpMessage="Network name for ZVML")]
        [ValidateNotNullOrEmpty()][string]
        $NetworkName,
        
        [Parameter(Mandatory = $true, HelpMessage = "SubnetMask address")]
        [ValidateNotNullOrEmpty()][string]
        $SubnetMask,

        [Parameter(Mandatory = $true, HelpMessage = "Default gateway")]
        [ValidateNotNullOrEmpty()][string]
        $DefaultGateway,

        [Parameter(Mandatory = $true, HelpMessage = "DNS server address")]
        [ValidateNotNullOrEmpty()][string]
        $DNS,

        [Parameter(Mandatory = $true, HelpMessage = "Azure Tenant Id, Globally unique identifier, found in Azure portal")]
        [ValidateNotNullOrEmpty()][string]
        $AzureTenantId, 

        [Parameter(Mandatory = $true, HelpMessage = "Azure Client ID - Application ID, found in Azure portal")]
        [ValidateNotNullOrEmpty()][string]
        $AzureClientID, 

        [Parameter(Mandatory = $true, HelpMessage = "Enables authentication to Azure Active Directory using a client secret")]
        [ValidateNotNullOrEmpty()][SecureString]
        $AvsClientSecret,

        [Parameter(Mandatory = $true, HelpMessage = "The ID of the target subscription")]
        [ValidateNotNullOrEmpty()][string]
        $AvsSubscriptionId, 

        [Parameter(Mandatory = $true, HelpMessage = "AWS resources that are all in the same AWS Region")]
        [ValidateNotNullOrEmpty()][string]
        $AvsResourceGroup, 

        [Parameter(Mandatory = $true, HelpMessage = "Private cloud name")]
        [ValidateNotNullOrEmpty()][string]
        $AvsCloudName,

        [Parameter(Mandatory=$true, HelpMessage= "Configure Ovf Properties")]
        [bool]$ConfigureOvfProperties
    )

    Process {

        try {
            Write-Host "Starting $($MyInvocation.MyCommand)"

            $ovfConfig = Set-OvfProperties -ConfigureOvfProperties $ConfigureOvfProperties -OvaPath $OvaPath -ZVMLIp $ZVMLIp -NetworkName $NetworkName -SubnetMask $SubnetMask -DefaultGateway $DefaultGateway -DNS $DNS -AzureTenantId $AzureTenantId -AzureClientID $AzureClientID -AvsClientSecret $AvsClientSecret -AvsSubscriptionId $AvsSubscriptionId -AvsResourceGroup $AvsResourceGroup -AvsCloudName $AvsCloudName
        
            $datastore = Get-Datastore -Name $DatastoreName
        
            $host = Get-VMHost -Name $VMHostName

            Write-Host "Deploying process might take a while, please wait ..."
            $start_time = Get-Date
            Import-VApp -Source $OvaPath -OvfConfiguration $ovfConfig -Name $ZVM_VM_NAME -VMHost $host -Datastore $datastore -ErrorAction stop | Out-Null

            Write-Host "$ZVM_VM_NAME was deployed succesfully, duration: $((Get-Date).Subtract($start_time).TotalSeconds) second(s)"
        }
        catch {
            Write-Error "Failed to deploy $ZVM_VM_NAME ZVML, exception = $_" -ErrorAction Stop
        }
        
    }
}

Function Set-OvfProperties{
    param(
        [Parameter(Mandatory=$false, HelpMessage= "Configure Ovf Properties")]
        [bool]$ConfigureOvfProperties,

        [Parameter(Mandatory=$true, HelpMessage = "Path for the OVA file")]
        [string]
        $OvaPath,

        [Parameter(Mandatory = $true, HelpMessage = "Zvm IP address")]
        [ValidateNotNullOrEmpty()][string]
        $ZVMLIp,

        [Parameter(Mandatory=$true, HelpMessage="Network device for ZVML")]
        [ValidateNotNullOrEmpty()][string]
        $NetworkName,
        
        [Parameter(Mandatory = $true, HelpMessage = "SubnetMask address")]
        [ValidateNotNullOrEmpty()][string]
        $SubnetMask,

        [Parameter(Mandatory = $true, HelpMessage = "Default gateway")]
        [ValidateNotNullOrEmpty()][string]
        $DefaultGateway,

        [Parameter(Mandatory = $true, HelpMessage = "DNS server address")]
        [ValidateNotNullOrEmpty()][string]
        $DNS,

        [Parameter(Mandatory = $true, HelpMessage = "Azure Tenant Id, Globally unique identifier, found in Azure portal")]
        [ValidateNotNullOrEmpty()][string]
        $AzureTenantId, 

        [Parameter(Mandatory = $true, HelpMessage = "Azure Client ID - Application ID, found in Azure portal")]
        [ValidateNotNullOrEmpty()][string]
        $AzureClientID, 

        [Parameter(Mandatory = $true, HelpMessage = "Enables authentication to Azure Active Directory using a client secret")]
        [ValidateNotNullOrEmpty()][SecureString]
        $AvsClientSecret,

        [Parameter(Mandatory = $true, HelpMessage = "The ID of the target subscription")]
        [ValidateNotNullOrEmpty()][string]
        $AvsSubscriptionId, 

        [Parameter(Mandatory = $true, HelpMessage = "AWS resources that are all in the same AWS Region")]
        [ValidateNotNullOrEmpty()][string]
        $AvsResourceGroup, 

        [Parameter(Mandatory = $true, HelpMessage = "Private cloud name")]
        [ValidateNotNullOrEmpty()][string]
        $AvsCloudName
    )
    
    Write-Host "Starting $($MyInvocation.MyCommand)..."
    

    try{
        $ovfConfig = Get-OvfConfiguration -Ovf $OvaPath -ErrorAction stop
    
        Write-Host "ovf configuration was fetched successfully for $ovaPath, ConfigureOvfProperties=$ConfigureOvfProperties"        

        $ovfConfig.NetworkMapping.Vlan_244_6_5_new.Value = $NetworkName 
        
        if ($ConfigureOvfProperties -eq $true)
        {
            $ovfConfig.ZVMConfigurationSettings.IsAutoDeployment.Value = $true
            $ovfConfig.ZVMConfigurationSettings.ZVMIpAddress.Value = $ZVMLIp
            $ovfConfig.ZVMConfigurationSettings.Gateway.Value = $DefaultGateway
            $ovfConfig.ZVMConfigurationSettings.Netmask.Value = $SubnetMask
            $ovfConfig.ZVMConfigurationSettings.DNS.Value = $DNS
            
            Write-Host "ZVMA configuration was set succesfully"
            
            $ovfConfig.AzureSettings.AzureTenantId.Value = $AzureTenantId
            $ovfConfig.AzureSettings.AzureClientId.Value = $AzureClientID
            $ovfConfig.AzureSettings.AvsSubscriptionId.Value = $AvsSubscriptionId
            $ovfConfig.AzureSettings.AvsResourceGroup.Value = $AvsResourceGroup
            $ovfConfig.AzureSettings.AvsCloudName.Value = $AvsCloudName
            $ovfConfig.AzureSettings.AvsClientSecret.Value = ConvertFrom-SecureString -SecureString $AvsClientSecret -AsPlainText
            
            Write-Host "Azure settings were set successfully"
            
            $ovfConfig.VcSettings.ZVMVcUser.Value = "ZertoDR"
            $ovfConfig.VcSettings.ZVMVcPassword.Value = $PersistentSecrets.ZertoPassword
            $ovfConfig.VcSettings.VcAddress.Value = $VC_ADDRESS
            
            Write-Host "ZVMA ovf properties were set successfully"
        }
        
        return $ovfConfig
    }
    
    catch{
        throw "Failed to set ovf properties for $ovfPath, exception = $_"
    }
}