vmware / PowerCLI-Example-Scripts

http://blogs.vmware.com/powercli
Other
765 stars 608 forks source link

New-HVPool & Nics #376

Open breezytm opened 4 years ago

breezytm commented 4 years ago

Hi,

I am writing a script to automate some pools creation since we are migrating from linked clones to instant clones and I have been facing an issue when it comes to the -Nics parameter. I know it's optional but due to VLANs and DCHP restrictions I would like to assign each pool their own network(s). Anyway someone can provide me a sample on how to use the parameter using a port group label as string.

-Nics <DesktopNetworkInterfaceCardSettings[]> desktopSpec.automatedDesktopSpec.virtualCenterProvisioningSettings.virtualCenterNetworkingSettings.nics

CajunBard commented 4 years ago

The parameter -nics for both New-HVPool and Set-HVPool are not fully fleshed out, so it involves a bit more work. The crux is to create an object of DesktopNetworkInterfaceCardSettings[] first, which is easier said than done.

This example updates an existing pool. It could be modified to create a new pool.

Start by making sure the 5 variables are changed to match your environment.

#Change these variables to match your desired settings
$PoolName = "vdi-win10"
$ClusterName = "Cluster-1"
$DataCenterName = "SDDC-Datacenter"
$VirtualCenterName = "vcenter.domain.com"
$NetworkLabelName = "Horizon-Network"

#Initiated service and objects
$services = $global:DefaultHVServers.ExtensionData
$DataCenterService = New-Object VMware.Hv.DatacenterService
$HostOrClusterService = New-Object VMware.Hv.HostOrClusterService
$NetworkLabelService = New-Object VMware.Hv.NetworkLabelService
$NetworkInterfaceCardService = New-Object VMware.Hv.NetworkInterfaceCardService

$VirtualCenterInfo = Get-HVvCenterServer -Name $VirtualCenterName
$DataCenterInfo = $DataCenterService.Datacenter_List($services, $VirtualCenterInfo.Id) | Where-Object { $_.ServerSpec.ServerName -eq $VirtualCenterName }
$HostOrClusterList = $HostOrClusterService.HostOrCluster_GetHostOrClusterTree($services, $DataCenterInfo.Id)
$ClusterInfo = $HostOrClusterList.TreeContainer.Children.Info | Where-Object { $_.Name -eq $ClusterName }

$NetworkLabelList = $NetworkLabelService.NetworkLabel_ListByHostOrCluster($services, $ClusterInfo.Id)
$NetworkLabelInfo = $NetworkLabelList | Where-Object {$_.Data.Name -eq $NetworkLabelName }

$PoolInfo = Get-HVPool -PoolName $PoolName
$NetworkInterfaceCardInfo = $NetworkInterfaceCardService.NetworkInterfaceCard_ListBySnapshot($services, $PoolInfo.AutomatedDesktopData.VirtualCenterProvisioningSettings.VirtualCenterProvisioningData.Snapshot)

# Build the spec
$DesktopNetworklabelAssignmentSpec = New-Object VMware.Hv.DesktopNetworkLabelAssignmentSpec
$DesktopNetworklabelAssignmentSpec.enabled = $true
$DesktopNetworklabelAssignmentSpec.networkLabel = $NetworkLabelInfo.Id
#Change these according to https://vdc-download.vmware.com/vmwb-repository/dcr-public/93e1f7c4-fae6-4e10-b3be-7c73720b4589/2f59c85d-2770-45cd-bd9d-3a5cc747f3a3/vdi.resources.Desktop.NetworkLabelAssignmentSpec.html
$DesktopNetworklabelAssignmentSpec.maxLabelType = "UNLIMITED"
$DesktopNetworklabelAssignmentSpec.maxLabel = $null

$DesktopNetworkInterfaceCardSettings = New-Object VMware.Hv.DesktopNetworkInterfaceCardSettings
$DesktopNetworkInterfaceCardSettings.Nic = $NetworkInterfaceCardInfo.Id
$DesktopNetworkInterfaceCardSettings.NetworkLabelAssignmentSpecs = $DesktopNetworklabelAssignmentSpec

[VMware.Hv.DesktopNetworkInterfaceCardSettings[]]$niclist = @()
$niclist += $DesktopNetworkInterfaceCardSettings

Set-HVPool -PoolName $PoolName -Key "automatedDesktopData.virtualCenterProvisioningSettings.virtualCenterNetworkingSettings.nics" -Value $niclist
breezytm commented 4 years ago

Thanks for the answer above. Unfortunately It didn't work. Some of the variables were not declared.

For example $DataCenterHelper and $DataCenter were never defined; therefore, these two lines errors out

$DataCenterInfo = $DataCenterHelper.Datacenter_List($services, $VirtualCenterInfo.Id) | Where-Object { $_.ServerSpec.ServerName -eq $VirtualCenterName }
$HostOrClusterList = $HostOrClusterService.HostOrCluster_GetHostOrClusterTree($services, $DataCenter.Id)

I was able to correct the script by doing the following

$DataCenterInfo = $DataCenterService.Datacenter_List($services, $VirtualCenterInfo.Id) | Where-Object { $_.Base.Name -eq $DataCenterName }
$HostOrClusterList = $HostOrClusterService.HostOrCluster_GetHostOrClusterTree($services, $DataCenterInfo.Id)

With these changes I was able to move forward with the script and then I reached a new problem which I don't fully comprehend. I attached the script to this thread. Perhaps you can take a look. Do keep in mind it is in its very early stage.

Error message

Exception calling "Desktop_Create" with "2" argument(s): "There is an error in the XML document."
At C:\Program Files\WindowsPowerShell\Modules\VMware.Hv.Helper\VMware.HV.Helper.psm1:4905 char:7
+       $id = $desktop_helper.Desktop_create($services,$desktopSpecObj)
+       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : InvalidOperationException
mattivoxy commented 4 years ago

@breezytm

Thanks for pressing on this. Couple things:

mattivoxy commented 4 years ago

Of note: this will only work once the pool is created and published; the "snapshot" property doesn't exist until the parent VM is published. Since you're trying to do this @ creation, it will certainly fail as the snapshot doesn't exist yet. Here's the line where it's breaking, most likely:

$NetworkInterfaceCardInfo = $NetworkInterfaceCardService.NetworkInterfaceCard_ListBySnapshot($services, $PoolInfo.AutomatedDesktopData.VirtualCenterProvisioningSettings.VirtualCenterProvisioningData.Snapshot)

So basically, we need to wait for the pool to completely provision/publish, and then we can make the change. Now, how to programatically sniff that out, or just setup a ~5m timer (ick)?

breezytm commented 4 years ago

@mattivoxy

The password to the script is VMware! I password protected it because it is in early stage and I need to do a lot of clean up. I didn't want to show it to the world yet.

So basically, we need to wait for the pool to completely provision/publish, and then we can make the change. Now, how to programatically sniff that out, or just setup a ~5m timer (ick)?

So far I've seen only two people used it and they both were updating a pool. I don't understand why would the cmdlet has a parameter that can't be used during pool creation.

mattivoxy commented 4 years ago

Is it necessary to reference $PoolInfo.AutomatedDesktopData.VirtualCenterProvisioningSettings.VirtualCenterProvisioningData.Snapshot as part of this operation? That is what doesn't exist until the pool is published, which takes some time obviously. If that part is unnecessary maybe we can get around that.

CajunBard commented 4 years ago

@breezytm Taking a look at your script, the New-HVPool command is using -nics, which to be clear, is not yet implemented.

See this line for what I mean by that. https://github.com/vmware/PowerCLI-Example-Scripts/blob/d64e0fbdc09309a3c7261d0faa9371695f64b9ef/Modules/VMware.Hv.Helper/VMware.HV.Helper.psm1#L4462

That being said, as a workaround you could create the pool as you do today, without specifying the -nic parameter. Make sure that -enableProvisioning is set to $false to prevent the new machines from being created.

Then follow my example of using -key and -value along with Set-HVPool (including the fixes that you reference in https://github.com/vmware/PowerCLI-Example-Scripts/issues/376#issuecomment-678787458).

Then in the next step, enable provisioning by running Set-HVPool -Key 'automatedDesktopData.virtualCenterProvisioningSettings.enableProvisioning' -Value $true

I realize this isn't an ideal workflow, but it's all I can offer at the moment, until I, or someone else, has time to flesh out the -nics parameter to both New-HVPool and Set-HVPool.

CajunBard commented 4 years ago

Is it necessary to reference $PoolInfo.AutomatedDesktopData.VirtualCenterProvisioningSettings.VirtualCenterProvisioningData.Snapshot as part of this operation? That is what doesn't exist until the pool is published, which takes some time obviously. If that part is unnecessary maybe we can get around that.

@mattivoxy This only needs to be referenced for existing pools. It was done this way to ensure that when editing an existing pool, we reference the same BaseImageSnapshotId that is in use for the pool.

For new pools, if you were to manually build the DesktopSpec, then you could obtain the BaseImageSnapshotId using BaseImageSnapshot_List() from the BaseImageSnapshot service. This method does require inputting a BaseImageVmId which can be obtained using BaseImageVm_List(), an example of which can be seen here: https://github.com/vmware/PowerCLI-Example-Scripts/blob/d64e0fbdc09309a3c7261d0faa9371695f64b9ef/Modules/VMware.Hv.Helper/VMware.HV.Helper.psm1#L4959

More information on the BaseImageSnapshot service: https://vdc-download.vmware.com/vmwb-repository/dcr-public/93e1f7c4-fae6-4e10-b3be-7c73720b4589/2f59c85d-2770-45cd-bd9d-3a5cc747f3a3/vdi.utils.virtualcenter.BaseImageSnapshot.html

breezytm commented 4 years ago

@freythman I did exactly what you mentioned and am still getting the error.

I removed the -nics parameter as well as setting -enableprovisioning $false but I still get the same error.

No error is retured with -WhatIf so i don't know where the problem is coming from at this point and tomorrow is the day. I am running out of time.

What if: Performing the operation "New-HVPool" on target "TESTVM".

Base                  : VMware.Hv.DesktopBase
DesktopSettings       : VMware.Hv.DesktopSettings
Type                  : AUTOMATED
AutomatedDesktopSpec  : VMware.Hv.DesktopAutomatedDesktopSpec
ManualDesktopSpec     : 
RdsDesktopSpec        : 
GlobalEntitlementData : 
CajunBard commented 4 years ago

The function has a debug mode, that is currently disabled. Can you uncomment this code block and re-run your script? You will need to unload/reload the module after the edit. That will output a .json file with the full output of the DesktopSpec. Seeing that would be helpful.

Optionally, you can also enable verbose output in PowerShell, which may (or may not) offer more useful information.

$VerbosePreference = 'Continue'

The error you referenced above means that something with the DesktopSpec is incorrect. At a glance, you can remove the following parameters to simplify troubleshooting this error since they are set as $null in your .csv file.

-SpecificNames
-PowerOffScriptName
-PowerOffScriptParameters
-PostSynchronizationScriptName
-ConnectionServerRestrictions
-GlobalEntitlement
breezytm commented 4 years ago

@freythman

Understood. As I troubleshoot further, I see there may be a potential issues with my csv containing the word $null. It may not like that. So far the items you mentioned above to remove where all set to $null

I think we reached the same conclusion. I can't get rid of them completely since some pools may have them populated and some may not. Currently I am trying to figure out a way to convert empty space in the csv as $null

I will test that and get back to you.

breezytm commented 4 years ago

@freythman

Here's an update. I was able to identify the issue with the pool creation. It turns out to be three things.

  1. -ConnectionServerRestrictions must have a value. It does not accept neither null nor an empty string. I am still trying to figure out how to code around that limitation.
  2. -Datastores, -StorageOvercommit,must be in this format Datastore1,Datastore2,Datastore3 and UNBOUNDED,UNBOUNDED,UNBOUNDED

However, the -nics is still an issue. If you can take a look at the code you send me with the changes I made and see if you can pinpoint the issue.

    #Initiated service and objects
    $services = $HVServer.ExtensionData
    $DataCenterService = New-Object VMware.Hv.DatacenterService
    $HostOrClusterService = New-Object VMware.Hv.HostOrClusterService
    $NetworkLabelService = New-Object VMware.Hv.NetworkLabelService
    $NetworkInterfaceCardService = New-Object VMware.Hv.NetworkInterfaceCardService

    $VirtualCenterInfo = Get-HVvCenterServer -Name $Pool.Vcenter
    $DataCenterInfo = $DataCenterService.Datacenter_List($services, $VirtualCenterInfo.Id) | Where-Object { $_.Base.Name -eq $Pool.datacenter }
    $HostOrClusterList = $HostOrClusterService.HostOrCluster_GetHostOrClusterTree($services, $DataCenterInfo.Id)
    $ClusterInfo = $HostOrClusterList.TreeContainer.Children.Info | Where-Object { $_.Name -eq $Pool.HostOrCluster }

    $NetworkLabelList = $NetworkLabelService.NetworkLabel_ListByHostOrCluster($services, $ClusterInfo.Id)
    $NetworkLabelInfo = $NetworkLabelList | Where-Object {$_.Data.Name -eq $Pool.Nics }

    # Build the spec
    $DesktopNetworklabelAssignmentSpec = New-Object VMware.Hv.DesktopNetworkLabelAssignmentSpec
    $DesktopNetworklabelAssignmentSpec.enabled = $true
    $DesktopNetworklabelAssignmentSpec.networkLabel = $NetworkLabelInfo.Id
    #Change these according to https://vdc-download.vmware.com/vmwb-repository/dcr-public/93e1f7c4-fae6-4e10-b3be-7c73720b4589/2f59c85d-2770-45cd-bd9d-3a5cc747f3a3/vdi.resources.Desktop.NetworkLabelAssignmentSpec.html
    $DesktopNetworklabelAssignmentSpec.maxLabelType = $Pool.maxLabelType
    $DesktopNetworklabelAssignmentSpec.maxLabel = $Pool.maxLabel

    $DesktopNetworkInterfaceCardSettings = New-Object VMware.Hv.DesktopNetworkInterfaceCardSettings
    $DesktopNetworkInterfaceCardSettings.Nic = $NetworkInterfaceCardInfo.Id
    $DesktopNetworkInterfaceCardSettings.NetworkLabelAssignmentSpecs = $DesktopNetworklabelAssignmentSpec

    [VMware.Hv.DesktopNetworkInterfaceCardSettings[]]$niclist = @()
    $niclist += $DesktopNetworkInterfaceCardSettings

    #assign nics to existing pool
    Set-HVPool -PoolName $Pool.PoolName -Key "automatedDesktopData.virtualCenterProvisioningSettings.virtualCenterNetworkingSettings.nics" -Value $niclist

Error

Updating the Pool:  TESTVM
Exception calling "Desktop_Update" with "3" argument(s): "There is an error in the XML document."
At C:\Program Files\WindowsPowerShell\Modules\VMware.Hv.Helper\VMware.HV.Helper.psm1:6362 char:8
+        $desktop_helper.Desktop_Update($services,$item,$updates)
+        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : InvalidOperationException