JSDR.Configuration.psm1

<#
    Prerequisite:
    =============
    1. Module VMware.vSphere.SsoAdmin should be present
    2. CloudAdmin role is present within vcenter
    3. powershell version > 6
#>


$js_url = "https://jsmms.blob.core.windows.net/jsdrmms/JSDR-GA-4.2.2.575-240116.zip"

function Get-JetDR {
<#
    .NOTES
    ===========================================================================
    Created by: JetStream Software Inc
    ===========================================================================
    .DESCRIPTION
    This function downloads JetStream DR software from MMS

    .PARAMETER Url
    Url of the bundle to download

    .PARAMETER DownloadPath
    Path where the bundle has to be downloaded

    .EXAMPLE
    Get-JetDR -Url https://example.com/file.zip -DownloadPath /home/user/downloads
#>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true,
                    HelpMessage="Url of the bundle to download")]
        [string]$Url,

        [Parameter(Mandatory=$true,
                    HelpMessage="Download location")]
        [string]$DownloadPath
    )

    Process {
        $Filename = Split-Path $Url -Leaf
        $download_file_path = $DownloadPath + '/' + $Filename
        download_jetdr_bundle $Url $download_file_path
    }
}

function Expand-JetDR {
<#
    .NOTES
    ===========================================================================
    Created by: JetStream Software Inc
    ===========================================================================
    .DESCRIPTION
    This function unzips JetStream DR software

    .PARAMETER Filename
    Name of the bundle

    .PARAMETER FilePath
    Path where the bundle is located

    .PARAMETER UnzipPath
    Path where bundle will be unzipped

    .EXAMPLE
    Expand-JetDR -FileName file.zip -FilePath /home/user/downloads/ -UnzipPath /home/user/downloads/jsdr/
#>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true,
                    HelpMessage="Name of the bundle")]
        [string]$Filename,

        [Parameter(Mandatory=$true,
                    HelpMessage="Bundle location")]
        [string]$FilePath,

        [Parameter(Mandatory=$true,
                    HelpMessage="Unzip location")]
        [string]$UnzipPath
    )

    Process {
        $js_download_path = $FilePath + '/' + $Filename
        unzip_ova $js_download_path $UnzipPath
    }
}

function Deploy-JetDRMSA {
<#
    .NOTES
    ===========================================================================
    Created by: JetStream Software Inc
    ===========================================================================
    .DESCRIPTION
    This function deploys JetStream DR Management Server Appliance(MSA), powers it on and waits for all services to be running

    .PARAMETER OvfPath
    Full path of the ova file

    .PARAMETER Network
    Network for the MSA, e.g "VM Network"

    .PARAMETER Hostname
    Hostname of the MSA

    .PARAMETER MSACredential
    MSACredential of root user

    .PARAMETER Gateway
    Gateway of MSA

    .PARAMETER Dns
    DNS IP that MSA should use

    .PARAMETER Ip
    IP of MSA

    .PARAMETER Netmask
    Netmask of MSA

    .PARAMETER VlanId
    VLAN Tag ID for MSA to be deployed (Leave blank if NA)

    .PARAMETER Cluster
    Cluster name where MSA needs to be deployed

    .PARAMETER VmName
    Name of the MSA VM

    .PARAMETER Datastore
    Datastore where the MSA has to be deployed

    .EXAMPLE
    Deploy-JetDRMSA -OvfPath /home/user/downloads/jsdr.ova -Network "VM Network" -Hostname msavm.example.com -MSACredential <root/PSCredential object> -Gateway xxx.xxx.xxx.xxx -Dns xxx.xxx.xxx.xxx -Ip xxx.xxx.xxx.xxx -Netmask xxx.xxx.xxx.xxx -VlanId 101 -Cluster Test-Cluster -VmName JS-MSA -Datastore md3817
#>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true,
                    HelpMessage="Location of the ova")]
        [string]$OvfPath,

        [Parameter(Mandatory=$true,
                    HelpMessage="Location of the ova signature")]
        [string]$SignaturePath,

        [Parameter(Mandatory=$true,
                    HelpMessage="Network device for MSA")]
        [string]$Network,

        [Parameter(Mandatory=$false,
                    HelpMessage="Hostname of MSA")]
        [string]$Hostname,

        [Parameter(Mandatory=$true,
                    HelpMessage="MSA Credentials of root user")]
        [ValidateNotNull()]
        [System.Management.Automation.PSCredential]
        [System.Management.Automation.Credential()]
        $MSACredential,

        [Parameter(Mandatory=$false,
                    HelpMessage="Gateway for MSA")]
        [string]$Gateway,

        [Parameter(Mandatory=$false,
                    HelpMessage="DNS IP that MSA should use")]
        [string]$Dns,

        [Parameter(Mandatory=$false,
                    HelpMessage="IP for MSA")]
        [string]$Ip,

        [Parameter(Mandatory=$false,
                    HelpMessage="Netmask for MSA")]
        [string]$Netmask,

        [Parameter(Mandatory=$false,
                    HelpMessage="VLAN Tag ID for MSA VM to be deployed. (Leave blank if NA)")]
        [String]$VlanId,

        [Parameter(Mandatory=$true,
                    HelpMessage="Cluster name where MSA will be deployed")]
        [string]$Cluster,

        [Parameter(Mandatory=$true,
                    HelpMessage="Vm name for MSA")]
        [string]$VmName,

        [Parameter(Mandatory=$true,
                    HelpMessage="Datastore where MSA will be deployed")]
        [string]$Datastore
    )

    Process {
        $SecureFolder = [AVSSecureFolder]::GetOrCreate("js-appliance")
        if ($null -eq $SecureFolder) {
            Write-Error "Could not create secure folder to deploy MSA. Contact JetStream support for help." -ErrorAction Stop
        }
        $Password=$MSACredential.GetNetworkCredential().Password
        $mycluster=Get-Cluster -Name $Cluster
        $msa=Get-VM -Name $VmName -Location $mycluster -ErrorAction SilentlyContinue
        if ($null -ne $msa) {
            write-host "MSA VM with the same name already exists in the Cluster $Cluster. Skipping creation"
            if($msa.PowerState -eq 'PoweredOff') {
                write-host "MSA VM is powered off, powering it on"
                start-vm $msa -confirm:$false | Out-Null
                if (!$?) {
                    write-host "Starting MSA VM failed"
                    break
                }
            }

            $vm_ip=get_vm_ip $VmName 600
            if ($null -ne $vm_ip) {
                $rc=ms_rest_state $vm_ip "root" $Password 600
                if (!$rc) {
                    write-host "Failed to ping $vm_ip after 600 seconds"
                    break
                }
                write-host "Sleep for 2 more minute after Management server becomes pingable"
                start-sleep 120
            }
            else {
                Write-Error "Could not determine MSA VM ip." -ErrorAction Stop
            }
        }
        else {
            # Deploy the Management server appliance from the ova
            $vm_ip=deploy_ova $OvfPath $SignaturePath $Network $Hostname $Password $Gateway $Dns $Ip  $Netmask $VlanId $Cluster $VmName $Datastore $SecureFolder

            if ($null -ne $vm_ip)
            {
                $rc=ms_rest_state $vm_ip "root" $Password 600
                if (!$rc)
                {
                    write-error "MSA $vm_ip is not ready after 600 seconds" -ErrorAction Stop
                }
                Write-Host "Sleep for 2 more minute after Management server REST server is running"
                start-sleep 120
            }
        }
        [AVSSecureFolder]::Secure($SecureFolder)
        return $vm_ip
    }
}

function Add-User {
<#
    .NOTES
    ===========================================================================
    Created by: JetStream Software Inc
    ===========================================================================
    .DESCRIPTION
    This function creates a new sso user

    .PARAMETER Username
    Username of the new sso user

    .PARAMETER Password
    Password of the new sso user

    .EXAMPLE
    Add-User -Username vsphere.local\tmpuser -Password ***
#>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true,
                    HelpMessage="New sso username")]
        [string]$Username,

        [Parameter(Mandatory=$true,
                    HelpMessage="Password of new sso user")]
        [string]$Password
    )

    Process {
        $domain = $Username.split("\")[0]
        $user = $Username.split("\")[1]
        $ssouser = Get-SsoPersonUser -Name $user -Domain $domain
        if($ssouser) {
            write-host "User $Username already exists. Deleting before creating again."
            delete_user $Username
            start-sleep 5
        }
        create_user $user $Password
    }
}

function Remove-User {
<#
    .NOTES
    ===========================================================================
    Created by: JetStream Software Inc
    ===========================================================================
    .DESCRIPTION
    This function deletes an sso user

    .PARAMETER Username
    Username of the sso user

    .EXAMPLE
    Remove-User -Username vsphere.local\tmpuser
#>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true,
                    HelpMessage="sso username")]
        [string]$Username
    )

    Process {
        delete_user $Username
        Write-Host "Script execution has completed. Please check status of the task for success/failure"
    }
}
function New-Role {
<#
    .NOTES
    ===========================================================================
    Created by: JetStream Software Inc
    ===========================================================================
    .DESCRIPTION
    This function creates a new role JSDR-elevated and assigns that role to the
    user created by Add-User

    .PARAMETER Username
    Username of the new sso user

    .PARAMETER Role
    Type of role to be created, elevated or operations

    .EXAMPLE
    New-Role -Username vsphere.local\tmpuser -Role elevated
    New-Role -Username vsphere.local\tmpuser -Role operations
#>


    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true,
                    HelpMessage="New sso username")]
        [string]$Username,

        [Parameter(Mandatory=$true,
                    HelpMessage="Type of role. Either elevated or operations")]
        [string]$Role
    )

    Begin {
        $extra_full_privilleges = "Maintenance", "Query patch", "CIM interaction", "Profile-driven storage update", "Register extension", "Unregister extension", "Update extension", "Security Profile and Firewall", "Update VM storage policies"
        $op_privilleges = "Register extension", "Unregister extension", "Update extension", "CIM interaction"
    }
    Process {
        if($Role -eq 'elevated') {
            $role = "JSDR-elevated"
            $privilleges = $extra_full_privilleges
        }
        elseif($Role -eq 'operations') {
            $role = "JSDR-operations"
            $privilleges = $op_privilleges
        }
        else {
            write-host "Invalid role specified. Must be one of 'elevated' or 'operations'"
            break
        }
        assign_new_role_to_user $role $Username $privilleges
    }
}

function Register-MS {
<#
    .NOTES
    ===========================================================================
    Created by: JetStream Software Inc
    ===========================================================================
    .DESCRIPTION
    This function registers JetStream MSA with vCenter

    .PARAMETER MS
    Management server ip/fqdn

    .PARAMETER MsaUser
    Management server user, e.g root

    .PARAMETER MsaPassword
    Management server password for MsaUser

    .PARAMETER VC
    vCenter ip/fqdn

    .PARAMETER Username
    Username of the new sso user, e.g vsphere.local\tmpuser

    .PARAMETER Password
    Password of the new sso user

    .PARAMETER RegisterWithIp
    Register MSA with IP instead of hostname

    .PARAMETER Mode
    Mode in which MSA has to be registered, e.g 'C2C'

    .EXAMPLE
    Register-MS -MS xxx.xxx.xxx.xxx -MsaUser root -MsaPassword *** -VC xxx.xxx.xxx.xxx -Username vsphere.local\tmpuser -Password *** -Mode C2C -RegisterWithIp $true
#>


    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true,
                    HelpMessage="ip/fqdn of MSA")]
        [string]$MS,

        [Parameter(Mandatory=$true,
                    HelpMessage="MSA user")]
        [string]$MsaUser,

        [Parameter(Mandatory=$true,
                    HelpMessage="MSA password")]
        [string]$MsaPassword,

        [Parameter(Mandatory=$true,
                    HelpMessage="ip/fqdn of vCenter")]
        [string]$VC,

        [Parameter(Mandatory=$true,
                    HelpMessage="sso username with which vCenter will be registered")]
        [string]$Username,

        [Parameter(Mandatory=$true,
                    HelpMessage="sso user password")]
        [string]$Password,

        [Parameter(Mandatory=$true,
                    HelpMessage="Register MSA with IP instead of hostname")]
        [bool]$RegisterWithIp,

        [Parameter(Mandatory=$true,
                    HelpMessage="Mode in which MSA will be registered C2C")]
        [string]$Mode="C2C"
    )

    Process {
        $response = get_ms_state $MS $MsaUser $MsaPassword
        if ($response.configured -eq $True) {
            write-host "MSA $MS already registered to vCenter. Skipping registration"
        }
        else {
            register_ms_with_vc $MS $MsaUser $MsaPassword $VC $Username $Password $Mode $RegisterWithIp
            start-sleep 10
        }
    }
}

function Unregister-MS {
<#
    .NOTES
    ===========================================================================
    Created by: JetStream Software Inc
    ===========================================================================
    .DESCRIPTION
    This function unregisters JetStream MSA from vCenter

    .PARAMETER MS
    Management server ip/fqdn

    .PARAMETER VC
    vCenter ip/fqdn

    .PARAMETER Username
    Username of the new sso user, e.g vsphere.local\tmpuser

    .PARAMETER Password
    Password of the new sso user

    .EXAMPLE
    Unregister-MS -MS xxx.xxx.xxx.xxx -VC xxx.xxx.xxx.xxx -Username vsphere.local\tmpuser -Password ***
#>


    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true,
                    HelpMessage="ip/fqdn of MSA")]
        [string]$MS,

        [Parameter(Mandatory=$true,
                    HelpMessage="ip/fqdn of vCenter")]
        [string]$VC,

        [Parameter(Mandatory=$true,
                    HelpMessage="sso username with which vCenter will be registered")]
        [string]$Username,

        [Parameter(Mandatory=$true,
                    HelpMessage="sso user password")]
        [string]$Password
    )

    Process {
        $fios_session_id = refresh_vc_session $MS $VC $Username $Password
        unregister_vcenter_from_ms $MS $VC $Username $Password $fios_session_id
        start-sleep 10
    }
}

function Install-Cluster {
<#
    .NOTES
    ===========================================================================
    Created by: JetStream Software Inc
    ===========================================================================
    .DESCRIPTION
    This function installs JetDR software to all hosts in the Cluster

    .PARAMETER MS
    Management server ip/fqdn

    .PARAMETER VC
    vCenter ip/fqdn

    .PARAMETER Username
    Username of the new sso user, e.g vsphere.local\tmpuser

    .PARAMETER Password
    Password of the new sso user

    .PARAMETER Cluster
    Cluster name which has to be configured

    .EXAMPLE
    Install-Cluster -MS xxx.xxx.xxx.xxx -VC xxx.xxx.xxx.xxx -Username vsphere.local\tmpuser -Password *** -Cluster prod-cluster
#>


    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true,
                    HelpMessage="ip/fqdn of MSA")]
        [string]$MS,

        [Parameter(Mandatory=$true,
                    HelpMessage="ip/fqdn of vCenter")]
        [string]$VC,

        [Parameter(Mandatory=$true,
                    HelpMessage="sso username with which vCenter will be registered")]
        [string]$Username,

        [Parameter(Mandatory=$true,
                    HelpMessage="sso user password")]
        [string]$Password,

        [Parameter(Mandatory=$true,
                    HelpMessage="Name of the cluster to be configured")]
        [string]$Cluster
    )

    Process {
        $fios_session_id = refresh_vc_session $MS $VC $Username $Password
        configure_cluster $MS $Cluster $fios_session_id
    }
}

function Uninstall-Cluster {
<#
    .NOTES
    ===========================================================================
    Created by: JetStream Software Inc
    ===========================================================================
    .DESCRIPTION
    This function uninstalls JetStream software from the cluster

    .PARAMETER MS
    Management server ip/fqdn

    .PARAMETER VC
    vCenter ip/fqdn

    .PARAMETER Username
    Username of the new sso user, e.g vsphere.local\tmpuser

    .PARAMETER Password
    Password of the new sso user

    .PARAMETER Cluster
    Cluster name which has to be unconfigured

    .EXAMPLE
    Uninstall-Cluster -MS xxx.xxx.xxx.xxx -VC xxx.xxx.xxx.xxx -Username vsphere.local\tmpuser -Password *** -Cluster prod-cluster
#>


    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true,
                    HelpMessage="ip/fqdn of MSA")]
        [string]$MS,

        [Parameter(Mandatory=$true,
                    HelpMessage="ip/fqdn of vCenter")]
        [string]$VC,

        [Parameter(Mandatory=$true,
                    HelpMessage="sso username with which vCenter will be unregistered")]
        [string]$Username,

        [Parameter(Mandatory=$true,
                    HelpMessage="sso user password")]
        [string]$Password,

        [Parameter(Mandatory=$true,
                    HelpMessage="Name of the cluster to be unconfigured")]
        [string]$Cluster
    )

    Process {
        $fios_session_id = refresh_vc_session $MS $VC $Username $Password
        unconfigure_cluster $MS $Cluster $fios_session_id
    }
}

function Remove-Role {
<#
    .NOTES
    ===========================================================================
    Created by: JetStream Software Inc
    ===========================================================================
    .DESCRIPTION
    This function deletes a role from the vCenter and the elevated permissions from
    the sso user

    .PARAMETER Username
    Username of the new sso user

    .PARAMETER Role
    Type of role to be created, elevated or operations

    .EXAMPLE
    Remove-Role -Username vsphere.local\tmpuser -Role elevated
    Remove-Role -Username vsphere.local\tmpuser -Role operations
#>


    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true,
                    HelpMessage="sso username")]
        [string]$Username,

        [Parameter(Mandatory=$true,
                    HelpMessage="Type of role. Either elevated or operations")]
        [string]$Role
    )

    Process {
        $user = $Domain + "\" + $Username
        if($Role -eq 'elevated') {
            $role = "JSDR-elevated"
        }
        elseif($Role -eq 'operations') {
            $role = "JSDR-operations"
        }
        else {
            write-host "Invalid role specified. Must be one of 'elevated' or 'operations'"
            break
        }
        $rootfolder = Get-Folder -NoRecursion
        $newly_added_permissions = Get-VIPermission -Entity $rootfolder -Principal $Username
        remove_permissions $newly_added_permissions
        remove_role $role
    }
}

function Restart-CIM {
<#
    .NOTES
    ===========================================================================
    Created by: JetStream Software Inc
    ===========================================================================
    .DESCRIPTION
    This function restarts CIM service on ESX hosts in the Cluster

    .PARAMETER Cluster
    Name of the cluster

    .EXAMPLE
    Restart-CIM -Cluster prod-cluster
#>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true,
                    HelpMessage="Name of the cluster")]
        [string]$Cluster
    )

    Process {
        restart_cim $Cluster
    }
}

function Install-JetDRWithStaticIP {
<#
    .NOTES
    ===========================================================================
    Created by: JetStream Software Inc
    ===========================================================================

    .DESCRIPTION

    Deploys JetDr Management Server Appliance(MSA) with Static network IP configuration and configures one cluster

    .PARAMETER Network
    Network mapping for the MSA to be deployed, e.g 'VM Network'"

    .PARAMETER HostName
    Hostname of the MSA to be deployed

    .PARAMETER MSACredential
    root user credential of the MSA to be deployed

    .PARAMETER Gateway
    Gateway of the MSA to be deployed

    .PARAMETER Dns
    DNS IP that MSA should use

    .PARAMETER MSAIp
    Ip of the MSA to be deployed

    .PARAMETER Netmask
    Netmask of the MSA to be deployed

    .PARAMETER VlanId
    VLAN Tag ID for MSA to be deployed (Leave blank if NA)

    .PARAMETER Cluster
    Cluster where the MSA will be deployed

    .PARAMETER VMName
    Name of the MSA VM

    .PARAMETER Datastore
    Datastore where MSA will be deployed

    .PARAMETER ProtectedCluster
    Cluster to be protected

    .PARAMETER RegisterWithIp
    Register MSA with IP instead of hostname

    .EXAMPLE

    Install-JetDRWithStaticIP -Network "VM Network" -HostName "jsdr-msa.example.com" -MSACredential <root/PSCredential Object> -Gateway xxx.xxx.xxx.xxx -Dns xxx.xxx.xxx.xxx -MSAIp xxx.xxx.xxx.xxx -Netmask xxx.xxx.xxx.xxx -VlanId 101 -Cluster MSA-Cluster -VMName jsdr-msa -Datastore shared-ds -ProtectedCluster Src-Cluster -RegisterWithIp $true

    .EXAMPLE

    Install-JetDRWithStaticIP -Network "VM Network" -HostName "jsdr-msa.example.com" -MSACredential <root/PSCredential Object> -Gateway xxx.xxx.xxx.xxx -Dns xxx.xxx.xxx.xxx -MSAIp xxx.xxx.xxx.xxx -Netmask xxx.xxx.xxx.xxx -VlanId 101 -Cluster MSA-Cluster -VMName jsdr-msa -Datastore shared-ds -ProtectedCluster Src-Cluster

#>


    [CmdletBinding()]
    [AVSAttribute(30, UpdatesSDDC = $True)]
    param(
        [Parameter(Mandatory=$true,
                    HelpMessage="Network mapping for the MSA to be deployed, e.g 'VM Network'")]
        [String]$Network,
        [Parameter(Mandatory=$false,
                    HelpMessage="Hostname(fqdn) of the MSA to be deployed")]
        [String]$HostName,
        [Parameter(Mandatory=$true,
                    HelpMessage="Credentials of root user of the MSA to be deployed")]
        [ValidateNotNull()]
        [System.Management.Automation.PSCredential]
        [System.Management.Automation.Credential()]
        $MSACredential,
        [Parameter(Mandatory=$true,
                    HelpMessage="Gateway of the MSA to be deployed.")]
        [String]$Gateway,
        [Parameter(Mandatory=$true,
                    HelpMessage="DNS IP that MSA should use.")]
        [String]$Dns,
        [Parameter(Mandatory=$true,
                    HelpMessage="Ip of the MSA to be deployed.")]
        [String]$MSAIp,
        [Parameter(Mandatory=$true,
                    HelpMessage="Netmask of the MSA to be deployed.")]
        [String]$Netmask,
        [Parameter(Mandatory=$false,
                    HelpMessage="VLAN Tag ID for MSA VM to be deployed. (Leave blank if NA)")]
        [String]$VlanId=$null,
        [Parameter(Mandatory=$true,
                    HelpMessage="Cluster where MSA will be deployed")]
        [String]$Cluster,
        [Parameter(Mandatory=$false,
                    HelpMessage="Name of the MSA VM")]
        [String]$VMName="msa@4.3.0+jetdr",
        [Parameter(Mandatory=$true,
                    HelpMessage="Datastore where MSA will be deployed")]
        [String]$Datastore,
        [Parameter(Mandatory=$true,
                    HelpMessage="Cluster to be protected")]
        [String]$ProtectedCluster,
        [Parameter(Mandatory=$false,
                    HelpMessage="Register MSA with Ip instead of hostname.")]
        [Bool]$RegisterWithIp=$true
    )
    Begin {
        $Mode = "C2C"
        # Script assumes that directory it is executed in is temporary
        $DownloadPath = "."

        $sso_user_name = "vsphere.local\jetdrusr"
        $sso_user_pwd=generate_password
        $js_download_path = $DownloadPath
        $js_destination_folder = $js_download_path + "/js_unzipped/"
        $UserName = $MSACredential.UserName.trim()
        $Password = $MSACredential.GetNetworkCredential().Password.trim()
        $VCFqdn = getVcFqdn

        #Trimming string parameters for any leading and trailing spaces
        foreach ($key in $($PSBoundParameters.keys)) {
            if ($PSBoundParameters[$key].GetType().Name -eq 'String') {
                $PSBoundParameters[$key] = $($PSBoundParameters[$key].trim())
                Set-Variable -Name $key -Value $($PSBoundParameters[$key].trim())
            }
        }
    }
    Process {
        # Run Preflight before install
        Invoke-PreflightJetDRInstall -ProtectedCluster $ProtectedCluster -Cluster $Cluster -VMName $VMName -Datastore $Datastore -Network $Network
        # Download JetDR bundle from MMS
        $js_zip = Split-Path $js_url -Leaf
        Get-JetDR -Url $js_url -DownloadPath $js_download_path

        # Unzip JetDR bundle to specified location
        Expand-JetDR -FileName $js_zip -FilePath $js_download_path -UnzipPath $js_destination_folder

        $ovf_path = Get-ChildItem -Path $js_destination_folder -Filter "jetstream*ova" -Recurse | %{$_.FullName}
        $signature_path = Get-ChildItem -Path $js_destination_folder -Filter "signature" -Recurse | %{$_.FullName}

        try {
            # Create a new sso user
            Add-User -Username $sso_user_name -Password $sso_user_pwd

            try {
                # Create JSDR-elevated role and assign it to the newly created sso user
                New-Role -Username $sso_user_name -Role elevated

                # Deploy JetStream MSA
                $MSAIp=Deploy-JetDRMSA -OvfPath $ovf_path -SignaturePath $signature_path -Network $Network -Hostname $HostName -MSACredential $MSACredential -Gateway $Gateway -Dns $Dns -Ip $MSAIp -Netmask $Netmask -VlanId $VlanId -Cluster $Cluster -VmName $VMName -Datastore $Datastore
                if ($null -eq $MSAIp) {
                    write-error "Deployment of MSA succeeded but no IP is assigned to MSA, please check your network configuration and try again" -ErrorAction Stop
                }

                # Register JetStream MSA with vCenter
                Register-MS -MS $MSAIp -MsaUser $UserName -MsaPassword $Password -VC $VCFqdn -Username $sso_user_name -Password $sso_user_pwd -Mode $Mode -RegisterWithIp $RegisterWithIp

                # Create iofrest user if vCenter version is 8 or above
                $vcenter_8 = is_vcenter_8($ProtectedCluster)
                if ($vcenter_8) {
                    Enable-JetStreamRESTUser -MSAIp $MSAIp -MSACredential $MSACredential
                }

                # Configure cluster with JetStream software
                Install-Cluster -MS $MSAIp -VC $VCFqdn -Username $sso_user_name -Password $sso_user_pwd -Cluster $ProtectedCluster

                # Restart CIM service on hosts
                Restart-CIM $ProtectedCluster

                # Unregister JetStream MSA from vCenter
                Unregister-MS -MS $MSAIp -VC $VCFqdn -Username $sso_user_name -Password $sso_user_pwd
            } finally {
                # Delete permissions of JSDR-elevated role from sso user and delete the role from vCenter
                Remove-Role -Username $sso_user_name -Role elevated
            }
            try {
                # Create JSDR-operations role and assign it to the newly created sso user
                New-Role -Username $sso_user_name -Role operations

                # Register JetStream MSA with vCenter
                Register-MS -MS $MSAIp -MsaUser $UserName -MsaPassword $Password -VC $VCFqdn -Username $sso_user_name -Password $sso_user_pwd -Mode $Mode -RegisterWithIp $RegisterWithIp
            } finally {
                # Delete permissions of JSDR-operations role from sso user and delete the role from vCenter
                Remove-Role -Username $sso_user_name -Role operations
            }
        } finally {
            # Delete the sso user created for this task
            Remove-User -Username $sso_user_name
        }
    }
}

function Install-JetDRWithDHCP {
<#
    .NOTES
    ===========================================================================
    Created by: JetStream Software Inc
    ===========================================================================

    .DESCRIPTION

    Deploys JetDr Management Server Appliance(MSA) with Dynamic network IP configurations and configures one cluster

    .PARAMETER Network
    Network mapping for the MSA to be deployed, e.g 'VM Network'"

    .PARAMETER HostName
    Hostname of the MSA to be deployed

    .PARAMETER MSACredential
    root user credential of the MSA to be deployed

    .PARAMETER VlanId
    VLAN Tag ID for MSA to be deployed (Leave blank if NA)

    .PARAMETER Cluster
    Cluster where the MSA will be deployed

    .PARAMETER VMName
    Name of the MSA VM

    .PARAMETER Datastore
    Datastore where MSA will be deployed

    .PARAMETER ProtectedCluster
    Cluster to be protected

    .PARAMETER RegisterWithIp
    Register MSA with IP instead of hostname

    .EXAMPLE

    Install-JetDRWithDHCP -Network "VM Network" -HostName "jsdr-msa.example.com" -MSACredential <root/PSCredential Object> -VlanId 101 -Cluster MSA-Cluster -VMName jsdr-msa -Datastore shared-ds -ProtectedCluster Src-Cluster
#>


    [CmdletBinding()]
    [AVSAttribute(30, UpdatesSDDC = $True)]
    param(
        [Parameter(Mandatory=$true,
                    HelpMessage="Network mapping for the MSA to be deployed, e.g 'VM Network'")]
        [String]$Network,
        [Parameter(Mandatory=$false,
                    HelpMessage="Hostname(fqdn) of the MSA to be deployed")]
        [String]$HostName,
        [Parameter(Mandatory=$true,
                    HelpMessage="Credentials of root user of the MSA to be deployed")]
        [ValidateNotNull()]
        [System.Management.Automation.PSCredential]
        [System.Management.Automation.Credential()]
        $MSACredential,
        [Parameter(Mandatory=$false,
                    HelpMessage="VLAN Tag ID for MSA VM to be deployed. (Leave blank if NA)")]
        [String]$VlanId=$null,
        [Parameter(Mandatory=$true,
                    HelpMessage="Cluster where MSA will be deployed")]
        [String]$Cluster,
        [Parameter(Mandatory=$false,
                    HelpMessage="Name of the MSA VM")]
        [String]$VMName="msa@4.3.0+jetdr",
        [Parameter(Mandatory=$true,
                    HelpMessage="Datastore where MSA will be deployed")]
        [String]$Datastore,
        [Parameter(Mandatory=$true,
                    HelpMessage="Cluster to be protected")]
        [String]$ProtectedCluster,
        [Parameter(Mandatory=$false,
                    HelpMessage="Register MSA with Ip instead of hostname.")]
        [Bool]$RegisterWithIp=$true
    )
    Begin {
        $Mode = "C2C"
        # Script assumes that directory it is executed in is temporary
        $DownloadPath = "."

        $sso_user_name = "vsphere.local\jetdrusr"
        $sso_user_pwd=generate_password
        $js_download_path = $DownloadPath
        $js_destination_folder = $js_download_path + "/js_unzipped/"
        $UserName = $MSACredential.UserName.trim()
        $Password = $MSACredential.GetNetworkCredential().Password.trim()
        $VCFqdn = getVcFqdn
        $Gateway = ''
        $Dns = ''
        $MSAIp = ''
        $Netmask = ''

        #Trimming string parameters for any leading and trailing spaces
        foreach ($key in $($PSBoundParameters.keys)) {
            if ($PSBoundParameters[$key].GetType().Name -eq 'String') {
                $PSBoundParameters[$key] = $($PSBoundParameters[$key].trim())
                Set-Variable -Name $key -Value $($PSBoundParameters[$key].trim())
            }
        }
    }
    Process {
        # Run Preflight before install
        Invoke-PreflightJetDRInstall -ProtectedCluster $ProtectedCluster -Cluster $Cluster -VMName $VMName -Datastore $Datastore -Network $Network
        # Download JetDR bundle from MMS
        $js_zip = Split-Path $js_url -Leaf
        Get-JetDR -Url $js_url -DownloadPath $js_download_path

        # Unzip JetDR bundle to specified location
        Expand-JetDR -FileName $js_zip -FilePath $js_download_path -UnzipPath $js_destination_folder

        $ovf_path = Get-ChildItem -Path $js_destination_folder -Filter "jetstream*ova" -Recurse | %{$_.FullName}
        $signature_path = Get-ChildItem -Path $js_destination_folder -Filter "signature" -Recurse | %{$_.FullName}

        try {
            # Create a new sso user
            Add-User -Username $sso_user_name -Password $sso_user_pwd

            try {
                # Create JSDR-elevated role and assign it to the newly created sso user
                New-Role -Username $sso_user_name -Role elevated

                # Deploy JetStream MSA
                $MSAIp=Deploy-JetDRMSA -OvfPath $ovf_path -SignaturePath $signature_path -Network $Network -Hostname $HostName -MSACredential $MSACredential -Gateway $Gateway -Dns $Dns -Ip $MSAIp -Netmask $Netmask -VlanId $VlanId -Cluster $Cluster -VmName $VMName -Datastore $Datastore
                if ($null -eq $MSAIp) {
                    write-error "Deployment of MSA succeeded but no IP is assigned to MSA, please check your network configuration and try again" -ErrorAction Stop
                }

                # Commenting these as they may not be required any more.
                #Invoke-VMScript -VM $VMName -ScriptText 'echo "jss.dr.vc.forceUnregister=true" >> /var/lib/vme2/conf/server.properties' -GuestUser $UserName -GuestPassword $Password | Out-Null
                #Invoke-VMScript -VM $VMName -ScriptText '/etc/init.d/vme2 restart' -GuestUser $UserName -GuestPassword $Password | Out-Null

                # Register JetStream MSA with vCenter
                Register-MS -MS $MSAIp -MsaUser $UserName -MsaPassword $Password -VC $VCFqdn -Username $sso_user_name -Password $sso_user_pwd -Mode $Mode -RegisterWithIp $RegisterWithIp

                # Create iofrest user if vCenter version is 8 or above
                $vcenter_8 = is_vcenter_8
                if ($vcenter_8) {
                    Enable-JetStreamRESTUser -MSAIp $MSAIp -MSACredential $MSACredential
                }

                # Configure cluster with JetStream software
                Install-Cluster -MS $MSAIp -VC $VCFqdn -Username $sso_user_name -Password $sso_user_pwd -Cluster $ProtectedCluster

                # Restart CIM service on hosts
                Restart-CIM $ProtectedCluster

                # Unregister JetStream MSA from vCenter
                Unregister-MS -MS $MSAIp -VC $VCFqdn -Username $sso_user_name -Password $sso_user_pwd
            } finally {
                # Delete permissions of JSDR-elevated role from sso user and delete the role from vCenter
                Remove-Role -Username $sso_user_name -Role elevated
            }
            try {
                # Create JSDR-operations role and assign it to the newly created sso user
                New-Role -Username $sso_user_name -Role operations

                # Register JetStream MSA with vCenter
                Register-MS -MS $MSAIp -MsaUser $UserName -MsaPassword $Password -VC $VCFqdn -Username $sso_user_name -Password $sso_user_pwd -Mode $Mode -RegisterWithIp $RegisterWithIp
            } finally {
                # Delete permissions of JSDR-operations role from sso user and delete the role from vCenter
                Remove-Role -Username $sso_user_name -Role operations
            }
        } finally {
            # Delete the sso user created for this task
            Remove-User -Username $sso_user_name
        }
    }
}

function Uninstall-JetDR {
<#
    .NOTES
    ===========================================================================
    Created by: JetStream Software Inc
    ===========================================================================

    .DESCRIPTION

    Unconfigures cluster, unregisters vCenter from the JetDr MSA

    .PARAMETER MSAIp
    MSA IP

    .PARAMETER MSACredential
    Credential of root user of MSA(root or PSCredential Object)

    .PARAMETER ProtectedCluster
    Cluster to be unconfigured

    .PARAMETER VMName
    Name of the MSA VM

    .EXAMPLE

    Uninstall-JetDR -MSAIp xxx.xxx.xxx.xxx -MSACredential <root/PSCredential Object> -ProtectedCluster Src-Cluster -VMName jsdr-msa

#>


    [CmdletBinding()]
    [AVSAttribute(30, UpdatesSDDC = $True)]
    param(
        [Parameter(Mandatory=$true,
                    HelpMessage="Ip of the MSA")]
        [String]$MSAIp,
        [Parameter(Mandatory=$true,
                    HelpMessage="Credential of the root user of MSA")]
        [System.Management.Automation.PSCredential]
        [System.Management.Automation.Credential()]
        $MSACredential,
        [Parameter(Mandatory=$true,
                    HelpMessage="Cluster to be unconfigured")]
        [String]$ProtectedCluster,
        [Parameter(Mandatory=$false,
                    HelpMessage="Name of the MSA VM")]
        [String]$VMName
    )
    Begin {
        $sso_user_name = "vsphere.local\jetdrusr"
        $sso_user_pwd=generate_password
        $VCFqdn = getVcFqdn
        $UserName = $MSACredential.UserName.trim()
        $Password = $MSACredential.GetNetworkCredential().Password.trim()

        #Trimming string parameters for any leading and trailing spaces
        foreach ($key in $($PSBoundParameters.keys)) {
            if ($PSBoundParameters[$key].GetType().Name -eq 'String') {
                $PSBoundParameters[$key] = $($PSBoundParameters[$key].trim())
                Set-Variable -Name $key -Value $($PSBoundParameters[$key].trim())
            }
        }

        $SecureFolder = [AVSSecureFolder]::GetOrCreate("js-appliance")
        if ('' -eq $VMName) {
            $msa_vms = Get-VM -Location $SecureFolder -Name msa@*+jetdr*
        }
        else {
            $msa_vms = Get-VM -Location $SecureFolder -Name $VMName -ErrorAction SilentlyContinue
            if ($null -eq $msa_vms) {
                $msa_vms = Get-VM $VMName -ErrorAction SilentlyContinue
            }
        }
        if ($null -eq $msa_vms) {
            Write-Error "Could not find MSA VM. Please rerun providing the correct VM name." -ErrorAction Stop
        }
        $msa_exists = $false
        foreach ($msa_vm in $msa_vms) {
            $vm_ip = (Get-VMGuest -VM (Get-VM -Name $msa_vm)).IPAddress
            if ($vm_ip -Contains $MSAIp) {
                Write-Host "IP of $msa_vm matches with provided $MSAIp"
                $msa_exists = $true
                break
            }
        }
        if ($msa_exists -eq $false) {
            Write-Error "The MSA Ip $MSAIp provided doesn't match with the ip of MSA VM" -ErrorAction Stop
        }
    }
    Process {
        # Run Preflight before uninstall
        Invoke-PreflightJetDRUninstall -MSAIp $MSAIp -MSACredential $MSACredential -ProtectedCluster $ProtectedCluster

        try {
            # Create a new sso user
            Add-User -Username $sso_user_name -Password $sso_user_pwd

            # Create JSDR-elevated role and assign it to the newly created sso user
            New-Role -Username $sso_user_name -Role elevated

            $registered_vc = get_registered_vcenter $MSAIp $UserName $Password
            # Check for presence of DR Virtual appliance before unregistering
            $fios_session_id = refresh_vc_session $MSAIp $registered_vc $sso_user_name $sso_user_pwd
            get_drvas $MSAIp $fios_session_id

            # Unconfigure JetStream software from cluster
            Uninstall-Cluster -MS $MSAIp -VC $registered_vc -Username $sso_user_name -Password $sso_user_pwd -Cluster $ProtectedCluster

            # Unregister JetStream MSA from vCenter
            Unregister-MS -MS $MSAIp -VC $registered_vc -Username $sso_user_name -Password $sso_user_pwd

            # Poweroff and delete MSA VM
            $result = msa_operation $msa_vm ([VmOperations]::ForcePowerOff)
            if ($result) {
                msa_operation $msa_vm ([VmOperations]::DeletePermanently)
            }
            else {
                Write-Error "Could not power off $msa_vm" -ErrorAction Stop
            }

        } finally {
            # Delete permissions of JSDR-elevated role from sso user and delete the role from vCenter
            Remove-Role -Username $sso_user_name -Role elevated

            # Delete the sso user created for this task
            Remove-User -Username $sso_user_name
        }
    }
}

function Invoke-PreflightJetDRInstall {
<#
    .NOTES
    ===========================================================================
    Created by: JetStream Software Inc
    ===========================================================================

    .DESCRIPTION

    Checks to display current state of the system and minimum requirement are met before deploying JeDR. It also checks for minimum of 3 hosts in a cluster, jetdr plugin if already present in vcenter and if a vm exists with same name as MSA

    .PARAMETER VMName
    Name of the MSA VM

    .PARAMETER Cluster
    Cluster where the MSA will be deployed

    .PARAMETER ProtectedCluster
    Cluster to be protected

    .PARAMETER Datastore
    Datastore where MSA will be deployed

    .PARAMETER Network
    Network mapping for the MSA to be deployed, e.g 'VM Network'

    .EXAMPLE

    Invoke-PreflightJetDRInstall -VMName jsdr-msa -Cluster MSA-Cluster -ProtectedCluster Src-Cluster -Datastore datastore-name -Network network-name

#>


    [CmdletBinding()]
    [AVSAttribute(5, UpdatesSDDC = $false)]
    param(
        [Parameter(Mandatory=$false,
                    HelpMessage="Name of MSA VM")]
        [String]$VMName="msa@4.3.0+jetdr",
        [Parameter(Mandatory=$true,
                    HelpMessage="Cluster Name where MSA will be deployed")]
        [String]$Cluster,
        [Parameter(Mandatory=$true,
                    HelpMessage="Cluster to be protected")]
        [String]$ProtectedCluster,
        [Parameter(Mandatory=$true,
                    HelpMessage="Datastore where MSA will be deployed")]
        [String]$Datastore,
        [Parameter(Mandatory=$true,
                    HelpMessage="Network mapping for the MSA to be deployed, e.g 'VM Network'")]
        [String]$Network
    )

    #Trimming string parameters for any leading and trailing spaces
    foreach ($key in $($PSBoundParameters.keys)) {
        if ($PSBoundParameters[$key].GetType().Name -eq 'String') {
            $PSBoundParameters[$key] = $($PSBoundParameters[$key].trim())
            Set-Variable -Name $key -Value $($PSBoundParameters[$key].trim())
        }
    }

    get_system_state_install $VMName $Cluster $ProtectedCluster $Datastore $Network
}

function Invoke-PreflightJetDRUninstall {
<#
    .NOTES
    ===========================================================================
    Created by: JetStream Software Inc
    ===========================================================================

    .DESCRIPTION

    Checks to display current state of the system and minimum requirement are met before uninstalling JeDR. It also checks for minimum of 4 hosts in a cluster

    .PARAMETER MSAIp

    Ip of the MSA

    .PARAMETER MSACredential

    root credentials of MSA

    .PARAMETER ProtectedCluster

    Cluster to be protected

    .EXAMPLE

    Invoke-PreflightJetDRUninstall -MSAIp xxx.xxx.xxx.xxx -MSACredential <root/PSCredential Object> -ProtectedCluster Src-Cluster

#>


    [CmdletBinding()]
    [AVSAttribute(5, UpdatesSDDC = $false)]
    param(
        [Parameter(Mandatory=$true,
                    HelpMessage="IP of MSA VM")]
        [String]$MSAIp,
        [Parameter(Mandatory=$true,
                    HelpMessage="Credential of the root user of MSA")]
        [System.Management.Automation.PSCredential]
        [System.Management.Automation.Credential()]
        $MSACredential,
        [Parameter(Mandatory=$true,
                    HelpMessage="Protected Cluster")]
        [String]$ProtectedCluster
    )

    if (!$MSACredential) {
        write-error "Please provide MSA credential, -MSACredential <root/PS Credential Object>" -ErrorAction Stop
    }
    else {
        $MSaUser = $MSACredential.UserName.trim()
        $MSaPassword = $MSACredential.GetNetworkCredential().Password.trim()
    }

    #Trimming string parameters for any leading and trailing spaces
    foreach ($key in $($PSBoundParameters.keys)) {
        if ($PSBoundParameters[$key].GetType().Name -eq 'String') {
            $PSBoundParameters[$key] = $($PSBoundParameters[$key].trim())
            Set-Variable -Name $key -Value $($PSBoundParameters[$key].trim())
        }
    }

    get_system_state_uninstall $MSAIp $ProtectedCluster $MSaUser $MSaPassword
}

function Invoke-PreflightJetDRSystemCheck {
<#
    .NOTES
    ===========================================================================
    Created by: JetStream Software Inc
    ===========================================================================

    .DESCRIPTION

    This Cmdlet checks and displays current state of the system
    It checks whether the minimal requirements for the script to run are met.

    .EXAMPLE

    Invoke-PreflightJetDRSystemCheck
#>


    [CmdletBinding()]
    param()
    Begin {
        $role = "CloudAdmin"
    }
    Process {
        checkPSVersion
        checkVcaddress
        checkRole $role
        checkModule "VMware.vSphere.SsoAdmin"
        checkModule "VMware.VimAutomation.Core"
        Write-Host "Invoke-PreflightJetDRSystemCheck option only checks required configuration in the system to execute other Cmdlets. For more detailed check, try running Invoke-PreflightJetDRInstall/Invoke-PreflightJetDRUninstall."
    }
}

function Enable-JetDRForCluster {
<#

    .NOTES
    ===========================================================================
    Created by: JetStream Software Inc
    ===========================================================================

    .DESCRIPTION

    Configures an additional cluster for protection. installs vib to all hosts in the cluster and creates storage policies.

    .PARAMETER MSAIp

    Ip of the MSA

    .PARAMETER MSACredential

    root credentials of MSA

    .PARAMETER ProtectedCluster

    Cluster to be protected

    .EXAMPLE

    Enable-JetDRForCluster -MSAIp xxx.xxx.xxx.xxx -MSACredential <root/PSCredential Object> -ProtectedCluster Src-Cluster

#>


    [CmdletBinding()]
    [AVSAttribute(20, UpdatesSDDC = $True)]
    param(
        [Parameter(Mandatory=$true,
                    HelpMessage="Ip of the MSA")]
        [String]$MSAIp,
        [Parameter(Mandatory=$true,
                    HelpMessage="Credentials of root user of the MSA to be deployed")]
        [ValidateNotNull()]
        [System.Management.Automation.PSCredential]
        [System.Management.Automation.Credential()]
        $MSACredential,
        [Parameter(Mandatory=$true,
                    HelpMessage="Cluster to be protected")]
        [String]$ProtectedCluster
    )
    Begin {
        $Mode = "C2C"
        $sso_user_name="vsphere.local\jetdrelevatedusr"
        $sso_user_pwd=generate_password
        $UserName = $MSACredential.UserName.trim()
        $Password = $MSACredential.GetNetworkCredential().Password.trim()

        #Trimming string parameters for any leading and trailing spaces
        foreach ($key in $($PSBoundParameters.keys)) {
            if ($PSBoundParameters[$key].GetType().Name -eq 'String') {
                $PSBoundParameters[$key] = $($PSBoundParameters[$key].trim())
                Set-Variable -Name $key -Value $($PSBoundParameters[$key].trim())
            }
        }
        $VCFqdn = getVcFqdn
    }
    Process {
        # Preflight checks for cluster configure
        get_system_state_configure $ProtectedCluster

        try {
            # Create a new sso user
            Add-User -Username $sso_user_name -Password $sso_user_pwd

            # Create JSDR-elevated role and assign it to the newly created sso user
            New-Role -Username $sso_user_name -Role elevated

            $registered_vc = get_registered_vcenter $MSAIp $UserName $Password
            # Configure cluster with JetStream software
            Install-Cluster -MS $MSAIp -VC $registered_vc -Username $sso_user_name -Password $sso_user_pwd -Cluster $ProtectedCluster

            # Restart CIM service on hosts
            Restart-CIM $ProtectedCluster
        } finally {
            # Delete permissions of JSDR-elevated role from sso user and delete the role from vCenter
            Remove-Role -Username $sso_user_name -Role elevated

            # Delete the sso user created for this task
            Remove-User -Username $sso_user_name
        }
    }
}

function Disable-JetDRForCluster {
<#

    .NOTES
    ===========================================================================
    Created by: JetStream Software Inc
    ===========================================================================

    .DESCRIPTION

    Unconfigures a cluster, uninstalls vibs from all hosts in the cluster and removes storage policies. It will not uninstall JetDR completely

    .PARAMETER MSAIp

    Ip of the MSA

    .PARAMETER MSACredential

    root credentials of MSA

    .PARAMETER ProtectedCluster

    Cluster to be unconfigured

    .EXAMPLE

    Disable-JetDRForCluster -MSAIp xxx.xxx.xxx.xxx -MSACredential <root/PSCredential Object> -ProtectedCluster Src-Cluster

#>


    [CmdletBinding()]
    [AVSAttribute(30, UpdatesSDDC = $True)]
    param(
        [Parameter(Mandatory=$true,
                    HelpMessage="Ip of the MSA")]
        [String]$MSAIp,
        [Parameter(Mandatory=$true,
                    HelpMessage="Credential of the root user of MSA")]
        [System.Management.Automation.PSCredential]
        [System.Management.Automation.Credential()]
        $MSACredential,
        [Parameter(Mandatory=$true,
                    HelpMessage="Cluster to be unconfigured")]
        [String]$ProtectedCluster
    )
    Begin {
        $sso_user_name = "vsphere.local\jetdrelevatedusr"
        $sso_user_pwd=generate_password
        $Mode = "C2C"
        $VCFqdn = getVcFqdn
        $UserName = $MSACredential.UserName.trim()
        $Password = $MSACredential.GetNetworkCredential().Password.trim()

        #Trimming string parameters for any leading and trailing spaces
        foreach ($key in $($PSBoundParameters.keys)) {
            if ($PSBoundParameters[$key].GetType().Name -eq 'String') {
                $PSBoundParameters[$key] = $($PSBoundParameters[$key].trim())
                Set-Variable -Name $key -Value $($PSBoundParameters[$key].trim())
            }
        }
    }
    Process {
        # Preflight check for cluster unconfigure
        Invoke-PreflightJetDRUninstall -MSAIp $MSAIp -MSACredential $MSACredential -ProtectedCluster $ProtectedCluster

        try {
            # Create a new sso user
            Add-User -Username $sso_user_name -Password $sso_user_pwd

            # Create JSDR-elevated role and assign it to the newly created sso user
            New-Role -Username $sso_user_name -Role elevated

            $registered_vc = get_registered_vcenter $MSAIp $UserName $Password
            # Unconfigure JetStream software from cluster
            Uninstall-Cluster -MS $MSAIp -VC $registered_vc -Username $sso_user_name -Password $sso_user_pwd -Cluster $ProtectedCluster
        } finally {
            # Delete permissions of JSDR-elevated role from sso user and delete the role from vCenter
            Remove-Role -Username $sso_user_name -Role elevated

            # Delete the sso user created for this task
            Remove-User -Username $sso_user_name
        }
    }
}

function Update-JetDRMSA {
<#

    .NOTES
    ===========================================================================
    Created by: JetStream Software Inc
    ===========================================================================

    .DESCRIPTION

    Upgrades JetDR MSA and plugin to latest available update.

    .PARAMETER MSAIp
    Ip of the MSA

    .PARAMETER MSACredential
    root credentials of MSA

    .PARAMETER Datacenter
    Datacenter which manages the clusters

    .PARAMETER Datastore
    Datastore where upgrade iso will be copied

    .PARAMETER VMName
    MSA VM name where upgrade iso will be mounted

    .EXAMPLE

    Update-JetDRMSA -MSAIp xxx.xxx.xxx.xxx -MSACredential <root/PSCredential Object> -Datacenter Datacenter -Datastore shared-ds -VMName js-dr

#>


    [CmdletBinding()]
    [AVSAttribute(30, UpdatesSDDC = $False)]
    param(
        [Parameter(Mandatory=$true,
                    HelpMessage="Ip of the MSA")]
        [String]$MSAIp,
        [Parameter(Mandatory=$true,
                    HelpMessage="Credential of the root user of MSA")]
        [System.Management.Automation.PSCredential]
        [System.Management.Automation.Credential()]
        $MSACredential,
        [Parameter(Mandatory=$true,
                    HelpMessage="Datacenter name")]
        [String]$Datacenter,
        [Parameter(Mandatory=$true,
                    HelpMessage="Datastore where upgrade iso will be copied")]
        [String]$Datastore,
        [Parameter(Mandatory=$true,
                    HelpMessage="MSA VM name where upgrade iso will be mounted")]
        [String]$VMName
    )
    Begin {
        # Script assumes that directory it is executed in is temporary
        $DownloadPath = "."

        $js_download_path = $DownloadPath
        $js_destination_folder = $js_download_path + "/js_unzipped/"
        $UserName = $MSACredential.UserName.trim()
        $Password = $MSACredential.GetNetworkCredential().Password.trim()
        $VCFqdn = getVcFqdn

        #Trimming string parameters for any leading and trailing spaces
        foreach ($key in $($PSBoundParameters.keys)) {
            if ($PSBoundParameters[$key].GetType().Name -eq 'String') {
                $PSBoundParameters[$key] = $($PSBoundParameters[$key].trim())
                Set-Variable -Name $key -Value $($PSBoundParameters[$key].trim())
            }
        }
    }
    Process {
        # Download JetDR bundle from MMS
        $js_zip = Split-Path $js_url -Leaf
        Get-JetDR -Url $js_url -DownloadPath $js_download_path

        # Unzip JetDR bundle to specified location
        Expand-JetDR -FileName $js_zip -FilePath $js_download_path -UnzipPath $js_destination_folder

        $iso_path = Get-ChildItem -Path $js_destination_folder -Filter "jetstream*iso" -Recurse | %{$_.FullName}
        $signature_path = Get-ChildItem -Path $js_destination_folder -Filter "signature_iso" -Recurse | %{$_.FullName}
        updateMSA $MSAIp $UserName $Password $Datacenter $Datastore $VMName $iso_path $signature_path
    }
}

function Update-DRVAs {
<#

    .NOTES
    ===========================================================================
    Created by: JetStream Software Inc
    ===========================================================================

    .DESCRIPTION

    Upgrades JetDR DRVAs to latest available update.

    .PARAMETER MSAIp
    Ip of the MSA

    .PARAMETER VC
    vCenter ip/fqdn

    .PARAMETER Username
    Username of the new sso user, e.g vsphere.local\tmpuser

    .PARAMETER Password
    Password of the new sso user

    .EXAMPLE

    Update-DRVAs -MSAIp xxx.xxx.xxx.xxx -VC xxx.xxx.xxx.xxx -Username vsphere.local\tmpuser -Password ***

#>


    [CmdletBinding()]
    [AVSAttribute(60, UpdatesSDDC = $False)]
    param(
        [Parameter(Mandatory=$true,
                    HelpMessage="Ip of the MSA")]
        [String]$MSAIp,

        [Parameter(Mandatory=$true,
                    HelpMessage="ip/fqdn of vCenter")]
        [string]$VC,

        [Parameter(Mandatory=$true,
                    HelpMessage="sso username with which vCenter will be registered")]
        [string]$Username,

        [Parameter(Mandatory=$true,
                    HelpMessage="sso user password")]
        [string]$Password
    )
    Process {
            $fios_session_id = refresh_vc_session $MSAIp $VC $Username $Password
            upgrade_drvas $MSAIp $fios_session_id
    }
}

function Update-RECOVERYVAs {
<#

    .NOTES
    ===========================================================================
    Created by: JetStream Software Inc
    ===========================================================================

    .DESCRIPTION

    Upgrades JetDR RECOVERY VAs to latest available update.

    .PARAMETER MSAIp
    Ip of the MSA

    .PARAMETER VC
    vCenter ip/fqdn

    .PARAMETER Username
    Username of the new sso user, e.g vsphere.local\tmpuser

    .PARAMETER Password
    Password of the new sso user

    .EXAMPLE

    Update-RECOVERYVAs -MSAIp xxx.xxx.xxx.xxx -VC xxx.xxx.xxx.xxx -Username vsphere.local\tmpuser -Password ***

#>


    [CmdletBinding()]
    [AVSAttribute(60, UpdatesSDDC = $False)]
    param(
        [Parameter(Mandatory=$true,
                    HelpMessage="Ip of the MSA")]
        [String]$MSAIp,

        [Parameter(Mandatory=$true,
                    HelpMessage="ip/fqdn of vCenter")]
        [string]$VC,

        [Parameter(Mandatory=$true,
                    HelpMessage="sso username with which vCenter will be registered")]
        [string]$Username,

        [Parameter(Mandatory=$true,
                    HelpMessage="sso user password")]
        [string]$Password
    )
    Process {
            $fios_session_id = refresh_vc_session $MSAIp $VC $Username $Password
            upgrade_recovery_vas $MSAIp $fios_session_id
    }
}

function Update-JetDRCluster {
<#

    .NOTES
    ===========================================================================
    Created by: JetStream Software Inc
    ===========================================================================

    .DESCRIPTION

    Upgrades JetDR iofilter to latest available update.

    .PARAMETER MSAIp
    Ip of the MSA

    .PARAMETER MSACredential
    Credentials of root user of MSA

    .PARAMETER VMName
    MSA VM Name

    .PARAMETER VC
    vCenter ip/fqdn

    .PARAMETER Username
    Username of the new sso user, e.g vsphere.local\tmpuser

    .PARAMETER Password
    Password of the new sso user

    .PARAMETER MajorUpgrade
    Major version upgrade

    .EXAMPLE

    Update-JetDRCluster -MSAIp xxx.xxx.xxx.xxx -VC xxx.xxx.xxx.xxx -Username vsphere.local\tmpuser -Password *** -MSAUser root -MSAPassword *** -VMName js-dr -MajorUpgrade $false

#>


    [CmdletBinding()]
    [AVSAttribute(30, UpdatesSDDC = $True)]
    param(
        [Parameter(Mandatory=$true,
                    HelpMessage="Ip of the MSA")]
        [String]$MSAIp,

        [Parameter(Mandatory=$true,
                    HelpMessage="Credential of the root user of MSA")]
        [System.Management.Automation.PSCredential]
        [System.Management.Automation.Credential()]
        $MSACredential,

        [Parameter(Mandatory=$true,
                    HelpMessage="MSA VM name")]
        [String]$VMName,

        [Parameter(Mandatory=$true,
                    HelpMessage="ip/fqdn of vCenter")]
        [string]$VC,

        [Parameter(Mandatory=$true,
                    HelpMessage="sso username with which vCenter will be registered")]
        [string]$Username,

        [Parameter(Mandatory=$true,
                    HelpMessage="sso user password")]
        [string]$Password,

        [Parameter(Mandatory=$true,
                    HelpMessage="Major version upgrade")]
        [bool]$MajorUpgrade
    )
    Begin {
        $UserName = $MSACredential.UserName.trim()
        $Password = $MSACredential.GetNetworkCredential().Password.trim()
    }
    Process {
        $fios_session_id = refresh_vc_session $MSAIp $VC $sso_user_name $sso_user_pwd
        update_clusters $MSAIp $fios_session_id $UserName $Password $VMName $MajorUpgrade
    }
}

function Update-JetDR {
<#

    .NOTES
    ===========================================================================
    Created by: JetStream Software Inc
    ===========================================================================

    .DESCRIPTION

    Upgrades JetDR components to latest available update.

    .PARAMETER Resume
    Resume upgrade

    .PARAMETER MSAIp
    Ip of the MSA

    .PARAMETER MSACredential
    root credentials of MSA

    .PARAMETER Datacenter
    Datacenter which manages the clusters

    .PARAMETER Datastore
    Datastore where upgrade iso will be copied

    .PARAMETER MSAVMName
    MSA VM name where upgrade iso will be mounted

    .EXAMPLE

    Update-JetDR -MSAIp xxx.xxx.xxx.xxx -MSACredential <root/PSCredential Object> -Datacenter Datacenter -Datastore shared-ds -MSAVMName js-dr

#>


    [CmdletBinding()]
    [AVSAttribute(180, UpdatesSDDC = $False)]
    param(
        [Parameter(Mandatory=$false,
                    HelpMessage="Resume upgrade if it failed at some point after upgrading MSA")]
        [Bool]$Resume,
        [Parameter(Mandatory=$true,
                    HelpMessage="Ip of the MSA")]
        [String]$MSAIp,
        [Parameter(Mandatory=$true,
                    HelpMessage="Credential of the root user of MSA")]
        [System.Management.Automation.PSCredential]
        [System.Management.Automation.Credential()]
        $MSACredential,
        [Parameter(Mandatory=$true,
                    HelpMessage="Datacenter name")]
        [String]$Datacenter,
        [Parameter(Mandatory=$true,
                    HelpMessage="Datastore where upgrade iso will be copied")]
        [String]$Datastore,
        [Parameter(Mandatory=$false,
                    HelpMessage="MSA VM name where upgrade iso will be mounted")]
        [String]$MSAVMName
    )
    Begin {
        $sso_user_name = "vsphere.local\jetdrelevatedusr"
        $sso_user_pwd=generate_password
        $UserName = $MSACredential.UserName.trim()
        $Password = $MSACredential.GetNetworkCredential().Password.trim()
        $VCFqdn = getVcFqdn

        #Trimming string parameters for any leading and trailing spaces
        foreach ($key in $($PSBoundParameters.keys)) {
            if ($PSBoundParameters[$key].GetType().Name -eq 'String') {
                $PSBoundParameters[$key] = $($PSBoundParameters[$key].trim())
                Set-Variable -Name $key -Value $($PSBoundParameters[$key].trim())
            }
        }

        # Check if provided datacenter exists
        $dc_obj=Get-DataCenter $Datacenter -ErrorAction SilentlyContinue
        if ($dc_obj -eq $null) {
            Write-Error "Specified datacenter $Datacenter not found. Please provide a correct name." -ErrorAction Stop
        }

        # Check if provided datastore exists in the datacenter
        $ds_obj=Get-DataStore $Datastore -Location $dc_obj -ErrorAction SilentlyContinue
        if ($ds_obj -eq $null) {
            Write-Error "Specified datastore $Datastore not found in the datacenter. Please provide a correct datastore name." -ErrorAction Stop
        }

        $SecureFolder = [AVSSecureFolder]::GetOrCreate("js-appliance")
        if ('' -eq $MSAVMName) {
            $MSAVMName = 'msa@*+jetdr*'
            $msa_vms = Get-VM -Location $SecureFolder -Name $MSAVMName
        }
        else {
            $msa_vms = Get-VM -Location $SecureFolder -Name $MSAVMName -ErrorAction SilentlyContinue
            if ($null -eq $msa_vms) {
                $msa_vms = Get-VM $MSAVMName -ErrorAction SilentlyContinue
            }
        }
        if ($null -eq $msa_vms) {
            Write-Error "Could not find MSA VM. Please rerun providing the correct VM name." -ErrorAction Stop
        }
        $msa_exists = $false
        foreach ($msa_vm in $msa_vms) {
            $vm_ip = (Get-VMGuest -VM (Get-VM -Name $msa_vm)).IPAddress
            if ($vm_ip -Contains $MSAIp) {
                Write-Host "IP of $msa_vm matches with provided $MSAIp"
                $msa_exists = $true
                $MSAVMName = $msa_vm
                break
            }
        }
        if (!$msa_exists) {
            Write-Error "The MSA Ip $MSAIp provided doesn't match with the ip of MSA VM" -ErrorAction Stop
        }
        $MajorUpgrade = compare_upgrade_builds $js_url
    }
    Process {
        try {
            # Create a new sso user
            Add-User -Username $sso_user_name -Password $sso_user_pwd

            # Create JSDR-elevated role and assign it to the newly created sso user
            New-Role -Username $sso_user_name -Role elevated
            if (!$Resume) {
                if ($MajorUpgrade) {
                    Update-JetDRMSAMajor -MSACredential $MSACredential -Datacenter $Datacenter -Datastore $Datastore -VMName $MSAVMName
                }
                else {
                    Update-JetDRMSA -MSAIp $MSAIp -MSACredential $MSACredential -Datacenter $Datacenter -Datastore $Datastore -VMName $MSAVMName
                }
            }
            $registered_vc = get_registered_vcenter $MSAIp $UserName $Password
            Update-DRVAs -MSAIp $MSAIp -VC $registered_vc -Username $sso_user_name -Password $sso_user_pwd
            Update-RECOVERYVAs -MSAIp $MSAIp -VC $registered_vc -Username $sso_user_name -Password $sso_user_pwd
            Update-JetDRCluster -MSAIp $MSAIp -VC $registered_vc -Username $sso_user_name -Password $sso_user_pwd -MSACredential $MSACredential -VMName $MSAVMName -MajorUpgrade $MajorUpgrade
        } finally {
            # Delete permissions of JSDR-elevated role from sso user and delete the role from vCenter
            Remove-Role -Username $sso_user_name -Role elevated

            # Delete the sso user created for this task
            Remove-User -Username $sso_user_name
        }
    }
}

function Resolve-HostIssue {
<#

    .NOTES
    ===========================================================================
    Created by: JetStream Software Inc
    ===========================================================================

    .DESCRIPTION

    Resolves last failed vCenter task on the host.

    .PARAMETER MSAIp
    Ip of the MSA

    .PARAMETER MSACredential
    root credentials of MSA

    .PARAMETER ProtectedCluster
    Cluster where the host resides

    .PARAMETER ESXHost
    Host where resolve issue will be done

    .EXAMPLE

    Resolve-HostIssue -MSAIp xxx.xxx.xxx.xxx -MSACredential <root/PSCredential Object> -ProtectedCluster Src-Cluster -ESXHost esxi-host-name

#>


    [CmdletBinding()]
    [AVSAttribute(30, UpdatesSDDC = $True)]
    param(
        [Parameter(Mandatory=$true,
                    HelpMessage="Ip of the MSA")]
        [String]$MSAIp,
        [Parameter(Mandatory=$true,
                    HelpMessage="Credential of the root user of MSA")]
        [System.Management.Automation.PSCredential]
        [System.Management.Automation.Credential()]
        $MSACredential,
        [Parameter(Mandatory=$true,
                    HelpMessage="Cluster where the host resides")]
        [String]$ProtectedCluster,
        [Parameter(Mandatory=$true,
                    HelpMessage="Host where resolve issue will be done")]
        [String]$ESXHost
    )
    Begin {
        $sso_user_name = "vsphere.local\jetdrelevatedusr"
        $sso_user_pwd=generate_password
        $Mode = "C2C"
        $VCFqdn = getVcFqdn
        $UserName = $MSACredential.UserName.trim()
        $Password = $MSACredential.GetNetworkCredential().Password.trim()

        #Trimming string parameters for any leading and trailing spaces
        foreach ($key in $($PSBoundParameters.keys)) {
            if ($PSBoundParameters[$key].GetType().Name -eq 'String') {
                $PSBoundParameters[$key] = $($PSBoundParameters[$key].trim())
                Set-Variable -Name $key -Value $($PSBoundParameters[$key].trim())
            }
        }
    }
    Process {
        Invoke-PreflightJetDRUninstall -MSAIp $MSAIp -MSACredential $MSACredential -ProtectedCluster $ProtectedCluster
        try {
            # Create a new sso user
            Add-User -Username $sso_user_name -Password $sso_user_pwd

            # Create JSDR-elevated role and assign it to the newly created sso user
            New-Role -Username $sso_user_name -Role elevated

            $registered_vc = get_registered_vcenter $MSAIp $UserName $Password
            $fios_session_id = refresh_vc_session $MSAIp $registered_vc $sso_user_name $sso_user_pwd
            $status = resolveHostIssue $MSAIp $ProtectedCluster $ESXHost $fios_session_id
            $vcenter_8 = is_vcenter_8

            if (($status -eq 0) -and (!$vcenter_8)) {
                # Restart CIM service on hosts
                Write-Host "Restarting CIM"
                Get-VMHost -name $ESXhost | Get-VMHostService | where {$_.key -eq 'sfcbd-watchdog'} | Stop-VMHostService -Confirm:$false
                Get-VMHost -name $ESXhost | Get-VMHostService | where {$_.key -eq 'sfcbd-watchdog'} | Start-VMHostService -Confirm:$false
            }
        } finally {
            # Delete permissions of JSDR-elevated role from sso user and delete the role from vCenter
            Remove-Role -Username $sso_user_name -Role elevated

            # Delete the sso user created for this task
            Remove-User -Username $sso_user_name
        }
    }
}


function Resolve-ClusterIssue {
<#

    .NOTES
    ===========================================================================
    Created by: JetStream Software Inc
    ===========================================================================

    .DESCRIPTION

    Resolves the errors occured during an install/uninstall/upgrade operation of an IO Filter on a cluster.

    .PARAMETER MSAIp
    Ip of the MSA

    .PARAMETER MSACredential
    root credentials of MSA

    .PARAMETER ProtectedCluster
    Cluster where resolve issue will be done

    .EXAMPLE

    Resolve-ClusterIssue -MSAIp xxx.xxx.xxx.xxx -MSACredential <root/PSCredential Object> -ProtectedCluster Src-Cluster

#>


    [CmdletBinding()]
    [AVSAttribute(30, UpdatesSDDC = $True)]
    param(
        [Parameter(Mandatory=$true,
                    HelpMessage="Ip of the MSA")]
        [String]$MSAIp,
        [Parameter(Mandatory=$true,
                    HelpMessage="Credential of the root user of MSA")]
        [System.Management.Automation.PSCredential]
        [System.Management.Automation.Credential()]
        $MSACredential,
        [Parameter(Mandatory=$true,
                    HelpMessage="Cluster where resolve issue will be done")]
        [String]$ProtectedCluster
    )
    Begin {
        $sso_user_name = "vsphere.local\jetdrelevatedusr"
        $sso_user_pwd=generate_password
        $Mode = "C2C"
        $VCFqdn = getVcFqdn
        $UserName = $MSACredential.UserName.trim()
        $Password = $MSACredential.GetNetworkCredential().Password.trim()

        #Trimming string parameters for any leading and trailing spaces
        foreach ($key in $($PSBoundParameters.keys)) {
            if ($PSBoundParameters[$key].GetType().Name -eq 'String') {
                $PSBoundParameters[$key] = $($PSBoundParameters[$key].trim())
                Set-Variable -Name $key -Value $($PSBoundParameters[$key].trim())
            }
        }
    }
    Process {
        Invoke-PreflightJetDRUninstall -MSAIp $MSAIp -MSACredential $MSACredential -ProtectedCluster $ProtectedCluster
        try {
            # Create a new sso user
            Add-User -Username $sso_user_name -Password $sso_user_pwd

            # Create JSDR-elevated role and assign it to the newly created sso user
            New-Role -Username $sso_user_name -Role elevated

            $registered_vc = get_registered_vcenter $MSAIp $UserName $Password
            $fios_session_id = refresh_vc_session $MSAIp $registered_vc $sso_user_name $sso_user_pwd
            $status = resolveClusterIssue $MSAIp $ProtectedCluster $fios_session_id

            if ($status -eq 0) {
                # Restart CIM service on all hosts
                restart_cim $ProtectedCluster
            }

        } finally {
            # Delete permissions of JSDR-elevated role from sso user and delete the role from vCenter
            Remove-Role -Username $sso_user_name -Role elevated

            # Delete the sso user created for this task
            Remove-User -Username $sso_user_name
        }
    }
}

function Register-JetDRPlugin {
<#

    .NOTES
    ===========================================================================
    Created by: JetStream Software Inc
    ===========================================================================

    .DESCRIPTION
    Registers JetDR plugin to vCenter

    .PARAMETER MSAIp
    Ip of the MSA

    .PARAMETER MSACredential
    root credentials of MSA

    .PARAMETER RegisterWithIp
    Register MSA with Ip instead of hostname

    .EXAMPLE

    Register-JetDRPlugin -MSAIp xxx.xxx.xxx.xxx -MSACredential <root/PSCredential Object> -RegisterWithIp:$true

#>


    [CmdletBinding()]
    [AVSAttribute(5, UpdatesSDDC = $False)]
    param(
        [Parameter(Mandatory=$true,
                    HelpMessage="Ip of the MSA")]
        [String]$MSAIp,
        [Parameter(Mandatory=$true,
                    HelpMessage="Credential of the root user of MSA")]
        [System.Management.Automation.PSCredential]
        [System.Management.Automation.Credential()]
        $MSACredential,
        [Parameter(Mandatory=$false,
                    HelpMessage="Register MSA with Ip instead of hostname.")]
        [Bool]$RegisterWithIp=$true
    )
    Begin {
        $sso_user_name = "vsphere.local\jetdrusr"
        $sso_user_pwd=generate_password
        $Mode = "C2C"
        $VCFqdn = getVcFqdn
        $UserName = $MSACredential.UserName.trim()
        $Password = $MSACredential.GetNetworkCredential().Password.trim()

        #Trimming string parameters for any leading and trailing spaces
        foreach ($key in $($PSBoundParameters.keys)) {
            if ($PSBoundParameters[$key].GetType().Name -eq 'String') {
                $PSBoundParameters[$key] = $($PSBoundParameters[$key].trim())
                Set-Variable -Name $key -Value $($PSBoundParameters[$key].trim())
            }
        }
    }
    Process {
        try {
            # Create a new sso user
            Add-User -Username $sso_user_name -Password $sso_user_pwd

            # Create JSDR-operations role and assign it to the newly created sso user
            New-Role -Username $sso_user_name -Role operations

            Write-Host "Registering MSA with vCenter $VCFqdn"
            # Register JetStream MSA with vCenter
            Register-MS -MS $MSAIp -MsaUser $UserName -MsaPassword $Password -VC $VCFqdn -Username $sso_user_name -Password $sso_user_pwd -Mode $Mode -RegisterWithIp $RegisterWithIp
        } finally {
            # Delete permissions of JSDR-operations role from sso user and delete the role from vCenter
            Remove-Role -Username $sso_user_name -Role operations

            # Delete the sso user created for this task
            Remove-User -Username $sso_user_name
        }
    }
}

function Unregister-JetDRPlugin {
<#

    .NOTES
    ===========================================================================
    Created by: JetStream Software Inc
    ===========================================================================

    .DESCRIPTION
    Unregisters JetDR plugin from vCenter

    .PARAMETER MSAIp
    Ip of the MSA

    .PARAMETER MSACredential
    Credential of root user of MSA

    .EXAMPLE

    Unregister-JetDRPlugin -MSAIp xxx.xxx.xxx.xxx -MSACredential <root/PSCredential Object>

#>


    [CmdletBinding()]
    [AVSAttribute(5, UpdatesSDDC = $False)]
    param(
        [Parameter(Mandatory=$false,
                    HelpMessage="Ip of the MSA. Leave blank if MSA is not available.")]
        [String]$MSAIp,
        [Parameter(Mandatory=$false,
                    HelpMessage="Credential of the root user of MSA. Leave blank if MSA is not available.")]
        [System.Management.Automation.PSCredential]
        [System.Management.Automation.Credential()]
        $MSACredential
    )
    Begin {
        $sso_user_name = "vsphere.local\jetdrusr"
        $sso_user_pwd=generate_password
        $VCFqdn = getVcFqdn
        if ( $MSACredential -ne $null ) {
            $UserName = $MSACredential.UserName.trim()
            $Password = $MSACredential.GetNetworkCredential().Password.trim()
        }
        if (( $MSAIp -ne "" ) -And ( $MSACredential -eq $null )) {
            write-error "MSA ip is provided, but MSA credentials are missing. Please run again with proper root credentials of MSA." -ErrorAction Stop
        }
        #Trimming string parameters for any leading and trailing spaces
        foreach ($key in $($PSBoundParameters.keys)) {
            if ($PSBoundParameters[$key].GetType().Name -eq 'String') {
                $PSBoundParameters[$key] = $($PSBoundParameters[$key].trim())
                Set-Variable -Name $key -Value $($PSBoundParameters[$key].trim())
            }
        }
    }
    Process {
        try {
                # Create a new sso user
                Add-User -Username $sso_user_name -Password $sso_user_pwd

                # Create JSDR-operations role and assign it to the newly created sso user
                New-Role -Username $sso_user_name -Role operations

                if ( $MSAIp -ne "") {
                    $registered_vc = get_registered_vcenter $MSAIp $UserName $Password
                    # Unregister JetStream MSA from vCenter
                    Unregister-MS -MS $MSAIp -VC $registered_vc -Username $sso_user_name -Password $sso_user_pwd
                }
                else {
                    # Force unregister JetStream MSA from vCenter
                    force_unregister_ms
                }
        } finally {
            # Delete permissions of JSDR-operations role from sso user and delete the role from vCenter
            Remove-Role -Username $sso_user_name -Role operations

            # Delete the sso user created for this task
            Remove-User -Username $sso_user_name
        }
    }
}

function Restart-JetDRDaemon {
<#

    .NOTES
    ===========================================================================
    Created by: JetStream Software Inc
    ===========================================================================

    .DESCRIPTION
    Restarts JetDR daemon on every host in the cluster

    .PARAMETER ProtectedCluster
    Cluster where daemon should be restarted for all hosts

    .EXAMPLE
    Restart-JetDRDaemon -ProtectedCluster Src-Cluster

#>

[CmdletBinding()]
    [AVSAttribute(5, UpdatesSDDC = $False)]
    param(
        [Parameter(Mandatory=$true,
                    HelpMessage="Cluster where daemon should be restarted for all hosts")]
        [String]$ProtectedCluster
    )
    Process {
        restart_jetdr $ProtectedCluster
    }
}

function Test-JetDRApplianceConnection {
<#

    .NOTES
    ===========================================================================
    Created by: JetStream Software Inc
    ===========================================================================

    .DESCRIPTION
    Checks connection from Run Cmd infra to JetSream MSA

    .PARAMETER MSAIp
    MSA Ip

    .EXAMPLE
    Test-JetDRApplianceConnection -MSAIp xxx.xxx.xxx.xxx

#>

[CmdletBinding()]
    [AVSAttribute(5, UpdatesSDDC = $False)]
    param(
        [Parameter(Mandatory=$true,
                    HelpMessage="IP of the MSA")]
        [String]$MSAIp
    )
    Process {
        test_jetdr_conn $MSAIp
    }
}

function Enable-JetDRSshd {
<#

    .NOTES
    ===========================================================================
    Created by: JetStream Software Inc
    ===========================================================================

    .DESCRIPTION
    Starts sshd on JetSream MSA

    .PARAMETER VMName
    MSA VM Name

    .PARAMETER MSACredential
    MSACredential of root user

    .EXAMPLE
    Enable-JetDRSshd -VMName JS-MSA -MSACredential xxx

#>

    [CmdletBinding()]
    [AVSAttribute(5, UpdatesSDDC = $False)]
    param(
        [Parameter(Mandatory=$False,
                    HelpMessage="Name of the MSA VM")]
        [String]$VmName="msa@4.3.0+jetdr",

        [Parameter(Mandatory=$true,
                    HelpMessage="MSA Credentials of root user")]
        [ValidateNotNull()]
        [System.Management.Automation.PSCredential]
        [System.Management.Automation.Credential()]
        $MSACredential
    )
    Begin {
        $UserName = $MSACredential.UserName.trim()
        $Password = $MSACredential.GetNetworkCredential().Password.trim()
    }
    Process {
        $msa_vm = Get-VM $VMName -ErrorAction SilentlyContinue
        if ($null -eq $msa_vm) {
            Write-Error "Could not find MSA VM. Please rerun providing the correct VM name." -ErrorAction Stop
        }
        $status_out = Invoke-VMScript -VM $VMName -ScriptText 'service sshd status' -GuestUser $UserName -GuestPassword $Password
        if($status_out.ExitCode -ne 0) {
            Write-Host "sshd service is not running on $VMName. Starting the service..."
            $start_out = Invoke-VMScript -VM $VMName -ScriptText 'service sshd start' -GuestUser $UserName -GuestPassword $Password
            if($start_out.ExitCode -eq 0) {
                Write-Host "Successfully started sshd on $VMName. For security reasons, please make sure to stop it once you are done by calling Disable-JetDRSshd"
            }
            else {
                Write-Error "Could not start sshd on $VMName" -ErrorAction Stop
            }
        }
        else {
            Write-Host "sshd service is already running on $VMname. For security reasons, please make sure to stop it if it is not needed by calling Disable-JetDRSshd."
        }
    }
}

function Disable-JetDRSshd {
<#

    .NOTES
    ===========================================================================
    Created by: JetStream Software Inc
    ===========================================================================

    .DESCRIPTION
    Stops sshd on JetSream MSA

    .PARAMETER VMName
    MSA VM Name

    .PARAMETER MSACredential
    MSACredential of root user

    .EXAMPLE
    Disable-JetDRSshd -VMName JS-MSA -MSACredential xxx

#>

    [CmdletBinding()]
    [AVSAttribute(5, UpdatesSDDC = $False)]
    param(
        [Parameter(Mandatory=$False,
                    HelpMessage="Name of the MSA VM")]
        [String]$VmName="msa@4.3.0+jetdr",

        [Parameter(Mandatory=$true,
                    HelpMessage="MSA Credentials of root user")]
        [ValidateNotNull()]
        [System.Management.Automation.PSCredential]
        [System.Management.Automation.Credential()]
        $MSACredential
    )
    Begin {
        $UserName = $MSACredential.UserName.trim()
        $Password = $MSACredential.GetNetworkCredential().Password.trim()
    }
    Process {
        $msa_vm = Get-VM $VMName -ErrorAction SilentlyContinue
        if ($null -eq $msa_vm) {
            Write-Error "Could not find MSA VM. Please rerun providing the correct VM name." -ErrorAction Stop
        }
        $status_out = Invoke-VMScript -VM $VMName -ScriptText 'service sshd status' -GuestUser $UserName -GuestPassword $Password
        if($status_out.ExitCode -eq 0) {
            Write-Host "sshd service is running on $VMName. Stopping the service..."
            $stop_out = Invoke-VMScript -VM $VMName -ScriptText 'service sshd stop' -GuestUser $UserName -GuestPassword $Password
            if($stop_out.ExitCode -eq 0) {
                Write-Host "Successfully stopped sshd on $VMName."
            }
            else {
                Write-Error "Could not stop sshd on $VMName" -ErrorAction Stop
            }
        }
        else {
            Write-Host "sshd service is already stopped on $VMname."
        }
    }
}

function Update-JetDRMSAMajor {
<#

    .NOTES
    ===========================================================================
    Created by: JetStream Software Inc
    ===========================================================================

    .DESCRIPTION
    Upgrades JetDR MSA and plugin to the latest available Major version MSA.

    .PARAMETER MSACredential
    root credentials of MSA

    .PARAMETER Datacenter
    Datacenter which manages the clusters

    .PARAMETER Datastore
    Datastore where new MSA will be deployed

    .PARAMETER VMName
    Current MSA VMName to copy configuration details

    .EXAMPLE
    Update-JetDRMSAMajor -MSACredential <root/PSCredential Object> -Datacenter Datacenter -Datastore shared-ds -VMName js-dr

#>


    [CmdletBinding()]
    [AVSAttribute(30, UpdatesSDDC = $False)]
    param(
        [Parameter(Mandatory=$true,
                    HelpMessage="Credential of the root user of MSA")]
        [System.Management.Automation.PSCredential]
        [System.Management.Automation.Credential()]
        $MSACredential,
        [Parameter(Mandatory=$true,
                    HelpMessage="Datacenter name")]
        [String]$Datacenter,
        [Parameter(Mandatory=$true,
                    HelpMessage="Datastore where new MSA will be deployed")]
        [String]$Datastore,
        [Parameter(Mandatory=$true,
                    HelpMessage="Current MSA VMName to copy configuration details")]
        [String]$VMName
    )
    Begin {
        # Script assumes that directory it is executed in is temporary
        $DownloadPath = "."
        $js_download_path = $DownloadPath
        $js_destination_folder = $js_download_path + "/js_unzipped/"
        $UserName = $MSACredential.UserName.trim()
        $Password = $MSACredential.GetNetworkCredential().Password.trim()
        $VCFqdn = getVcFqdn

        #Trimming string parameters for any leading and trailing spaces
        foreach ($key in $($PSBoundParameters.keys)) {
            if ($PSBoundParameters[$key].GetType().Name -eq 'String') {
                $PSBoundParameters[$key] = $($PSBoundParameters[$key].trim())
                Set-Variable -Name $key -Value $($PSBoundParameters[$key].trim())
            }
        }
        $Cluster = $($(Get-VM -Name $VMName) | Get-Cluster).Name
        $Network = $($(Get-VM -Name $VMName) | Get-NetworkAdapter).NetworkName
        $New_VMName = "msa@4.3.0+jetdr"
        $Gateway = ""
        $Dns = ""
        $MSAIp = ""
        $Netmask = ""
        $VlanId = ""
        $HostName = ""
        $msa_has_ip = $false

    }
    Process {
        # Download JetDR bundle from MMS
        $js_zip = Split-Path $js_url -Leaf
        Get-JetDR -Url $js_url -DownloadPath $js_download_path

        # Unzip JetDR bundle to specified location
        Expand-JetDR -FileName $js_zip -FilePath $js_download_path -UnzipPath $js_destination_folder

        $ovf_path = Get-ChildItem -Path $js_destination_folder -Filter "jetstream*ova" -Recurse | %{$_.FullName}
        $signature_path = Get-ChildItem -Path $js_destination_folder -Filter "signature" -Recurse | %{$_.FullName}

        # Deploy JetStream MSA
        $MSAIp = Deploy-JetDRMSA -OvfPath $ovf_path -SignaturePath $signature_path -Network $Network -Hostname $HostName -MSACredential $MSACredential -Gateway $Gateway -Dns $Dns -Ip $MSAIp -Netmask $Netmask -VlanId $VlanId -Cluster $Cluster -VmName $New_VMName -Datastore $Datastore

        # Upgrade MSA
        if ($null -ne $MSAIp) {
            $msa_has_ip = $true
        }
        if (!$msa_has_ip) {
            #Check for vmtools status in the MSA,
            Write-Host "Ip is not assigned for MSA, hence checking if vmware tools is running in MSA"
            $new_msa_vm = Get-VM -Name $New_VMName
            $vm_tool_run_status = $new_msa_vm.ExtensionData.Summary.Guest.ToolsRunningStatus
            if ($vm_tool_run_status -eq "guestToolsRunning") {
                Write-Host "VMware tools is running in the MSA and hence can proceed to upgrading"
            }
            else{
                Write-Error "VMWare tools is not running on MSA hence Upgrade cannot progress, Contact Jetstream for further assistance" -ErrorAction Stop
            }
        }

        #MSA upgrade to version with Alma9 based OS. The new MSA is destroyed if the upgrade fails and system continues to run from the existing one.
        majorUpdateMSA $VMName $UserName $Password $New_VMName | Out-Null

        #Rename $New_VMName if the vm name is not msa@4.2.0+jetdr, Gets Executed only if the majorUpdateMSA is sucessfull
        if ($VMName -ne "msa@4.2.0+jetdr") {
            $msa_vm_backup_name = $VMName + "-Backup"
            Get-VM -Name $VMName | Set-VM -Name $msa_vm_backup_name -Confirm:$false
            Get-VM -Name $New_VMName | Set-VM -Name $VMName -Confirm:$false
        }
        else {
            Write-Host "The upgraded MSA name is retained and is $New_VMName"
        }
    }
}

function Enable-JetStreamRESTUser {
<#

    .NOTES
    ===========================================================================
    Created by: JetStream Software Inc
    ===========================================================================

    .DESCRIPTION
    Create a 'Partner REST Read+Write' role and a user for communication between MSA and ESXi

    .PARAMETER MSAIp
    Ip of the MSA

    .PARAMETER MSACredential
    root credentials of MSA

    .PARAMETER IOFRestUserName
    Name of the iofrest user to be created, default=jetiofrest

    .EXAMPLE
    Enable-JetStreamRESTUser -MSAIp xxx.xxx.xxx.xxx -MSACredential <root/PSCredential Object>

#>

    [CmdletBinding()]
    [AVSAttribute(15, UpdatesSDDC = $False)]
    param(
        [Parameter(Mandatory=$true,
                    HelpMessage="IP Address of the MSA")]
        [String]$MSAIp,
        [Parameter(Mandatory=$true,
                    HelpMessage="Credential of the root user of MSA")]
        [System.Management.Automation.PSCredential]
        [System.Management.Automation.Credential()]
        $MSACredential,
        [Parameter(Mandatory=$false,
                    HelpMessage="Name of the user to be created")]
        [String]$IOFRestUserName="jetiofrest"
    )
    Begin {
        $Username = $MSACredential.UserName.trim()
        $Password = $MSACredential.GetNetworkCredential().Password.trim()

        #Trimming string parameters for any leading and trailing spaces
        foreach ($key in $($PSBoundParameters.keys)) {
            if ($PSBoundParameters[$key].GetType().Name -eq 'String') {
                $PSBoundParameters[$key] = $($PSBoundParameters[$key].trim())
                Set-Variable -Name $key -Value $($PSBoundParameters[$key].trim())
            }
        }
        $new_user_name = $IOFRestUserName + "@vsphere.local"
        $new_role_name="Partner REST Read+Write"
        $privilege_group = "Interact with Partner Rest Daemons"
        $VCFqdn = getVcFqdn
    }
    Process {
        update_rest_user_on_msa $MSAIp $Username $Password $privilege_group $new_role_name $new_user_name
    }
}

function Start-MSA {
<#

    .NOTES
    ===========================================================================
    Created by: JetStream Software Inc
    ===========================================================================

    .DESCRIPTION
    Power On MSA VM

    .PARAMETER VMName
    Name of the MSA VM

    .EXAMPLE
    Start-MSA -VMName jsdr-msa

#>

    [CmdletBinding()]
    [AVSAttribute(5, UpdatesSDDC = $False)]
    param(
        [Parameter(Mandatory=$false,
                    HelpMessage="Name of the MSA VM")]
        [String]$VMName="msa@4.3.0+jetdr"
    )
    Begin {
        #Trimming string parameters for any leading and trailing spaces
        foreach ($key in $($PSBoundParameters.keys)) {
            if ($PSBoundParameters[$key].GetType().Name -eq 'String') {
                $PSBoundParameters[$key] = $($PSBoundParameters[$key].trim())
                Set-Variable -Name $key -Value $($PSBoundParameters[$key].trim())
            }
        }
    }
    Process {
        $result = msa_operation $VMName ([VmOperations]::PowerOn) 300
        if ($result) {
            Write-Host "Start-VM task completed successfully"
        }
        else {
            Write-Error "Start-VM task failed" -ErrorAction Stop
        }
    }
}

function Restart-MSA {
<#

    .NOTES
    ===========================================================================
    Created by: JetStream Software Inc
    ===========================================================================

    .DESCRIPTION
    Restart MSA VM

    .PARAMETER VMName
    Name of the MSA VM

    .EXAMPLE
    Restart-MSA -VMName jsdr-msa

#>

    [CmdletBinding()]
    [AVSAttribute(5, UpdatesSDDC = $False)]
    param(
        [Parameter(Mandatory=$false,
                    HelpMessage="Name of the MSA VM")]
        [String]$VMName="msa@4.3.0+jetdr"
    )
    Begin {
        #Trimming string parameters for any leading and trailing spaces
        foreach ($key in $($PSBoundParameters.keys)) {
            if ($PSBoundParameters[$key].GetType().Name -eq 'String') {
                $PSBoundParameters[$key] = $($PSBoundParameters[$key].trim())
                Set-Variable -Name $key -Value $($PSBoundParameters[$key].trim())
            }
        }
    }
    Process {
        $result = msa_operation $VMName ([VmOperations]::Restart) 120
        if($result) {
            Write-Host "Restart-VM task completed successfully"
        }
        else {
            Write-Error "Restart-VM task failed" -ErrorAction Stop
        }
    }
}

# SIG # Begin signature block
# MIIUoAYJKoZIhvcNAQcCoIIUkTCCFI0CAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCBZnyzXIhyJJvN1
# n8tGTJJEtICYyL2aGcO0wepprMLEB6CCEVswggVvMIIEV6ADAgECAhBI/JO0YFWU
# jTanyYqJ1pQWMA0GCSqGSIb3DQEBDAUAMHsxCzAJBgNVBAYTAkdCMRswGQYDVQQI
# DBJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAOBgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoM
# EUNvbW9kbyBDQSBMaW1pdGVkMSEwHwYDVQQDDBhBQUEgQ2VydGlmaWNhdGUgU2Vy
# dmljZXMwHhcNMjEwNTI1MDAwMDAwWhcNMjgxMjMxMjM1OTU5WjBWMQswCQYDVQQG
# EwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMS0wKwYDVQQDEyRTZWN0aWdv
# IFB1YmxpYyBDb2RlIFNpZ25pbmcgUm9vdCBSNDYwggIiMA0GCSqGSIb3DQEBAQUA
# A4ICDwAwggIKAoICAQCN55QSIgQkdC7/FiMCkoq2rjaFrEfUI5ErPtx94jGgUW+s
# hJHjUoq14pbe0IdjJImK/+8Skzt9u7aKvb0Ffyeba2XTpQxpsbxJOZrxbW6q5KCD
# J9qaDStQ6Utbs7hkNqR+Sj2pcaths3OzPAsM79szV+W+NDfjlxtd/R8SPYIDdub7
# P2bSlDFp+m2zNKzBenjcklDyZMeqLQSrw2rq4C+np9xu1+j/2iGrQL+57g2extme
# me/G3h+pDHazJyCh1rr9gOcB0u/rgimVcI3/uxXP/tEPNqIuTzKQdEZrRzUTdwUz
# T2MuuC3hv2WnBGsY2HH6zAjybYmZELGt2z4s5KoYsMYHAXVn3m3pY2MeNn9pib6q
# RT5uWl+PoVvLnTCGMOgDs0DGDQ84zWeoU4j6uDBl+m/H5x2xg3RpPqzEaDux5mcz
# mrYI4IAFSEDu9oJkRqj1c7AGlfJsZZ+/VVscnFcax3hGfHCqlBuCF6yH6bbJDoEc
# QNYWFyn8XJwYK+pF9e+91WdPKF4F7pBMeufG9ND8+s0+MkYTIDaKBOq3qgdGnA2T
# OglmmVhcKaO5DKYwODzQRjY1fJy67sPV+Qp2+n4FG0DKkjXp1XrRtX8ArqmQqsV/
# AZwQsRb8zG4Y3G9i/qZQp7h7uJ0VP/4gDHXIIloTlRmQAOka1cKG8eOO7F/05QID
# AQABo4IBEjCCAQ4wHwYDVR0jBBgwFoAUoBEKIz6W8Qfs4q8p74Klf9AwpLQwHQYD
# VR0OBBYEFDLrkpr/NZZILyhAQnAgNpFcF4XmMA4GA1UdDwEB/wQEAwIBhjAPBgNV
# HRMBAf8EBTADAQH/MBMGA1UdJQQMMAoGCCsGAQUFBwMDMBsGA1UdIAQUMBIwBgYE
# VR0gADAIBgZngQwBBAEwQwYDVR0fBDwwOjA4oDagNIYyaHR0cDovL2NybC5jb21v
# ZG9jYS5jb20vQUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNAYIKwYBBQUHAQEE
# KDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5jb21vZG9jYS5jb20wDQYJKoZI
# hvcNAQEMBQADggEBABK/oe+LdJqYRLhpRrWrJAoMpIpnuDqBv0WKfVIHqI0fTiGF
# OaNrXi0ghr8QuK55O1PNtPvYRL4G2VxjZ9RAFodEhnIq1jIV9RKDwvnhXRFAZ/ZC
# J3LFI+ICOBpMIOLbAffNRk8monxmwFE2tokCVMf8WPtsAO7+mKYulaEMUykfb9gZ
# pk+e96wJ6l2CxouvgKe9gUhShDHaMuwV5KZMPWw5c9QLhTkg4IUaaOGnSDip0TYl
# d8GNGRbFiExmfS9jzpjoad+sPKhdnckcW67Y8y90z7h+9teDnRGWYpquRRPaf9xH
# +9/DUp/mBlXpnYzyOmJRvOwkDynUWICE5EV7WtgwggXGMIIELqADAgECAhEAx5f+
# KBbVHZKKYsCngzhy/DANBgkqhkiG9w0BAQwFADBUMQswCQYDVQQGEwJHQjEYMBYG
# A1UEChMPU2VjdGlnbyBMaW1pdGVkMSswKQYDVQQDEyJTZWN0aWdvIFB1YmxpYyBD
# b2RlIFNpZ25pbmcgQ0EgUjM2MB4XDTIzMDUwMzAwMDAwMFoXDTI1MDUwMjIzNTk1
# OVowXDELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExGzAZBgNVBAoM
# EkpldFN0cmVhbSBTb2Z0d2FyZTEbMBkGA1UEAwwSSmV0U3RyZWFtIFNvZnR3YXJl
# MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEA303037LJy/ygxXhA/dpm
# taFbP40OUibB16KHBG8MsH1RA3KyDNm8IATCm5b8F4YT4umB7osCUewzuHmMebba
# iG4R7+0eJ4ks+RpNbx5XXQ85KnaYRHqyqxeokJzD24Hn154M6Fjmbfj1cG/QgqRX
# +tGngozNVouAhVP7XjNFPeNpNo16aAQElyAkdbJ6phDhENKT8sINmzVxPT53GZZm
# mZx3Kk5VSHamELY4uD3fivSKjxUXAQEUOsEs4nm1Bet7J2Zl+VG6jbSLwWbzbCf3
# Y9ue3MZR95LCASqaKGppMj5PDeYtUm8Ww4Kjc3tvPtJfDaYE8Xwr8T6C6AwGqacE
# a9Vry7XKuL2nucqWvc5bZwHFrpoHphvLXeGqNucyKvT47/w7ASonz3D3u7HvZnHH
# xFL2XljDntOvIGDUvf7q4+P6rmJrrF+8VDLwx6us56bxUi30Hl8hVdPYHwDCEZB8
# T6arb5dq1XhAgS+m3v8GbP5KYwh08bWSXH+HDtv35aK9AgMBAAGjggGJMIIBhTAf
# BgNVHSMEGDAWgBQPKssghyi47G9IritUpimqF6TNDDAdBgNVHQ4EFgQUDjCOWzEl
# bVPAwKfIjtElrJOezhUwDgYDVR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwEwYD
# VR0lBAwwCgYIKwYBBQUHAwMwSgYDVR0gBEMwQTA1BgwrBgEEAbIxAQIBAwIwJTAj
# BggrBgEFBQcCARYXaHR0cHM6Ly9zZWN0aWdvLmNvbS9DUFMwCAYGZ4EMAQQBMEkG
# A1UdHwRCMEAwPqA8oDqGOGh0dHA6Ly9jcmwuc2VjdGlnby5jb20vU2VjdGlnb1B1
# YmxpY0NvZGVTaWduaW5nQ0FSMzYuY3JsMHkGCCsGAQUFBwEBBG0wazBEBggrBgEF
# BQcwAoY4aHR0cDovL2NydC5zZWN0aWdvLmNvbS9TZWN0aWdvUHVibGljQ29kZVNp
# Z25pbmdDQVIzNi5jcnQwIwYIKwYBBQUHMAGGF2h0dHA6Ly9vY3NwLnNlY3RpZ28u
# Y29tMA0GCSqGSIb3DQEBDAUAA4IBgQCEQuY+MjBvY7xvU4BU0+PAASEGVEJgVO6e
# eu0IBb1d0HJCOgOhhg3T6vLAIGTfB5BRhpHOnI73/7t+4GaqAORJkAqQNhryfxtm
# N9JqUDUx/KvCq0+5oHYaVCWvjap3U1/vc5TbdIVIRRh+EZ92fEafQLlIDVrHun1Z
# TKEdeoRkCDnpexs0X3Lz2IwTPGXqz0OIlGwsyUI/nBuwa//APQPq+q9MS6e1D3RI
# 2IpCd9VuSNiFCcispPaT/E0dwqDe8vYZX7sOdcJTp5whLKC8bFQL2Fpt1pHRzmSz
# hLAJbrRcnmqcnJr7hR+hWsYycnlkvUUxIHPg27bsZwjNJbG0xNSepo8VN8/MdeFE
# ghkRE1QYSryE8JoQjrbk4oXsRvviZAFSGCp9yqeqvmpDrDNCaLwJk0JZ2L5Cpz79
# NvHJ+15kcIFKipn/ExiMZ5Hbj8IehE2vOI0L2olQ5LsPvB8/PA4E/yMq4bgbGg23
# Tn9u11KQlnaeju+dZW3DBs2WVEZmpUkwggYaMIIEAqADAgECAhBiHW0MUgGeO5B5
# FSCJIRwKMA0GCSqGSIb3DQEBDAUAMFYxCzAJBgNVBAYTAkdCMRgwFgYDVQQKEw9T
# ZWN0aWdvIExpbWl0ZWQxLTArBgNVBAMTJFNlY3RpZ28gUHVibGljIENvZGUgU2ln
# bmluZyBSb290IFI0NjAeFw0yMTAzMjIwMDAwMDBaFw0zNjAzMjEyMzU5NTlaMFQx
# CzAJBgNVBAYTAkdCMRgwFgYDVQQKEw9TZWN0aWdvIExpbWl0ZWQxKzApBgNVBAMT
# IlNlY3RpZ28gUHVibGljIENvZGUgU2lnbmluZyBDQSBSMzYwggGiMA0GCSqGSIb3
# DQEBAQUAA4IBjwAwggGKAoIBgQCbK51T+jU/jmAGQ2rAz/V/9shTUxjIztNsfvxY
# B5UXeWUzCxEeAEZGbEN4QMgCsJLZUKhWThj/yPqy0iSZhXkZ6Pg2A2NVDgFigOMY
# zB2OKhdqfWGVoYW3haT29PSTahYkwmMv0b/83nbeECbiMXhSOtbam+/36F09fy1t
# sB8je/RV0mIk8XL/tfCK6cPuYHE215wzrK0h1SWHTxPbPuYkRdkP05ZwmRmTnAO5
# /arnY83jeNzhP06ShdnRqtZlV59+8yv+KIhE5ILMqgOZYAENHNX9SJDm+qxp4Vqp
# B3MV/h53yl41aHU5pledi9lCBbH9JeIkNFICiVHNkRmq4TpxtwfvjsUedyz8rNyf
# QJy/aOs5b4s+ac7IH60B+Ja7TVM+EKv1WuTGwcLmoU3FpOFMbmPj8pz44MPZ1f9+
# YEQIQty/NQd/2yGgW+ufflcZ/ZE9o1M7a5Jnqf2i2/uMSWymR8r2oQBMdlyh2n5H
# irY4jKnFH/9gRvd+QOfdRrJZb1sCAwEAAaOCAWQwggFgMB8GA1UdIwQYMBaAFDLr
# kpr/NZZILyhAQnAgNpFcF4XmMB0GA1UdDgQWBBQPKssghyi47G9IritUpimqF6TN
# DDAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADATBgNVHSUEDDAK
# BggrBgEFBQcDAzAbBgNVHSAEFDASMAYGBFUdIAAwCAYGZ4EMAQQBMEsGA1UdHwRE
# MEIwQKA+oDyGOmh0dHA6Ly9jcmwuc2VjdGlnby5jb20vU2VjdGlnb1B1YmxpY0Nv
# ZGVTaWduaW5nUm9vdFI0Ni5jcmwwewYIKwYBBQUHAQEEbzBtMEYGCCsGAQUFBzAC
# hjpodHRwOi8vY3J0LnNlY3RpZ28uY29tL1NlY3RpZ29QdWJsaWNDb2RlU2lnbmlu
# Z1Jvb3RSNDYucDdjMCMGCCsGAQUFBzABhhdodHRwOi8vb2NzcC5zZWN0aWdvLmNv
# bTANBgkqhkiG9w0BAQwFAAOCAgEABv+C4XdjNm57oRUgmxP/BP6YdURhw1aVcdGR
# P4Wh60BAscjW4HL9hcpkOTz5jUug2oeunbYAowbFC2AKK+cMcXIBD0ZdOaWTsyNy
# BBsMLHqafvIhrCymlaS98+QpoBCyKppP0OcxYEdU0hpsaqBBIZOtBajjcw5+w/Ke
# FvPYfLF/ldYpmlG+vd0xqlqd099iChnyIMvY5HexjO2AmtsbpVn0OhNcWbWDRF/3
# sBp6fWXhz7DcML4iTAWS+MVXeNLj1lJziVKEoroGs9Mlizg0bUMbOalOhOfCipnx
# 8CaLZeVme5yELg09Jlo8BMe80jO37PU8ejfkP9/uPak7VLwELKxAMcJszkyeiaer
# lphwoKx1uHRzNyE6bxuSKcutisqmKL5OTunAvtONEoteSiabkPVSZ2z76mKnzAfZ
# xCl/3dq3dUNw4rg3sTCggkHSRqTqlLMS7gjrhTqBmzu1L90Y1KWN/Y5JKdGvspbO
# rTfOXyXvmPL6E52z1NZJ6ctuMFBQZH3pwWvqURR8AgQdULUvrxjUYbHHj95Ejza6
# 3zdrEcxWLDX6xWls/GDnVNueKjWUH3fTv1Y8Wdho698YADR7TNx8X8z2Bev6SivB
# BOHY+uqiirZtg0y9ShQoPzmCcn63Syatatvx157YK9hlcPmVoa1oDE5/L9Uo2bC5
# a4CH2RwxggKbMIIClwIBATBpMFQxCzAJBgNVBAYTAkdCMRgwFgYDVQQKEw9TZWN0
# aWdvIExpbWl0ZWQxKzApBgNVBAMTIlNlY3RpZ28gUHVibGljIENvZGUgU2lnbmlu
# ZyBDQSBSMzYCEQDHl/4oFtUdkopiwKeDOHL8MA0GCWCGSAFlAwQCAQUAoIGEMBgG
# CisGAQQBgjcCAQwxCjAIoAKAAKECgAAwGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcC
# AQQwHAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIE
# IJ3qtpByfuyX81GtS9JGVs+g42lUsHBpnFXcTiTPJOH0MA0GCSqGSIb3DQEBAQUA
# BIIBgNmj09hdvpdFWtBTAHThtvd4NU6EbUyi7UO3iw+Ch2oRAAhtZthFYRS+QjJH
# 4/b6zBP98ztQG57VCFO+BVUNC9fH3nlQxPeOXcQtuVayRz+xfwlH6tjN+HeeSKWc
# 2NMacY225VgUJxze7m4uBX3CBP9EwOm7IvdXfSbxlyxE4RXTLpBMFBRSZCqfAVVA
# M/e/vRMiWY9JCVFCjHEoCugpJ0YGJ60ou2g+PFihoabveB2jEyrnnq7BhewF/KWS
# FAQnzyg0lCN/B3t7bvsakvHf4QAoWV3PYHhjjneQOFdK06K1dP69IUF1B0JrOaMo
# KM6v5dQTcMo9xIEgpe02eKECL+0DXQOPz/MD9jbFsg57Ii+UTDd2Yk3D7D8tvTtd
# YrGWiyD68623QKOvtA9Inu8s0yj7uh6g/Q/3eXq9xYFIH7itmSViZrIILc+hfJke
# XrXfFCGGvBFS/q9E74lqAMFuNh70sVUe0qKr8nmbdtOhxIQQEklVHRJbR6imd1YS
# FHZ1yw==
# SIG # End signature block