2

How can I convert an array of hash tables to an array of strings?

I'm trying to create a simple menu which will allow a user to select a server from a list. Here's a sample of the list:

$sqlServers = @(
    @{
        key="LOCALDB";
        serverName="(localdb)\mssqllocaldb"; 
        credentials="-E";
        userEntry="L"; 
        menuText="(L)ocaldb`t`t((localdb)\mssqllocaldb)"
    },
    @{
        key="DEV";
        serverName="DEV_SERVER"; 
        credentials="-E";
        userEntry="D"; 
        menuText="(D)ev`t`t`t(DEV_SERVER)"
    },
    @{
        key="TEST";
        serverName="TEST_SERVER"; 
        credentials="-E";
        userEntry="T"; 
        menuText="(T)est`t`t`t(TEST_SERVER)"
    }
)

This will be displayed like:

(L)ocaldb       ((localdb)\mssqllocaldb) 
(D)ev           (DEV_SERVER)
(T)est          (TEST_SERVER)

I want to read the list of valid user choices from my list of servers, then check the key the user has pressed is in that list of valid choices. This is what I've got so far:

function Get-UserSelection (
    [Parameter(Mandatory=$True)]
    $servers
    )
{
    Write-Host "Select the server to run the SQL scripts on (type a letter followed by the [Enter] key, or press CTRL+C to exit)"

    foreach ($server in $servers)
    {
        Write-Host "`t" $server.menuText
    }

    $validSelections = $servers | Select-Object {$_.userEntry}
    $userSelection = ""

    while ($True)
    {
        $userSelection = Read-Host         

        ForEach ($validSelection in $validSelections)
        {
            if ($userSelection -eq $validSelection) 
            {
                return $userSelection
            }
        }
                
        Write-Host "Invalid selection.  Please try again or press CTRL+C to exit"
    }
}

The problem is that the $validSelection, instead of having a value of L or D, has a value like @{$_.userEntry=L} when casting to a string, so the $userSelection (eg "d") is never seen as valid.

I assume the problem is in the line:

$validSelections = $servers | Select-Object {$_.userEntry}

How can I modify this so that $validSelections is an array of strings instead of an array of custom objects?

0

2 Answers 2

2

You are almost there. Just use the ForEach-Object cmdlet to iterate over each hashtable and select the value of userEntry:

$validSelections = $sqlServers | ForEach-Object {$_.userEntry}
Sign up to request clarification or add additional context in comments.

Comments

2

Use Member-Access Enumeration

Starting in PowerShell 3.0, the member-access enumeration feature improves the convenience of using the member-access operator (.) on list collection objects

$sqlServers = @(
    @{userEntry="L"; },
    @{userEntry="D"; },
    @{userEntry="T"; }
)
$sqlServers.userEntry
# [L,D,T]

Use Select-Object with -ExpandProperty

  • Powershell v6 and above

    Starting in PowerShell 6, Select-Object supports selecting the keys of hashtable input as properties.

    $sqlServers = @(
        @{userEntry="L"; },
        @{userEntry="D"; },
        @{userEntry="T"; }
    )
    $sqlServers | Select-Object -ExpandProperty userEntry
    # [L,D,T]
    
  • Powershell v5.1 and below

    To do this in previous versions, you can convert the hash table to an PS Object first:

    $sqlServers = @(
        [PsCustomObject]@{userEntry="L"; },
        [PsCustomObject]@{userEntry="D"; },
        [PsCustomObject]@{userEntry="T"; }
    )
    $sqlServers | Select-Object -ExpandProperty userEntry
    # [L,D,T]
    

3 Comments

I like this answer. However, it only works in PowerShell 7, not in Windows PowerShell 5.1. In 5.1 it throws an error Select-Object : Property "menuText" cannot be found.
Thanks @SimonTewsi for the comment. Actually opened an issue in the PS-Docs and got this behavior documented, and clarified the answer with solutions for each version range.
That's much better :)

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.