[...] 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
@{}) is not a hash set - it's a hashtable - and looping through the input collection is indeed the way to go :-)