Find-JsonContent.ps1

function Find-JsonContent
{
    <#
    .Synopsis
        Finds content within a json object
    .Description
        Recursively finds content within a json object
    #>

    param(
    # The input object
    [Parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
    [PSObject]
    $InputObject,

    # The key (the name of the property) we're finding.
    [Parameter(Mandatory=$true,ParameterSetName='Key',Position=0,ValueFromPipelineByPropertyName=$true)]
    [Parameter(Mandatory=$true,ParameterSetName='KeyValue',Position=0,ValueFromPipelineByPropertyName=$true)]
    [string]
    $Key,

    # The value we're trying to find.
    [Parameter(Mandatory=$true,ParameterSetName='KeyValue',Position=1,ValueFromPipelineByPropertyName=$true)]
    [PSObject]
    $Value,

    # If set, will find values like the wildcard.
    [Parameter(ParameterSetName='Key',ValueFromPipelineByPropertyName=$true)]
    [Parameter(ParameterSetName='KeyValue',ValueFromPipelineByPropertyName=$true)]
    [switch]
    $Like,

    # If set, will find values that match the regular expression.
    [Parameter(ParameterSetName='Key',ValueFromPipelineByPropertyName=$true)]
    [Parameter(ParameterSetName='KeyValue',ValueFromPipelineByPropertyName=$true)]
    [switch]
    $Match,

    # If set, will find values that are not like a wildcard.
    [Parameter(ParameterSetName='Key',ValueFromPipelineByPropertyName=$true)]
    [Parameter(ParameterSetName='KeyValue',ValueFromPipelineByPropertyName=$true)]
    [switch]
    $NotLike,

    # If set, will find values that do not match a regular expression.
    [Parameter(ParameterSetName='Key',ValueFromPipelineByPropertyName=$true)]
    [Parameter(ParameterSetName='KeyValue',ValueFromPipelineByPropertyName=$true)]
    [switch]
    $NotMatch,

    # A list of parent objects. This parameter will be passed recursively.
    [PSObject[]]
    $Parent,

    # The maximum depth to search
    [Uint32]
    $Depth,

    # The name of the current property. This parameter will be passed recursively.
    [string[]]
    $Property)

    begin {
        $OutputMatch = {
            param([Parameter(Mandatory)][PSObject]$in)

            $OutObject = [Ordered]@{}
            foreach ($prop in $in.psobject.properties) {
                $OutObject[$prop.Name] = $prop.Value
            }
            $OutObject['ParentObject'] = $parent
            $OutObject['PropertyName'] = if ($property) {$Property[-1]}

            $OutObject['JSONPath']     = @(
                $np =0
                foreach ($p in $property) {
                    if ($p.StartsWith('[') -or -not $np) {
                        $p
                    } else {
                        ".$p"
                    }
                    $np++
                }) -join ''
            [PSCustomObject]$OutObject
        }
    }

    process {
        $mySplat = @{} + $PSBoundParameters
        $mySplat.Remove('InputObject')
        if (-not $InputObject) { return }


        $index = -1
        foreach ($in in $InputObject) {
            if (-not $in) { continue }
            $index++
            if ($in -is [string] -or $in -is [int] -or $in -is [bool] -or
                $in -is [double] -or $in -is [long] -or $in -is [float]) {
                continue
            }

            if ($PSCmdlet.ParameterSetName -eq 'KeyValue') {
                if ($in.psobject.properties.item($key)) {
                    if (($like -and $in.$key -like $Value) -or
                        ($Match -and $in.$key -match $Value) -or
                        ($NotLike -and $in.$key -notlike $Value) -or
                        ($NotMatch -and $in.$key -notmatch $Value) -or
                        ($in.$key -eq $Value -and -not ($NotLike -or $NotMatch))) {
                        $property += $key
                        . $outputMatch $in
                    }
                }
            } elseif ($PSCmdlet.ParameterSetName -eq 'Key') {
                $propertyNames = @(foreach ($_ in $in.psobject.properties) { $_.Name })
                if (($Like -and $propertyNames -like $key) -or
                    ($Match -and $propertyNames -match $key) -or
                    ($propertyNames -eq $key -and -not ($NotLike -or $NotMatch)))
                {
                    $matchingKeys =
                        @(if ($like) {
                            $propertyNames -like $key
                        } elseif ($match) {
                            $propertyNames -match $key
                        } else {
                            $key
                        })
                    $property += $matchingKeys
                    . $OutputMatch $in
                }
                elseif (
                    ($NotMatch -and $propertyNames -notmatch $Key) -or
                    ($NotLike -and $propertyNames -notlike $Key)
                )
                {
                    . $OutputMatch $in
                }
            }


            if ($parent -contains $in) {
                continue
            }
            $mySplat.Parent = @($in) + $Parent

            if ($depth -and $mySplat.Parent.Length -ge $Depth) {
                continue
            }

            if ($in -is [Object[]]) {

                Find-JsonContent @mySplat -InputObject $in
            } else {
                $propertyAndIndex =
                    @(if ($Property) {
                        $property
                    }
                    if ($InputObject.Count) {
                        "[$index]"
                    })
                foreach ($prop in $in.psobject.properties) {
                    if (-not $prop.Value) { continue }
                    if ($prop.Name -like 'parent*') { continue }
                    $mySplat.Property = $propertyAndIndex + $prop.Name


                    Find-JsonContent @mySplat -InputObject $prop.Value
                }
            }
        }
    }
}