Home > Net >  Powershell - Display contents of two tables next to each other
Powershell - Display contents of two tables next to each other

Time:02-05

I am attempting to display information for administrators processing user changes to easily see what changes are being made to certain fields in Active Directory users. I've written a PowerShell script to process these changes, but I'm having trouble formatting the output for the administrators who are running the script. See this post for a similar, but different problem.

My code:

$output = [pscustomobject]@{'UserName' = $user.samAccountName; 'FirstName' = $user.GivenName;'LastName' = $user.Surname;'DisplayName' = $user.DisplayName;'UPN' = $user.UserPrincipalName;'E-Mail_Address' = $user.proxyAddresses;'Title' = $user.Title;'Office' = $user.PhysicalDeliveryOfficeName;'Dept' = $user.Department;}
$output[$index  ] | Add-Member -NotePropertyMembers @{'NewUserName' = $samAccountName; 'NewFirstName' = $firstName;'NewLastName' = $lastname;'NewDisplayName' = $displayName;'NewUPN' = $UPN;'NewE-Mail_Address' = $SMTP1;'NewTitle' = $Title;'Newoffice' = $office;'NewDept' = $department;}
$output

Output:

UserName          : FirstLast
FirstName         : First
LastName          : Last
DisplayName       : First Last
UPN               : [email protected]
E-Mail_Address    : SMTP:[email protected]
Title             : CEO
Office            : HQ
Dept              : Executives
NewDept           : Maintenance
NewE-Mail_Address : SMTP:[email protected]
NewOffice         : The Dump
NewFirstName      : First
NewLastName       : Last
NewUserName       : FirstLast
NewDisplayName    : First Last
NewUPN            : [email protected]
NewTitle          : Trash Collector

Desired Output:

UserName          : FirstLast                     NewUserName       : FirstLast
FirstName         : First                         NewFirstName      : First
LastName          : Last                          NewLastName       : Last
DisplayName       : First Last                    NewDisplayName    : First Last
UPN               : [email protected]         NewUPN            : [email protected]
E-Mail_Address    : SMTP:[email protected]    NewE-Mail_Address : SMTP:[email protected]
Title             : CEO                           NewTitle          : Trash Collector
Office            : HQ                            Newoffice         : The Dump
Dept              : Executives                    NewDept           : Maintenance

CodePudding user response:

Below will create the two Format-List outputs next to eachother.
Because more than likely this will not fit the width of the console screen, the output is captured first and output using Out-String with a high number for parameter -Width.
Like this, you can also save to text file.

$outputOld = [pscustomobject]@{
                'UserName' = $user.samAccountName; 'FirstName' = $user.GivenName;
                'LastName' = $user.Surname;'DisplayName' = $user.DisplayName;
                'UPN' = $user.UserPrincipalName;'E-Mail_Address' = $user.proxyAddresses;
                'Title' = $user.Title;'Office' = $user.PhysicalDeliveryOfficeName;
                'Dept' = $user.Department}
$outputNew = [pscustomobject]@{
                'NewUserName' = $samAccountName; 'NewFirstName' = $firstName;
                'NewLastName' = $lastname;'NewDisplayName' = $displayName;'NewUPN' = $UPN;
                'NewE-Mail_Address' = $SMTP1;'NewTitle' = $Title;'Newoffice' = $office;
                'NewDept' = $department}

# capture the Format-List output of each object and split into a string array
$outLeft  = @(($outputOld | Format-List | Out-String) -split '\r?\n')
$outRight = @(($outputNew | Format-List | Out-String) -split '\r?\n')

# determine the maximum length of each string in the list that goes to the left
$maxLength = ($outLeft | Measure-Object -Property Length -Maximum).Maximum
# get the maximum number of lines
$maxLines  = [math]::Max($outLeft.Count, $outRight.Count)

# collect the combined output
$result = for ($i = 0; $i -lt $maxLines; $i  ) {
    $left  = if ($i -lt $outLeft.Count) { "{0,-$maxLength}" -f $outLeft[$i] } else { ' ' * $maxLength }
    $right = if ($i -lt $outRight.Count) { $outRight[$i] } else {''}
    ('{0}    {1}' -f $left, $right).TrimEnd()
}

# display on screen
$result | Out-String -Width 1000

# save to text file
$result | Out-String -Width 1000 | Set-Content -Path 'D:\Test\output.txt'

CodePudding user response:

This doesn't produce exactly the same character-by-character output as you're after, but it does produce something similar using the built-in formatting methods without lots of stringifying of values.

First, set up some test data, which would need a small change to your sample code to generate as two objects, instead of your combined $output variable:

$oldValues = [pscustomobject] [ordered] @{
    "UserName"          = "FirstLast"
    "FirstName"         = "First"
    "LastName"          = "Last"
    "DisplayName"       = "First Last"
    "UPN"               = "[email protected]"
    "E-Mail_Address"    = "SMTP:[email protected]"
    "Title"             = "CEO"
    "Office"            = "HQ"
    "Dept"              = "Executives"
};

$newValues = [pscustomobject] [ordered] @{
    "NewDept"           = "Maintenance"
    "NewE-Mail_Address" = "SMTP:[email protected]"
    "NewOffice"         = "The Dump"
    "NewFirstName"      = "First"
    "NewLastName"       = "Last"
    "NewUserName"       = "FirstLast"
    "NewDisplayName"    = "First Last"
    "NewUPN"            = "[email protected]"
    "NewTitle"          = "Trash Collector"
};

Next, we map the variables into an array of PropertyName, OldValue, NewValue objects:

$rows = $oldValues.psobject.properties `
    | foreach-object {
        $property = $_;
        [pscustomobject] [ordered] @{
            "PropertyName" = $property.Name
            "OldValue"     = $property.Value
            "NewValue"     = $newValues.("New"   $property.Name) 
        }
    };

And then we can format it using the built-in cmdlets:

$rows | format-table

# PropertyName   OldValue                   NewValue
# ------------   --------                   --------
# UserName       FirstLast                  FirstLast
# FirstName      First                      First
# LastName       Last                       Last
# DisplayName    First Last                 First Last
# UPN            [email protected]      [email protected]
# E-Mail_Address SMTP:[email protected] SMTP:[email protected]
# Title          CEO                        Trash Collector
# Office         HQ                         The Dump
# Dept           Executives                 Maintenance

The nice thing is you can adjust things like column widths, word wrap, etc just using the Format-Table parameters, or even use Format-List instead:

$rows | format-list

# ... etc ...
#
# PropertyName : Title
# OldValue     : CEO
# NewValue     : Trash Collector
#
# PropertyName : Office
# OldValue     : HQ
# NewValue     : The Dump
#
# ... etc ...

And you can filter it to show just changed values:

$rows | where-object { $_.NewValue -ne $_.OldValue } | format-table

# PropertyName OldValue   NewValue
# ------------ --------   --------
# Title        CEO        Trash Collector
# Office       HQ         The Dump
# Dept         Executives Maintenance

It relies on the property names being in the format "Xyz -> NewXyz", but there's ways around that if it's not true in all cases...

  • Related