Public/Export-RubrikVApp.ps1
#Requires -Version 3 function Export-RubrikVApp { <# .SYNOPSIS Exports a given snapshot for a vCD vApp .DESCRIPTION The Export-RubrikVApp cmdlet exports a snapshot from a protected vCD vApp. .NOTES Written by Matt Elliott for community usage Twitter: @NetworkBrouhaha GitHub: shamsway .LINK https://rubrik.gitbook.io/rubrik-sdk-for-powershell/command-documentation/reference/export-rubrikvapp .EXAMPLE Export-RubrikVApp -id 'VcdVapp:::01234567-8910-1abc-d435-0abc1234d567' -snapshotid '7acdf6cd-2c9f-4661-bd29-b67d86ace70b' -ExportMode 'ExportToNewVapp' -PowerOn This exports the vApp snapshot with an id of 7acdf6cd-2c9f-4661-bd29-b67d86ace70b to a new vApp in the same Org VDC .EXAMPLE Export-RubrikVApp -id 'VcdVapp:::01234567-8910-1abc-d435-0abc1234d567' -snapshotid '7acdf6cd-2c9f-4661-bd29-b67d86ace70b' -ExportMode 'ExportToNewVapp' -NoMapping -PowerOn This exports the vApp snapshot with an id of 7acdf6cd-2c9f-4661-bd29-b67d86ace70b to a new vApp in the same Org VDC and remove existing network mappings from VM NICs .EXAMPLE Export-RubrikVApp -id 'VcdVapp:::01234567-8910-1abc-d435-0abc1234d567' -snapshotid '7acdf6cd-2c9f-4661-bd29-b67d86ace70b' -ExportMode 'ExportToNewVapp' -TargetOrgVDCID 'VcdOrgVdc:::01234567-8910-1abc-d435-0abc1234d567' -PowerOn This exports the vApp snapshot with an id of 7acdf6cd-2c9f-4661-bd29-b67d86ace70b to a new vApp in an alternate Org VDC .EXAMPLE $vapp = Get-RubrikVApp -Name 'vApp01' -PrimaryClusterID local $snapshot = Get-RubrikSnapshot -id $vapp.id -Latest $restorableVms = $vapp.vms $restorableVms[0].PSObject.Properties.Remove('vcenterVm') $vm = @() $vm += $restorableVms[0] Export-RubrikVApp -id $vapp.id -snapshotid $snapshot.id -Partial $vm -ExportMode ExportToTargetVapp This retreives the latest snapshot from the given vApp 'vApp01' and perform a partial export on the first VM in the vApp. The VM is exported into the existing parent vApp. Set the ExportMode parameter to 'ExportToNewVapp' parameter to create a new vApp for the partial export. This is an advanced use case and the user is responsible for parsing the output from Get-RubrikVApp, or gathering data directly from the API. Syntax of the object passed with the -Partial Parameter is available in the API documentation. #> [CmdletBinding(SupportsShouldProcess = $true,ConfirmImpact = 'High')] Param( # Rubrik id of the vApp to export [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true,ParameterSetName='Full')] [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true,ParameterSetName='Partial')] [ValidateNotNullOrEmpty()] [String]$id, # Rubrik snapshot id of the vApp to export [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true,ParameterSetName='Full')] [Parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true,ParameterSetName='Partial')] [ValidateNotNullOrEmpty()] [Alias('snapshot_id')] [String]$snapshotid, # Perform a Partial vApp restore. Default operation is a Full vApp restore, unless this parameter is specified. [Parameter(Mandatory = $true,ParameterSetName='Partial')] [ValidateNotNullOrEmpty()] [ValidateScript({ if ('PSCustomObject' -ne $_.GetType().Name) { Throw "Partial parameter should be a PSCustomObject" } $requiredProperties = @("name","vcdMoid","networkConnections") ForEach($item in $requiredProperties) { if(!$_.PSObject.Properties.Name.Contains($item)) { Throw "Object passed via Partial parameter missing property $($item)" } } return $true })] [PSCustomObject]$Partial, # Specifies whether export should use the existing vApp or create a new vApp. Valid values are ExportToNewVapp or ExportToTargetVapp [Parameter(Mandatory = $true)] [ValidateSet('ExportToNewVapp','ExportToTargetVapp')] [Alias('export_mode')] [String]$ExportMode, # ID of target vApp for Partial vApp Export. By default the VM(s) will be exported to their existing vApp. [Parameter(ParameterSetName='Partial')] [String]$TargetVAppID, # ID of target Org VDC for Full vApp Export. By default the VM(s) will be exported to their existing Org VDC. /vcd/hierarchy API calls can be used to determine Org VDC IDs. [Parameter(ParameterSetName='Full')] [String]$TargetOrgVDCID, # Disable NICs upon restoration. The NIC(s) will be disabled, but remain mapped to their existing network. [Parameter(ParameterSetName='Full')] [Switch]$DisableNetwork, # Remove network mapping upon restoration. The NIC(s) will not be connected to any existing networks. [Parameter(ParameterSetName='Full')] [Switch]$NoMapping, # Remove network interfaces from the restored vApp virtual machines. [Parameter(ParameterSetName='Full')] [Switch]$RemoveNetworkDevices, # Map all vApp virtual machine NICs to specified network. [Parameter(ParameterSetName='Full')] [ValidateNotNullOrEmpty()] [String]$NetworkMapping, # Power on vApp after restoration. [Parameter(ParameterSetName='Full')] [Parameter(ParameterSetName='Partial')] [switch]$PowerOn, # Rubrik server IP or FQDN [Parameter(ParameterSetName='Full')] [Parameter(ParameterSetName='Partial')] [String]$Server = $global:RubrikConnection.server, # API version [Parameter(ParameterSetName='Full')] [Parameter(ParameterSetName='Partial')] [String]$api = $global:RubrikConnection.api ) Begin { # The Begin section is used to perform one-time loads of data necessary to carry out the function's purpose # If a command needs to be run with each iteration or pipeline input, place it in the Process section # Check to ensure that a session to the Rubrik cluster exists and load the needed header data for authentication Test-RubrikConnection # API data references the name of the function # For convenience, that name is saved here to $function $function = $MyInvocation.MyCommand.Name # Retrieve all of the URI, method, body, query, result, filter, and success details for the API endpoint Write-Verbose -Message "Gather API Data for $function" $resources = Get-RubrikAPIData -endpoint $function Write-Verbose -Message "Load API data for $($resources.Function)" Write-Verbose -Message "Description: $($resources.Description)" } Process { #region oneoff $resources.Body.exportMode = $ExportMode if($PowerOn.IsPresent) { $resources.Body.shouldPowerOnVmsAfterRecovery = $true } else { $resources.Body.shouldPowerOnVmsAfterRecovery = $false } if($Partial) { Write-Verbose -Message "Performing Partial vApp Recovery" $resources.Body.vmsToExport = @() $resources.Body.vmsToExport += $Partial # Rename vApp VMs and remove unneeded data foreach($vm in $resources.Body.vmsToExport) { $vm.name = $vm.name + "-" + [string](Get-Date -Format "ddd MMM yyyy HH:mm:ss 'GMT'K") Write-Verbose -Message "vApp VM renamed to $($vm.name)" $vm.PSObject.Properties.Remove('storagePolicyId') # If exporting to a different vApp, unmap network connections if($TargetVAppID) { foreach($network in $vm.networkConnections) { Write-Verbose -Message "Unmapping $($network.vappNetworkName) from $($vm.Name)" $network.PSObject.Properties.Remove('vappNetworkName') } } } if($ExportMode -eq 'ExportToTargetVapp') { Write-Verbose -Message "Performing Partial vApp Export to Existing Target vApp" if($TargetVAppID) { $resources.Body.targetVappId = $TargetVAppID } else { $resources.Body.targetVappId = $id } $resources.Body.networksToRestore = @() $resources.Body.Remove('newVappParams') $body = ConvertTo-Json -InputObject $resources.Body -Depth 4 Write-Verbose -Message "vApp Export REST Request Body `n$($body)" } else { Write-Verbose -Message "Performing Partial vApp Export to New vApp" $vapp = Get-RubrikVapp -id $id # Collect networks to restore $networks = [System.Collections.ArrayList]@() foreach($vm in $resources.Body.vmsToExport) { foreach($network in $vm.networkConnections) { if($false -eq $networks.Contains($network.vappNetworkName)) { $networks.Add($network.vappNetworkName) | Out-Null Write-Verbose -Message "Flagged network $($network.vappNetworkName) for restore" } } } if($TargetOrgVDCID) { $orgvdc = $TargetOrgVDCID } else { # Find orgVdcId from existing vApp foreach($item in $vapp.infraPath) { if($item.id.StartsWith('VcdOrgVdc:::')) { $orgvdc = $item.id Write-Verbose -Message "Using Org VDC $($orgvdc) for export" } } } # Build networksToRestore based on networks collected from vApp $resources.Body.networksToRestore = [System.Collections.ArrayList]@() foreach($availablenet in $vapp.networks) { if($networks.Contains($availablenet.name)) { $resources.Body.networksToRestore.Add($availablenet) | Out-Null Write-Verbose -Message "Found network $($availablenet.name) information for restore" } } # Set new vApp name and orgVdcId $resources.Body.newVappParams.name = $vapp.name + "-" + [string](Get-Date -Format "ddd MMM yyyy HH:mm:ss 'GMT'K") Write-Verbose -Message "Exported vApp will be named $($resources.Body.newVappParams.name)" $resources.Body.newVappParams.orgVdcId = $orgvdc $body = ConvertTo-Json -InputObject $resources.Body -Depth 4 Write-Verbose -Message "vApp Export REST Request Body `n$($body)" } } else { # Full vApp export is always to a New vApp Write-Verbose -Message "Performing Full vApp Export to New vApp" $vapp = Get-RubrikVapp -id $id # Collect networks to restore if(-Not $NoMapping -and -Not $RemoveNetworkDevices) { $networks = [System.Collections.ArrayList]@() foreach($vm in $vapp.vms) { foreach($network in $vm.networkConnections) { if($false -eq $networks.Contains($network.vappNetworkName)) { $networks.Add($network.vappNetworkName) | Out-Null Write-Verbose -Message "Flagged network $($network.vappNetworkName) for restore" } } } } if($TargetOrgVDCID) { $orgvdc = $TargetOrgVDCID } else { # Find orgVdcId from existing vApp foreach($item in $vapp.infraPath) { if($item.id.StartsWith('VcdOrgVdc:::')) { $orgvdc = $item.id Write-Verbose -Message "Using Org VDC $($orgvdc) for export" } } } # Set new vApp name and orgVdcId $resources.Body.newVappParams.name = $vapp.name + "-" + [string](Get-Date -Format "ddd MMM yyyy HH:mm:ss 'GMT'K") Write-Verbose -Message "Exported vApp will be named $($resources.Body.newVappParams.name)" $resources.Body.newVappParams.orgVdcId = $orgvdc $resources.Body.vmsToExport = [System.Collections.ArrayList]@() foreach($vm in $vapp.vms) { $resources.Body.vmsToExport.Add($vm) | Out-Null Write-Verbose -Message "Added $($vm.name) to request" } # Build networksToRestore based on networks collected from vApp if(-Not $NoMapping -and -Not $RemoveNetworkDevices) { $resources.Body.networksToRestore = [System.Collections.ArrayList]@() foreach($availablenet in $recoveropts.availableVappNetworks) { if($networks.Contains($availablenet.name)) { $resources.Body.networksToRestore.Add($availablenet) | Out-Null Write-Verbose -Message "Found network $($availablenet.name) information for restore" } } } # Rename vApp VMs and remove unneeded data foreach($vm in $resources.Body.vmsToExport) { $vm.name = $vm.name + "-" + [string](Get-Date -Format "ddd MMM yyyy HH:mm:ss 'GMT'K") Write-Verbose -Message "vApp VM renamed to $($vm.name)" $vm.PSObject.Properties.Remove('vcenterVm') $vm.PSObject.Properties.Remove('storagePolicyId') } if($DisableNetwork) { foreach($vm in $resources.Body.vmsToExport) { foreach($network in $vm.networkConnections) { $network.isConnected = $false Write-Verbose -Message "Disabled NIC $($network.nicIndex) on $($vm.Name)" } } } if($NoMapping) { $resources.Body.networksToRestore = @() foreach($vm in $resources.Body.vmsToExport) { foreach($network in $vm.networkConnections) { Write-Verbose -Message "Unmapping $($network.vappNetworkName) from $($vm.Name)" $network.PSObject.Properties.Remove('vappNetworkName') } } } if($RemoveNetworkDevices) { $resources.Body.networksToRestore = @() foreach($vm in $resources.Body.vmsToExport) { $vm.networkConnections = @() } Write-Verbose -Message "Removed all NICs from vApp" } if($NetworkMapping) { foreach($vm in $resources.Body.vmsToExport) { foreach($network in $vm.networkConnections) { Write-Verbose -Message "Mapping NIC $($network.nicIndex) to $($NetworkMapping) network" $network.vappNetworkName = $NetworkMapping } } } $body = ConvertTo-Json -InputObject $resources.Body -Depth 4 Write-Verbose -Message "vApp Export REST Request Body `n$($body)" } #endregion $uri = New-URIString -server $Server -endpoint ($resources.URI) -id $snapshotid $uri = Test-QueryParam -querykeys ($resources.Query.Keys) -parameters ((Get-Command $function).Parameters.Values) -uri $uri # $body = New-BodyString -bodykeys ($resources.Body.Keys) -parameters ((Get-Command $function).Parameters.Values) $result = Submit-Request -uri $uri -header $Header -method $($resources.Method) -body $body $result = Test-ReturnFormat -api $api -result $result -location $resources.Result $result = Test-FilterObject -filter ($resources.Filter) -result $result return $result } # End of process } # End of function |