1

My goal is to write a function that supports writing any array as a table, where the args given are the array, and the number of columns wanted in the table.

I have the following code...

Function PrintArrayAsTable
{
    Param ([String[]]$array ,[Int]$numOfItemsPerRow)

    $elementCounter = 1
    [String[]]$row = @()
    [String[]]$tableArray = @()

    ForEach ($element in $array)
    {
        $row += $element
        if ($elementCounter % $numOfItemsPerRow -eq 0)
        {
            $tableArray += ,($row)
            [String[]]$row = @()
        }
        $elementCounter++
    }

    if ($row)
    {
        $tableArray += ,($row)
        [String[]]$row = @()
    }

    $tableArray | Format-Table
}

[String[]]$array = @('SamAccountName', 'msRTCSIP-UserEnabled', 'msRTCSIP-OptionFlags', 'msRTCSIP-PrimaryUserAddress', 'msRTCSIP-PrimaryHomeServer', 
                     'mail', 'msExchMasterAccountSid', 'homeMDB', 'proxyaddresses', 'legacyExchangeDN', 
                     'lastLogonTimestamp', 'logonCount', 'lastLogoff', 'lastLogon', 'pwdLastSet', 'userAccountControl', 'whenCreated', 'whenChanged', 'accountExpires', 
                     'sn', 'givenName', 'displayName', 'distinguishedName', 'initials', 'l', 'st', 'street', 'title', 'description', 'postalCode', 'physicalDeliveryOfficeName', 'telephoneNumber', 'facsimileTelephoneNumber', 'info', 'memberOf', 'co', 'department', 'company', 'streetAddress', 'employeeNumber', 'employeeType', 'objectGUID', 'employeeID', 'homeDirectory', 'homeDrive', 'scriptPath', 'objectSid', 'userPrincipalName', 'url', 'msDS-SourceObjectDN', 'manager', 'extensionattribute8')

PrintArrayAsTable $array 5

This will print the following output...

SamAccountName msRTCSIP-UserEnabled msRTCSIP-OptionFlags msRTCSIP-PrimaryUserAddress msRTCSIP-PrimaryHomeServer
mail msExchMasterAccountSid homeMDB proxyaddresses legacyExchangeDN
lastLogonTimestamp logonCount lastLogoff lastLogon pwdLastSet
userAccountControl whenCreated whenChanged accountExpires sn
givenName displayName distinguishedName initials l
st street title description postalCode
physicalDeliveryOfficeName telephoneNumber facsimileTelephoneNumber info memberOf
co department company streetAddress employeeNumber
employeeType objectGUID employeeID homeDirectory homeDrive
scriptPath objectSid userPrincipalName url msDS-SourceObjectDN
manager extensionattribute8

Instead, I want the format printout to be like the following...

SamAccountName             msRTCSIP-UserEnabled   msRTCSIP-OptionFlags     msRTCSIP-PrimaryUserAddress msRTCSIP-PrimaryHomeServer
mail                       msExchMasterAccountSid homeMDB                  proxyaddresses              legacyExchangeDN
lastLogonTimestamp         logonCount             lastLogoff               lastLogon                   pwdLastSet
userAccountControl         whenCreated            whenChanged              accountExpires              sn
givenName                  displayName            distinguishedName        initials                    l
st                         street                 title                    description                 postalCode
physicalDeliveryOfficeName telephoneNumber        facsimileTelephoneNumber info                        memberOf
co                         department             company                  streetAddress               employeeNumber
employeeType               objectGUID             employeeID               homeDirectory               homeDrive
scriptPath                 objectSid              userPrincipalName        url                         msDS-SourceObjectDN
manager                    extensionattribute8

Any idea how to do this?

2
  • Just to be clear, you're trying to render the array in X equal-width columns, not arrange a 2-dimensional array into a table with named columns? Commented Feb 26, 2016 at 23:02
  • well the input arg is just an array. I separate it into a two dimensional array, so each array in the two dimensional array will be printed as a row of the table. The amount of columns will be based on the input arg of the function. In this example, we use 5, so there will be 5 columns. The width should equal the longest string in that column. Commented Feb 26, 2016 at 23:30

4 Answers 4

4

Format-Wide does basically what you describe already.

All you need to do is construct an object with a single property for each string, and then refer to that property name with Format-Wide -Property:

function Print-Grid
{
    param(
        [Parameter(Mandatory,ValueFromPipeline,Position=0)]
        [string[]]$Array,

        [Parameter(Position=1)]
        [ValidateRange(1,24)]
        [int]$ColumnCount
    )
    $GridSplat = @{
        InputObject = $Array|ForEach-Object {
            New-Object psobject -Property @{'Value' = $_}
        }
        Property    = 'Value'
    }

    if(-not $PSBoundParameters.ContainsKey('ColumnCount'))
    {
        $GridSplat['AutoSize'] = $true
    }
    else
    {
        $GridSplat['Column'] = $ColumnCount
    }

    Format-Wide @GridSplat
}
Sign up to request clarification or add additional context in comments.

5 Comments

Hi Mathias, thanks for the response. PowerGUI is showing a squiggly line under the V in '[Parameter(Mandatory,ValueFromPipeline,Position=0)]'. It says Parsing Error: The "=" operator is missing after a named argument. Any idea why this is? NOTE: the code does work with powershell.exe, but errors out when compiled with PowerGUI Script Editor version 1.9.5.966.
@FiddleFreak Because PowerGUI expects you to explicitly mark each named Parameter attribute either $true or $false (maybe for version 2.0 compliance, just a guess)
ah your right, after a little googling I found this... github.com/smurawski/PowerShellGuard/issues/4. All I did was remove lines [Parameter(Mandatory,ValueFromPipeline,Position=0)] and [Parameter(Position=1)]. Runs fine now for both Powershell and PowerGUI. Thanks :D
Don't remove them (they serve a purpose), just give them a value (ie. [Parameter(Mandatory=$true,ValueFromPipeline=$true,Position=0)])
Why construct objects when you can use calculated properties $GridSplat = {InputObject = $Array; Property = {$_}; Force = $true}?
0

It looks like the bit that is missing is getting your rows of data into neat, equal-width columns...

I'd try to work out the maximum width you'd need a column to be (say, the length of the longest string in the array plus 1). You could do this using:

$width = ($array | %{$_.Length} | Measure-Object -Maximum).Maximum + 1

And then you could pad out each element to this width:

$row += $element.PadRight($width)

2 Comments

Actually, this isn't quite what you wanted, as every element is padded to the width of the longest one in the whole array. What you needed was each to be padded to the width of the widest, per column. Looks like @Mathias has a better answer!
Thanks, this is an option, but your right. However, it's good to know this method exists as well.
0

I found this post while trying to do something similar and seem to find a different way of doing this;

$arrayName | select-object -Property @{Name = 'Col1 name'; Expression = { $_[1]}},
                                     @{Name = 'Col2 name'; Expression = { $_[2]}},
                                     @{Name = 'Col3 name'; Expression = { $_[3]}},
                                     @{Name = 'Col4 name'; Expression = { $_[4]}} 

Comments

0

And if you want to control the column format, here is the full answer;

$s1errorcode_list | select-object -Property @{Name = 'Col1 name'; Expression = { $_[1]}},
                                        @{Name = 'Col2 name'; Expression = { $_[2]}},
                                        @{Name = 'Col3 name'; Expression = { $_[3]}},
                                        @{Name = 'Col4 name'; Expression = { $_[4]}} | 
                       format-table -Property @{ Expression = 'Col1 name'; width=6 },
                                              @{ Expression = 'Col2 name'; width=84 },
                                              @{ Expression = 'Col3 name'; width=80 },
                                              @{ Expression = 'Col4 name'}

Comments

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.