-
Notifications
You must be signed in to change notification settings - Fork 9
/
Data.ps1
584 lines (467 loc) · 16.7 KB
/
Data.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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
function ConvertTo-PsObject
{
<#
.SYNOPSIS
Convert a set of variables into a PsObject
.DESCRIPTION
Constructs new PsObject from the available variables.
Simplifies packing of data into one object that Powershell can work with.
Alias: construct
.PARAMETER Args
All parameters are detected dynamically. You should pass here names
of the variables you'd like to convert into the PsObject.
.EXAMPLE
$a = "a_value"
$b = [int] 5
$c = "one", "two"
construct a b c
Constructs PsObject with properties a, b and c. Values are taken from
variables $a, $b and $c.
#>
$properties = [ordered] @{}
foreach( $name in $args )
{
$local = Get-Variable $name -Scope local -ea Ignore
if( $local ) { $properties.$name = $local.Value; continue }
$script = Get-Variable $name -Scope script -ea Ignore
if( $script ) { $properties.$name = $script.Value; continue }
$global = Get-Variable $name -Scope global -ea Ignore
if( $global ) { $properties.$name = $global.Value; continue }
Write-Warning "Could not resolve variable with name '$name'"
}
New-Object -TypeName PSObject -Property $properties
}
function ConvertTo-Hash( [object] $object )
{
<#
.SYNOPSIS
Convert an object into a hash table
.DESCRIPTION
This function takes any object, gets all not $false properties and creates
hash table out of the found properties. This can be useful to pass some
object through a process boundary or to remove property from an object.
.PARAMETER Object
Object to deconstruct into hash table
.EXAMPLE
ConvertTo-Hash (ls | select -f 1)
Get hash table from the first found child item.
#>
$hash = [ordered] @{}
$object |
foreach{ $psitem.PsObject.Members } |
where MemberType -match "^(Note)?Property$" |
foreach Name |
where{ $object.$psitem } |
foreach{ $hash[$psitem] = $object.$psitem }
$hash
}
function Get-Parameter
{
<#
.SYNOPSIS
Get names of all available parameters from input objects
.DESCRIPTION
This filter analyses what parameters are present in all objects passed to
the filter and outputs all unique parameter names.
.PARAMETER Pattern
Constrain output only to parameter names that match this pattern.
By default all parameter names are returned.
.PARAMETER Single
Specify this switch if there must be only one parameter that match the
pattern. If there is no single matching parameter, exception is thrown.
.EXAMPLE
Get-ChildItem | Get-Parameter
List all available parameters from Get-ChildItem command.
Both file info and directory info parameter names will be listed.
.EXAMPLE
Get-Process | Get-Parameter priority
List all parameters for Process object (returned from Get-Process) that
contain 'priority' substring in the parameter name.
'priority' here is a regex.
.LINK
Use-Project
Use-Filter
#>
param
(
[string] $Pattern = ".*",
[switch] $Single
)
begin { $accumulator = @() }
process { $accumulator += $psitem }
end
{
if( -not $accumulator )
{
return
}
# Get properties that match the pattern
$result = @(
$accumulator |
foreach{ $psitem.PsObject.Members } |
where Name -match $pattern |
where MemberType -match "Property" |
foreach Name |
Get-UniqueUnsorted)
# Need to return all entries
if( -not $single ) { return $result }
# No ambulation with matches
if( $result.Length -eq 1 ) { return $result[0] }
# Strict match disambiguation
if( @($result | where{ $psitem -eq $pattern }).Length -eq 1 ) { return $pattern }
# Warn user about ambulation
Write-Warning "Disambiguate '$pattern'`n$($result | Out-String)"
}
}
function Use-Project
{
<#
.SYNOPSIS
Project several parameters from input objects
.DESCRIPTION
This command performs project operation from relational algebra with not
strict column name matching. It allows to compress data output only to
the columns you are interested in.
You are not forced to specify full column names to do so. You only need
to supply enough info to perform unambiguous column name match. It makes
working with table-like date more interactive and less time consuming.
Behavior is very similar to Select-Object with not strict (but unambiguous)
properties specified.
Alias: p
.PARAMETER Args
Pass as many column name patterns as you like - they would be parsed
dynamically.
.EXAMPLE
Get-ChildItem | Use-Project name len
Would output Name and Length properties of all child items. Projection
doesn't require you to specify full property name if you can supply
unambiguous matching regex pattern.
.EXAMPLE
Get-ChildItem | Use-Project name time
WARNING: Disambiguate 'time'
CreationTime
CreationTimeUtc
LastAccessTime
LastAccessTimeUtc
LastWriteTime
LastWriteTimeUtc
Would output warning showing that 'time' parameter is ambiguous and there
are 6 parameter names that match it. You must supply more specific
parameter name so the match would be unambiguous.
[The same command via aliases]
ls | p name time
.LINK
Get-Parameter
Use-Filter
#>
begin { $accumulator = @() }
process { $accumulator += $psitem }
end
{
# Display available parameters if no arguments are specified
if( $args.Count -eq 0 ) { Write-Warning "What property?`n$($accumulator | Get-Parameter | Out-String)"; return }
# Resolve all passed parameter names
$resolved = [string[]] @($args | foreach{ $accumulator | Get-Parameter $psitem -Single } )
# Output all resolved parameters
# If there is an unresolved parameter do nothing
if( $args.Count -eq $resolved.Count ) { $accumulator | Select-Object -Property $resolved }
}
}
function Use-Filter
{
<#
.SYNOPSIS
Regex based parameter filter for input objects
.DESCRIPTION
Filters pipeline passing through only objects that match specific property
and value pattern. Allows to quickly explore data and discover property
names and values.
Alias: f
.PARAMETER ParameterPattern
Regex pattern for a parameter. Only not ambiguous matches are accepted.
All ambiguities are explained via Warnings. If parameter pattern is omitted,
all existing property names are shown.
.PARAMETER ValuePattern
Regex pattern for a parameter value. Only not ambiguous matches are accepted.
All ambiguities are explained via Warnings. If value pattern is omitted, all
existing property values are shown.
.PARAMETER NoValue
Specify this switch if you want to filter properties that match property
pattern but have no value.
.EXAMPLE
PS> Get-ChildItem | Use-Filter name
PS> ls | f name ps1
Exploring Get-ChildItem output. Output unique values for a property that
match 'name' pattern. Then specify ps1 files for the name.
.EXAMPLE
ls | f len -NoValue
Filter ls output, find files which don't have Length property set.
.LINK
Get-Parameter
Use-Project
#>
param
(
[string] $ParameterPattern,
[string] $ValuePattern,
[switch] $NoValue
)
begin { $accumulator = @() }
process { $accumulator += $psitem }
end
{
# Display available parameters if no parameter pattern is specified
if( -not $parameterPattern ) { Write-Warning "What property?`n$($accumulator | Get-Parameter | Out-String)"; return }
# Resolve parameter name
$parameter = $accumulator | Get-Parameter $parameterPattern -Single
if( -not $parameter ) { return }
# No value special case
if( $noValue ) { return $accumulator | where{ -not $psitem.$parameter } }
# Display all values if no value pattern is specified
if( -not $valuePattern ) { Write-Warning "What value?`n$($accumulator | foreach{ $psitem.$parameter } | Get-UniqueUnsorted | Out-String)"; return }
# Output object that has matches in property and value
$accumulator | where{ $psitem.$parameter -match $valuePattern }
}
}
function Get-Ini
{
<#
.SYNOPSIS
Parse INI file as a hashtable object
.DESCRIPTION
Features:
- Both section and section-less parameters are supported.
- Comments are supported.
- Non-literal names are supported.
- Collapsing of empty sections is supported.
.PARAMETER Path
Path to INI file.
Can't be used at the same time with Content.
.PARAMETER KeepEmptySections
Specify this switch if you want to keep empty INI sections in the output.
By default empty sections are removed.
.PARAMETER Content
Content of the INI file.
Can't be used at the same time with Path.
.PARAMETER Comment
Regex that specifies how comments are started in ini file.
By default: ;
.EXAMPLE
Get-Ini Shared.ini
Parse Shared.ini file.
.LINK
Show-Ini
http://stackoverflow.com/questions/417798/ini-file-parsing-in-powershell
#>
param
(
[string] $Path,
[switch] $KeepEmptySections,
[string[]] $Content,
[string] $Comment = ";"
)
# Parameter validation
if( $path -and $content )
{
throw "It is not possible to specify both -Path and -Content parameters"
}
# Initialize
$section = ""
$ini = [ordered]@{}
$ini[$section] = [ordered]@{}
$content = if( $content )
{
$content -split "`r?`n"
}
else
{
Get-Content $path
}
# Parsing
foreach( $line in $content )
{
$withoutComments = ($line -replace "$comment.*").Trim()
if( $withoutComments.Length -eq 0 ) { continue }
switch -regex ($withoutComments)
{
"^\[([^\]]+)\]\s*$"
{
$section = $matches[1].Trim()
$ini[$section] = [ordered]@{}
}
"^([^=]+)\s*=\s*(.*)?\s*$"
{
$name, $value = $matches[1..2]
$ini[$section][$name.Trim()] = $value
}
default
{
Write-Warning "Unknown sentence '$line' in file '$path'. Skipping the line."
}
}
}
# Remove empty sections, we create a new ini object since in ConstrainedMode
# it is not possible to call any methods, the needed $ini.Remove() included
if( -not $KeepEmptySections )
{
$newIni = [ordered]@{}
$ini.keys | where{ $ini[$psitem].Count -gt 0 } | foreach{ $newIni[$psitem] = $ini.$psitem }
$ini = $newIni
}
# Copy entries from no-section if it's possible
if( $ini[""] -and $ini[""].Keys )
{
$withoutSection = @($ini[""].Keys) | where{ @($ini.keys) -notcontains $psitem }
$withoutSection | foreach{ $ini[$psitem] = $ini[""][$psitem] }
}
$ini
}
function ConvertFrom-Ini
{
<#
.SYNOPSIS
Converts ini strings into Powershell hashtable object
.DESCRIPTION
Features:
- Both section and section-less parameters are supported.
- Comments are supported.
- Non-literal names are supported.
- Collapsing of empty sections is supported.
.PARAMETER Content
Content of an INI file.
.PARAMETER Comment
Regex that specifies how comments are started in ini file.
By default: ;
.PARAMETER KeepEmptySections
Specify this switch if you want to keep empty INI sections in the output.
By default empty sections are removed.
.EXAMPLE
ConvertFrom-Ini (Get-Content Shared.ini)
Convert content of Shared.ini file to a hashtable object.
.LINK
http://stackoverflow.com/questions/417798/ini-file-parsing-in-powershell
#>
param
(
[string[]] $Content,
[string] $Comment = ";",
[switch] $KeepEmptySections
)
# Initialize
$section = ""
$ini = [ordered]@{}
$ini[$section] = [ordered]@{}
$content = $content -split "`r?`n"
# Parsing
foreach( $line in $content )
{
$withoutComments = ($line -replace "$comment.*").Trim()
if( $withoutComments.Length -eq 0 ) { continue }
switch -regex ($withoutComments)
{
"^\[([^\]]+)\]\s*$"
{
$section = $matches[1].Trim()
$ini[$section] = [ordered]@{}
}
"^([^=]+)\s*=\s*(.*)?\s*$"
{
$name, $value = $matches[1..2]
$ini[$section][$name.Trim()] = $value
}
default
{
Write-Warning "Unknown sentence '$line' in file '$path'. Skipping the line."
}
}
}
# Remove empty sections, we create a new ini object since in ConstrainedMode
# it is not possible to call any methods, the needed $ini.Remove() included
if( -not $KeepEmptySections )
{
$newIni = [ordered]@{}
$ini.keys | where{ $ini[$psitem].Count -gt 0 } | foreach{ $newIni[$psitem] = $ini.$psitem }
$ini = $newIni
}
# Copy entries from no-section if it's possible
if( $ini[""] -and $ini[""].Keys )
{
$withoutSection = @($ini[""].Keys) | where{ @($ini.keys) -notcontains $psitem }
$withoutSection | foreach{ $ini[$psitem] = $ini[""][$psitem] }
}
$ini
}
function Import-Ini
{
<#
.SYNOPSIS
Imports ini file into Powershell hashtable object
.DESCRIPTION
Features:
- Both section and section-less parameters are supported.
- Comments are supported.
- Non-literal names are supported.
- Collapsing of empty sections is supported.
.PARAMETER Path
Path to an existing INI file.
.PARAMETER Comment
Regex that specifies how comments are started in ini file.
By default: ;
.PARAMETER KeepEmptySections
Specify this switch if you want to keep empty INI sections in the output.
By default empty sections are removed.
.EXAMPLE
Import-Ini Shared.ini
Convert content of Shared.ini file to a hashtable object.
.LINK
http://stackoverflow.com/questions/417798/ini-file-parsing-in-powershell
#>
param
(
[Parameter(Mandatory = $true)]
[ValidateScript({Test-Path $psitem -PathType Leaf})]
[string] $Path,
[string] $Comment = ";",
[switch] $KeepEmptySections
)
$content = Get-Content $path
ConvertFrom-Ini $content -Comment:$Comment -KeepEmptySections:$KeepEmptySections
}
function Show-Ini
{
<#
.SYNOPSIS
Print contents of INI parsed file, received from Get-Ini command
.DESCRIPTION
Formats INI file in hash table form to make it console-readable.
You can specify section filter to get only the sections of interest
at the moment.
.PARAMETER Ini
Content of a INI file in hash table form. Usually it is out from
Get-Ini command.
.PARAMETER SectionFilter
Filter that should pass each section in order to be outputted.
By default all sections are shown.
.EXAMPLE
Show-Ini (Get-Ini Shared.ini) machine
Print all sections of Shared.ini containing 'machine' word.
.LINK
Get-Ini
#>
param
(
[hashtable] $Ini,
[string] $SectionFilter = ".*"
)
foreach( $section in ($ini.Keys | sort | where{ $psitem -match $sectionFilter }) )
{
$section
foreach( $key in $ini[$section].keys )
{
" $($key) = $($ini[$section][$key])"
}
""
}
}