PowerShell 开始在文件路径前面添加 Microsoft.PowerShell.Core\FileSystem::

Ren*_*ger 3 filesystems powershell

我在 PowerShell 中遇到以下行为,我无法解释并且觉得很麻烦。

我正在任意目录中工作,目录的路径显示在提示中:

PS C:\Users\Rene\AppData\Local\Temp>
Run Code Online (Sandbox Code Playgroud)

另外,get-location报告“正确”路径:

PS C:\Users\Rene\AppData\Local\Temp> get-location

Path
----
C:\Users\Rene\AppData\Local\Temp
Run Code Online (Sandbox Code Playgroud)

然后,我键入命令mkdir xyz | cd以创建一个目录并将工作目录更改为这个新目录:

PS C:\Users\Rene\AppData\Local\Temp> mkdir xyz | cd
Run Code Online (Sandbox Code Playgroud)

突然,提示中的路径带有前缀Microsoft.PowerShell.Core\FileSystem::

PS Microsoft.PowerShell.Core\FileSystem::C:\Users\Rene\AppData\Local\Temp\xyz>
Run Code Online (Sandbox Code Playgroud)

这一变化也反映在get-location

PS Microsoft.PowerShell.Core\FileSystem::C:\Users\Rene\AppData\Local\Temp\xyz> get-location

Path
----
Microsoft.PowerShell.Core\FileSystem::C:\Users\Rene\AppData\Local\Temp\xyz
Run Code Online (Sandbox Code Playgroud)

这是怎么回事以及如何关闭该前缀?

Mat*_*sen 5

按相反顺序:

如何关闭该前缀?

简单,使用显式管道绑定!

mkdir xyz |cd -Path {$_.FullName}
Run Code Online (Sandbox Code Playgroud)

这里发生了什么?

好问题!Get-ChildItem您在这里看到的是提供程序 cmdlet( 、Get-ItemSet-Location)如何实现管道绑定的副作用。

当您针对提供程序调用New-Item(这就是mkdir所做的)FileSystem时,它会返回一个对象(对应于新创建的文件或目录),该对象具有一堆隐藏属性,PowerShell 使用这些属性来跟踪提供程序之间的项目 - 这些可以通过以下方式发现Get-Member -Force:

PS C:\> Get-Item .|Get-Member PS* -MemberType NoteProperty -Force


   TypeName: System.IO.DirectoryInfo

Name          MemberType   Definition
----          ----------   ----------
PSChildName   NoteProperty string PSChildName=C:\
PSDrive       NoteProperty PSDriveInfo PSDrive=C
PSIsContainer NoteProperty bool PSIsContainer=True
PSParentPath  NoteProperty string PSParentPath=
PSPath        NoteProperty string PSPath=Microsoft.PowerShell.Core\FileSystem::C:\
PSProvider    NoteProperty ProviderInfo PSProvider=Microsoft.PowerShell.Core\FileSystem
Run Code Online (Sandbox Code Playgroud)

当您使用下游提供程序 cmdlet(例如Set-Location/cd例如)构造管道语句时,它使用提供程序限定的PSPath值来数字绑定输入对象。

这可以通过以下方式观察到Trace-Command

PS C:\> Trace-Command -Expression {Get-Item .|Set-Location} -Name ParameterBinding,MemberResolution -PSHost
Run Code Online (Sandbox Code Playgroud)

结果是(为了Get-Item简洁起见,我删除了详细信息):

mkdir xyz |cd -Path {$_.FullName}
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,PowerShell 放弃绑定C:\Set-Locations-Path参数,因为以某种方式将PSPath属性值绑定到-LiteralPath更合适?!

原因是该-LiteralPath参数被别名为PSPath,通过挖掘一点可以看出Get-Command

PS C:\> Get-Item .|Get-Member PS* -MemberType NoteProperty -Force


   TypeName: System.IO.DirectoryInfo

Name          MemberType   Definition
----          ----------   ----------
PSChildName   NoteProperty string PSChildName=C:\
PSDrive       NoteProperty PSDriveInfo PSDrive=C
PSIsContainer NoteProperty bool PSIsContainer=True
PSParentPath  NoteProperty string PSParentPath=
PSPath        NoteProperty string PSPath=Microsoft.PowerShell.Core\FileSystem::C:\
PSProvider    NoteProperty ProviderInfo PSProvider=Microsoft.PowerShell.Core\FileSystem
Run Code Online (Sandbox Code Playgroud)

提供程序 cmdlet 的管道绑定以这种方式实现的真正原因有两个:

  1. 直接绑定“provider-native”字符串表示形式可能会产生与通配符Path相关的意外后果
    • Get-Item -Path 'a[bcd]'例如,这Get-Item -LiteralPath 'a[bcd]'是两个截然不同的查询
  2. 绑定提供者限定PSPath值意味着我们可以将位置切换到不同的提供者而不会丢失自动绑定:
    • IE。PS Cert:\> $aFile |Get-Content 正常工作