functions/Test-SubPath.ps1

function Test-SubPath
{
    <#
    .SYNOPSIS
    Tests whether one path is a subpath of another.
 
    .DESCRIPTION
    Tests whether one path is a subpath of another.
    The values passed in are compared as file path strings.
    An optional switch allows for checking of the physical existence of the paths.
 
    .PARAMETER ChildPath
    The path of the child item.
 
    .PARAMETER ParentPath
    The path of the parent item.
 
    .PARAMETER Physical
    When the Physical switch is used, the output will be true only if the child item (and therefore also the parent item) actually exists.
 
    .EXAMPLE
    ## Test paths as strings ##
 
    PS C:\> $childPath = 'C:\NonExistentFolder\NonExistentFile.txt'
    PS C:\> $parentPath = 'C:\NonExistentFolder'
    PS C:\> Test-SubPath -ChildPath $childPath -ParentPath $parentPath
    True
 
    # Returns True because the parent path is a subpath of the child path.
 
    .EXAMPLE
    ## Test paths as strings ##
 
    PS C:\> $childPath = 'C:\NonExistentFolder\NonExistentFile.txt'
    PS C:\> $parentPath = 'C:\NonExistent'
    PS C:\> Test-SubPath -ChildPath $childPath -ParentPath $parentPath
    False
 
    # Returns False because, although the parent path is a substring of the child path, it is not a subpath.
 
    .EXAMPLE
    ## Test paths as strings and check existence ##
 
    PS C:\> $childPath = 'C:\NonExistentFolder\NonExistentFile.txt'
    PS C:\> $parentPath = 'C:\NonExistentFolder'
    PS C:\> Test-SubPath -ChildPath $childPath -ParentPath $parentPath -Physical
    False
 
    # Returns False because, although the parent path is a subpath of the child path, the child item does not exist.
 
    .EXAMPLE
    ## Test paths as strings and check existence ##
 
    PS C:\> $childPath = $Env:HOME
    PS C:\> $parentPath = "$Env:HOMEDRIVE\"
    PS C:\> Test-SubPath -ChildPath $childPath -ParentPath $parentPath -Physical
    True
 
    # Returns True because the parent path is a subpath of the child path and the child item (and therefore the parent item) exists.
 
    .INPUTS
    [System.String]
    Accepts string objects via the ChildPath parameter. The output of Get-ChildItem can be piped into Test-SubPath.
 
    .OUTPUTS
    [System.Boolean]
    Returns a boolean (true/false) object.
 
    .NOTES
    Author : nmbell
 
    .LINK
    Test-PowdrgitPath
    .LINK
    about_powdrgit
    .LINK
    https://github.com/nmbell/powdrgit/blob/main/help/about_powdrgit.md
    #>


    # Use cmdlet binding
    [CmdletBinding()]

    # Declare output type
    [OutputType([System.Boolean])]

    # Declare parameters
    Param
    (


        [Parameter(
            Mandatory                       = $false
          , Position                        = 0
          , ValueFromPipeline               = $true
          , ValueFromPipelineByPropertyName = $true
          )]
        [Alias('FullName','Path')]
        [String]
        $ChildPath

    ,    [Parameter(
            Mandatory                       = $false
          , Position                        = 1
          , ValueFromPipeline               = $false
          , ValueFromPipelineByPropertyName = $true
          )]
        [String]
        $ParentPath

    ,    [Switch]
        $Physical
    )

    BEGIN
    {
        $bk = 'B'

        # Common BEGIN:
        Set-StrictMode -Version 3.0
        $thisFunctionName = $MyInvocation.MyCommand
        $start            = Get-Date
        $indent           = ($Powdrgit.DebugIndentChar[0]+' ')*($PowdrgitCallDepth++)
        $PSDefaultParameterValues += @{ '*:Verbose' = $(If ($DebugPreference -notin 'Ignore','SilentlyContinue') { $DebugPreference } Else { $VerbosePreference }) } # turn on Verbose with Debug
        Write-Debug " $(ts)$indent[$thisFunctionName][$bk]Start: $($start.ToString('yyyy-MM-dd HH:mm:ss.fff'))"

        # Function BEGIN:
    }

    PROCESS
    {
        # $bk = 'P'

        $result = $false

        If ($ChildPath.Trim() -and $ParentPath.Trim())
        {
            # Test by the string values of the paths
            $testPath = $ChildPath
            Do {
                If ($testPath -eq $ParentPath)
                {
                    $result = $true
                    Break
                }
                $testPath = Split-Path -Path $testPath -Parent
            } While ($testPath)

            # Test for physical existence
            If ($result -and $Physical)
            {
                $result = Test-Path -Path $ChildPath
            }
        }

        Write-Output $result
    }

    END
    {
        $bk = 'E'

        # Function END:

        # Common END:
        $end      = Get-Date
        $duration = New-TimeSpan -Start $start -End $end
        Write-Debug " $(ts)$indent[$thisFunctionName][$bk]Finish: $($end.ToString('yyyy-MM-dd HH:mm:ss.fff')) ($($duration.ToString('d\d\ hh\:mm\:ss\.fff')))"
        $PowdrgitCallDepth--
    }
}