ZertoAVSModule.psm1
using module Microsoft.AVS.Management $ZERTO_FOLDER_ON_HOST = "/var/zerto" $LOCAL_TEMP_FOLDER_FOR_ZERTO_DRIVER_LOGS = ('{0}/zertoDriverLogs/' -f $psScriptRoot) $LOCAL_TEMP_FOLDER_FOR_DOWNLOADED_FILES = ('{0}/filesFromDatastore/' -f $psScriptRoot) $ZERTO_USER_NAME = "ZertoDR" $ZERTO_ROLE = "ZertoRole" $DOMAIN = "vsphere.local" Function IsZertoUserExists { <# .DESCRIPTION Get a zertoUsername and a domain, and return whether or not the user exists in the domain. .EXAMPLE IsZertoUserExists #> Process { Write-Host "Starting $($MyInvocation.MyCommand)..." if(Get-SsoPersonUser -Name $ZERTO_USER_NAME -Domain $DOMAIN -ErrorAction SilentlyContinue) { Write-Host "$ZERTO_USER_NAME already exists in $VC_ADDRESS, domain: $DOMAIN." return $true; } Write-Host "$ZERTO_USER_NAME doesn't exist in $VC_ADDRESS, domain: $DOMAIN." return $false; } } Function IsZertoRoleExists { <# .DESCRIPTION Return true if ZertoRole exists, otherwise return false. .EXAMPLE IsZertoRoleExists #> Process { Write-Host "Starting $($MyInvocation.MyCommand)..." If (Get-VIRole -Name $ZERTO_ROLE -ErrorAction SilentlyContinue) { Write-Host "$ZERTO_ROLE already exists in $VC_ADDRESS" return $true } Write-Host "$ZERTO_ROLE doesn't exist in $VC_ADDRESS" return $false; } } Function IsZertoDriverLoaded { <# .DESCRIPTION Return true if Zerto driver is loaded, otherwise return false. .PARAMETER HostName Host Name to connect with SSH .EXAMPLE IsZertoDriverLoaded -HostName <HostName> #> [CmdletBinding()] [AVSAttribute(30, UpdatesSDDC = $false)] param( [Parameter(Mandatory = $true, HelpMessage = "Host Name to connect with SSH")] [string]$HostName ) Process { Write-Host "Starting $($MyInvocation.MyCommand)..." $vmkload = '/tmp/vmklod_output' $ZertoDriver = '/tmp/zertoDriver' $Command = ('vmkload_mod -l > {0}' -f $vmkload) $Res = RunSSHCommands -HostName $HostName -Commands $Command $Command = ('grep "zdriver" {0} > {1}' -f $vmkload, $ZertoDriver) $Res = RunSSHCommands -HostName $HostName -Commands $Command -ExitStatusAction "Skip" $ExitStatus = $Res["0_exitStatus"] if ($ExitStatus -eq '0') { Write-Host "Zerto driver is loaded" return $true; } if ($ExitStatus -eq '1') { Write-Host "Zerto driver is not loaded" return $false; } } } Function GetDriverLogsFromHost { <# .DESCRIPTION Copy Zerto driver logs from host to datastore .PARAMETER HostName Host Name to connect with SSH .PARAMETER DatastoreName Datastore Name .EXAMPLE GetDriverLogsFromHost -HostName <HostName> -DatastoreName <DatastoreName> #> [CmdletBinding()] [AVSAttribute(30, UpdatesSDDC = $false)] param( [Parameter(Mandatory = $true, HelpMessage = "Host Name to connect with SSH")] [string]$HostName, [Parameter(Mandatory = $true, HelpMessage = "Datastore Name")] [string]$DatastoreName ) Write-Host "Starting $($MyInvocation.MyCommand)..." DownloadDriverLogFilesFromHostToPSEngine -HostName $HostName UploadDriverLogFilesFromPSEngineToDatastore -DatastoreName $DatastoreName -HostName $HostName } Function DownloadDriverLogFilesFromHostToPSEngine { param( [Parameter(Mandatory = $true, HelpMessage = "Host Name to connect with SSH")] [string]$HostName ) Write-Host "Starting $($MyInvocation.MyCommand)..." $sftpSessionId = ($SFTP_Sessions[$HostName]).Value.SessionId if (!(Test-Path -path $LOCAL_TEMP_FOLDER_FOR_ZERTO_DRIVER_LOGS)) { New-Item $LOCAL_TEMP_FOLDER_FOR_ZERTO_DRIVER_LOGS -Type Directory Write-Host "Create $LOCAL_TEMP_FOLDER_FOR_ZERTO_DRIVER_LOGS folder on powerShell engine" } $files = '/etc/vmware/zloadmod.txt', '/etc/vmware/zunloadmod.txt' foreach ($file in $files) { if (Test-SFTPPath -SessionId $sftpSessionId -Path $file) { Write-Host "Going to download $file from $HostName to powerShell engine ($LOCAL_TEMP_FOLDER_FOR_ZERTO_DRIVER_LOGS)" Get-SFTPItem -SessionId $sftpSessionId -Destination $LOCAL_TEMP_FOLDER_FOR_ZERTO_DRIVER_LOGS -Path $file -Force Write-Host "$file was copied from $HostName to powerShell engine" } else { Write-Host "File $file doesn't exist on $HostName" } } } Function UploadDriverLogFilesFromPSEngineToDatastore { param( [Parameter(Mandatory = $true, HelpMessage = "Datastore Name")] [string]$DatastoreName, [Parameter(Mandatory = $true, HelpMessage = "Host Name to connect with SSH")] [string]$HostName ) Write-Host "Starting $($MyInvocation.MyCommand)..." $psDriverName = "ds" $zertoDriverLogsDSPath = ('{0}:\zertoDriverLogsFromHost\{1}\' -f $psDriverName, $HostName) $zertoDriverLogsPSPath = ('{0}*' -f $LOCAL_TEMP_FOLDER_FOR_ZERTO_DRIVER_LOGS) $datastore = Get-Datastore $DatastoreName New-PSDrive -Location $datastore -Name $psDriverName -PSProvider VimDatastore -Root "\" -ErrorAction Stop Copy-DatastoreItem -Item $zertoDriverLogsPSPath -Destination $zertoDriverLogsDSPath -Force -ErrorAction Stop $files = (Get-ChildItem -Path $zertoDriverLogsDSPath -Name) -join ";" Write-Host "$MyInvocation.MyCommand - ZertoDriverFiles: {$files} were copied from powerShell engine ($zertoDriverLogsPSPath) to datastore ($zertoDriverLogsDSPath)" Remove-PSDrive -Name $psDriverName } Function GetZertoFilesListFromHost { <# .DESCRIPTION Return a list of all Zerto files on host under /var/zerto .PARAMETER HostName Host Name to connect with SSH .EXAMPLE GetZertoFilesListFromHost -HostName <HostName> #> [CmdletBinding()] [AVSAttribute(5, UpdatesSDDC = $false)] param( [Parameter(Mandatory = $true, HelpMessage = "Host Name to connect with SSH")] [string]$HostName ) process { Write-Host "Starting $($MyInvocation.MyCommand)..." $Command = ('ls -l {0}' -f $ZERTO_FOLDER_ON_HOST) return RunSSHCommands -HostName $HostName -Commands $Command } } Function TestConnection { return "TestConnection" } Function CreateZertoUser { <# .DESCRIPTION Create a ZertoDR user and a ZertoDR role which includes required privileges. The script creates a permission by assigning the ZertoDR role to the ZertoDR user. .EXAMPLE CreateZertoUser #> Process{ Write-Host "Starting $($MyInvocation.MyCommand)..." try { $zertoPrincipal = $DOMAIN + "\" + $ZERTO_USER_NAME #if the user already exists - do nothing if(IsZertoUserExists) { Write-Host "$ZERTO_USER_NAME already exists in $VC_ADDRESS. Skip creation..." } else { #Create Zerto user $PersistentSecrets.ZertoPassword = GenerateRandomPassword New-SsoPersonUser -UserName $ZERTO_USER_NAME -Password $PersistentSecrets.ZertoPassword -Description "Zerto DR user" -EmailAddress "ZertoDR@zerto.com" -FirstName "Zerto" -LastName "DR" -ErrorAction Stop # Add user to CloudAdmins group $group = "CloudAdmins" $SsoGroup = Get-SsoGroup -Name $group -Domain $DOMAIN Get-SsoPersonUser -Name $ZERTO_USER_NAME -Domain $DOMAIN -ErrorAction Stop | Add-UserToSsoGroup -TargetGroup $SsoGroup -ErrorAction Stop Write-Host "Finish creating ZertoUser ($ZERTO_USER_NAME)" } UpdateZertoRole } catch{ Write-Error "Failed creating Zerto User, exception = $_" -ErrorAction Stop } } } Function UpdateZertoRole { <# .DESCRIPTION Updates a ZertoDR user with the latest ZertoDR role which includes required privileges. The script creates a permission by assigning the ZertoDR role to the ZertoDR user. .EXAMPLE UpdateZertoRole #> Process { Write-Host "Starting $($MyInvocation.MyCommand)..." $zertoPrincipal = $DOMAIN + "\" + $ZERTO_USER_NAME $zertoPrivileges = @( "Alarm.Create", "Alarm.Delete", "Authorization.ModifyPermissions", "Cryptographer.Access", "Datastore.AllocateSpace", "Datastore.Browse", "Datastore.Config", "Datastore.DeleteFile", "Datastore.FileManagement", "Datastore.UpdateVirtualMachineFiles", "StoragePod.Config", "Extension.Register", "Extension.Unregister", "Folder.Create", "Global.CancelTask", "Global.Diagnostics", "Global.DisableMethods", "Global.EnableMethods", "Global.LogEvent", "Host.Config.AdvancedConfig", "Host.Config.AutoStart", "Host.Config.Settings", "Host.Config.NetService", "Host.Config.Patch", "Host.Inventory.EditCluster", "Network.Assign", "Resource.AssignVAppToPool", "Resource.AssignVMToPool", "Resource.ColdMigrate", "Resource.HotMigrate", "Sessions.ValidateSession", "Task.Create", "Task.Update", "VApp.ApplicationConfig", "VApp.AssignResourcePool", "VApp.AssignVM", "VApp.Create", "VApp.Delete", "VApp.Import", "VApp.PowerOff", "VApp.PowerOn", "VirtualMachine.Config.AddExistingDisk", "VirtualMachine.Config.AddNewDisk", "VirtualMachine.Config.AddRemoveDevice", "VirtualMachine.Config.AdvancedConfig", "VirtualMachine.Config.CPUCount", "VirtualMachine.Config.DiskExtend", "VirtualMachine.Config.EditDevice", "VirtualMachine.Config.ManagedBy", "VirtualMachine.Config.Memory", "VirtualMachine.Config.RawDevice", "VirtualMachine.Config.RemoveDisk", "VirtualMachine.Config.Resource", "VirtualMachine.Config.Settings", "VirtualMachine.Config.SwapPlacement", "VirtualMachine.Config.UpgradeVirtualHardware", "VirtualMachine.Interact.PowerOff", "VirtualMachine.Interact.PowerOn", "VirtualMachine.Inventory.CreateFromExisting", "VirtualMachine.Inventory.Create", "VirtualMachine.Inventory.Register", "VirtualMachine.Inventory.Delete", "VirtualMachine.Inventory.Unregister", "VirtualMachine.State.RemoveSnapshot" ) if((IsZertoUserExists $ZERTO_USER_NAME) -eq $false) { Write-Host "$ZERTO_USER_NAME doesn't exists in $VC_ADDRESS..." throw "$ZERTO_USER_NAME doesn't exists in $VC_ADDRESS..." } If (IsZertoRoleExists) { $joinedPrivilgaes = ($zertoPrivileges -join ";") Write-Host "Role: $ZERTO_ROLE already exists. Overwrite it with the following privilages: $joinedPrivilgaes" Remove-VIRole -Role (Get-VIRole -Name $ZERTO_ROLE) -Force:$true -Confirm:$false New-VIRole -name $ZERTO_ROLE -Privilege (Get-VIPrivilege -Server $VC_ADDRESS -id $zertoPrivileges) -Server $VC_ADDRESS } else { #Create a new role New-VIRole -name $ZERTO_ROLE -Privilege (Get-VIPrivilege -Server $VC_ADDRESS -id $zertoPrivileges) -Server $VC_ADDRESS -ErrorAction Stop Write-Host "Role $ZERTO_ROLE created on $VC_ADDRESS" } # Get the Root Folder $rootFolder = Get-Folder -NoRecursion # Create permission on vCenter object by assigning role to user New-VIPermission -Entity $rootFolder -Principal $zertoPrincipal -Role $ZERTO_ROLE -Propagate:$true -ErrorAction Stop Write-Host "Finish to update ZertoRole ($ZERTO_ROLE) for ZertoUser ($ZERTO_USER_NAME)" } } Function ResetZertoPassword { <# .DESCRIPTION Change password for Zerto user .EXAMPLE ResetZertoPassword #> process { Write-Host "Starting $($MyInvocation.MyCommand)..." $zertoUser = Get-SsoPersonUser -Name $ZERTO_USER_NAME -Domain $DOMAIN if($zertoUser) { $newPassword = GenerateRandomPassword Set-SsoPersonUser -User $zertoUser -NewPassword $newPassword -ErrorAction Stop $PersistentSecrets.ZertoPassword = $newPassword Write-Host "Password for $zertoUsername changed successfully" } else{ throw "Error! Failed to reset Zerto password for $zertoUsername, user doesn't exist" } } } Function SetSSHTimeout{ <# .DESCRIPTION Determines how long SSH session remains open .PARAMETER HostName Host Name to connect with SSH .PARAMETER SSHTimeout SSH timeout value .EXAMPLE SetSSHTimeout -HostName <HostName> -SSHTimeout <SSHTimeout> #> [CmdletBinding()] [AVSAttribute(30, UpdatesSDDC = $false)] param( [Parameter(Mandatory = $true, HelpMessage = "Host Name to connect with SSH")] [string]$HostName, [Parameter(Mandatory = $true, HelpMessage = "SSH timeout value")] [string]$SSHTimeout ) process { Write-Host "Starting $($MyInvocation.MyCommand)..." $vmHost = Get-VMHost -Name $HostName Get-AdvancedSetting -Entity $vmHost -Name "UserVars.ESXiShellInteractiveTimeOut" -ErrorAction SilentlyContinue | Set-AdvancedSetting -Value $SSHTimeout -Confirm:$false -ErrorAction SilentlyContinue Write-Host "Set configuration setting ""UserVars.ESXiShellInteractiveTimeOut"" on $HostName to $SSHTimeout" } } Function VerifyAndUploadFilesFromPSEngineToHost { param( [Parameter(Mandatory = $true, HelpMessage = "Host Name to connect with SSH")] [string]$HostName ) Write-Host "Starting $($MyInvocation.MyCommand)..." CreateZertoFolderOnHost -HostName $HostName foreach ($file in Get-ChildItem $LOCAL_TEMP_FOLDER_FOR_DOWNLOADED_FILES* -Include *.sh, *.o) { $signature = ("{0}_signature" -f $file) if ((VerifyFileBySignature -FilePath $file -SignatureFilePath $signature)){ 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 Name")] [string]$DatastoreName, [Parameter(Mandatory = $true, HelpMessage = "Host Bios Uuid || mob-> Property Path: host.hardware.systemInfo.uuid")] [string]$BiosUuid ) Write-Host "Starting $($MyInvocation.MyCommand)..." $psDriverName = "ds" $FullRemoteFileLocation = ('{0}:\zagentid\{1}\*' -f $psDriverName, $BiosUuid) $datastore = Get-Datastore $DatastoreName Write-Host "Going to download files from $darastore ($FullRemoteFileLocation) to PS engine ($LOCAL_TEMP_FOLDER_FOR_DOWNLOADED_FILES)." New-PSDrive -Location $datastore -Name $psDriverName -PSProvider VimDatastore -Root "\" -ErrorAction Stop Copy-DatastoreItem -Item $FullRemoteFileLocation -Destination $LOCAL_TEMP_FOLDER_FOR_DOWNLOADED_FILES -Force -ErrorAction Stop $files = (Get-ChildItem -Path $LOCAL_TEMP_FOLDER_FOR_DOWNLOADED_FILES -Name) -join ";" Write-Host "ZertoFiles: {$files} were copied from darastore $DatastoreName ($FullRemoteFileLocation) to PS engine ($LOCAL_TEMP_FOLDER_FOR_DOWNLOADED_FILES)" Remove-PSDrive -Name $psDriverName } Function CopyFilesFromDatastoreToHost { param( [Parameter(Mandatory = $true, HelpMessage = "Host Name to connect with SSH")] [string]$HostName, [Parameter(Mandatory = $true, HelpMessage = "Datastore Name")] [string]$DatastoreName, [Parameter(Mandatory = $true, HelpMessage = "Host Bios Uuid || mob-> Property Path: host.hardware.systemInfo.uuid")] [string]$BiosUuid ) Write-Host "Starting $($MyInvocation.MyCommand)..." DownloadFilesFromDatastoreToPSEngine -DatastoreName $DatastoreName -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, [Parameter(Mandatory = $false, HelpMessage = "Action on exitStatus 1")] [string]$ExitStatusAction = "Stop" ) process { Write-Host "Starting $($MyInvocation.MyCommand)..." $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 $Output = ($SSH.Output -join ";") if ($ExitStatus -ne 0 -Or $Error) { if (($ExitStatus -eq 1) -And (!$Error) -And ($ExitStatusAction -eq "Skip")) { Write-Host "ExitStatus of ""$Command"" is 1, while ExitStatusAction = Skip. Skipping..." } else { throw "Error! failed to run ""$Command"" on host $HostName, ExitStatus: $ExitStatus, Output: $Output, Error: $Error, ExitStatusAction: $ExitStatusAction" } } Write-Host "Finish to run ""$Command"" on host $HostName, ExitStatus: $ExitStatus, Output: $Output, Error: $Error" $NamedOutputs["$($i)_cmd"] = $Command $NamedOutputs["$($i)_exitStatus"] = $ExitStatus $NamedOutputs["$($i)_output"] = $Output $NamedOutputs["$($i)_error"] = $Error $i++; } return $NamedOutputs } } Function Get-HostTempFolderInfo { <# .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 #> [CmdletBinding()] [AVSAttribute(5, UpdatesSDDC = $false)] param( [Parameter(Mandatory = $true, HelpMessage = "Host Name to connect with SSH")] [string]$HostName ) process { Write-Host "Starting $($MyInvocation.MyCommand)..." $Command = "vdf" return RunSSHCommands -HostName $HostName -Commands $Command } } Function EnsureConnectivity { <# .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 #> [CmdletBinding()] [AVSAttribute(5, UpdatesSDDC = $false)] param( [Parameter(Mandatory = $true, HelpMessage = "Host Name to connect with SSH")] [string]$HostName ) process { Write-Host "Starting $($MyInvocation.MyCommand)..." $Command = "echo testing123" return RunSSHCommands -HostName $HostName -Commands $Command } } Function Get-HostEsxiVersion { <# .DESCRIPTION Retrieve the ESXi version (For Internal Use) .PARAMETER HostName Host Name to connect with SSH .EXAMPLE Get-HostEsxiVersion -HostName xxx.xxx.xxx.xxx #> [CmdletBinding()] [AVSAttribute(5, UpdatesSDDC = $false)] param( [Parameter(Mandatory = $true, HelpMessage = "Host Name to connect with SSH")] [string]$HostName ) process { Write-Host "Starting $($MyInvocation.MyCommand)..." $Command = "vmware -l" return RunSSHCommands -HostName $HostName -Commands $Command } } Function ChangeStartupFile { <# .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 DatastoreName Datastore Name .PARAMETER BiosUuid "Host Bios Uuid || mob-> Property Path: host.hardware.systemInfo.uuid" .EXAMPLE ChangeStartupFile -HostName xxx.xxx.xxx.xxx -DatastoreName xxx -BiosUuid xxx #> [CmdletBinding()] [AVSAttribute(30, UpdatesSDDC = $false)] param( [Parameter(Mandatory = $true, HelpMessage = "Host Name to connect with SSH")] [string]$HostName, [Parameter(Mandatory = $true, HelpMessage = "Datastore Name")] [string]$DatastoreName, [Parameter(Mandatory = $true, HelpMessage = "Host Bios Uuid || mob-> Property Path: host.hardware.systemInfo.uuid")] [string]$BiosUuid, [Parameter(Mandatory = $true, HelpMessage = "Zerto driver memory size in MB")] [string]$DriverMemoryInMB, [Parameter(Mandatory = $true, HelpMessage = "Use explicit argument for zloadmod script (True / False)")] [string]$UseExplicitDriverArgs ) Process { Write-Host "Starting $($MyInvocation.MyCommand)..." if(((ValidateDatastoreName -DatastoreName $DatastoreName) -ne $true) -or ((ValidateBiosUUID -DatastoreName $DatastoreName -BiosUuid $BiosUuid) -ne $true) -or ((ValidateDigitsOnly -InputString $DriverMemoryInMB) -ne $true)) { throw "validation failed" } $zloadmod = ('{0}/zloadmod.sh' -f $ZERTO_FOLDER_ON_HOST) CopyFilesFromDatastoreToHost -HostName $HostName -DatastoreName $DatastoreName -BiosUuid $BiosUuid $startupFile = ('{0}/startup_file.sh' -f $ZERTO_FOLDER_ON_HOST) if($UseExplicitDriverArgs -eq $true) { $driverArgs = "load -ds $DatastoreName -uid $BiosUuid -mem $DriverMemoryInMB -avs" } else { $driverArgs = "load $DatastoreName $BiosUuid 0 `"`" 1" } $Commands = ('grep -v "ZeRTO\|exit 0" /etc/rc.local.d/local.sh > {0}' -f $startupFile), ('echo \#ZeRTO\ >> {0}' -f $startupFile), ('echo sh {0} {1} \> /etc/vmware/zloadmod.txt \2\>\&\1 \#ZeRTO\ >> {2}' -f $zloadmod, $driverArgs, $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 } } Function InstallDriver { <# .DESCRIPTION Install the driver .PARAMETER HostName Host Name to connect with SSH .PARAMETER DatastoreName Datastore Name .PARAMETER BiosUuid Host Bios Uuid || mob-> Property Path: host.hardware.systemInfo.uuid .PARAMETER EsxiVersion Esxi version .EXAMPLE InstallDriver -HostName xxx.xxx.xxx.xxx -DatastoreName <DatastoreName> -BiosUuid <UUID> -EsxiVersion xx #> [CmdletBinding()] [AVSAttribute(30, UpdatesSDDC = $false)] param( [Parameter(Mandatory = $true, HelpMessage = "Host Name to connect with SSH")] [string]$HostName, [Parameter(Mandatory = $true, HelpMessage = "Datastore Name")] [string]$DatastoreName, [Parameter(Mandatory = $true, HelpMessage = "Host Bios Uuid || mob-> Property Path: host.hardware.systemInfo.uuid")] [string]$BiosUuid, [Parameter(Mandatory = $true, HelpMessage = "Esxi version")] [string]$EsxiVersion, [Parameter(Mandatory = $true, HelpMessage = "Driver memory in MB for Zerto driver")] [string]$DriverMemoryInMB, [Parameter(Mandatory = $true, HelpMessage = "Use explicit argument for zloadmod script (True / False)")] [string]$UseExplicitDriverArgs ) Process { Write-Host "Starting $($MyInvocation.MyCommand)..." if(((ValidateDatastoreName -DatastoreName $DatastoreName) -ne $true) -or ((ValidateBiosUUID -DatastoreName $DatastoreName -BiosUuid $BiosUuid) -ne $true) -or ((ValidateDigitsOnly -InputString $EsxiVersion) -ne $true) -or ((ValidateDigitsOnly -InputString $DriverMemoryInMB) -ne $true)) { throw "validation failed" } if (IsZertoDriverLoaded $HostName) { Write-Host "Warning! Zerto driver is already loaded on $HostName" } $zloadmod = ('{0}/zloadmod.sh' -f $ZERTO_FOLDER_ON_HOST) CopyFilesFromDatastoreToHost -HostName $HostName -DatastoreName $DatastoreName -BiosUuid $BiosUuid if($UseExplicitDriverArgs -eq $true) { $driverArgs = "init -ds $DatastoreName -uid $BiosUuid -ver $EsxiVersion -mem $DriverMemoryInMB -avs"; } else { $driverArgs = "init $DatastoreName $BiosUuid 0 $EsxiVersion 1"; } $Commands = ('chmod a+x {0}' -f $zloadmod), ('{0} {1} > /etc/vmware/zloadmod.txt' -f $zloadmod, $driverArgs) return RunSSHCommands -HostName $HostName -Commands $Commands } } Function UninstallDriver { <# .DESCRIPTION Uninstall the driver .PARAMETER HostName Host Name to connect with SSH .PARAMETER DatastoreName Datastore Name .PARAMETER BiosUuid Host Bios Uuid || mob-> Property Path: host.hardware.systemInfo.uuid .EXAMPLE UninstallDriver -HostName xxx.xxx.xxx.xxx -DatastoreName <DatastoreName> -BiosUuid <UUID> #> [CmdletBinding()] [AVSAttribute(30, UpdatesSDDC = $false)] param( [Parameter(Mandatory = $true, HelpMessage = "Host Name to connect with SSH")] [string]$HostName, [Parameter(Mandatory = $true, HelpMessage = "Datastore Name")] [string]$DatastoreName, [Parameter(Mandatory = $true, HelpMessage = "Host Bios Uuid || mob-> Property Path: host.hardware.systemInfo.uuid")] [string]$BiosUuid ) process { Write-Host "Starting $($MyInvocation.MyCommand)..." if (IsZertoDriverLoaded $HostName) { $zunloadmod = ('{0}/zunloadmod.sh' -f $ZERTO_FOLDER_ON_HOST) CopyFilesFromDatastoreToHost -HostName $HostName -DatastoreName $DatastoreName -BiosUuid $BiosUuid $Commands = ('chmod a+x {0}' -f $zunloadmod), ('{0} cleanup > /etc/vmware/zunloadmod.txt' -f $zunloadmod) return RunSSHCommands -HostName $HostName -Commands $Commands } else { throw "Error! Failed to run UninstallDriver, Zerto driver is not loaded on $HostName." } } } Function Install-Zerto { <# .DESCRIPTION Install Zerto Applience .PARAMETER MyZertoToken My Zerto token for downloading the OVA and signature file .PARAMETER HostName Host Name deploy OVA on .PARAMETER ZVMLIp IP of the ZVM applience .PARAMETER DatastoreName Datastore Name .PARAMETER AzureTenantId Azure Tenant ID .PARAMETER AzureClientID Azure Client ID .PARAMETER AvsClientSecret AVS Client Secret .PARAMETER AvsSubscriptionId AVS Subscription ID .PARAMETER AvsResourceGroup Avs Resource Group .PARAMETER AvsCloudName Avs Cloud Name .PARAMETER SubnetMask Subnet Mask of the applience network .PARAMETER DefaultGateway Default Gateway of the applience network .PARAMETER DNS DNS name server for the applience .EXAMPLE Install-Zerto -MyZertoToken <MyZertoToken> -HostName xxx.xxx.xxx.xxx -ZVMLIp xxx.xxx.xxx.xxx -DatastoreName <DatastoreName> -AzureTenantId <AzureTenantId> -AzureClientID <AzureClientID> -AvsClientSecret ********* -AvsSubscriptionId <AvsSubscriptionId> -AvsResourceGroup <AvsResourceGroup> -AvsCloudName <AvsCloudName> -.DefaultGateway xxx.xxx.xxx.xxx -SubnetMask xxx.xxx.xxx.xxx -DNS xxx.xxx.xxx.xxx #> [CmdletBinding()] [AVSAttribute(30, UpdatesSDDC = $false)] param( [Parameter(Mandatory = $true, HelpMessage = "Token for MyZerto")] [ValidateNotNullOrEmpty()][string] $MyZertoToken, [Parameter(Mandatory = $false, HelpMessage = "VC host name to put the machine on")] [string] $HostName, [Parameter(Mandatory = $true, HelpMessage = "Zvm IP address")] [ValidateNotNullOrEmpty()][string] $ZVMLIp, [Parameter(Mandatory = $true, HelpMessage = "DatastoreName")] [ValidateNotNullOrEmpty()][string] $DatastoreName, [Parameter(Mandatory = $true, HelpMessage = "Azure Tenant Id, Globally unique identifier, found in Azure portal")] [ValidateNotNullOrEmpty()][string] $AzureTenantId, [Parameter(Mandatory = $true, HelpMessage = "Azure Client ID - Application ID, found in Azure portal")] [ValidateNotNullOrEmpty()][string] $AzureClientID, [Parameter(Mandatory = $true, HelpMessage = "Enables authentication to Azure Active Directory using a client secret")] [ValidateNotNullOrEmpty()][SecureString] $AvsClientSecret, [Parameter(Mandatory = $true, HelpMessage = "The ID of the target subscription")] [ValidateNotNullOrEmpty()][string] $AvsSubscriptionId, [Parameter(Mandatory = $true, HelpMessage = "AWS resources that are all in the same AWS Region")] [ValidateNotNullOrEmpty()][string] $AvsResourceGroup, [Parameter(Mandatory = $true, HelpMessage = "Private cloud name")] [ValidateNotNullOrEmpty()][string] $AvsCloudName, [Parameter(Mandatory = $true, HelpMessage = "SubnetMask address")] [ValidateNotNullOrEmpty()][string] $SubnetMask, [Parameter(Mandatory = $true, HelpMessage = "Default gateway")] [ValidateNotNullOrEmpty()][string] $DefaultGateway, [Parameter(Mandatory = $true, HelpMessage = "DNS server address")] [ValidateNotNullOrEmpty()][string] $DNS, [Parameter(Mandatory = $false, HelpMessage= "Configure ovf properties")] [bool] $ConfigureOvfProperties = $false ) Process { Write-Host "Starting $($MyInvocation.MyCommand)..." CreateZertoUser $HostName = GetAndValidateHostName -HostName $HostName ValidateVcEnvParams -DatastoreName "$DatastoreName" -ZVMLIp "$ZVMLIp" -SubnetMask "$SubnetMask" -DefaultGateway "$DefaultGateway" -DNS "$DNS" $OvaFilePath = GetZertoOVAFile -MyZertoToken $MyZertoToken try { DeployVm -OvaPath $OvaFilePath -VMHostName $HostName -DatastoreName $DatastoreName -ZVMLIp $ZVMLIp -SubnetMask $SubnetMask -DefaultGateway $DefaultGateway -DNS $DNS -AzureTenantId $AzureTenantId -AzureClientID $AzureClientID -AvsClientSecret $AvsClientSecret -AvsSubscriptionId $AvsSubscriptionId -AvsResourceGroup $AvsResourceGroup -AvsCloudName $AvsCloudName -ConfigureOvfProperties $ConfigureOvfProperties } catch { Write-Error "Failed to deploy $ZVM_VM_NAME, exception = $_" Uninstall-Zerto -Confirmation "yes" Write-Error "Finish cleanup environment" -ErrorAction Stop } StartZVM } } Function Uninstall-Zerto { <# .DESCRIPTION Uninstall Zerto Applience .PARAMETER Confirmation Confirmation for uninstalling Zerto Applience that check if the input is "yes" .EXAMPLE Uninstall-Zerto -Confirmation "yes" #> [CmdletBinding()] [AVSAttribute(30, UpdatesSDDC = $false)] param( [Parameter(Mandatory = $true, HelpMessage = "Confirmation for unistall, type yes to confirm.")] [ValidateNotNullOrEmpty()][string] $Confirmation ) Process { Write-Host "Starting $($MyInvocation.MyCommand)..." if ($Confirmation -ne "yes"){ Write-Error "Need to confirm uninstall by typing 'yes'" -ErrorAction Stop } if((IsVmExists -VmName $ZVM_VM_NAME) -eq $true) { $VM = Get-VM $ZVM_VM_NAME if($VM.PowerState -eq "PoweredOn") { Write-Host "Stoping $ZVM_VM_NAME VM" Stop-VM -VM $VM -Confirm:$False -ErrorAction Stop } Write-Host "Deleting $ZVM_VM_NAME VM from disk" Remove-VM -VM $VM -DeletePermanently -confirm:$false Write-Host "Finished uninstalling Zerto..." } else { Write-Error "$ZVM_VM_NAME doesn't exist, failed to uninstall Zerto" } } } |