2

I'm brand new to powershell, as in less than a day experience. I have an array of objects returned from a Get-ADUser call. I will be doing a lot of lookups so thought it best to build a hashtable from it.

Is there a shorthand way to initialize the hashtable with this array and specify one of the object's attributes to use as a key?

Or do I have to loop the whole array and manually add to the set?

$adSet = @{}

foreach ($user in $allusers) {

    $adSet.add($user.samAccountname, $user)
}
2
  • 1
    That (@{}) is not a hash set - it's a hashtable - and looping through the input collection is indeed the way to go :-) Commented Feb 5, 2021 at 17:10
  • Ah thanks for the clarification. Commented Feb 5, 2021 at 17:12

1 Answer 1

7

[...] do I have to loop

Yes

... the whole array ...

No

You don't have to materialize an array and use a loop statement (like foreach(){...}), you can use the pipeline to turn a stream of objects into a hashtable as well, using the ForEach-Object cmdlet - this might prove faster if the input source (in the example below, that would be Get-Service) is slow:

$ServiceTable = Get-Service |ForEach-Object -Begin { $ht = @{} } -Process { $ht[$_.Name] = $_ } -End { return $ht }

The block passed as -Begin will execute once (at the beginning), the block passed to -Process will execute once per pipeline input item, and the block passed to -End will execute once, after all the input has being recevied and processed.

With your example, that would look something like this:

$ADUserTable = Get-ADUser -Filter * |ForEach-Object -Begin { $ht = @{} } -Process { $ht[$_.SAMAccountName] = $_ } -End { return $ht }

Every single "cmdlet" in PowerShell maps onto this Begin/Process/End lifecycle, so generalizing this pattern with a custom function is straightforward:

function New-LookupTable {
    param(
        [Parameter(Mandatory, ValueFromPipeline)]
        [array]$InputObject,

        [Parameter(Mandatory)]
        [string]$Property
    )

    begin {
        # initialize table
        $lookupTable = @{}
    }

    process {
        # populate table
        foreach($object in $InputObject){
            $lookupTable[$object.$Property] = $object
        }
    }

    end {
        return $lookupTable
    }
}

And use like:

$ADUserTable = Get-ADUser |New-LookupTable -Property SAMAccountName

See the about_Functions_Advanced document and related help topics for more information about writing advanced and pipeline-enabled functions

Sign up to request clarification or add additional context in comments.

5 Comments

Thanks, this helps out a lot.
@Phaelaxz That's great, you're most welcome :) You might find PSCache interesting as well (uses a hashtable to cache items but allows for granular updates)
I wish PowerShell had something like Groovy's collectEntries method or your New-LookupTable built into it. BTW, you have a typo, $PropertyName should be $Property.
@zett42 thanks updated. Yeah, it'd be nice. I guess that's the price of co-opting any existing type system, it's all designed with C# or VB in mind,
@zett42, FYI, I did a purpose for this some time ago: #13817 Enhance hash table syntax

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.