Updated function to support Cloud Motion & other HCX Migrations
This commit is contained in:
@@ -12,7 +12,7 @@
|
||||
RootModule = 'VMware.HCX.psm1'
|
||||
|
||||
# Version number of this module.
|
||||
ModuleVersion = '1.0.0'
|
||||
ModuleVersion = '1.0.1'
|
||||
|
||||
# Supported PSEditions
|
||||
# CompatiblePSEditions = @()
|
||||
@@ -36,7 +36,7 @@ Description = 'PowerShell Module for Managing Hybrid Cloud Extension (HCX) on VM
|
||||
PowerShellVersion = '6.0'
|
||||
|
||||
# Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export.
|
||||
FunctionsToExport = 'Connect-HcxServer', 'Get-HcxCloudConfig', 'Connect-HcxVAMI', 'Get-HcxVAMIVCConfig'
|
||||
FunctionsToExport = 'Connect-HcxServer', 'Get-HcxCloudConfig', 'Get-HcxEndpoint', 'New-HcxMigration', 'Get-HcxMigration', 'Connect-HcxVAMI', 'Get-HcxVCConfig'
|
||||
# Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export.
|
||||
CmdletsToExport = @()
|
||||
|
||||
|
||||
@@ -94,6 +94,409 @@ Function Get-HcxCloudConfig {
|
||||
}
|
||||
}
|
||||
|
||||
Function Get-HcxEndpoint {
|
||||
<#
|
||||
.NOTES
|
||||
===========================================================================
|
||||
Created by: William Lam
|
||||
Date: 09/24/2018
|
||||
Organization: VMware
|
||||
Blog: http://www.virtuallyghetto.com
|
||||
Twitter: @lamw
|
||||
===========================================================================
|
||||
|
||||
.SYNOPSIS
|
||||
List all HCX endpoints (onPrem and Cloud)
|
||||
.DESCRIPTION
|
||||
This cmdlet lists all HCX endpoints (onPrem and Cloud)
|
||||
.EXAMPLE
|
||||
Get-HcxEndpoint -cloudVCConnection $cloudVCConnection
|
||||
#>
|
||||
Param (
|
||||
[Parameter(Mandatory=$true)]$cloudVCConnection
|
||||
)
|
||||
|
||||
If (-Not $global:hcxConnection) { Write-error "HCX Auth Token not found, please run Connect-HcxManager " } Else {
|
||||
#Cloud HCX Manager
|
||||
$cloudHCXConnectionURL = $global:hcxConnection.Server + "/cloudConfigs"
|
||||
|
||||
if($PSVersionTable.PSEdition -eq "Core") {
|
||||
$cloudRequests = Invoke-WebRequest -Uri $cloudHCXConnectionURL -Method GET -Headers $global:hcxConnection.headers -UseBasicParsing -SkipCertificateCheck
|
||||
} else {
|
||||
$cloudRequests = Invoke-WebRequest -Uri $cloudHCXConnectionURL -Method GET -Headers $global:hcxConnection.headers -UseBasicParsing
|
||||
}
|
||||
$cloudData = ($cloudRequests.Content | ConvertFrom-Json).data.items[0]
|
||||
|
||||
$hcxInventoryUrl = $global:hcxConnection.Server + "/service/inventory/resourcecontainer/list"
|
||||
|
||||
$payload = @{
|
||||
"cloud" = @{
|
||||
"local"="true";
|
||||
"remote"="true";
|
||||
}
|
||||
}
|
||||
$body = $payload | ConvertTo-Json
|
||||
|
||||
if($PSVersionTable.PSEdition -eq "Core") {
|
||||
$requests = Invoke-WebRequest -Uri $hcxInventoryUrl -Body $body -Method POST -Headers $global:hcxConnection.headers -UseBasicParsing -SkipCertificateCheck
|
||||
} else {
|
||||
$requests = Invoke-WebRequest -Uri $hcxInventoryUrl -Body $body -Method POST -Headers $global:hcxConnection.headers -UseBasicParsing
|
||||
}
|
||||
if($requests.StatusCode -eq 200) {
|
||||
$items = ($requests.Content | ConvertFrom-Json).data.items
|
||||
|
||||
$results = @()
|
||||
foreach ($item in $items) {
|
||||
$tmp = [pscustomobject] @{
|
||||
SourceResourceName = $item.resourceName;
|
||||
SourceResourceType = $item.resourceType;
|
||||
SourceResourceId = $item.resourceId;
|
||||
SourceEndpointName = $item.endpoint.name;
|
||||
SourceEndpointType = "VC"
|
||||
SourceEndpointId = $item.endpoint.endpointId;
|
||||
RemoteResourceName = $cloudVCConnection.name;
|
||||
RemoteResourceType = "VC"
|
||||
RemoteResourceId = $cloudVCConnection.InstanceUuid
|
||||
RemoteEndpointName = $cloudData.cloudName;
|
||||
RemoteEndpointType = $cloudData.cloudType;
|
||||
RemoteEndpointId = $cloudData.endpointId;
|
||||
}
|
||||
$results+=$tmp
|
||||
}
|
||||
return $results
|
||||
} else {
|
||||
Write-Error "Failed to list HCX Connection Resources"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Function New-HcxMigration {
|
||||
<#
|
||||
.NOTES
|
||||
===========================================================================
|
||||
Created by: William Lam
|
||||
Date: 09/24/2018
|
||||
Organization: VMware
|
||||
Blog: http://www.virtuallyghetto.com
|
||||
Twitter: @lamw
|
||||
===========================================================================
|
||||
|
||||
.SYNOPSIS
|
||||
Initiate a "Bulk" migrations supporting Cold, vMotion, VR or new Cloud Motion
|
||||
.DESCRIPTION
|
||||
This cmdlet initiates a "Bulk" migrations supporting Cold, vMotion, VR or new Cloud Motionn
|
||||
.EXAMPLE
|
||||
Validate Migration request only
|
||||
|
||||
New-HcxMigration -onPremVCConnection $onPremVC -cloudVCConnection $cloudVC `
|
||||
-MigrationType bulkVMotion `
|
||||
-VMs @("SJC-CNA-34","SJC-CNA-35","SJC-CNA-36") `
|
||||
-NetworkMappings @{"SJC-CORP-WORKLOADS"="sddc-cgw-network-1";"SJC-CORP-INTERNAL-1"="sddc-cgw-network-2";"SJC-CORP-INTERNAL-2"="sddc-cgw-network-3"} `
|
||||
-StartTime "Sep 24 2018 1:30 PM" `
|
||||
-EndTime "Sep 24 2018 2:30 PM"
|
||||
.EXAMPLE
|
||||
Start Migration request
|
||||
|
||||
New-HcxMigration -onPremVCConnection $onPremVC -cloudVCConnection $cloudVC `
|
||||
-MigrationType bulkVMotion `
|
||||
-VMs @("SJC-CNA-34","SJC-CNA-35","SJC-CNA-36") `
|
||||
-NetworkMappings @{"SJC-CORP-WORKLOADS"="sddc-cgw-network-1";"SJC-CORP-INTERNAL-1"="sddc-cgw-network-2";"SJC-CORP-INTERNAL-2"="sddc-cgw-network-3"} `
|
||||
-StartTime "Sep 24 2018 1:30 PM" `
|
||||
-EndTime "Sep 24 2018 2:30 PM" `
|
||||
-MigrationType bulkVMotion
|
||||
#>
|
||||
Param (
|
||||
[Parameter(Mandatory=$true)][String[]]$VMs,
|
||||
[Parameter(Mandatory=$true)][Hashtable]$NetworkMappings,
|
||||
[Parameter(Mandatory=$true)]$onPremVCConnection,
|
||||
[Parameter(Mandatory=$true)]$cloudVCConnection,
|
||||
[Parameter(Mandatory=$true)][String]$StartTime,
|
||||
[Parameter(Mandatory=$true)][String]$EndTime,
|
||||
[Parameter(Mandatory=$true)][ValidateSet("Cold","vMotion","VR","bulkVMotion")][String]$MigrationType,
|
||||
[Parameter(Mandatory=$false)]$ValidateOnly=$true
|
||||
)
|
||||
|
||||
If (-Not $global:hcxConnection) { Write-error "HCX Auth Token not found, please run Connect-HcxManager " } Else {
|
||||
$hcxEndpointInfo = Get-HcxEndpoint -cloudVCConnection $cloudVCConnection
|
||||
|
||||
$inputArray = @()
|
||||
foreach ($vm in $VMs) {
|
||||
$vmView = Get-View -Server $onPremVCConnection -ViewType VirtualMachine -Filter @{"name"=$vm}
|
||||
|
||||
$cloudResourcePoolName = "Compute-ResourcePool"
|
||||
$cloudFolderName = "Workloads"
|
||||
$cloudDatastoreName = "WorkloadDatastore"
|
||||
$cloudDatacenterName = "SDDC-Datacenter"
|
||||
|
||||
$cloudResourcePool = (Get-ResourcePool -Server $cloudVCConnection -Name $cloudResourcePoolName).ExtensionData
|
||||
$cloudFolder = (Get-Folder -Server $cloudVCConnection -Name $cloudFolderName).ExtensionData
|
||||
$cloudDatastore = (Get-Datastore -Server $cloudVCConnection -Name $cloudDatastoreName).ExtensionData
|
||||
$cloudDatacenter = (Get-Datacenter -Server $cloudVCConnection -Name $cloudDatacenterName).ExtensionData
|
||||
|
||||
$placementArray = @()
|
||||
$placement = @{
|
||||
"containerType"="folder";
|
||||
"containerId"=$cloudFolder.MoRef.Value;
|
||||
"containerName"=$cloudFolderName;
|
||||
}
|
||||
$placementArray+=$placement
|
||||
$placement = @{
|
||||
"containerType"="resourcePool";
|
||||
"containerId"=$cloudResourcePool.MoRef.Value;
|
||||
"containerName"=$cloudResourcePoolName;
|
||||
}
|
||||
$placementArray+=$placement
|
||||
$placement = @{
|
||||
"containerType"="dataCenter";
|
||||
"containerId"=$cloudDatacenter.MoRef.Value;
|
||||
"containerName"=$cloudDatacenterName;
|
||||
}
|
||||
$placementArray+=$placement
|
||||
|
||||
$networkArray = @()
|
||||
$vmNetworks = $vmView.Network
|
||||
foreach ($vmNetwork in $vmNetworks) {
|
||||
if($vmNetwork.Type -eq "Network") {
|
||||
$sourceNetworkType = "VirtualNetwork"
|
||||
} else { $sourceNetworkType = $vmNetwork.Type }
|
||||
|
||||
$sourceNetworkRef = New-Object VMware.Vim.ManagedObjectReference
|
||||
$sourceNetworkRef.Type = $vmNetwork.Type
|
||||
$sourceNetworkRef.Value = $vmNetwork.Value
|
||||
$sourceNetwork = Get-View -Server $onPremVCConnection $sourceNetworkRef
|
||||
|
||||
$sourceNetworkName = $sourceNetwork.Name
|
||||
$destNetworkName = $NetworkMappings[$sourceNetworkName]
|
||||
|
||||
$destNetwork = Get-VDPortGroup -Server $cloudVCConnection -Name $destNetworkName
|
||||
|
||||
if($destNetwork.Id -match "DistributedVirtualPortgroup") {
|
||||
$destNetworkType = "DistributedVirtualPortgroup"
|
||||
$destNetworkId = ($destNetwork.Id).Replace("DistributedVirtualPortgroup-","")
|
||||
} else {
|
||||
$destNetworkType = "Network"
|
||||
$destNetworkId = ($destNetwork.Id).Replace("Network-","")
|
||||
}
|
||||
|
||||
$tmp = @{
|
||||
"srcNetworkType" = $sourceNetworkType;
|
||||
"srcNetworkValue" = $vmNetwork.Value;
|
||||
"srcNetworkHref" = $vmNetwork.Value;
|
||||
"srcNetworkName" = $sourceNetworkName;
|
||||
"destNetworkType" = $destNetworkType;
|
||||
"destNetworkValue" = $destNetworkId;
|
||||
"destNetworkHref" = $destNetworkId;
|
||||
"destNetworkName" = $destNetworkName;
|
||||
}
|
||||
$networkArray+=$tmp
|
||||
}
|
||||
|
||||
$input = @{
|
||||
"input" = @{
|
||||
"migrationType"=$MigrationType;
|
||||
"entityDetails" = @{
|
||||
"entityId"=$vmView.MoRef.Value;
|
||||
"entityName"=$vm;
|
||||
}
|
||||
"source" = @{
|
||||
"endpointType"=$hcxEndpointInfo.SourceEndpointType;
|
||||
"endpointId"=$hcxEndpointInfo.SourceEndpointId;
|
||||
"endpointName"=$hcxEndpointInfo.SourceEndpointName;
|
||||
"resourceType"=$hcxEndpointInfo.SourceResourceType;
|
||||
"resourceId"=$hcxEndpointInfo.SourceResourceId;
|
||||
"resourceName"=$hcxEndpointInfo.SourceResourceName;
|
||||
}
|
||||
"destination" = @{
|
||||
"endpointType"=$hcxEndpointInfo.RemoteEndpointType;
|
||||
"endpointId"=$hcxEndpointInfo.RemoteEndpointId;
|
||||
"endpointName"=$hcxEndpointInfo.RemoteEndpointName;
|
||||
"resourceType"=$hcxEndpointInfo.RemoteResourceType;
|
||||
"resourceId"=$hcxEndpointInfo.RemoteResourceId;
|
||||
"resourceName"=$hcxEndpointInfo.RemoteResourceName;
|
||||
}
|
||||
"placement" = $placementArray
|
||||
"storage" = @{
|
||||
"datastoreId"=$cloudDatastore.Moref.Value;
|
||||
"datastoreName"=$cloudDatastoreName;
|
||||
"diskProvisionType"="thin";
|
||||
}
|
||||
"networks" = @{
|
||||
"retainMac" = $true;
|
||||
"targetNetworks" = $networkArray;
|
||||
}
|
||||
"decisionRules" = @{
|
||||
"removeSnapshots"=$true;
|
||||
"removeISOs"=$true;
|
||||
"forcePowerOffVm"=$false;
|
||||
"upgradeHardware"=$false;
|
||||
"upgradeVMTools"=$false;
|
||||
}
|
||||
"schedule" = @{}
|
||||
}
|
||||
}
|
||||
$inputArray+=$input
|
||||
}
|
||||
|
||||
$spec = @{
|
||||
"migrations"=$inputArray
|
||||
}
|
||||
$body = $spec | ConvertTo-Json -Depth 20
|
||||
|
||||
Write-Verbose -Message "Pre-Validation JSON Spec: $body"
|
||||
$hcxMigrationValiateUrl = $global:hcxConnection.Server+ "/migrations?action=validate"
|
||||
|
||||
if($PSVersionTable.PSEdition -eq "Core") {
|
||||
$requests = Invoke-WebRequest -Uri $hcxMigrationValiateUrl -Body $body -Method POST -Headers $global:hcxConnection.headers -UseBasicParsing -ContentType "application/json" -SkipCertificateCheck
|
||||
} else {
|
||||
$requests = Invoke-WebRequest -Uri $hcxMigrationValiateUrl -Body $body -Method POST -Headers $global:hcxConnection.headers -UseBasicParsing -ContentType "application/json"
|
||||
}
|
||||
|
||||
if($requests.StatusCode -eq 200) {
|
||||
$validationErrors = ($requests.Content|ConvertFrom-Json).migrations.validationInfo.validationResult.errors
|
||||
if($validationErrors -ne $null) {
|
||||
Write-Host -Foreground Red "`nThere were validation errors found for this HCX Migration Spec ..."
|
||||
foreach ($message in $validationErrors) {
|
||||
Write-Host -Foreground Yellow "`t" $message.message
|
||||
}
|
||||
} else {
|
||||
Write-Host -Foreground Green "`nHCX Pre-Migration Spec successfully validated"
|
||||
if($ValidateOnly -eq $false) {
|
||||
try {
|
||||
$startDateTime = $StartTime | Get-Date
|
||||
} catch {
|
||||
Write-Host -Foreground Red "Invalid input for -StartTime, please check for typos"
|
||||
exit
|
||||
}
|
||||
|
||||
try {
|
||||
$endDateTime = $EndTime | Get-Date
|
||||
} catch {
|
||||
Write-Host -Foreground Red "Invalid input for -EndTime, please check for typos"
|
||||
exit
|
||||
}
|
||||
|
||||
$offset = (Get-TimeZone).GetUtcOffset($startDateTime).TotalMinutes
|
||||
$offset = [int]($offSet.toString().replace("-",""))
|
||||
|
||||
$schedule = @{
|
||||
scheduledFailover = $true;
|
||||
startYear = $startDateTime.Year;
|
||||
startMonth = $startDateTime.Month;
|
||||
startDay = $startDateTime.Day;
|
||||
startHour = $startDateTime | Get-Date -UFormat %H;
|
||||
startMinute = $startDateTime | Get-Date -UFormat %M;
|
||||
endYear = $endDateTime.Year;
|
||||
endMonth = $endDateTime.Month;
|
||||
endDay = $endDateTime.Day;
|
||||
endHour = $endDateTime | Get-Date -UFormat %H;
|
||||
endMinute = $endDateTime | Get-Date -UFormat %M;
|
||||
timezoneOffset = $offset;
|
||||
}
|
||||
|
||||
foreach ($migration in $spec.migrations) {
|
||||
$migration.input.schedule = $schedule
|
||||
}
|
||||
$body = $spec | ConvertTo-Json -Depth 8
|
||||
|
||||
Write-Verbose -Message "Validated JSON Spec: $body"
|
||||
$hcxMigrationStartUrl = $global:hcxConnection.Server+ "/migrations?action=start"
|
||||
|
||||
if($PSVersionTable.PSEdition -eq "Core") {
|
||||
$requests = Invoke-WebRequest -Uri $hcxMigrationStartUrl -Body $body -Method POST -Headers $global:hcxConnection.headers -UseBasicParsing -ContentType "application/json" -SkipCertificateCheck
|
||||
} else {
|
||||
$requests = Invoke-WebRequest -Uri $hcxMigrationStartUrl -Body $body -Method POST -Headers $global:hcxConnection.headers -UseBasicParsing -ContentType "application/json"
|
||||
}
|
||||
|
||||
if($requests.StatusCode -eq 200) {
|
||||
$migrationIds = ($requests.Content | ConvertFrom-Json).migrations.migrationId
|
||||
Write-Host -ForegroundColor Green "Starting HCX Migration ..."
|
||||
foreach ($migrationId in $migrationIds) {
|
||||
Write-Host -ForegroundColor Green "`tMigrationID: $migrationId"
|
||||
}
|
||||
} else {
|
||||
Write-Error "Failed to start HCX Migration"
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Write-Error "Failed to validate HCX Migration spec"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Function Get-HcxMigration {
|
||||
<#
|
||||
.NOTES
|
||||
===========================================================================
|
||||
Created by: William Lam
|
||||
Date: 09/24/2018
|
||||
Organization: VMware
|
||||
Blog: http://www.virtuallyghetto.com
|
||||
Twitter: @lamw
|
||||
===========================================================================
|
||||
|
||||
.SYNOPSIS
|
||||
List all HCX Migrations that are in-progress, have completed or failed
|
||||
.DESCRIPTION
|
||||
This cmdlet lists ist all HCX Migrations that are in-progress, have completed or failed
|
||||
.EXAMPLE
|
||||
List all HCX Migrations
|
||||
|
||||
Get-HcxMigration
|
||||
.EXAMPLE
|
||||
List all running HCX Migrations
|
||||
|
||||
Get-HcxMigration -RunningMigrations
|
||||
.EXAMPLE
|
||||
List all HCX Migrations
|
||||
|
||||
Get-HcxMigration -MigrationId <MigrationID>
|
||||
#>
|
||||
Param (
|
||||
[Parameter(Mandatory=$false)][String]$MigrationId,
|
||||
[Switch]$RunningMigrations
|
||||
)
|
||||
|
||||
If (-Not $global:hcxConnection) { Write-error "HCX Auth Token not found, please run Connect-HcxManager " } Else {
|
||||
$spec = @{}
|
||||
$body = $spec | ConvertTo-Json
|
||||
|
||||
$hcxQueryUrl = $global:hcxConnection.Server + "/migrations?action=query"
|
||||
if($PSVersionTable.PSEdition -eq "Core") {
|
||||
$requests = Invoke-WebRequest -Uri $hcxQueryUrl -Method POST -body $body -Headers $global:hcxConnection.headers -UseBasicParsing -SkipCertificateCheck
|
||||
} else {
|
||||
$requests = Invoke-WebRequest -Uri $hcxQueryUrl -Method POST -Headers $global:hcxConnection.headers -UseBasicParsing
|
||||
}
|
||||
|
||||
$migrations = ($requests.content | ConvertFrom-Json).rows
|
||||
|
||||
if($PSBoundParameters.ContainsKey("MigrationId")){
|
||||
$migrations = $migrations | where { $_.migrationId -eq $MigrationId }
|
||||
}
|
||||
|
||||
if($RunningMigrations){
|
||||
$migrations = $migrations | where { $_.jobInfo.state -ne "MIGRATE_FAILED" -and $_.jobInfo.state -ne "MIGRATE_CANCELED"-and $_.jobInfo.state -ne "MIGRATED" }
|
||||
}
|
||||
|
||||
$results = @()
|
||||
foreach ($migration in $migrations) {
|
||||
$tmp = [pscustomobject] @{
|
||||
ID = $migration.migrationId;
|
||||
VM = $migration.migrationInfo.entityDetails.entityName;
|
||||
State = $migration.jobInfo.state;
|
||||
Progress = ($migration.migrationInfo.progressDetails.progressPercentage).toString() + " %";
|
||||
DataCopied = ([math]::round($migration.migrationInfo.progressDetails.diskCopyBytes/1Gb, 2)).toString() + " GB";
|
||||
Message = $migration.migrationInfo.message;
|
||||
InitiatedBy = $migration.jobInfo.username;
|
||||
CreateDate = $migration.jobInfo.creationDate;
|
||||
LastUpdated = $migration.jobInfo.lastUpdated;
|
||||
}
|
||||
$results+=$tmp
|
||||
}
|
||||
$results
|
||||
}
|
||||
}
|
||||
|
||||
Function Connect-HcxVAMI {
|
||||
<#
|
||||
.NOTES
|
||||
@@ -136,7 +539,7 @@ Function Connect-HcxVAMI {
|
||||
$global:hcxVAMIConnection
|
||||
}
|
||||
|
||||
Function Get-HcxVAMIVCConfig {
|
||||
Function Get-HcxVCConfig {
|
||||
<#
|
||||
.NOTES
|
||||
===========================================================================
|
||||
@@ -152,7 +555,7 @@ Function Get-HcxVAMIVCConfig {
|
||||
.DESCRIPTION
|
||||
This cmdlet returns the onPrem vCenter Server registered with HCX Manager
|
||||
.EXAMPLE
|
||||
Get-HcxVAMIVCConfig
|
||||
Get-HcxVCConfig
|
||||
#>
|
||||
If (-Not $global:hcxVAMIConnection) { Write-error "HCX Auth Token not found, please run Connect-HcxVAMI " } Else {
|
||||
$vcConfigUrl = $global:hcxVAMIConnection.Server + "/api/admin/global/config/vcenter"
|
||||
|
||||
Reference in New Issue
Block a user