PowerShell. How I can output first pair of "key" = value; from hash table, then do something, then continue to putput other pairs from collection?

Viewed 38
$hash = [ordered]@{"Name" = "Con1"; "IP" = "192.168.0.44"; MAC = "00-00-00-11-22-33";}

I need output to be like that

Name "is" Con1
Details are:
IP "is" 192.168.0.44
MAC "is" 00-00-00-11-22-33

I know how to iterate thorugh keys in hashtable, but I can not understand how to:

  1. Output first "key" = value; pair
  2. Do something
  3. Continue iteration
1 Answers

I suggest to use a functional approach using Select-Object:

# Output first key/value pair (if there is any)
$hash.GetEnumerator() | Select-Object -First 1 | ForEach-Object {
    '{0} "is" {1}' -f $_.Key, $_.Value
}

'Details are:'

# Output all remaining key/value pairs (if there are any)
$hash.GetEnumerator() | Select-Object -Skip 1 | ForEach-Object {
    '{0} "is" {1}' -f $_.Key, $_.Value
}

Alternatively split the hashtable into head item and tail array.

# Collect the hashtable entries in an array @(), then split into head and tail
$head, $tail = @($hash.GetEnumerator())

# Output the head
'{0} "is" {1}' -f $head.Key, $head.Value

# Output the tail array
'Details are:'
$tail.ForEach{ '{0} "is" {1}' -f $_.Key, $_.Value }

Note this has some memory overhead as a new array is created, but it contains only references so this won't matter unless you have a really large amount of hashtable items.


Another alternative, imperative way is to use the IEnumerator methods directly:

$hash = [ordered]@{"Name" = "Con1"; "IP" = "192.168.0.44"; MAC = "00-00-00-11-22-33";}
$enumerator = $hash.GetEnumerator()

# Output first key/value pair (if there is any)
if( $enumerator.MoveNext() ) { 
    '{0} "is" {1}' -f $enumerator.Current.Key, $enumerator.Current.Value
}

'Details are:'

# Output all remaining key/value pairs (if there are any)
foreach( $item in $enumerator ) { 
    '{0} "is" {1}' -f $item.Key, $item.Value
}

Remarks:

  • IEnumerator.MoveNext() is somewhat counter-intuitive as it needs to be called before enumerating the 1st element. Otherwise the IEnumerator.Current property isn't populated.
  • The foreach loop starts off, where .MoveNext() has left the enumerator, so it starts at the 2nd item.
  • IMO the functional approach using Select-Object is clearer as each of the loops can be viewed in isolation and a quick glance at the Select-Object parameters tells us what is happening, whereas using the IEnumerator methods you have to consider what the current state of the enumerator is.

Output for all variants:

Name "is" Con1
Details are:  
IP "is" 192.168.0.44      
MAC "is" 00-00-00-11-22-33
Related