functions/utility/Search-PSMDPropertyValue.ps1

function Search-PSMDPropertyValue
{
<#
    .SYNOPSIS
        Recursively search an object for property values.
     
    .DESCRIPTION
        Recursively search an object for property values.
        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.
     
    .PARAMETER Object
        The object to search.
     
    .PARAMETER Value
        The value to search for.
     
    .PARAMETER Match
        Search by comparing with regex, rather than equality comparison.
     
    .PARAMETER Depth
        Default: 3
        How deep should the query recurse.
        The deeper, the longer it can take on deeply nested objects.
     
    .EXAMPLE
        PS C:\> Get-Mailbox Max.Mustermann | Search-PSMDPropertyValue -Object 'max.mustermann@contoso.com' -Match
     
        Searches all properties on the mailbox of Max Mustermann for his email address.
#>

    [CmdletBinding()]
    param (
        [AllowNull()]
        $Value,
        
        [Parameter(ValueFromPipeline = $true, Mandatory = $true)]
        $Object,
        
        [switch]
        $Match,
        
        [int]
        $Depth = 3
    )
    
    begin
    {
        function Search-Value
        {
            [CmdletBinding()]
            param (
                $Object,
                
                $Value,
                
                [bool]
                $Match,
                
                [int]
                $Depth,
                
                [string[]]
                $Elements,
                
                $InputObject
            )
            
            $path = $Elements -join "."
            Write-PSFMessage -Level Verbose -Message "Processing $path"
            
            foreach ($property in $Object.PSObject.Properties)
            {
                if ($Match)
                {
                    if ($property.Value -match $Value)
                    {
                        New-Object PSModuleDevelopment.Utility.PropertySearchResult($property.Name, $Elements, $property.Value, $InputObject)
                    }
                }
                else
                {
                    if ($Value -eq $property.Value)
                    {
                        New-Object PSModuleDevelopment.Utility.PropertySearchResult($property.Name, $Elements, $property.Value, $InputObject)
                    }
                }
                
                if ($Elements.Count -lt $Depth)
                {
                    $newItems = New-Object System.Object[]($Elements.Count)
                    $Elements.CopyTo($newItems, 0)
                    $newItems += $property.Name
                    Search-Value -Object $property.Value -Value $Value -Match $Match -Depth $Depth -Elements $newItems -InputObject $InputObject
                }
            }
        }
    }
    
    process
    {
        Search-Value -Object $Object -Value $Value -Match $Match.ToBool() -Depth $Depth -Elements @() -InputObject $Object
    }
}