VMware Cloud Community
DBAScottClark
Contributor
Contributor

Using customization specifications with Content Library ovf

Problem statement:
We are in the process of converting our provisioning code from utilizing conventional Templates stored in specific datastores to leveraging a Content Library per datacenter to allow templates to be used across a larger surface area.  Reading through the documentation for PowerCLI New-VM doesn't support the -OSCustomizationSpec when the VM is being created from a Content Library.

Question:
Is there a way via powershell and powercli (or other means) to set the OS Customization Spec after a vm has been created via New-VM?  If so, what am I missing?

Notes:
Current snippet is as follows.

# Workaround for misplaced Templates in various datacenters $templateName = Get-MyTemplateName -Site $decodedname.Site -OS $server.OperatingSystem -Version $server.OperatingSystemVersion -Server $vcenter -Credential $Credential # -DataCenter $datacenter $datacentername = Get-MyDataCenterName -Server $vcenter -Site $decodedname.Site -Zone $decodedname.Zone -Credential $Credential $clustername = Get-MyClusterName -Server $vcenter -Site $decodedname.Site -Zone $decodedname.Zone -Category $server.Category -Credential $Credential #-ComputerName $server.ComputerName $foldername = Get-MyFolderName -Server $vcenter -Type VM -ApplicationCode $decodedname.App -Datacenter $datacentername -Credential $Credential #-ComputerName $server.ComputerName # Build the hashtable which will be used to splat params to the call to New-VM $params = @{} $params.'Name' = $server.ComputerName.ToUpper() $params.'Datastore' = try { $datastoreclustername = Get-MyDataStoreClusterName -Server $vcenter -Category $server.Category -Credential $Credential Get-DatastoreCluster -Name $datastoreclustername -Server $vcenter -ErrorAction Stop } catch { $datastorename = Get-MyDataStoreName -Server $vcenter -ComputerName $server.ComputerName -Credential $Credential Get-Datastore -Name $datastorename -Server $vcenter } $params.'ResourcePool' = try { Get-Cluster -Name $clustername -Server $vcenter -ErrorAction Stop } catch { Get-VMHost -Name $clustername -Server $vcenter } $params.'ContentLibraryItem' = Get-ContentLibraryItem -Name $templateName.Name -Server $vcenter | Where-Object{$_.ContentLibrary.Name -eq ($templateName.ContentLibrary).Name} $params.'Location' = Get-Folder -Name $foldername -Server $vcenter -Location $datacentername $params.'Server' = $vcenter $params.'OSCustomizationSpec' = try { $customizationParams = @{} $customizationParams.'Name' = $server.ComputerName $customizationParams.'IPAddress' = $ipaddress $customizationParams.'SubnetMask' = Get-MySubnetMaskFromCIDR -CIDR $server.CIDRAddress.Split('/')[1] $customizationParams.'DefaultGateway' = Get-MyDefaultGatewayFromIPAddress -IPAddress $customizationParams.IPAddress $customizationParams.'Dns' = Get-MyDNSServerIPAddress -Site $decodedname.Site -Zone $decodedname.Zone $customizationParams.'Server' = $vcenter $customizationParams.'Specification' = ('OSC_{0}_{1}' -f $server.OperatingSystem,$server.Domain).ToUpper() $customizationParams.'Credential' = $Credential New-EzVmOSCustomizationSpec @customizationParams } catch { $customizationspec = Get-OSCustomizationSpec -Name ('temp_{0}' -f $params.Name) -ErrorAction SilentlyContinue if ($customizationspec -ne $null) { Remove-OSCustomizationSpec -OSCustomizationSpec $customizationspec -Confirm:$false -ErrorAction Stop } Write-Error ('Could not create OSCustomization Spec for {0}. Error details: {1}' -f $server.ComputerName,$Error[0].Exception) } Write-Verbose ('Creating virtual machine {0} using parameters:' -f $server.ComputerName) # Create the new VM try { $vm = New-VM @params -ErrorAction Stop # Doesn't work currently with OS Customization Specifications due to implementation of Content Library for storage of templates.
# How could we apply the OS Customization Specification after the New-VM command?

} catch { Write-Error ('Could not create VM {0}. Error details: {1}' -f $server.ComputerName,$Error[0].Exception) continue } finally { Remove-OSCustomizationSpec -OSCustomizationSpec $params.OSCustomizationSpec -Confirm:$false -ErrorAction Stop }

    # Workaround for misplaced Templates in various datacenters
    $templateName = Get-F5VMWareTemplateName -Site $decodedname.Site -OS $server.OperatingSystem -Version $server.OperatingSystemVersion -Server $vcenter -Credential $Credential # -DataCenter $datacenter
 
    $datacentername = Get-F5VmWareDataCenterName -Server $vcenter -Site $decodedname.Site -Zone $decodedname.Zone -Credential $Credential
    $clustername = Get-F5VmWareClusterName -Server $vcenter -Site $decodedname.Site -Zone $decodedname.Zone -Category $server.Category -Credential $Credential  #-ComputerName $server.ComputerName
    $foldername = Get-F5VmWareFolderName -Server $vcenter -Type VM -ApplicationCode $decodedname.App -Datacenter $datacentername -Credential $Credential #-ComputerName $server.ComputerName
    
    # Build the hashtable which will be used to splat params to the call to New-VM
    $params = @{}
    $params.'Name' = $server.ComputerName.ToUpper()
    $params.'Datastore' = 
        try 
        { 
            $datastoreclustername = Get-F5VmWareDataStoreClusterName -Server $vcenter -Category $server.Category -Credential $Credential
            Get-DatastoreCluster -Name $datastoreclustername -Server $vcenter -ErrorAction Stop
        }
        catch 
        {
            $datastorename = Get-F5VMWareDataStoreName -Server $vcenter -ComputerName $server.ComputerName -Credential $Credential
            Get-Datastore -Name $datastorename -Server $vcenter
        }
 
    $params.'ResourcePool' = 
        try 
        {
            Get-Cluster -Name $clustername -Server $vcenter -ErrorAction Stop 
        }
        catch 
        {
            Get-VMHost -Name $clustername -Server $vcenter
        }
 
    $params.'ContentLibraryItem' = Get-ContentLibraryItem -Name $templateName.Name -Server $vcenter | Where-Object{$_.ContentLibrary.Name -eq ($templateName.ContentLibrary).Name}
    $params.'Location' = Get-Folder -Name $foldername -Server $vcenter -Location $datacentername
    $params.'Server' = $vcenter
    $params.'OSCustomizationSpec' = 
        try 
        {
            $customizationParams = @{}
            $customizationParams.'Name' = $server.ComputerName     
            $customizationParams.'IPAddress' = $ipaddress 
            $customizationParams.'SubnetMask' = Get-F5SubnetMaskFromCIDR -CIDR $server.CIDRAddress.Split('/')[1]
            $customizationParams.'DefaultGateway' = Get-F5DefaultGatewayFromIPAddress -IPAddress $customizationParams.IPAddress
            $customizationParams.'Dns' = Get-F5DNSServerIPAddress -Site $decodedname.Site -Zone $decodedname.Zone
            $customizationParams.'Server' = $vcenter
            $customizationParams.'Specification' = ('OSC_{0}_{1}' -f $server.OperatingSystem,$server.Domain).ToUpper()
            $customizationParams.'Credential' = $Credential
 
            New-EzVmOSCustomizationSpec @customizationParams
        }
        catch 
        {
            $customizationspec = Get-OSCustomizationSpec -Name ('temp_{0}' -f $params.Name) -ErrorAction SilentlyContinue
            
            if ($customizationspec -ne $null) {
                Remove-OSCustomizationSpec -OSCustomizationSpec $customizationspec -Confirm:$false -ErrorAction Stop
            }
            
            Write-Error ('Could not create OSCustomization Spec for {0}.  Error details: {1}' -f $server.ComputerName,$Error[0].Exception)
        }
 
    Write-Verbose ('Creating virtual machine {0} using parameters:' -f $server.ComputerName)
 
    # Create the new VM
    try 
    {
        $vm = New-VM @params -ErrorAction Stop # Doesn't work currently with OS Customization Specifications due to implementation of Content Library for storage of templates.
        
    }
    catch
    {
        Write-Error ('Could not create VM {0}.  Error details: {1}' -f $server.ComputerName,$Error[0].Exception)
 
        continue
    }
    finally 
    {
        Remove-OSCustomizationSpec -OSCustomizationSpec $params.OSCustomizationSpec -Confirm:$false -ErrorAction Stop
    }
Reply
0 Kudos
2 Replies
DBAScottClark
Contributor
Contributor

Sorry code didn't render properly  her it is in plaintext

    # Workaround for misplaced Templates in various datacenters

    $templateName = Get-MyTemplateName -Site $decodedname.Site -OS $server.OperatingSystem -Version $server.OperatingSystemVersion -Server $vcenter -Credential $Credential # -DataCenter $datacenter

 

    $datacentername = Get-MyDataCenterName -Server $vcenter -Site $decodedname.Site -Zone $decodedname.Zone -Credential $Credential

    $clustername = Get-MyClusterName -Server $vcenter -Site $decodedname.Site -Zone $decodedname.Zone -Category $server.Category -Credential $Credential  #-ComputerName $server.ComputerName

    $foldername = Get-MyFolderName -Server $vcenter -Type VM -ApplicationCode $decodedname.App -Datacenter $datacentername -Credential $Credential #-ComputerName $server.ComputerName

    

    # Build the hashtable which will be used to splat params to the call to New-VM

    $params = @{}

    $params.'Name' = $server.ComputerName.ToUpper()

    $params.'Datastore' = 

        try 

        { 

            $datastoreclustername = Get-MyDataStoreClusterName -Server $vcenter -Category $server.Category -Credential $Credential

            Get-DatastoreCluster -Name $datastoreclustername -Server $vcenter -ErrorAction Stop

        }

        catch 

        {

            $datastorename = Get-MyDataStoreName -Server $vcenter -ComputerName $server.ComputerName -Credential $Credential

            Get-Datastore -Name $datastorename -Server $vcenter

        }

 

    $params.'ResourcePool' = 

        try 

        {

            Get-Cluster -Name $clustername -Server $vcenter -ErrorAction Stop 

        }

        catch 

        {

            Get-VMHost -Name $clustername -Server $vcenter

        }

 

    $params.'ContentLibraryItem' = Get-ContentLibraryItem -Name $templateName.Name -Server $vcenter | Where-Object{$_.ContentLibrary.Name -eq ($templateName.ContentLibrary).Name}

    $params.'Location' = Get-Folder -Name $foldername -Server $vcenter -Location $datacentername

    $params.'Server' = $vcenter

    $params.'OSCustomizationSpec' = 

        try

        {

            $customizationParams = @{}

            $customizationParams.'Name' = $server.ComputerName     

            $customizationParams.'IPAddress' = $ipaddress 

            $customizationParams.'SubnetMask' = Get-MySubnetMaskFromCIDR -CIDR $server.CIDRAddress.Split('/')[1]

            $customizationParams.'DefaultGateway' = Get-MyDefaultGatewayFromIPAddress -IPAddress $customizationParams.IPAddress

            $customizationParams.'Dns' = Get-MyDNSServerIPAddress -Site $decodedname.Site -Zone $decodedname.Zone

            $customizationParams.'Server' = $vcenter

            $customizationParams.'Specification' = ('OSC_{0}_{1}' -f $server.OperatingSystem,$server.Domain).ToUpper()

            $customizationParams.'Credential' = $Credential

 

            New-EzVmOSCustomizationSpec @customizationParams

        }

        catch 

        {

            $customizationspec = Get-OSCustomizationSpec -Name ('temp_{0}' -f $params.Name) -ErrorAction SilentlyContinue

            

            if ($customizationspec -ne $null) {

                Remove-OSCustomizationSpec -OSCustomizationSpec $customizationspec -Confirm:$false -ErrorAction Stop

            }

            

            Write-Error ('Could not create OSCustomization Spec for {0}.  Error details: {1}' -f $server.ComputerName,$Error[0].Exception)

        }

 

    Write-Verbose ('Creating virtual machine {0} using parameters:' -f $server.ComputerName)

 

    # Create the new VM

    try 

    {

        $vm = New-VM @params -ErrorAction Stop # Doesn't work currently with OS Customization Specifications due to implementation of Content Library for storage of templates.

        

    }

    catch

    {

        Write-Error ('Could not create VM {0}.  Error details: {1}' -f $server.ComputerName,$Error[0].Exception)

 

        continue

    }

    finally 

    {

        Remove-OSCustomizationSpec -OSCustomizationSpec $params.OSCustomizationSpec -Confirm:$false -ErrorAction Stop

    }

    # Workaround for misplaced Templates in various datacenters
    $templateName = Get-MyTemplateName -Site $decodedname.Site -OS $server.OperatingSystem -Version $server.OperatingSystemVersion -Server $vcenter -Credential $Credential # -DataCenter $datacenter
 
    $datacentername = Get-MyDataCenterName -Server $vcenter -Site $decodedname.Site -Zone $decodedname.Zone -Credential $Credential
    $clustername = Get-MyClusterName -Server $vcenter -Site $decodedname.Site -Zone $decodedname.Zone -Category $server.Category -Credential $Credential  #-ComputerName $server.ComputerName
    $foldername = Get-MyFolderName -Server $vcenter -Type VM -ApplicationCode $decodedname.App -Datacenter $datacentername -Credential $Credential #-ComputerName $server.ComputerName
    
    # Build the hashtable which will be used to splat params to the call to New-VM
    $params = @{}
    $params.'Name' = $server.ComputerName.ToUpper()
    $params.'Datastore' = 
        try 
        { 
            $datastoreclustername = Get-MyDataStoreClusterName -Server $vcenter -Category $server.Category -Credential $Credential
            Get-DatastoreCluster -Name $datastoreclustername -Server $vcenter -ErrorAction Stop
        }
        catch 
        {
            $datastorename = Get-MyDataStoreName -Server $vcenter -ComputerName $server.ComputerName -Credential $Credential
            Get-Datastore -Name $datastorename -Server $vcenter
        }
 
    $params.'ResourcePool' = 
        try 
        {
            Get-Cluster -Name $clustername -Server $vcenter -ErrorAction Stop 
        }
        catch 
        {
            Get-VMHost -Name $clustername -Server $vcenter
        }
 
    $params.'ContentLibraryItem' = Get-ContentLibraryItem -Name $templateName.Name -Server $vcenter | Where-Object{$_.ContentLibrary.Name -eq ($templateName.ContentLibrary).Name}
    $params.'Location' = Get-Folder -Name $foldername -Server $vcenter -Location $datacentername
    $params.'Server' = $vcenter
    $params.'OSCustomizationSpec' = 
        try
        {
            $customizationParams = @{}
            $customizationParams.'Name' = $server.ComputerName     
            $customizationParams.'IPAddress' = $ipaddress 
            $customizationParams.'SubnetMask' = Get-MySubnetMaskFromCIDR -CIDR $server.CIDRAddress.Split('/')[1]
            $customizationParams.'DefaultGateway' = Get-MyDefaultGatewayFromIPAddress -IPAddress $customizationParams.IPAddress
            $customizationParams.'Dns' = Get-MyDNSServerIPAddress -Site $decodedname.Site -Zone $decodedname.Zone
            $customizationParams.'Server' = $vcenter
            $customizationParams.'Specification' = ('OSC_{0}_{1}' -f $server.OperatingSystem,$server.Domain).ToUpper()
            $customizationParams.'Credential' = $Credential
 
            New-EzVmOSCustomizationSpec @customizationParams
        }
        catch 
        {
            $customizationspec = Get-OSCustomizationSpec -Name ('temp_{0}' -f $params.Name) -ErrorAction SilentlyContinue
            
            if ($customizationspec -ne $null) {
                Remove-OSCustomizationSpec -OSCustomizationSpec $customizationspec -Confirm:$false -ErrorAction Stop
            }
            
            Write-Error ('Could not create OSCustomization Spec for {0}.  Error details: {1}' -f $server.ComputerName,$Error[0].Exception)
        }
 
    Write-Verbose ('Creating virtual machine {0} using parameters:' -f $server.ComputerName)
 
    # Create the new VM
    try 
    {
        $vm = New-VM @params -ErrorAction Stop # Doesn't work currently with OS Customization Specifications due to implementation of Content Library for storage of templates.
        
    }
    catch
    {
        Write-Error ('Could not create VM {0}.  Error details: {1}' -f $server.ComputerName,$Error[0].Exception)
 
        continue
    }
    finally 
    {
        Remove-OSCustomizationSpec -OSCustomizationSpec $params.OSCustomizationSpec -Confirm:$false -ErrorAction Stop
    }
Reply
0 Kudos
DBAScottClark
Contributor
Contributor

Through some thought sorted a method to get past this hurdle.  We also had one other item that wasn't exposing itself.  It seems we ran into a bug with the master in a linked vcenter environment with synched content libraries.
Changing this code to use $vm | Set-VM -OSCustomizationSpec $customizationspec -confirm:$false.  Also had to remove the parameter from the hash that is used to splat the parameters into New-VM.

Hope this helps others.
Reply
0 Kudos