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

This topic contains 8 replies, has 2 voices, and was last updated by Profile photo of Simon Wåhlin Simon Wåhlin 2 years, 1 month ago.

  • Author
    Posts
  • #20161
    Profile photo of CTX_Christian
    CTX_Christian
    Participant

    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

  • #20173
    Profile photo of Simon Wåhlin
    Simon Wåhlin
    Participant

    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.

  • #20194
    Profile photo of CTX_Christian
    CTX_Christian
    Participant

    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: (:) [], 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

  • #20196
    Profile photo of Simon Wåhlin
    Simon Wåhlin
    Participant

    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)
    
  • #20198
    Profile photo of CTX_Christian
    CTX_Christian
    Participant

    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

  • #20199
    Profile photo of CTX_Christian
    CTX_Christian
    Participant

    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

  • #20246
    Profile photo of CTX_Christian
    CTX_Christian
    Participant

    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

  • #20258
    Profile photo of CTX_Christian
    CTX_Christian
    Participant

    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

  • #20261
    Profile photo of Simon Wåhlin
    Simon Wåhlin
    Participant

    Exactly! Good Job!

You must be logged in to reply to this topic.