回答編集履歴

1

追記

2018/03/10 06:06

投稿

Zuishin
Zuishin

スコア28660

test CHANGED
@@ -7,3 +7,423 @@
7
7
 
8
8
 
9
9
  [Join-Object](https://blogs.msdn.microsoft.com/powershell/2012/07/13/join-object/)
10
+
11
+
12
+
13
+ ###追記
14
+
15
+ カレントディレクトリに user.csv と machine.csv があるときに result.csv に書き込みます。
16
+
17
+ result.csv が既にあるとエラーになります。
18
+
19
+
20
+
21
+ ```
22
+
23
+ function AddItemProperties($item, $properties, $output) {
24
+
25
+ if ($item -ne $null) {
26
+
27
+ foreach ($property in $properties) {
28
+
29
+ $propertyHash = $property -as [hashtable]
30
+
31
+ if ($propertyHash -ne $null) {
32
+
33
+ $hashName = $propertyHash["name"] -as [string]
34
+
35
+ if ($hashName -eq $null) {
36
+
37
+ throw "there should be a string Name"
38
+
39
+ }
40
+
41
+
42
+
43
+ $expression = $propertyHash["expression"] -as [scriptblock]
44
+
45
+ if ($expression -eq $null) {
46
+
47
+ throw "there should be a ScriptBlock Expression"
48
+
49
+ }
50
+
51
+
52
+
53
+ $_ = $item
54
+
55
+ $expressionValue = & $expression
56
+
57
+
58
+
59
+ $output | add-member -MemberType "NoteProperty" -Name $hashName -Value $expressionValue
60
+
61
+ }
62
+
63
+ else {
64
+
65
+ # .psobject.Properties allows you to list the properties of any object, also known as "reflection"
66
+
67
+ foreach ($itemProperty in $item.psobject.Properties) {
68
+
69
+ if ($itemProperty.Name -like $property) {
70
+
71
+ $output | add-member -MemberType "NoteProperty" -Name $itemProperty.Name -Value $itemProperty.Value
72
+
73
+ }
74
+
75
+ }
76
+
77
+ }
78
+
79
+ }
80
+
81
+ }
82
+
83
+ }
84
+
85
+
86
+
87
+
88
+
89
+ function WriteJoinObjectOutput($leftItem, $rightItem, $leftProperties, $rightProperties, $Type) {
90
+
91
+ $output = new-object psobject
92
+
93
+
94
+
95
+ if ($Type -eq "AllInRight") {
96
+
97
+ # This mix of rightItem with LeftProperties and vice versa is due to
98
+
99
+ # the switch of Left and Right arguments for AllInRight
100
+
101
+ AddItemProperties $rightItem $leftProperties $output
102
+
103
+ AddItemProperties $leftItem $rightProperties $output
104
+
105
+ }
106
+
107
+ else {
108
+
109
+ AddItemProperties $leftItem $leftProperties $output
110
+
111
+ AddItemProperties $rightItem $rightProperties $output
112
+
113
+ }
114
+
115
+ $output
116
+
117
+ }
118
+
119
+
120
+
121
+ <#
122
+
123
+ .Synopsis
124
+
125
+ Joins two lists of objects
126
+
127
+ .DESCRIPTION
128
+
129
+ Joins two lists of objects
130
+
131
+ .EXAMPLE
132
+
133
+ Join-Object $a $b "Id" ("Name","Salary")
134
+
135
+ #>
136
+
137
+ function Join-Object {
138
+
139
+ [CmdletBinding()]
140
+
141
+ [OutputType([int])]
142
+
143
+ Param
144
+
145
+ (
146
+
147
+ # List to join with $Right
148
+
149
+ [Parameter(Mandatory = $true,
150
+
151
+ Position = 0)]
152
+
153
+ [object[]]
154
+
155
+ $Left,
156
+
157
+
158
+
159
+ # List to join with $Left
160
+
161
+ [Parameter(Mandatory = $true,
162
+
163
+ Position = 1)]
164
+
165
+ [object[]]
166
+
167
+ $Right,
168
+
169
+
170
+
171
+ # Condition in which an item in the left matches an item in the right
172
+
173
+ # typically something like: {$args[0].Id -eq $args[1].Id}
174
+
175
+ [Parameter(Mandatory = $true,
176
+
177
+ Position = 2)]
178
+
179
+ [scriptblock]
180
+
181
+ $Where,
182
+
183
+
184
+
185
+ # Properties from $Left we want in the output.
186
+
187
+ # Each property can:
188
+
189
+ # – Be a plain property name like "Name"
190
+
191
+ # – Contain wildcards like "*"
192
+
193
+ # – Be a hashtable like @{Name="Product Name";Expression={$_.Name}}. Name is the output property name
194
+
195
+ # and Expression is the property value. The same syntax is available in select-object and it is
196
+
197
+ # important for join-object because joined lists could have a property with the same name
198
+
199
+ [Parameter(Mandatory = $true,
200
+
201
+ Position = 3)]
202
+
203
+ [object[]]
204
+
205
+ $LeftProperties,
206
+
207
+
208
+
209
+ # Properties from $Right we want in the output.
210
+
211
+ # Like LeftProperties, each can be a plain name, wildcard or hashtable. See the LeftProperties comments.
212
+
213
+ [Parameter(Mandatory = $true,
214
+
215
+ Position = 4)]
216
+
217
+ [object[]]
218
+
219
+ $RightProperties,
220
+
221
+
222
+
223
+ # Type of join.
224
+
225
+ # AllInLeft will have all elements from Left at least once in the output, and might appear more than once
226
+
227
+ # if the where clause is true for more than one element in right, Left elements with matches in Right are
228
+
229
+ # preceded by elements with no matches. This is equivalent to an outer left join (or simply left join)
230
+
231
+ # SQL statement.
232
+
233
+ # AllInRight is similar to AllInLeft.
234
+
235
+ # OnlyIfInBoth will cause all elements from Left to be placed in the output, only if there is at least one
236
+
237
+ # match in Right. This is equivalent to a SQL inner join (or simply join) statement.
238
+
239
+ # AllInBoth will have all entries in right and left in the output. Specifically, it will have all entries
240
+
241
+ # in right with at least one match in left, followed by all entries in Right with no matches in left,
242
+
243
+ # followed by all entries in Left with no matches in Right.This is equivallent to a SQL full join.
244
+
245
+ [Parameter(Mandatory = $false,
246
+
247
+ Position = 5)]
248
+
249
+ [ValidateSet("AllInLeft", "OnlyIfInBoth", "AllInBoth", "AllInRight")]
250
+
251
+ [string]
252
+
253
+ $Type = "OnlyIfInBoth"
254
+
255
+ )
256
+
257
+
258
+
259
+ Begin {
260
+
261
+ # a list of the matches in right for each object in left
262
+
263
+ $leftMatchesInRight = new-object System.Collections.ArrayList
264
+
265
+
266
+
267
+ # the count for all matches
268
+
269
+ $rightMatchesCount = New-Object "object[]" $Right.Count
270
+
271
+
272
+
273
+ for ($i = 0; $i -lt $Right.Count; $i++) {
274
+
275
+ $rightMatchesCount[$i] = 0
276
+
277
+ }
278
+
279
+ }
280
+
281
+
282
+
283
+ Process {
284
+
285
+ if ($Type -eq "AllInRight") {
286
+
287
+ # for AllInRight we just switch Left and Right
288
+
289
+ $aux = $Left
290
+
291
+ $Left = $Right
292
+
293
+ $Right = $aux
294
+
295
+ }
296
+
297
+
298
+
299
+ # go over items in $Left and produce the list of matches
300
+
301
+ foreach ($leftItem in $Left) {
302
+
303
+ $leftItemMatchesInRight = new-object System.Collections.ArrayList
304
+
305
+ $null = $leftMatchesInRight.Add($leftItemMatchesInRight)
306
+
307
+
308
+
309
+ for ($i = 0; $i -lt $right.Count; $i++) {
310
+
311
+ $rightItem = $right[$i]
312
+
313
+
314
+
315
+ if ($Type -eq "AllInRight") {
316
+
317
+ # For AllInRight, we want $args[0] to refer to the left and $args[1] to refer to right,
318
+
319
+ # but since we switched left and right, we have to switch the where arguments
320
+
321
+ $whereLeft = $rightItem
322
+
323
+ $whereRight = $leftItem
324
+
325
+ }
326
+
327
+ else {
328
+
329
+ $whereLeft = $leftItem
330
+
331
+ $whereRight = $rightItem
332
+
333
+ }
334
+
335
+
336
+
337
+ if (Invoke-Command -ScriptBlock $where -ArgumentList $whereLeft, $whereRight) {
338
+
339
+ $null = $leftItemMatchesInRight.Add($rightItem)
340
+
341
+ $rightMatchesCount[$i]++
342
+
343
+ }
344
+
345
+
346
+
347
+ }
348
+
349
+ }
350
+
351
+
352
+
353
+ # go over the list of matches and produce output
354
+
355
+ for ($i = 0; $i -lt $left.Count; $i++) {
356
+
357
+ $leftItemMatchesInRight = $leftMatchesInRight[$i]
358
+
359
+ $leftItem = $left[$i]
360
+
361
+
362
+
363
+ if ($leftItemMatchesInRight.Count -eq 0) {
364
+
365
+ if ($Type -ne "OnlyIfInBoth") {
366
+
367
+ WriteJoinObjectOutput $leftItem $null $LeftProperties $RightProperties $Type
368
+
369
+ }
370
+
371
+
372
+
373
+ continue
374
+
375
+ }
376
+
377
+
378
+
379
+ foreach ($leftItemMatchInRight in $leftItemMatchesInRight) {
380
+
381
+ WriteJoinObjectOutput $leftItem $leftItemMatchInRight $LeftProperties $RightProperties $Type
382
+
383
+ }
384
+
385
+ }
386
+
387
+ }
388
+
389
+
390
+
391
+ End {
392
+
393
+ #produce final output for members of right with no matches for the AllInBoth option
394
+
395
+ if ($Type -eq "AllInBoth") {
396
+
397
+ for ($i = 0; $i -lt $right.Count; $i++) {
398
+
399
+ $rightMatchCount = $rightMatchesCount[$i]
400
+
401
+ if ($rightMatchCount -eq 0) {
402
+
403
+ $rightItem = $Right[$i]
404
+
405
+ WriteJoinObjectOutput $null $rightItem $LeftProperties $RightProperties $Type
406
+
407
+ }
408
+
409
+ }
410
+
411
+ }
412
+
413
+ }
414
+
415
+ }
416
+
417
+ $users = Import-Csv .\user.csv | ForEach-Object { $_.employeeID = "JP" + $_.employeeID; $_ }
418
+
419
+ $machines = Import-Csv .\machine.csv
420
+
421
+ Join-Object $users $machines -Where { $args[0].employeeID -eq $args[1].Name }`
422
+
423
+ -LeftProperties EmployeeName, City, Description -RightProperties Name, operatingSystem |
424
+
425
+ Select-Object Name, operatingSystem, EmployeeName, City, Description |
426
+
427
+ Export-Csv .\result.csv -NoClobber -NoTypeInformation -Encoding utf8
428
+
429
+ ```