Skip to content

Commit 4c148ed

Browse files
Implementing Search-PSMDPropertyValue
1 parent f3c7521 commit 4c148ed

File tree

9 files changed

+285
-51
lines changed

9 files changed

+285
-51
lines changed

PSModuleDevelopment/PSModuleDevelopment.psd1

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@
8484
'Remove-PSMDTemplate',
8585
'Rename-PSMDParameter',
8686
'Restart-PSMDShell',
87+
'Search-PSMDPropertyValue',
8788
'Set-PSMDEncoding',
8889
'Set-PSMDModuleDebug',
8990
'Set-PSMDCmdletBinding',
512 Bytes
Binary file not shown.
Binary file not shown.

PSModuleDevelopment/bin/PSModuleDevelopment.xml

Lines changed: 59 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

PSModuleDevelopment/changelog.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
# Changelog
2+
##
3+
- New: Format-PSMDParameter - updates legacy parameter notation
4+
- New: Search-PSMDPropertyValue - search objects for values in properties
5+
- Fix: New-PSMDTemplate records binary files as text files
6+
27
## 2.2.5.37 ( October 20th, 2018)
38
- Upd: Set-PSMDModulePath - add `-Module` parameter to persist the setting
49
- Upd: Set-PSMDModulePath - add `-Register` parameter for integrated persistence
Lines changed: 76 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,79 +1,104 @@
11
function Search-PSMDPropertyValue
22
{
3+
<#
4+
.SYNOPSIS
5+
Recursively search an object for property values.
6+
7+
.DESCRIPTION
8+
Recursively search an object for property values.
9+
This can be useful to determine just where an object stores a given piece of information in scenarios, where objects either have way too many properties or a deeply nested data structure.
10+
11+
.PARAMETER Object
12+
The object to search.
13+
14+
.PARAMETER Value
15+
The value to search for.
16+
17+
.PARAMETER Match
18+
Search by comparing with regex, rather than equality comparison.
19+
20+
.PARAMETER Depth
21+
Default: 3
22+
How deep should the query recurse.
23+
The deeper, the longer it can take on deeply nested objects.
24+
25+
.EXAMPLE
26+
PS C:\> Get-Mailbox Max.Mustermann | Search-PSMDPropertyValue -Object '[email protected]' -Match
27+
28+
Searches all properties on the mailbox of Max Mustermann for his email address.
29+
#>
330
[CmdletBinding()]
431
param (
5-
$Object,
6-
32+
[AllowNull()]
733
$Value,
834

35+
[Parameter(ValueFromPipeline = $true, Mandatory = $true)]
36+
$Object,
37+
938
[switch]
1039
$Match,
1140

1241
[int]
1342
$Depth = 3
1443
)
1544

16-
function Search-Value
45+
begin
1746
{
18-
[CmdletBinding()]
19-
param (
20-
$Object,
21-
22-
$Value,
23-
24-
[bool]
25-
$Match,
47+
function Search-Value
48+
{
49+
[CmdletBinding()]
50+
param (
51+
$Object,
52+
53+
$Value,
54+
55+
[bool]
56+
$Match,
57+
58+
[int]
59+
$Depth,
60+
61+
[string[]]
62+
$Elements,
63+
64+
$InputObject
65+
)
2666

27-
[int]
28-
$Depth,
67+
$path = $Elements -join "."
68+
Write-PSFMessage -Level Verbose -Message "Processing $path"
2969

30-
[string[]]
31-
$Elements
32-
)
33-
34-
$path = $Elements -join "."
35-
Write-PSFMessage -Level Verbose -Message "Processing $path"
36-
37-
foreach ($property in $Object.PSObject.Properties)
38-
{
39-
if ($path) { $tempPath = $path, $property.Name -join "." }
40-
else { $tempPath = $property.Name }
41-
if ($Match)
70+
foreach ($property in $Object.PSObject.Properties)
4271
{
43-
if ($property.Value -match $Value)
72+
if ($path) { $tempPath = $path, $property.Name -join "." }
73+
else { $tempPath = $property.Name }
74+
if ($Match)
4475
{
45-
[PSCustomObject]@{
46-
Parent = $path
47-
Path = $tempPath
48-
Value = $property.Value
49-
Type = $property.Value.GetType()
50-
Depth = $Elements.Count + 1
76+
if ($property.Value -match $Value)
77+
{
78+
New-Object PSModuleDevelopment.Utility.PropertySearchResult($property.Name, $Elements, $property.Value, $InputObject)
5179
}
5280
}
53-
}
54-
else
55-
{
56-
if ($Value -eq $property.Value)
81+
else
5782
{
58-
[PSCustomObject]@{
59-
Parent = $path
60-
Path = $tempPath
61-
Value = $property.Value
62-
Type = $property.Value.GetType()
63-
Depth = $Elements.Count + 1
83+
if ($Value -eq $property.Value)
84+
{
85+
New-Object PSModuleDevelopment.Utility.PropertySearchResult($property.Name, $Elements, $property.Value, $InputObject)
6486
}
6587
}
66-
}
67-
68-
if ($Elements.Count -lt $Depth)
69-
{
70-
$newItems = New-Object System.Object[]($Elements.Count)
71-
$Elements.CopyTo($newItems, 0)
72-
$newItems += $property.Name
73-
Search-Value -Object $property.Value -Value $Value -Match $Match -Depth $Depth -Elements $newItems
88+
89+
if ($Elements.Count -lt $Depth)
90+
{
91+
$newItems = New-Object System.Object[]($Elements.Count)
92+
$Elements.CopyTo($newItems, 0)
93+
$newItems += $property.Name
94+
Search-Value -Object $property.Value -Value $Value -Match $Match -Depth $Depth -Elements $newItems -InputObject $InputObject
95+
}
7496
}
7597
}
7698
}
7799

78-
Search-Value -Object $Object -Value $Value -Match $Match.ToBool() -Depth $Depth -Elements @()
100+
process
101+
{
102+
Search-Value -Object $Object -Value $Value -Match $Match.ToBool() -Depth $Depth -Elements @() -InputObject $Object
103+
}
79104
}

PSModuleDevelopment/xml/PSModuleDevelopment.Format.ps1xml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,5 +137,40 @@
137137
</TableRowEntries>
138138
</TableControl>
139139
</View>
140+
141+
<!-- PSModuleDevelopment.Utility.PropertySearchResult -->
142+
<View>
143+
<Name>PSModuleDevelopment.Utility.PropertySearchResult</Name>
144+
<ViewSelectedBy>
145+
<TypeName>PSModuleDevelopment.Utility.PropertySearchResult</TypeName>
146+
</ViewSelectedBy>
147+
<TableControl>
148+
<AutoSize/>
149+
<TableHeaders>
150+
<TableColumnHeader/>
151+
<TableColumnHeader/>
152+
<TableColumnHeader/>
153+
<TableColumnHeader/>
154+
</TableHeaders>
155+
<TableRowEntries>
156+
<TableRowEntry>
157+
<TableColumnItems>
158+
<TableColumnItem>
159+
<PropertyName>Path</PropertyName>
160+
</TableColumnItem>
161+
<TableColumnItem>
162+
<PropertyName>Depth</PropertyName>
163+
</TableColumnItem>
164+
<TableColumnItem>
165+
<PropertyName>Name</PropertyName>
166+
</TableColumnItem>
167+
<TableColumnItem>
168+
<PropertyName>Value</PropertyName>
169+
</TableColumnItem>
170+
</TableColumnItems>
171+
</TableRowEntry>
172+
</TableRowEntries>
173+
</TableControl>
174+
</View>
140175
</ViewDefinitions>
141176
</Configuration>

library/PSModuleDevelopment/PSModuleDevelopment/PSModuleDevelopment.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
<Compile Include="Template\TemplateItemFile.cs" />
6363
<Compile Include="Template\TemplateItemFolder.cs" />
6464
<Compile Include="Template\TemplateType.cs" />
65+
<Compile Include="Utility\PropertySearchResult.cs" />
6566
<Compile Include="Utility\TextAlignment.cs" />
6667
<Compile Include="Utility\TextHeader.cs" />
6768
<Compile Include="Utility\UtilityHost.cs" />
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
7+
namespace PSModuleDevelopment.Utility
8+
{
9+
/// <summary>
10+
/// The result object returned by Search-PSMDPropertyValue
11+
/// </summary>
12+
[Serializable]
13+
public class PropertySearchResult
14+
{
15+
/// <summary>
16+
/// Path notation on nested properties
17+
/// </summary>
18+
public string Path
19+
{
20+
get
21+
{
22+
return String.Join(".", PathElements);
23+
}
24+
set { }
25+
}
26+
27+
/// <summary>
28+
/// The name of the property found
29+
/// </summary>
30+
public string Name;
31+
32+
/// <summary>
33+
/// The full name of the property
34+
/// </summary>
35+
public string FullName
36+
{
37+
get
38+
{
39+
if (PathElements.Length > 0)
40+
return String.Format("{0}.{1}", Path, Name);
41+
return Name;
42+
}
43+
set { }
44+
}
45+
46+
/// <summary>
47+
/// Individual property names on a found nested property.
48+
/// </summary>
49+
public string[] PathElements = new string[0];
50+
51+
/// <summary>
52+
/// The actual value found
53+
/// </summary>
54+
public object Value;
55+
56+
/// <summary>
57+
/// The type of the value found
58+
/// </summary>
59+
public Type Type
60+
{
61+
get
62+
{
63+
if (Value != null)
64+
return Value.GetType();
65+
return null;
66+
}
67+
set { }
68+
}
69+
70+
/// <summary>
71+
/// How deeply nested was the property found.
72+
/// </summary>
73+
public int Depth
74+
{
75+
get { return PathElements.Length; }
76+
set { }
77+
}
78+
79+
/// <summary>
80+
/// The original input object
81+
/// </summary>
82+
public object InputObject;
83+
84+
/// <summary>
85+
/// Creates an empty object. Only used for serialization support.
86+
/// </summary>
87+
public PropertySearchResult()
88+
{
89+
90+
}
91+
92+
/// <summary>
93+
/// Creates a full report object from using Search-PSMDPropertyValue
94+
/// </summary>
95+
/// <param name="Name">The name of the property</param>
96+
/// <param name="PathElements">The path elements if it is a nested property</param>
97+
/// <param name="Value">The actual value found</param>
98+
/// <param name="InputObject">The original input object offered to the command.</param>
99+
public PropertySearchResult(string Name, string[] PathElements, object Value, object InputObject)
100+
{
101+
this.Name = Name;
102+
if (PathElements != null)
103+
this.PathElements = PathElements;
104+
this.Value = Value;
105+
this.InputObject = InputObject;
106+
}
107+
}
108+
}

0 commit comments

Comments
 (0)