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 ($ZVM -eq $null) { Write-Error "$ZVM_VM_NAME doesn't exists" -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 ($ZVM -eq $null) { Write-Error "$ZVM_VM_NAME doesn't exists" -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 -FilePathOnDatastore "$VC_PASSWORD_ROTATION_STATUS_FOLDER_NAME\$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 -FilePathOnDatastore "$CONFIGURATION_STATUS_FOLDER_NAME\$CONFIGURATION_STATUS_FILE_NAME" } } Function Wait-ForFile { param( [Parameter(Mandatory = $true, HelpMessage = "File path on datastore to wait for.")] [string]$FilePathOnDatastore ) 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 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-StatusFile -DatastoreName $dsName -FilePathOnDatastore $FilePathOnDatastore -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-StatusFile -DatastoreName $dsName -FilePathOnDatastore $VC_PASSWORD_ROTATION_STATUS_FOLDER_NAME -DatacenterName $dcName -ShowErrors } } 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-StatusFile -DatastoreName $dsName -FilePathOnDatastore $CONFIGURATION_STATUS_FOLDER_NAME -DatacenterName $dcName -ShowErrors } } Function Remove-StatusFile { param( [Parameter(Mandatory = $true, HelpMessage = "Datastore name")] [string]$DatastoreName, [Parameter(Mandatory = $true, HelpMessage = "FilePathOnDatastore")] [string]$FilePathOnDatastore, [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] $FilePathOnDatastore" $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: ` [$DatastoreName] $FilePathOnDatastore - $_. Please delete it manually." } } } } |