ZertoAVSModule.psm1

using module Microsoft.AVS.Management


$PUBLIC_KEY = ('{0}/ZertoPublicKey.pem' -f $psScriptRoot)
$ZERTO_FOLDER_ON_HOST = "/var/zerto"
$LOCAL_TEMP_FOLDER_FOR_DOWNLOADED_FILES = ('{0}/filesFromDatastore/' -f $psScriptRoot)

Function TestConnection {
    return "TestConnection"
}

Function CreateZertoFolderOnHost {
    param(
        [Parameter(Mandatory = $true, 
            HelpMessage = "Host Name to connect with SSH")]
        [string]$HostName 
    )
    
    process {
        $Command = "mkdir -p $ZERTO_FOLDER_ON_HOST"
        $Res = RunSSHCommands -HostName $HostName -Commands $Command
        $ExitStatus = $Res["0_exitStatus"];
        
        if ( $ExitStatus -ne '0' ) {
            throw "failed to create $ZERTO_FOLDER_ON_HOST on host $HostName. Exit status for ""$Command"" is $ExitStatus"
        }
    }
}

Function VerifyAndUploadFilesFromPSEngineToHost {
    param(
        [Parameter(Mandatory = $true, 
            HelpMessage = "Host Name to connect with SSH")]
        [string]$HostName
    )
    
    CreateZertoFolderOnHost -HostName $HostName
    
    foreach ($file in Get-ChildItem $LOCAL_TEMP_FOLDER_FOR_DOWNLOADED_FILES* -Include *.sh, *.o) {
        $signature = ("{0}_signature" -f $file)

        $isVerified = (openssl dgst -sha256 -verify $PUBLIC_KEY -signature $signature $file 2>&1) -join ";"
        
        if ($isVerified -eq "Verified OK") {
            Set-SFTPItem -SessionId ($SFTP_Sessions[$HostName]).Value.SessionId -Destination $ZERTO_FOLDER_ON_HOST -Path $file -Force
        }
        else {
            throw "Error! host $HostName failed to verify $file with $signature, openSSL output: $isVerified"
        }
    }
}

Function DownloadFilesFromDatastoreToPSEngine {
    param(
        [Parameter(Mandatory = $true, 
            HelpMessage = "Datastore Uuid")]
        [string]$DatastoreUuid,
        [Parameter(Mandatory = $true, 
            HelpMessage = "Host Bios Uuid || mob-> Property Path: host.hardware.systemInfo.uuid")]
        [string]$BiosUuid
    )

    $psDriverName = "ds"
    $FullRemoteFileLocation = ('{0}:\zagentid\{1}\*' -f $psDriverName, $BiosUuid)
    $datastore = Get-Datastore $DatastoreUuid

    New-PSDrive -Location $datastore -Name $psDriverName -PSProvider VimDatastore -Root "\"
    Copy-DatastoreItem -Item $FullRemoteFileLocation -Destination $LOCAL_TEMP_FOLDER_FOR_DOWNLOADED_FILES -Force
    Remove-PSDrive -Name $psDriverName
}

Function CopyFilesFromDatastoreToHost {
    param(
        [Parameter(Mandatory = $true, 
            HelpMessage = "Host Name to connect with SSH")]
        [string]$HostName,
        [Parameter(Mandatory = $true, 
            HelpMessage = "Datastore Uuid")]
        [string]$DatastoreUuid,
        [Parameter(Mandatory = $true, 
            HelpMessage = "Host Bios Uuid || mob-> Property Path: host.hardware.systemInfo.uuid")]
        [string]$BiosUuid
    )
    
    DownloadFilesFromDatastoreToPSEngine -DatastoreUuid $DatastoreUuid -BiosUuid $BiosUuid
    VerifyAndUploadFilesFromPSEngineToHost -HostName $HostName
}

Function RunSSHCommands {
    param(
        [Parameter(Mandatory = $true, 
            HelpMessage = "Host Name to connect with SSH")]
        [string]$HostName,
        [Parameter(Mandatory = $true, 
            HelpMessage = "Commands to execute")]
        [String[]]$Commands
    )
    
    process {
        $NamedOutputs = @{}
        Set-Variable -Name NamedOutputs -Value $NamedOutputs -Scope Global
        
        $i = 0
        foreach ($Command in $Commands) {
            $SSH = Invoke-SSHCommand -SSHSession $SSH_Sessions[$HostName].Value -Command $Command

            if (!$SSH)
            { 
                throw "Error! failed to Invoke-SSHCommand ""$Command"" on host $HostName"
            }

            $ExitStatus = $SSH.ExitStatus
            $Error = $SSH.Error
            
            if ($ExitStatus -ne 0 -Or $Error) 
            {
                throw "Error! failed to run ""$Command"" on host $HostName, exitStatus: $ExitStatus, error: $Error"
            }

            $NamedOutputs["$($i)_cmd"] = $Command
            $NamedOutputs["$($i)_exitStatus"] = $ExitStatus
            $NamedOutputs["$($i)_output"] = ($SSH.Output -join ";")
            $NamedOutputs["$($i)_error"] = $Error

            $i++;
        }
        
        return $NamedOutputs
    }
}

<#
.DESCRIPTION
 
Display information about the available disk space (For Internal Use)
 
    .PARAMETER HostName
    Host Name to connect with ssh
 
.EXAMPLE
 
Get-HostTempFolderInfo -HostName xxx.xxx.xxx.xxx
#>

Function Get-HostTempFolderInfo {
    [CmdletBinding()]
    [AVSAttribute(5, UpdatesSDDC = $false)]
    param(
        [Parameter(Mandatory = $true, 
            HelpMessage = "Host Name to connect with SSH")]
        [string]$HostName 
    )
    
    process {
        $Command = "vdf"
        return RunSSHCommands -HostName $HostName -Commands $Command
    }
}

<#
.DESCRIPTION
 
Check if the host is up and running (For Internal Use)
 
    .PARAMETER HostName
    Host Name to connect with ssh
 
.EXAMPLE
 
EnsureConnectivity -HostName xxx.xxx.xxx.xxx
#>

Function EnsureConnectivity {    
    [CmdletBinding()]
    [AVSAttribute(5, UpdatesSDDC = $false)]
    param(
        [Parameter(Mandatory = $true, 
            HelpMessage = "Host Name to connect with SSH")]
        [string]$HostName 
    )
    
    process {
        $Command = "echo testing123"
        return RunSSHCommands -HostName $HostName -Commands $Command
    }
}

<#
.DESCRIPTION
 
Retrieve the ESXi version (For Internal Use)
 
    .PARAMETER HostName
    Host Name to connect with ssh
 
.EXAMPLE
 
Get-HostEsxiVersion -HostName xxx.xxx.xxx.xxx
#>

Function Get-HostEsxiVersion {
    [CmdletBinding()]
    [AVSAttribute(5, UpdatesSDDC = $false)]
    param(
        [Parameter(Mandatory = $true, 
            HelpMessage = "Host Name to connect with SSH")]
        [string]$HostName 
    )
    
    process {
        $Command = "vmware -l"
        return RunSSHCommands -HostName $HostName -Commands $Command
    }
}

<#
.DESCRIPTION
 
Responsible for loading the driver when the host is booting.
/etc/rc.local.d/local.sh file is executed after all the normal system services are started
 
    .PARAMETER HostName
    Host Name to connect with ssh
 
    .PARAMETER DatastoreUuid
    Datastore Uuid
 
    .PARAMETER BiosUuid
    "Host Bios Uuid || mob-> Property Path: host.hardware.systemInfo.uuid"
 
.EXAMPLE
 
ChangeStartupFile -HostName xxx.xxx.xxx.xxx -DatastoreUuid xxx -BiosUuid xxx
#>

Function ChangeStartupFile {
    [CmdletBinding()]
    [AVSAttribute(30, UpdatesSDDC = $false)]
    param(
        [Parameter(Mandatory = $true, 
            HelpMessage = "Host Name to connect with SSH")]
        [string]$HostName,
        [Parameter(Mandatory = $true, 
            HelpMessage = "Datastore Uuid")]
        [string]$DatastoreUuid,
        [Parameter(Mandatory = $true, 
            HelpMessage = "Host Bios Uuid || mob-> Property Path: host.hardware.systemInfo.uuid")]    
        [string]$BiosUuid
    )

    Process {

        $zloadmod = ('{0}/zloadmod.sh' -f $ZERTO_FOLDER_ON_HOST)

        CopyFilesFromDatastoreToHost -HostName  $HostName -DatastoreUuid $DatastoreUuid -BiosUuid $BiosUuid

        $startupFile = ('{0}/startup_file.sh' -f $ZERTO_FOLDER_ON_HOST)
    
        $Commands =    ('grep -v "ZeRTO\|exit 0" /etc/rc.local.d/local.sh > {0}' -f $startupFile),
        ('echo \#ZeRTO\ >> {0}' -f $startupFile),
        ('echo sh {0} load {1} {2} \"\" \"\" 1 \> /etc/vmware/zloadmod.txt \2\>\&\1 \#ZeRTO\ >> {3}' -f $zloadmod, $DatastoreUuid, $BiosUuid, $startupFile),
        ('echo \#ZeRTO\ >> {0}' -f $startupFile),
        ('echo "exit 0" >> {0}' -f $startupFile),
        ('cp -f {0} /etc/rc.local.d/local.sh' -f $startupFile),
        ('chmod a+x {0}' -f $zloadmod)
                    
        return RunSSHCommands -HostName $HostName -Commands $Commands
    }
}

<#
.DESCRIPTION
 
Install the driver
 
    .PARAMETER HostName
    Host Name to connect with SSH
     
    .PARAMETER DatastoreUuid
    Datastore Uuid
 
    .PARAMETER BiosUuid
    Host Bios Uuid || mob-> Property Path: host.hardware.systemInfo.uuid
 
    .PARAMETER IsInit
    Init or load the driver
 
    .PARAMETER EsxiVersion
    Esxi version
 
.EXAMPLE
InstallDriver -HostName xxx.xxx.xxx.xxx -DatastoreUuid <UUID> -BiosUuid <UUID> -IsInit <init/load> -EsxiVersion xx
#>

Function InstallDriver {
    [CmdletBinding()]
    [AVSAttribute(30, UpdatesSDDC = $false)]
    param(
        [Parameter(Mandatory = $true, 
            HelpMessage = "Host Name to connect with SSH")]
        [string]$HostName,
        [Parameter(Mandatory = $true, 
            HelpMessage = "Datastore Uuid")]
        [string]$DatastoreUuid,
        [Parameter(Mandatory = $true,
            HelpMessage = "Host Bios Uuid || mob-> Property Path: host.hardware.systemInfo.uuid")]    
        [string]$BiosUuid,
        [Parameter(Mandatory = $true,    
            HelpMessage = "Init or load the driver")]    
        [string]$IsInit,
        [Parameter(Mandatory = $true,    
            HelpMessage = "Esxi version")]    
        [string]$EsxiVersion
    )

    Process {

        $zloadmod = ('{0}/zloadmod.sh' -f $ZERTO_FOLDER_ON_HOST)
        
        CopyFilesFromDatastoreToHost -HostName  $HostName -DatastoreUuid $DatastoreUuid -BiosUuid $BiosUuid
        
        $Commands = ('chmod a+x {0}' -f $zloadmod),
            ('{0} {1} {2} {3} 1 {4} 1 > /etc/vmware/zloadmod.txt' -f $zloadmod, $IsInit, $DatastoreUuid, $BiosUuid, $EsxiVersion)

        return RunSSHCommands -HostName $HostName -Commands $Commands
    }
}

<#
.DESCRIPTION
 
Uninstall the driver
 
    .PARAMETER HostName
    Host Name to connect with SSH
     
    .PARAMETER DatastoreUuid
    Datastore Uuid
 
    .PARAMETER BiosUuid
    Host Bios Uuid || mob-> Property Path: host.hardware.systemInfo.uuid
 
 
.EXAMPLE
UninstallDriver -HostName xxx.xxx.xxx.xxx -DatastoreUuid <UUID> -BiosUuid <UUID>
#>

Function UninstallDriver {
    [CmdletBinding()]
    [AVSAttribute(30, UpdatesSDDC = $false)]
    param(
        [Parameter(Mandatory = $true,
            HelpMessage = "Host Name to connect with SSH")]
        [string]$HostName,
        [Parameter(Mandatory = $true,
            HelpMessage = "Datastore Uuid")]
        [string]$DatastoreUuid,
        [Parameter(Mandatory = $true,
            HelpMessage = "Host Bios Uuid || mob-> Property Path: host.hardware.systemInfo.uuid")]
        [string]$BiosUuid
    )
    
    process {

        $zunloadmod = ('{0}/zunloadmod.sh' -f $ZERTO_FOLDER_ON_HOST)
        
        CopyFilesFromDatastoreToHost -HostName  $HostName -DatastoreUuid $DatastoreUuid -BiosUuid $BiosUuid

        $Commands = ('chmod a+x {0}' -f $zunloadmod),
                    ('{0} cleanup > /etc/vmware/zunloadmod.txt' -f $zunloadmod)

        return RunSSHCommands -HostName $HostName -Commands $Commands
    }
}