common_utils.ps1
$ZVM_VM_NAME = "ZVML" $CONFIGURATION_STATUS_FOLDER_NAME = ".ZvmConfigurationStatus" $CONFIGURATION_STATUS_FILE_NAME = ".zvmConfigurationStatus.json" $VC_PASSWORD_ROTATION_STATUS_FOLDER_NAME = ".ZvmVcPasswordRotationStatus" $VC_PASSWORD_ROTATION_STATUS_FILE_NAME = ".zvmVcPasswordRotationStatus.json" Function Start-ZVM { process { try { Write-Host "Starting $($MyInvocation.MyCommand)..." $ZVM = Get-VM -Name $ZVM_VM_NAME if ($null -eq $ZVM) { Write-Error "$ZVM_VM_NAME does not exist" -ErrorAction Stop } else { if ($ZVM.PowerState -eq 'PoweredOff') { Write-Host "$ZVM_VM_NAME is powered off, going to power it on" Start-VM $ZVM -ErrorAction Stop | Out-Null } else { Write-Host "$ZVM_VM_NAME is up and running" } } } catch { Write-Error "Failed to start $ZVM_VM_NAME, exception = $_" -ErrorAction Stop } } } Function Stop-ZVM { process { try { Write-Host "Starting $($MyInvocation.MyCommand)..." $ZVM = Get-VM -Name $ZVM_VM_NAME if ($null -eq $ZVM) { Write-Error "$ZVM_VM_NAME does not exist" -ErrorAction Stop } else { if ($ZVM.PowerState -eq 'PoweredOn') { Write-Host "$ZVM_VM_NAME is powered on, going to power it off" Stop-VM -VM $ZVM -Confirm:$False -ErrorAction Stop | Out-Null } else { Write-Host "$ZVM_VM_NAME is off" } } } catch { Write-Error "Failed to stop $ZVM_VM_NAME, exception = $_" -ErrorAction Stop } } } Function New-RandomPassword { Process { #Generate a password with at least 2 uppercase, 4 lowercase, 4 digits & 2 special character (!@#$%^&*()) Write-Host "Starting $($MyInvocation.MyCommand)..." $upperChars = (65..90) $lowerChars = (97..122) $numerics = (48..57) $specialChars = @(33, 35, 36, 37, 38, 40, 41, 42, 45, 64, 94) $seedArray = ($upperChars | Get-Random -Count 2) $seedArray += ($lowerChars | Get-Random -Count 4) $seedArray += ($numerics | Get-Random -Count 4) $seedArray += ($specialChars | Get-Random -Count 2) Foreach ($a in $seedArray) { $passwordAscii += , [char][byte]$a } $password = $passwordAscii -join "" return $password } } Function New-ZertoFolderOnHost { param( [Parameter(Mandatory = $true, HelpMessage = "Host Name to connect with SSH")] [string]$HostName ) process { Write-Host "Starting $($MyInvocation.MyCommand)..." $Command = "mkdir -p $ZERTO_FOLDER_ON_HOST" $Res = Invoke-SSHCommands -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" } else { Write-Host "Zerto folder ($ZERTO_FOLDER_ON_HOST) was created on $HostName." } } } Function Wait-ZVMPasswordChange { process { Write-Host "Waiting for ZVM VC password rotation. It can take up to 30 min." Wait-ForFile -FolderName $VC_PASSWORD_ROTATION_STATUS_FOLDER_NAME -FileName $VC_PASSWORD_ROTATION_STATUS_FILE_NAME } } Function Wait-ZVMConfiguration { process { Write-Host "Waiting for ZVM configuration to finish. It can take up to 1 hour." Wait-ForFile -FolderName $CONFIGURATION_STATUS_FOLDER_NAME -FileName $CONFIGURATION_STATUS_FILE_NAME } } Function Wait-ForFile { param( [Parameter(Mandatory = $true, HelpMessage = "Path of the folder that contains the file to wait for.")] [string]$FolderName, [Parameter(Mandatory = $true, HelpMessage = "File name on datastore to wait for.")] [string]$FileName ) process { $vm = Get-Vm -Name $ZVM_VM_NAME $dc = $vm | Get-Datacenter $ds = $vm | Get-Datastore $dcName = $dc.Name $dsName = $ds.Name $timeout = 3600 $startTime = Get-Date $filePathOnDatastore = Join-Path -Path $FolderName -ChildPath $FileName do { $tempPath = [System.IO.Path]::GetTempPath() $file = Copy-DatastoreItem "vmstore:\$dcName\$dsName\$filePathOnDatastore" ` -Destination $tempPath -PassThru -ErrorAction SilentlyContinue if ($null -ne $file) { $jsonContent = Get-Content -Path $file.FullName -Raw $statusInfo = $jsonContent | ConvertFrom-Json $file.Delete() Remove-StatusFileFolder -DatastoreName $dsName -FolderPathOnDatastore $FolderName -DatacenterName $dcName -ShowErrors Write-Host "Zerto configuration took: $((Get-Date).Subtract($startTime).TotalSeconds) second(s)" return $statusInfo } else { Start-Sleep -Seconds 10 $elapsedTime = (Get-Date) - $startTime if ($elapsedTime.TotalSeconds -ge $timeout) { return [PSCustomObject]@{ status = 'Failure' description = 'Timed out' } } } } until ($null -ne $file) } } Function Remove-PasswordRotationStatusFile { process { $vm = Get-Vm -Name $ZVM_VM_NAME $dc = $vm | Get-Datacenter $ds = $vm | Get-Datastore $dcName = $dc.Name $dsName = $ds.Name Remove-StatusFileFolder -DatastoreName $dsName -FolderPathOnDatastore $VC_PASSWORD_ROTATION_STATUS_FOLDER_NAME -DatacenterName $dcName } } Function Remove-ZvmConfigurationStatusFile { process { $vm = Get-Vm -Name $ZVM_VM_NAME $dc = $vm | Get-Datacenter $ds = $vm | Get-Datastore $dcName = $dc.Name $dsName = $ds.Name Remove-StatusFileFolder -DatastoreName $dsName -FolderPathOnDatastore $CONFIGURATION_STATUS_FOLDER_NAME -DatacenterName $dcName } } Function Remove-StatusFileFolder { param( [Parameter(Mandatory = $true, HelpMessage = "Datastore name")] [string]$DatastoreName, [Parameter(Mandatory = $true, HelpMessage = "FolderPathOnDatastore")] [string]$FolderPathOnDatastore, [Parameter(Mandatory = $false, HelpMessage = "Host name")] [string]$HostName, [Parameter(Mandatory = $false, HelpMessage = "Datacenter name")] [string]$DatacenterName, [Parameter(Mandatory = $false, HelpMessage = "Show errors")] [switch]$ShowErrors ) process { try { if ($HostName) { $vmHost = Get-VMHost -Name $HostName $dc = $vmHost | Get-Datacenter } elseif ($DatacenterName) { $dc = Get-Datacenter -Name $DatacenterName } else { throw "Either HostName or DatacenterName must be specified." } $file = "[$DatastoreName] $FolderPathOnDatastore" $si = Get-View ServiceInstance $fileMgr = Get-View -Id $si.Content.FileManager $fileMgr.DeleteDatastoreFile($file, $dc.ExtensionData.MoRef) } catch { if ($ShowErrors) { Write-Error "An error occurred while deleting the status file folder: [$DatastoreName] $FolderPathOnDatastore - $_. Please delete it manually." } } } } |