【问题标题】:Why doesn't PowerShell Core 7 recognize UNC paths when Windows PowerShell and cmd do?为什么 PowerShell Core 7 不能识别 UNC 路径,而 Windows PowerShell 和 cmd 可以?
【发布时间】:2021-08-16 15:46:44
【问题描述】:

PowerShell 似乎无法识别 \\?\ 表示法。为什么不呢?

=== cmd.exe

C:>ver
Microsoft Windows [Version 10.0.17763.1935]
C:>DIR "\\?\C:\Users\*"
 Volume in drive \\?\C: is Windows
 Volume Serial Number is 1C66-809A

 Directory of \\?\C:\Users

2021-08-04  12:27    <DIR>          .
2021-08-04  12:27    <DIR>          ..
2019-11-25  16:22    <DIR>          Administrator
...               0 File(s)              0 bytes
              28 Dir(s)  81,919,647,744 bytes free

=== Windows powershell.exe

PS C:\Users> $PSVersionTable.PSVersion.ToString()
5.1.17763.1852
PS C:\Users> Get-ChildItem -Path "\\?\C:\Users\*"

    Directory: \\?\C:\Users

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----       2019-11-25     15:22                Administrator
...
PS C:\Users>

=== PowerShell 核心 pwsh.exe

PS C:\Users> $PSVersionTable.PSVersion.ToString()
7.1.4
PS C:\Users> Get-ChildItem -Path "\\?\C:\Users\*"
PS C:\Users>

【问题讨论】:

  • 我不知道为什么,但Get-ChildItem -LiteralPath "\\?\C:\Users\" 的工作原理可能与-Path 中的通配符匹配有关
  • “为什么”很容易回答为“因为它是这样写的”;如果您想知道它是有意的还是错误的(如果是错误,是否要修复),PowerShell repo 似乎比 SO 更好。稍微搜索一下就给了我#10805,看起来它涵盖了这个。
  • @phuclv,如果你仔细观察,在 PS Core 中 Get-ChildItem -LiteralPath "\\?\C:\Users\" 实际上并没有工作:虽然它确实产生了输出,但它错误地报告了 root 目录的内容(已验证在 PowerShell Core 7.2.0-preview.8 上)。

标签: powershell path filesystems powershell-core


【解决方案1】:

您的路径语法UNC 路径无关;它使用特殊前缀[1]\\?\,其目的是选择支持长度超过259字符的文件系统路径。

Windows PowerShell(Windows 附带的旧 PowerShell 版本,其最新和最终版本是 v5.1):

  • \\?\ 支持,如您的问题所示。

PowerShell (Core) 6+(跨平台按需安装版)中:

  • \\?\不再需要,因为默认支持长路径

  • 也就是说,它仍应支持 - 尤其是为了支持在 两个 PowerShell 版本中运行的代码 - 事实它不是,从 PowerShell 7.2 开始 - 有时会导致 no 输出,使用 通配符 路径,Get-ChildItem -Path \\?\C:\Users\*,或使用 root 目录的内容(!),带有 literal 路径 Get-ChildItem -LiteralPath \\?\C:\Users - 是 GitHub issue #10805 的主题。


[1] 此类前缀标识 Win32 命名空间\\?\的具体细节在here进行说明。

【讨论】:

    【解决方案2】:

    鉴于此约定特定于 Win32(并且 PowerShell 已被重新编写为跨平台),很可能不再支持。

    如果您的代码的其他部分需要这种格式,则可以使用适当的内联 -replace 将其去掉

    $("\\?\C:\Users\*" -replace '\\\\\?\\', '')
    

    【讨论】:

    • 它与URI格式无关。这是fully-qualified name
    • \\?\ 前缀禁用文件名规范化,因此您可以创建具有很长路径的文件,或具有无效字符的文件(因为 NTFS 完全兼容 POSIX 并允许具有除 NUL 和/) Where is the use of “\\?\” defined?, Why can't I mkdir \\?\%temp%\very\long\path in cmd.exe?, How can use CD command in command prompt to change to a folder named only with a space?
    • 每个链接:Many but not all file I/O APIs support "\\?\"; you should look at the reference topic for each API to be sure. 鉴于这是 Win32 文档,最好避免它,因为 PowerShell 已被重写为跨平台。 @phuclv - 感谢您的链接 - 使用该信息更新我的答案。
    • 实际上文件名由FileSystemProvider 接收,它调用DirectoryInfo.GetFiles 并在Windows 实现中以Find­First­FileFindNextFile 结束,它可以理解\\?不影响输出。这仍然没有回答为什么会发生的问题
    • 简而言之:PowerShell Core 不再需要 \\?\ 前缀,因为它默认支持长路径。但是,前缀仍应支持——尤其是为了便于编写跨版代码——而且它不支持这一事实从 v7.2 开始应该被视为一个 bug - 请参阅 GitHub issue #。 /cc @phuclv
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-26
    • 1970-01-01
    • 2011-12-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多