Scripts/Clone/Copy-CohesityVMwareVM.ps1

function Copy-CohesityVMwareVM {
    <#
        .SYNOPSIS
        Clones the specified VMware virtual machine.
        .DESCRIPTION
        Clones the specified VMware virtual machine. The cmdlet can copy VM from remote cluster as well.
        .NOTES
        Published by Cohesity
        .LINK
        https://cohesity.github.io/cohesity-powershell-module/#/README
        .EXAMPLE
        Copy-CohesityVMwareVM -TaskName "test-clone-task" -SourceId 883 -TargetViewName "test-vm-datastore" -JobId 49402 -VmNamePrefix "clone-" -DisableNetwork -PoweredOn -ResourcePoolId 893
        Clones the VMware virtual machine with the given source id using the latest run of job id 49402.
    #>

    [CmdletBinding(DefaultParameterSetName = "Default", SupportsShouldProcess = $True, ConfirmImpact = "High")]
    Param(
        [Parameter(Mandatory = $false)]
        # Specifies the name of the clone task.
        [string]$TaskName = "Copy-VMware-VM-" + (Get-Date -Format "dddd-MM-dd-yyyy-HH-mm-ss").ToString(),
        [Parameter(Mandatory = $true)]
        # Specifies the name of the View where the cloned VM is stored.
        [string]$TargetViewName,
        [Parameter(Mandatory = $true)]
        [ValidateRange(1, [long]::MaxValue)]
        # Specifies the source id of the VM to be cloned.
        [long]$SourceId,
        [Parameter(Mandatory = $true)]
        [ValidateRange(1, [long]::MaxValue)]
        # Specifies the job id that backed up this VM and will be used for cloning.
        [long]$JobId,
        [Parameter(Mandatory = $false, ParameterSetName = "Jobrun")]
        [ValidateRange(1, [long]::MaxValue)]
        # Specifies the job run id that captured the snapshot for this VM. If not specified the latest run is used.
        [long]$JobRunId,
        [Parameter(Mandatory = $false, ParameterSetName = "Jobrun")]
        # Specifies the time when the Job Run starts capturing a snapshot.
        # Specified as a Unix epoch Timestamp (in microseconds).
        # This must be specified if job run id is specified.
        [long]$StartTime,
        [Parameter(Mandatory = $false)]
        # Specifies the prefix to add to the name of the cloned VM.
        [string]$VmNamePrefix,
        [Parameter(Mandatory = $false)]
        # Specifies the suffix to add to the name of the cloned VM.
        [string]$VmNameSuffix,
        [Parameter(Mandatory = $false)]
        # Specifies whether the network should be left in disabled state.
        [switch]$DisableNetwork,
        [Parameter(Mandatory = $false)]
        # Specifies the power state of the cloned VM.
        # By default, the VM is powered off.
        [switch]$PoweredOn,
        [Parameter(Mandatory = $false)]
        [ValidateRange(1, [long]::MaxValue)]
        # Specifies the folder where the datastore should be created when the VM is being cloned.
        [long]$DatastoreFolderId,
        [Parameter(Mandatory = $false)]
        [ValidateRange(1, [long]::MaxValue)]
        # Specify this field to override the preserved network configuration or to attach a new network configuration to the cloned VM.
        # By default, original network configuration is preserved if the VM is cloned under the same parent source and the same resource pool.
        # Original network configuration is detached if the VM is cloned under a different vCenter or a different resource pool.
        [long]$NetworkId,
        [Parameter(Mandatory = $true)]
        [ValidateRange(1, [long]::MaxValue)]
        # Specifies the resource pool where the VM should be cloned.
        [long]$ResourcePoolId,
        [Parameter(Mandatory = $false)]
        [ValidateRange(1, [long]::MaxValue)]
        # Specifies the folder where the VM should be cloned.
        # This is applicable only when the VM is being cloned to an alternate location.
        [long]$VmFolderId,
        [Parameter(Mandatory = $true)]
        [ValidateRange(1, [long]::MaxValue)]
        # Specifies a new parent source such as vCenter to clone the VM.
        # If not specified, the VM is cloned to its original parent source.
        [long]$NewParentId
    )
    Begin {
        if (-not (Test-Path -Path "$HOME/.cohesity")) {
            throw "Failed to authenticate. Please connect to the Cohesity Cluster using 'Connect-CohesityCluster'"
        }
        $cohesitySession = Get-Content -Path $HOME/.cohesity | ConvertFrom-Json
        $cohesityCluster = $cohesitySession.ClusterUri
        $cohesityToken = $cohesitySession.Accesstoken.Accesstoken
    }

    Process {
        if ($PSCmdlet.ShouldProcess($SourceId)) {

            $job = Get-CohesityProtectionJob -Ids $JobId
            if (-not $job) {
                Write-Output "Cannot proceed, the job id '$JobId' is invalid"
                return
            }

            if ($job.IsActive -eq $false) {
                # executing operations from remote cluster
                $searchHeaders = @{'Authorization' = 'Bearer ' + $cohesityToken }

                $searchURL = $cohesityCluster + '/irisservices/api/v1/searchvms?entityTypes=kVMware&jobIds=' + $JobId
                $searchResult = Invoke-RestApi -Method Get -Uri $searchURL -Headers $searchHeaders
                if (-not $searchResult) {
                    Write-Output "Could not search VM with the job id $JobId"
                    return
                }
                $searchedVMDetails = $searchResult.vms | Where-Object { $_.vmDocument.objectId.jobId -eq $JobId -and $_.vmDocument.objectId.entity.id -eq $SourceId }
                if (-not $searchedVMDetails) {
                    Write-Output "Could not find details for VM id = "$SourceId
                    return
                }
                $vmwareDetail = $null
                if ($NewParentId) {
                    $searchURL = $cohesityCluster + '/irisservices/api/v1/entitiesOfType?environmentTypes=kVMware&vmwareEntityTypes=kVCenter&vmwareEntityTypes=kStandaloneHost&vmwareEntityTypes=kvCloudDirector'
                    $searchResult = Invoke-RestApi -Method Get -Uri $searchURL -Headers $searchHeaders
                    $vmwareDetail = $searchResult | Where-Object { $_.id -eq $NewParentId }
                    if (-not $vmwareDetail) {
                        Write-Output "The new parent id is incorrect '$NewParentId'"
                        return
                    }
                }

                $resourcePoolDetail = $null
                if ($ResourcePoolId) {
                    $searchURL = $cohesityCluster + '/irisservices/api/v1/resourcePools?vCenterId=' + $vmwareDetail.id
                    $searchResult = Invoke-RestApi -Method Get -Uri $searchURL -Headers $searchHeaders
                    $resourcePoolDetail = $searchResult | Where-Object { $_.resourcePool.id -eq $ResourcePoolId }
                    if (-not $resourcePoolDetail) {
                        Write-Output "The resourcepool id '$ResourcePoolId' is not available for parent id '$NewParentId'"
                        return
                    }
                    $resourcePoolDetail = $resourcePoolDetail.resourcePool
                }

                $datastoreDetail = $null
                if ($DatastoreFolderId) {
                    $searchURL = $cohesityCluster + '/irisservices/api/v1/datastores?resourcePoolId=' + $ResourcePoolId + '&vCenterId=' + $NewParentId
                    $searchResult = Invoke-RestApi -Method Get -Uri $searchURL -Headers $searchHeaders
                    $datastoreDetail = $searchResult | Where-Object { $_.id -eq $DatastoreFolderId }
                    if (-not $datastoreDetail) {
                        Write-Output "The datastore id '$DatastoreFolderId' is not available for resourcepool id '$ResourcePoolId' and parent id '$NewParentId'"
                        return
                    }
                }

                $vmFolderDetail = $null
                if ($VmFolderId) {
                    $searchURL = $cohesityCluster + '/irisservices/api/v1/vmwareFolders?resourcePoolId=' + $ResourcePoolId + '&vCenterId=' + $NewParentId
                    $searchResult = Invoke-RestApi -Method Get -Uri $searchURL -Headers $searchHeaders
                    $vmFolder = $searchResult.vmFolders | Where-Object { $_.id -eq $VmFolderId }
                    if (-not $vmFolder) {
                        Write-Output "The vm folder id '$VmFolderId' is not available for resourcepool id '$ResourcePoolId' and parent id '$NewParentId'"
                        return
                    }
                    $vmFolderDetail = @{
                        targetVmFolder = $vmFolder
                    }
                }

                $networkDetail = $null
                if ($NetworkId) {
                    $searchURL = $cohesityCluster + '/irisservices/api/v1/networkEntities?resourcePoolId=' + $ResourcePoolId + '&vCenterId=' + $NewParentId
                    $searchResult = Invoke-RestApi -Method Get -Uri $searchURL -Headers $searchHeaders
                    $foundNetwork = $searchResult | Where-Object { $_.id -eq $NetworkId }
                    if (-not $foundNetwork) {
                        Write-Output "The network id '$NetworkId' is not available for resourcepool id '$ResourcePoolId' and parent id '$NewParentId'"
                        return
                    }
                    $networkDetail = @{
                        networkEntity = $foundNetwork
                    }
                }

                $vmObject = $searchedVMDetails.vmDocument.objectId
                if ($JobRunId) {
                    $vmObject | Add-Member -NotePropertyName jobInstanceId -NotePropertyValue $JobRunId
                    $vmObject | Add-Member -NotePropertyName startTimeUsecs -NotePropertyValue $StartTime
                }
                $vmObjects = @()
                $vmObjects += $vmObject

                $renameVMObject = $null
                if ($VmNamePrefix -or $VmNameSuffix) {
                    $renameVMObject = @{}
                    if ($VmNamePrefix) {
                        $renameVMObject.Add("prefix", $VmNamePrefix)
                    }
                    if ($VmNameSuffix) {
                        $renameVMObject.Add("suffix", $VmNameSuffix)
                    }
                }
                $cloneRequest = @{
                    continueRestoreOnError       = $true
                    name                         = $TaskName
                    objects                      = $vmObjects
                    powerStateConfig             = @{
                        powerOn = $PoweredOn.IsPresent
                    }
                    renameRestoredObjectParam    = $renameVMObject
                    restoredObjectsNetworkConfig = @{
                        networkEntity  = $networkDetail.networkEntity
                        detachNetwork  = $false
                        disableNetwork = $DisableNetwork.IsPresent
                    }
                    restoreParentSource          = $vmwareDetail
                    resourcePoolEntity           = $resourcePoolDetail
                    datastoreEntity              = $datastoreDetail
                    vaultRestoreParams           = @{
                        glacier = @{
                            retrievalType = "kStandard"
                        }
                    }
                    vmwareParams                 = @{
                        targetVmFolder          = $vmFolderDetail.targetVmFolder
                        preserveTagsDuringClone = $true
                    }
                    viewName                     = $TargetViewName
                }
                $cohesityUrl = $cohesityCluster + '/irisservices/api/v1/clone'
            }
            else {
                $vmwareParams = [PSCustomObject]@{
                    detachNetwork = $false
                }
                if ($PoweredOn.IsPresent) {
                    $vmwareParams | Add-Member -NotePropertyName poweredOn -NotePropertyValue $true
                }
                if ($DisableNetwork.IsPresent) {
                    $vmwareParams | Add-Member -NotePropertyName disableNetwork -NotePropertyValue $true
                }
                if ($VmNamePrefix) {
                    $vmwareParams | Add-Member -NotePropertyName prefix -NotePropertyValue $VmNamePrefix
                }
                if ($VmNameSuffix) {
                    $vmwareParams | Add-Member -NotePropertyName suffix -NotePropertyValue $VmNameSuffix
                }
                if ($DatastoreFolderId) {
                    $vmwareParams | Add-Member -NotePropertyName datastoreFolderId -NotePropertyValue $DatastoreFolderId
                }
                if ($NetworkId) {
                    $vmwareParams | Add-Member -NotePropertyName networkId -NotePropertyValue $NetworkId
                }
                if ($ResourcePoolId) {
                    $vmwareParams | Add-Member -NotePropertyName resourcePoolId -NotePropertyValue $ResourcePoolId
                }
                if ($VmFolderId) {
                    $vmwareParams | Add-Member -NotePropertyName vmFolderId -NotePropertyValue $VmFolderId
                }
                $cloneObject = @{
                    jobId              = $JobId
                    protectionSourceId = $SourceId
                }
                if ($JobRunId) {
                    $cloneObject | Add-Member -NotePropertyName JobRunId -NotePropertyValue $JobRunId
                    $cloneObject | Add-Member -NotePropertyName StartedTimeUsecs -NotePropertyValue $StartTime
                }
                $cloneRequest = [PSCustomObject]@{
                    name             = $TaskName
                    type             = "kCloneVMs"
                    continueOnError  = $true
                    targetViewName   = $TargetViewName
                    vmwareParameters = $vmwareParams
                    newParentId      = $NewParentId
                    objects          = @($cloneObject)
                }
                $cohesityUrl = $cohesityCluster + '/irisservices/api/v1/public/restore/clone'
            }
            $payloadJson = $cloneRequest | ConvertTo-Json -Depth 100
            $cohesityHeaders = @{'Authorization' = 'Bearer ' + $cohesityToken }
            $resp = Invoke-RestApi -Method Post -Uri $cohesityUrl -Headers $cohesityHeaders -Body $payloadJson
            if ($resp) {
                $resp
            }
            else {
                $errorMsg = $Global:CohesityAPIStatus.ErrorMessage + ", VMwareVM : Failed to copy."
                Write-Output $errorMsg
                CSLog -Message $errorMsg
            }
        }
        else {
            return
        }
    }

    End {
    }
}