Search code examples
powershelltruncate

Powershell - Creating Wide Tables


Good afternoon!

I am a Powershell novice trying to understand how data output works. I am trying to find the differences between two users in Active Directory. I found a solution that worked (Compare-Object on two AD user accounts), but the data some of in the relevant fields was truncated with an ... which didn't help.

I found a solution which seems very elegant at the bottom of the page here: http://poshoholic.com/2010/11/11/powershell-quick-tip-creating-wide-tables-with-powershell/

I attempted to combine these two into a single script. This is what I have:

$user1 = get-aduser jdoe -Properties *
$user2 = get-aduser jsmith -Properties *

$Usercomparison = @()

$user1.GetEnumerator() | ForEach-Object {
    If ($User2.($_.Key) -eq $_.Value)
    {
        $Comparison = 'Equal'
    }
    else
    {
        $Comparison = 'Different'
    }

    $UserObj = New-Object PSObject -Property ([ordered]@{
        Property = $_.Key
        User1 = $_.Value
        User2 = $User2.($_.Key)
        Comparison = $Comparison
    })
    $UserComparison += $UserObj
}

$UserComparison
| Format-Table -Property * -AutoSize `
| Out-String -Width 4096 `
| Out-File C:\Users\USER\Desktop\differences.txt

This produces an error that "an empty pipe element is not allowed". If I delete a line return to put the first pipe line after the $UserComparison variable...

$UserComparison | Format-Table -Property * -AutoSize `
| Out-String -Width 4096 `
| Out-File C:\aliases.txt

...then the text file is created, but it's badly formatted. Only the first two columns appear in the output and there is a ton of wasted whitespace to the right and several blank line returns after each line... nothing like the example on the website.

Is this because the script I found writes the data to a variable and then just prints the variable on screen instead of using a command that can be output properly? I feel like I have all the pieces that I need, just not in the right configuration to get the output I want.

Thanks!


Solution

  • So, #1 the line:

    $UserComparison
    | Format-Table -Property * -AutoSize `
    | Out-String -Width 4096 `
    | Out-File C:\Users\USER\Desktop\differences.txt
    

    Doesn't work because you are first executing

    $UserComparison
    

    Which outputs the contents of $UserComparison. Next, you execute

    | Format-Table -Property * -AutoSize `
    

    Which errors out because nothing is being piped into Format-Table. The "ticks" ( ` ) at the end of the Format-Table statement is a continue line statement i.e. the second version:

    $UserComparison | Format-Table -Property * -AutoSize `
    | Out-String -Width 4096 `
    | Out-File C:\aliases.txt
    

    Is correct because it will be interpreted as one giant line.

    Second question, the reason why you are having issues is because 4096 characters is not enough space to hold everything, and so is truncated. Remember, -AutoSize will calculate the width of the longest item, and make that the width of the column. There are some items that are too long. For ex. For me, the thumbnailPhoto (which happened to be item 140 in my array):

    $UserComparison[140]
    

    Gives something like this (truncated depending on width):

    Property       User1
    --------       -----
    thumbnailPhoto {255 216 255 224 0 16 74 70 73 70 0 1 1 1 0 96 0...
    

    When I calculate the width of this, it gives me:

    #Calculate  width of User1
    ($UserComparison[140].User1 | Out-String).Length
    
    7555
    
    #Calculate width of full field
    ($UserComparison[140] | Out-String).Length
    
    12297
    

    Yes, User1 is 7,555 characters long. That means that Format-Table -Autosize will make the User1 column at least 7,555 characters wide, which obviously is truncated by the 4,096 width limit that you specified on the Out-String, and then won't display the User2 or Comparison columns. In this case, your Out-String needs to have a width of at least 12,297 wide in order to display the full field.

    The workaround is to specify an even bigger width on the Out-String that is guaranteed to be wider, like, say, 50,000 so your code would be:

    $UserComparison | Format-Table -Property * -AutoSize `
    | Out-String -Width 50000 `
    | Out-File C:\Users\USER\Desktop\differences.txt
    

    Now, the downside to doing things this way is that every line in the text file will be the full width of the longest item, and so (in my case) every line will be 12,297 characters long. This makes things harder to read.

    Other ways to output things would be to:

    Limit things to just displaying the Property and Comparison columns:

    $UserComparison | Select Property, Comparison `
    | Format-Table -Property * -AutoSize `
    | Out-String -Width 4096 `
    | Out-File SimpleCompare.txt
    

    Or if you need to see what the full values are, chop each property up into a separate table with a ForEach-Object, and then pass that through so that would be easier to read, and each property is limited to it's specific width:

    $UserComparison | Select Property, Comparison, User1, User2 `
    | ForEach-Object { $_ | Format-Table -Property * -AutoSize `
    | Out-String -Width 50000 `
    | Out-File EasyToRead.txt -Append }