Functions/New-VMFromSnapshot.psm1

function New-VMFromSnapshot {
<#
    .SYNOPSIS
    Function to create a clone from a snapshot of a VM.
     
    .DESCRIPTION
    Function to create a clone from a snapshot of a VM.
     
    .PARAMETER SourceVM
    VM to clone from.
 
    .PARAMETER CloneName
    Name of the clone to create
 
    .PARAMETER SnapshotName
    Name of the snapshot to clone from
 
    .PARAMETER CurrentSnapshot
    Use the current snapshot instead of a named snapshot
 
    .PARAMETER Cluster
    Name of the cluster to place the clone in
 
    .PARAMETER Datastore
    Name of the datastore to place the clone in
 
    .PARAMETER VMFolder
    Name of the Virtual Machine folder to put the VM in
 
    .PARAMETER LinkedClone
    Create a linked clone from the snapshot, rather than a full clone
 
    .INPUTS
    String.
    System.Management.Automation.PSObject.
 
    .OUTPUTS
    VMware.Vim.ManagedObjectReference.
 
    .EXAMPLE
    PS> New-VMFromSnapshot -SourceVM VM01 -CloneName "Clone01" -Cluster "Test Cluster" -Datastore "Datastore01"
 
    .EXAMPLE
    PS> New-VMFromSnapshot -SourceVM VM01 -CloneName "Clone01" -SnapshotName "Testing" -Cluster "Test Cluster" -Datastore "Datastore01" -VMFolder "Test Clones" -LinkedClone
#>

[CmdletBinding(DefaultParameterSetName=”Current Snapshot”)][OutputType('VMware.Vim.ManagedObjectReference')]

    Param
    (

    [parameter(Mandatory=$true)]
    [ValidateNotNullOrEmpty()]
    [PSObject]$SourceVM,
    
    [parameter(Mandatory=$true)]
    [ValidateNotNullOrEmpty()]
    [String]$CloneName,

    [parameter(Mandatory=$true,ParameterSetName="Named Snapshot")]
    [ValidateNotNullOrEmpty()]
    [String]$SnapshotName,

    [parameter(Mandatory=$false)]
    [ValidateNotNullOrEmpty()]
    [String]$Cluster,

    [parameter(Mandatory=$false)]
    [ValidateNotNullOrEmpty()]
    [String]$Datastore,

    [parameter(Mandatory=$false)]
    [ValidateNotNullOrEmpty()]
    [String]$VMFolder,

    [parameter(Mandatory=$false)]
    [ValidateNotNullOrEmpty()]
    [Switch]$LinkedClone
    )
    
        

    # --- Retrieve snapshot tree using try / catch since if it doesn't exist, an exception is generated
    function Test-SnapshotExists ($SnapshotQuery) {

        try {
            Write-Verbose "Testing $SnapshotQuery....`n"
            $TestSnapshot = Invoke-Expression $SnapshotQuery
            Write-Output $TestSnapshot
        }

        catch [Exception]{

            $TestSnapshot = $false
            Write-Output $TestSnapshot
        }
    }

    try {            

        if ($SourceVM.GetType().Name -eq "string"){
                
            try {
                $SourceVM = Get-VM $SourceVM -ErrorAction Stop
            }
            catch [Exception]{
                Write-Warning "VM $SourceVM does not exist"
            }
        }
                
        elseif ($SourceVM -isnot [VMware.VimAutomation.ViCore.Impl.V1.Inventory.VirtualMachineImpl]){
            Write-Warning "You did not pass a string or a VM object"
            Return
        }                
                
        # --- Set values for the Clone Spec
        if ($PSBoundParameters.ContainsKey('Cluster')){
            
            $DefaultClusterResourcePoolMoRef = (Get-Cluster $Cluster | Get-ResourcePool "Resources").ExtensionData.MoRef
        }

        if ($PSBoundParameters.ContainsKey('Datastore')){

            $DatastoreMoRef = (Get-Datastore $Datastore).ExtensionData.MoRef
        }

        if ($PSBoundParameters.ContainsKey('LinkedClone')){

            $CloneType = "createNewChildDiskBacking"
        }
        else {

            $CloneType = "moveAllDiskBackingsAndDisallowSharing"
        }

        if ($PSBoundParameters.ContainsKey('VMFolder')){

            try {

                $Folder = Get-Folder $VMFolder -Type VM -ErrorAction Stop
                $CloneFolder = $Folder.ExtensionData.MoRef
            }
            catch [Exception] {

                Write-Warning "VM Folder $VMFolder does not exist, using existing folder instead"
                $CloneFolder = $SourceVM.ExtensionData.Parent
            }
        }
        else {

            $CloneFolder = $SourceVM.ExtensionData.Parent
        }                

        # --- Create CloneSpec and initiate Clone Task
        switch ($PsCmdlet.ParameterSetName) 
        { 
            "Named Snapshot"  {
                    
                $Snapshots = @()
                $SnapshotQuery = '$SourceVM.ExtensionData.Snapshot.RootSnapshotList[0]'

                while ($Snapshot = Test-SnapshotExists -SnapshotQuery $SnapshotQuery){

                    $SnapshotQuery += '.ChildSnapshotList[0]'
                    $Snapshots += $Snapshot
                }                        

                $CloneSpec = New-Object Vmware.Vim.VirtualMachineCloneSpec
                $CloneSpec.Snapshot = ($Snapshots | Where-Object {$_.Name -eq $SnapshotName}).Snapshot
                $CloneSpec.Location = New-Object Vmware.Vim.VirtualMachineRelocateSpec
                $CloneSpec.Location.Pool = $DefaultClusterResourcePoolMoRef
                $CloneSpec.Location.Datastore = $DatastoreMoRef
                $CloneSpec.Location.DiskMoveType = [Vmware.Vim.VirtualMachineRelocateDiskMoveOptions]::$CloneType

                $SourceVM.ExtensionData.CloneVM_Task($CloneFolder, $CloneName, $CloneSpec)
            }

            "Current Snapshot"  {

                $CloneSpec = New-Object Vmware.Vim.VirtualMachineCloneSpec
                $CloneSpec.Snapshot = $SourceVM.ExtensionData.Snapshot.CurrentSnapshot
                $CloneSpec.Location = New-Object Vmware.Vim.VirtualMachineRelocateSpec
                $CloneSpec.Location.Pool = $DefaultClusterResourcePoolMoRef
                $CloneSpec.Location.Datastore = $DatastoreMoRef
                $CloneSpec.Location.DiskMoveType = [Vmware.Vim.VirtualMachineRelocateDiskMoveOptions]::$CloneType

                $SourceVM.ExtensionData.CloneVM_Task($CloneFolder, $CloneName, $CloneSpec)                    
            }
        }
    }
    catch [Exception]{
        
        throw "Unable to deploy new VM from snapshot"
    }
}