Q: got trouble getting a hash table / custom object together

Hi NG,

I got a script here from which I want to create a little table that wraps together:

  1. the URL from the XenServer poolmaster and
  2. the XenDesktop machine catalogs that are pointing to it

The result should look sort of like this:

poolmaster machine catalog
http://1234567 Catalog 1
Catalog 2
Catalog 3
http://6789832 Catalog 1
Catalog 2

My issue is that I use a hash table…well from what I understand so far but only the last foreach interation is in the hash table. The script itself is technically working as I can see on the console.

Add-PSSnapin Citrix*
Add-PSSnapin xenserver

$stradminaddress = “MYDELIVERYCONTROLLER”
$currentVDArelease = “-V1234-”

Login Data

$credentials = Get-Credential -UserName “MYDOMAIN” -Message “Enter your domain credentials here

Get all Poolmaster IPs from XenDesktop broker

$poolmasterips = get-ChildItem xdhyp:\connections -AdminAddress $stradminaddress | select -ExpandProperty HypervisorAddress -Unique
$poolmasterips

#Connect to all poolmasters
foreach ($poolmasterip in $poolmasterips)
{
try
{
connect-xenserver -url $poolmasterip -Creds $credentials
}

catch
{
write-output "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
write-output "Could not connect to $poolmasterip"
write-output "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
}

}

Get all Poolnames

$xensession = get-xensession | select -ExpandProperty opaque_ref
$poolnames = $xensession | foreach {(get-xenpool -SessionOpaqueRef $_).name_label}

Check if newest release Machine catalog exist for Standard and Premium

Check each Poolmaster IP for existing current VDA release machine catalogs

foreach ($poolmasterip in $poolmasterips)
{

Get hypervisorconnection names from pool master IP

write-output “STEP 1:---------------------------------------------------------”
write-output “Getting host connection names for poolmaster ip $poolmasterip…”
$hypervisornames = get-childitem xdhyp:\connections -AdminAddress $stradminaddress | where {$_.HypervisorAddress -eq $poolmasterip} | select -ExpandProperty HypervisorConnectionName
$hypervisornames
write-output “Done with STEP 1!”
Write-output “----------------------------------------------------------------”

foreach ($hypervisorname in $hypervisornames)
{
# Get hosting unit Uid by host connection names
write-output "STEP 2:---------------------------------------------------------" 
write-output "Getting hosting unit Uid by host connection names for $hypervisorname..."
$hostingunitids = Get-ChildItem xdhyp:\hostingunits -AdminAddress $stradminaddress | where {$_.HypervisorConnection -like "*$hypervisorname*"} | select -ExpandProperty HostingUnitUid | select -ExpandProperty GuiD
$hostingunitids
write-output "Done with STEP 2!"
Write-output "----------------------------------------------------------------------"
  

    # Cycle through $hostingunitids and retrieve prov schemes and put them in a list
    $ProvisioningSchemelist = foreach ($hostingunitid in $hostingunitids)
    {
    $provschemeid = Get-ProvScheme -AdminAddress $stradminaddress | where {$_.HostingUnitUid -like "*$hostingunitid*"} | select -ExpandProperty ProvisioningSchemeUid | select -ExpandProperty Guid
    @($provschemeid)
    }

    foreach ($ProvisioningSchemeUid in $ProvisioningSchemelist)
    {
    # Get machine catalogs matching the Provisioning Schema ID
    write-output "STEP 3:---------------------------------------------------------"
    write-output "Getting machine catalogs matching the Provisioning Schema ID $ProvisioningSchemeUid..."
    $brokercatalogs = get-brokercatalog -AdminAddress $stradminaddress | where {$_.PvsForVM -like "*$ProvisioningSchemeUid*"} | select -expandproperty name
    $brokercatalogs
    Write-Output "Done with STEP 3!"
    Write-output "------------------------------------------------------------------"
    $PoolmasterCataloglist = @{PoolmasterIP=$poolmasterip; BrokerCatalog=$brokercatalogs} 
    }    
} 

}

$PoolmasterCataloglist

get-xensession | Disconnect-XenServer

 -------------- END -----------------

Regards

Christian

Hi Christian,

You are replacing the hash-table in each loop.

Try to define an empty hash-table in the beginning of the script like this:
$PoolmasterCataloglist = @{}

Then in each iteration, add one entry to the hash-table:
$PoolmasterCataloglist.Add($poolmasterip, $brokercatalogs)

This will create a hash-table where the IP is the key and the list of brokercatalogs will be the value.

Hi Simon,

thanks for your fast reply but I still have issues.

I inserted $PoolmasterCataloglist = @{} just before the 1st foreach loop.

I exchanged $PoolmasterCataloglist = @{PoolmasterIP=$poolmasterip; BrokerCatalog=$brokercatalogs} with $PoolmasterCataloglist.Add($poolmasterip, $brokercatalogs).

It is better now but I’m still missing info. When I run the script now I repeatedly receive this error:

Exception calling “Add” with “2” argument(s): “Item has already been added. Key in dictionary: ‘http://172.16.36.2’ Key being added: ‘http://172.16.36.2’”
At C:\Users\myusername\Desktop\New folder\Untitled2.ps1:86 char:9

  •     $PoolmasterCataloglist.Add($poolmasterip, $brokercatalogs)
    
  •     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    • CategoryInfo : NotSpecified: (:slight_smile: [], MethodInvocationException
    • FullyQualifiedErrorId : ArgumentException

My hast table has 1 machine catalog now for each hypervisor URL. We got multiple machine catalogs though pointing to each of the hypervisor URLs. When I run the script I can see through the console that the loops themself work because the correct values are displayed on the console.

I believe the script want to add a value to the hash table that is already present which is fully understandable. The script checks the hypervisor URL then checks for the machine catalogs and want to add 3 machine catalogs. The machine catalogs are not the issue because they all have different names but from what I understand is the script wants to add the hypervisor URL again for each machine catalog belonging to that particular hypervisor URL.

Is it somewhat clear what I mean?

Regards

Christian

Hi Christian,

I am not quite sure that I follow but the thing with hashtables is that they are a list of Keys that each has a Value and each Key has to be unique.
That is why you are getting the errors.

Hashtables are great when dealing with large amounts of data where each entry has a key attribute because they are extremely fast to search for that key attribute and return its value.

If you just want a table you might be better off using a custom object.

In that case I would use a trick to create a generic list by invoking an empty scriptblock in the beginning of the script.
$List = {}.Invoke()

Then create PSCustomObjects and add them to the list like this:

$Entry = [PSCustomObject] @{
   PoolmasterIP   = $poolmasterip
   BrokerCatalog = $brokercatalogs
}
$List.Add($Entry)

Hi Simon,

“…each Key has to be unique.” I think that’s the reason why it does not work since I would have the hypervisor URL multiple times.

I will try the PScustomobject then. I’ll report back about my progress. Thanks a lot for your quick help here!

Regards

Christian

Hi Simon,

I must admit I still have only 1 catalog per hypervisorconnection URL.

I don’t want to stress your support too much. I will dig down the PS custom object docu to get some more insight.

Thanks for all your support.

Regards

Christian

Hi again Simon,

I tested around a little bit with PScustomobject.

Essentially I ran into these issues:

  1. As mentioned before I don’t have unique value for at least one of the members in my custom object.
  2. My custom object does not have the method ADD - at least what the error is telling me.

I tried this combo:

$poolmasterbrokerlist = New-Object psobject -Property @{poolmaster=""; brokercatalog=""}

$poolmasterbrokerlist.add($poolmasterip,$brokercatalogs)

Result:

Method invocation failed because [System.Management.Automation.PSCustomObject] doesn’t contain a method named ‘add’.
At line:1 char:1

  • $poolmasterbrokerlist.add($poolmasterip,$brokercatalogs)
  •   + CategoryInfo          : InvalidOperation: (add:String) [], RuntimeException
      + FullyQualifiedErrorId : MethodNotFound
    
    
    

I checked on the shell for the methods:

TypeName: System.Management.Automation.PSCustomObject

Name MemberType Definition


Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
ToString Method string ToString()
brokercatalog NoteProperty System.String brokercatalog=
poolmaster NoteProperty System.String poolmaster=

…no ADD.

I googled around to find some way to add “values” to my custom object. All I could find with my limited knowledge was ADD-MEMBER. This didn’t give me the solution though because it want to add my members again and of course tells me that those members already exist.

Most of the time I see people create a hash table first and then use the variable to create a custom object… well that does not work for me since I produce multple similar values which the hash table does not accept.

PCcustom object seems like it’s a way to for. How can I add the ADD-method to it?

Regards

Christian

Hi again Simon,

I finally made it.

I found this page http://www.powershellmagazine.com/2013/02/04/creating-powershell-custom-objects/ and read it again, again and again.

On the beginnen of the script I placed:

$poolmasterbrokerlistcol = @()

At the end of the last loop I placed this:

$properties = @{

    poolmaster=$poolmasterip;
    brokercatalog=$brokercatalogs
    }

    
    $object = New-Object PSObject -Property $properties 
    
    $poolmasterbrokerlistcol += $object

Works!

Regards

Christian

Exactly! Good Job!