Search code examples
powershellpowershell-5.0uncget-childitem

Powershell get-childitem works different with long-path prefix (\\?\)


I have different results in these two cases:

  • case 1: Get-ChildItem -Path "\\?\UNC\very\long\path"
  • case 2: Get-ChildItem -Path "\\very\long\path"

If the long path is less than 260 characters long, I have diferent results.

  • case 1: Zero child items returned.
  • case 2: all the child items expected.

For getting same results, I should do different in case 1:

Get-ChildItem -Path "\\?\UNC\very\long\path\*"

Why this difference? I use \\?\UNC prefix because the fullpath is variable and I do not know it.

Perhaps I should use \* wildcard in both cases?


Solution

  • You're seeing a bug in Windows PowerShell that surfaces when you pass literal paths (non-wildcard) paths using a long-path prefix (\\?\ for local paths, \\?\Unc\ for UNC paths) to the (possibly positionally implied) -Path parameter. See the bottom section for details.

    To work around it, use the -LiteralPath parameter instead, which is the right thing to do for non-wildcard paths anyway:

    Get-ChildItem -LiteralPath \\?\UNC\server1\share1\very\long\path
    

    Note:

    • PowerShell (Core) 7 is no longer affected, because it has implicit support for long paths; that is, you don't need the long-path prefixes anymore.

    • However, these prefixes should still be accepted, which is something that is partially broken up to at least PowerShell 7.4.x - see GitHub issue #10805


    Windows PowerShell bug details:

    The bug surfaces when you pass a non-wildcard root path that has a long-path prefix to -Path, which applies to both using the local and the UNC forms of the prefix, though the symptoms differ:

    # UNC root path: 
    # NO OUTPUT
    Get-ChildItem -Path \\?\UNC\server1\share1
    
    # LOCAL root path:
    # -> SPURIOUS ERROR "Cannot retrieve Cannot retrieve the dynamic parameters for the cmdlet. ..."
    Get-ChildItem -Path \\?\C:\
    

    Appending at least one additional path component makes the problem go away; e.g.:

    # Both OK, due to addition of another path component.
    Get-ChildItem -Path \\?\UNC\server1\share1\subfolder
    Get-ChildItem -Path \\?\C:\Windows
    

    Curiously, however, the local form doesn't support wildcards on the level of the drive root:

    # !! NO OUTPUT
    Get-ChildItem -Path \\?\C:\*
    
    # By contrast, wildcards DO work with the UNC prefix at the 
    # top-level of the share
    Get-ChildItem -Path \\?\UNC\server1\share1\*
    

    As an aside:

    • Irrespective of whether a long-path prefix is used or not, wildcard matching of UNC share names is unsupported and quietly returns nothing.

    • That is, you cannot use * in order to discover available shares on a given server; something like Get-ChildItem -Path \\server1\* or Get-ChildItem -Path \\?UNC\server1\* never produces output.