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...