1

I am trying to create an nicely formatted Txt file (has to be Txt cannot be CSV) from a hashtable.

Here is the code that I have that creates the text file

$hashTable.GetEnumerator() | Sort-Object Name |
ForEach-Object {"{0} `t`t: {1} `t`t: {2} `t`t: {3} `t`t: {4}" -f $_.DisplayName,$_.EmployeeNo,$_.Email, $_.SamName,$_.Upn}|
Add-Content $textFilePath

As you can see - when someone is input into the Txt file with a long name it messes up the formatting because the tabs just get shifted along. enter image description here

I'm looking for a solution that dynamically sets the width of the columns in a text file.

1
  • As an aside: I assume it's just a posting artifact, but your code doesn't work as-is, because what is seen as $_ in the pipeline isn't an AD user object directly, it is a System.Collections.DictionaryEntry instance whose .Value property contains the AD user object. In other word, instead of $_.DisplayName it would have to be $_.Value.DisplayName, and so on. Commented Oct 29, 2020 at 13:00

1 Answer 1

3

Use PowerShell's output-formatting system, whose Format-Table cmdlet produces human-readable, column-aligned representations, but note that these are generally not suitable for later programmatic processing:

($hashTable.GetEnumerator() | Sort-Object Name).Value | 
  Format-Table -AutoSize -Property DisplayName, EmployeeNo, Email, SamName, Upn | 
    Out-File $textFilePath -Encoding Utf8 -Width 1024 
  • $hashTable.GetEnumerator() | Sort-Object Name enumerates the hashtable entries as System.Collections.DictionaryEntry entries and sorts them by their .Name (.Key) property.

    • Note that the .GetEnumerator() call is necessary to sort the hash table entries by their key (name); without it, the hash table as a whole would be sent as a single object through the pipeline, in which case the Sort-Object would effectively be a no-op - by definition, there's nothing to sort if there's only one object; compare the output from:
      @{ zach = 1; moe = 2; aardvark = 0 } | Sort-Object Name
      to the output from:
      @{ zach = 1; moe = 2; aardvark = 0 }.GetEnumerator() | Sort-Object Name
      In the first command, the Sort-Object call has no effect.
  • .Value then extracts the entries' values (this could also be done in streaming fashion with ... | ForEach-Object Value).

  • The values appears to be Active Directory user objects, so you can just pass a list of the desired property names to Format-Table, which form the output-table column names, whereas the corresponding property values form the column values.

  • Note that Out-File rather than Add-Content (Set-Content) is used, because only it automatically converts the formatting objects that Format-Table outputs to their intended string representations, as you would see in the console (terminal).

    • -Width 1024 ensures that the table lines aren't truncated based on whatever the width of the current console window happens to be; adjust as needed.
    • -Encoding Utf8 is used as an example to control the output encoding; note that Windows PowerShell defaults to "Unicode" (UTF-16LE), whereas the default is BOM-less UTF-8 in PowerShell [Core] v6+. See this answer for more information about default character encodings in Windows PowerShell vs. PowerShell [Core].
Sign up to request clarification or add additional context in comments.

5 Comments

Does Format-Table have a -Width parameter? I think maybe that goes with Out-File. Checked documentation and tested in 5.1 and 7.0. I'm also not sure we need .GetEnumerator() , in this scenario $hashTable.Values | Sort-Object Name | ... seems to work just as well. Is there a reason to specify the encoding?
Yes - thank you @Steven: the -Width belongs with the Out-File command - fixed. As for your other points: please see my update.
Ah I see my mistake. In my test data I included a name property. So sorting on the underlying object’s name property rather than the key of the hash. Thanks!
I understand. In my erroneous experiment I didn't send the hash table in whole down the pipeline. I sent the .Values property of the hash table. Should the objects stored in the hash have a name property, like an AD users, PwSh would sort on it. Of course, that's not the same as sorting on the key. My error was in creating test data that indeed had a name property when in fact I didn't know what the key was. And, the rest followed.
Got it, @Steven. What probably added to the confusion is that the code in the question doesn't work as-is, because instead of $_.DisplayName it would have to be $_.Value.DisplayName, and so on.

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.