-
Notifications
You must be signed in to change notification settings - Fork 0
/
FUNCTION___Out-Vertical.ps1
142 lines (111 loc) · 5.47 KB
/
FUNCTION___Out-Vertical.ps1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
<#
.SYNOPSIS
Out-Vertical
Think of it as Format-Table, turned 90° counterclockwise.
.DESCRIPTION
Out-Vertical takes any number of objects and puts them on display in columns next to each other, with all properties merged and sorted as the first column
Each output line is an object, so it can further be piped, e.g. to Out-GridView, Export-Csv, etc.
.PARAMETER InputObject
Objects to process
Mandatory
Pipeline enabled
accepts Arrays
.PARAMETER DifferenceOnly
Switch to only output properties where the objects differ from each other
.EXAMPLE
PS C:\> 'einstein','kierkegaard' | Get-ADUser | Out-Vertical
Get's the basic AD data for users einstein ein kierkegaard and shows them next to each other in columns with the properties on the left:
Properties Object_1 Object_2
Name EINSTEIN Albert KIERKEGAARD Soeren
Distinguishedname CN=EINSTEIN Albert,OU=... CN=KIERKEGAARD Soeren,OU=...
SamAccountName einstein kierkegaard
... ... ...
.INPUTS
Any number or type of objects
.OUTPUTS
A collection of objects, each object holding one property name and the associated values of all give input objects
.NOTES
by Maximilian Otter, 201911
#>
function Out-Vertical {
param (
[Parameter(Mandatory,ValueFromPipeline,Position=0)]
[PSCustomObject[]]$InputObject,
[switch]$DifferenceOnly
)
begin {
$Objects = [System.Collections.ArrayList]@()
}
process {
# collect all objects, from pipeline or not
foreach ($obj in $InputObject) {
$null = $Objects.Add($obj)
}
}
end {
# Collect properties of first object. Sort them, so we can use binary search for increased performance later
$Properties = [System.Collections.ArrayList]($Objects[0].PSObject.Properties.Name | Sort-Object)
# collect properties of all other objects if they have others and sort them in
# the function can accept all sorts of objecst at once, so we have to get all properties from all objects,
# even if it is e.g. an AD-User and a file (does not make sense, but nevertheless possible)
for ($i = 1; $i -lt $Objects.count; $i++) {
foreach ($prop in $Objects[$i].PSObject.Properties.Name) {
$Index = $Properties.BinarySearch($prop)
if ($Index -lt 0) {
$Properties.Insert(-1*($Index+1),$prop)
}
}
}
# Build an array of custom objects with one column holding the properties
foreach ($prop in $Properties) {
# exclude properties automatically created by the addresslist
if ($prop -notin @('AddedProperties','ModifiedProperties','RemovedProperties','PropertyCount','PropertyNames')) {
# first column will hold the properties of the objects. [Ordered] makes sure, it stays the first column.
$hash = [Ordered]@{
Property = $prop
}
# add one column for each object
$count = 1
foreach ($obj in $Objects) {
$hash.Add("Object_$count",$obj.$prop)
$count++
}
# Did the user request to only output properties which differ from each other?
if (-not($DifferenceOnly)) {
[PSCustomObject]$hash
} else {
$Output = $false
$Nulls = 0
$Fulls = 0
# check for not existing or $nul properties
# if we have $null and non-$null values, we already have a mismatch and may output the hash
foreach ($obj in $Objects) {
if ([string]::IsNullOrEmpty($obj.$prop)) { $Nulls++ } else { $Fulls++ }
if ($Nulls -and $Fulls) {
$Output = $true
break
}
}
# no output yet?
if (-not($Output)) {
# we can ignore $nulls -eq $Objects.count, because that means all are equal and we don't have to output them
# for all fulls...
if ($Fulls -eq $Objects.Count) {
# ...create -eq pairs of Object[0] comparing to all others
$filter_elements = for ($i = 1; $i -lt $Objects.Count -and -not($Output); $i++) {
'$Objects[0].$prop -eq $Objects[' + $i + ']'
}
# ... then join the pairs with -and and create a scriptblock of the filters to user with the following IF
$filter = [ScriptBlock]::Create(($filter_elements -join ' -and '))
# IF one of our -eq pairs does not match, we have a mismatch and may output the hash
if (-not(& $filter)) { $Output = $true }
}
}
if ($Output) {
[PSCustomObject]$hash
}
}
}
}
}
}