Utility/Search-ObjectProperty.ps1

function Search-ObjectProperty {
    <#
        .SYNOPSIS
            Searches PSCustomObject(s) for a specified search pattern, returning a list of matching properties.
 
        .DESCRIPTION
            Search-ObjectProperty searches PSCustomObject(s) for a specified search pattern, returning a list of matching properties.
 
        .PARAMETER InputObject
            The object(s) to search.
 
        .PARAMETER Pattern
            The pattern to use when searching. Regular expressions are supported.
 
        .PARAMETER Depth
            The number of layers (sub-objects/properties) in every object to search. Using a search depth that is too deep can significantly increase search time.
 
        .PARAMETER CurrentDepth
            Do not use. This parameter is used internally when searching recursively to keep track of the current depth in the object.
 
        .PARAMETER ParentProperty
            Do not use. This parameter is used internally when searching recursively to keep track of the full path to a matching property.
 
        .EXAMPLE
 
        .NOTES
            Author(s): : David Seibel
            Contributor(s) :
            Date Created : 07/20/2017
            Date Modified : 11/08/2017
 
        .LINK
            https://github.com/davidseibel/PoshBPA
    #>

    [CmdletBinding()]
    param(
        [Parameter(ValueFromPipeline = $true)]
        $InputObject,

        [string]$Pattern,
        
        [ValidateScript({$_ -gt 0})]
        [int]$Depth = 3,

        [int]$CurrentDepth = 0,

        [ValidateNotNullOrEmpty()]
        [string]$ParentProperty = ""
    )
    BEGIN {
        $result = @()
    }

    PROCESS {
        foreach ($obj in $InputObject) {
            $found = $false
            $matchedProps = @()

            foreach ($property in ($obj | Get-Member -MemberType CodeProperty,NoteProperty,Property,ScriptProperty | Where-Object {$_.Name -ne "MatchedProperty"}).Name) {
                if ($obj."$property" -is [PSCustomObject] -or $obj."$property" -is [Array]) {
                    if ($CurrentDepth -le $Depth) {
                        Write-Verbose "Searching sub-object $ParentProperty.$property"
                        $subProperties = $obj."$property" | Search-ObjectProperty -Pattern $Pattern -ParentProperty "$ParentProperty.$property" -Depth $Depth -CurrentDepth ($CurrentDepth + 1)
                        if ($subProperties) {
                            $matchedProps += $subProperties.MatchedProperty
                            $found = $true
                        }
                    }
                } elseif ($obj."$property" -match $Pattern) {
                    Write-Verbose "Found '$Pattern' in $ParentProperty.$property"
                    $matchedProps += "$ParentProperty.$property"
                    $found = $true                        
                }
            }
            if ($found) {
                if ($null -eq ($obj | Get-Member -Name "MatchedProperty")) {
                    $obj | Add-Member -NotePropertyName "MatchedProperty" -NotePropertyValue $matchedProps
                } else {
                    $obj.MatchedProperty = $matchedProps
                }
                $result += $obj
            }
        }
    }

    END {
        return $result
    }
}