PowerShell начинает добавлять пути к файлам с помощью Microsoft.PowerShell.Core \ FileSystem :: - PullRequest
1 голос
/ 26 марта 2020

Я наблюдаю следующее поведение в PowerShell, которое не могу объяснить и нахожу громоздким.

Я работаю в произвольном каталоге, и путь к каталогу показан в приглашении:

PS C:\Users\Rene\AppData\Local\Temp>

Кроме того, get-location сообщает «правильный» путь:

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

Path
----
C:\Users\Rene\AppData\Local\Temp

Затем я набираю mkdir xyz | cd, чтобы создать каталог и изменить рабочий каталог на этот новый каталог:

PS C:\Users\Rene\AppData\Local\Temp> mkdir xyz | cd

Внезапно путь в приглашении начинается с префикса Microsoft.PowerShell.Core\FileSystem:::

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

Это изменение также отражается с помощью 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

Что здесь происходит и как я могу отключить этот префикс?

1 Ответ

1 голос
/ 26 марта 2020

В обратном порядке:

Как отключить этот префикс?

Легко, используйте явное конвейерное связывание!

mkdir xyz |cd -Path {$_.FullName}

Что здесь происходит?

Отличный вопрос! Здесь вы видите побочный эффект от того, как командлеты провайдера (Get-ChildItem, Get-Item, Set-Location et c.) Реализуют конвейерную привязку .

Когда вы вызываете 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

Когда вы создаете оператор конвейера с помощью командлета поставщика (например, Set-Location / cd) в нисходящем направлении , он использует значение PSPath, определенное поставщиком, чтобы связать входной объект.

Это можно наблюдать с помощью Trace-Command:

PS C:\> Trace-Command -Expression {Get-Item .|Set-Location} -Name ParameterBinding,MemberResolution -PSHost

Что приводит к (я удалил детали для Get-Item для краткости):

DEBUG: ParameterBinding Information: 0 : BIND NAMED cmd line args [Set-Location]
DEBUG: ParameterBinding Information: 0 : BIND POSITIONAL cmd line args [Set-Location]
DEBUG: ParameterBinding Information: 0 : BIND cmd line args to DYNAMIC parameters.
DEBUG: ParameterBinding Information: 0 : MANDATORY PARAMETER CHECK on cmdlet [Set-Location]
DEBUG: ParameterBinding Information: 0 : CALLING BeginProcessing
DEBUG: ParameterBinding Information: 0 : CALLING BeginProcessing
DEBUG: ParameterBinding Information: 0 : BIND PIPELINE object to parameters: [Set-Location]
DEBUG: ParameterBinding Information: 0 :     PIPELINE object TYPE = [System.IO.DirectoryInfo]
DEBUG: ParameterBinding Information: 0 :     RESTORING pipeline parameter's original values
DEBUG: ParameterBinding Information: 0 :     Parameter [Path] PIPELINE INPUT ValueFromPipeline NO COERCION
DEBUG: ParameterBinding Information: 0 :     BIND arg [C:\\] to parameter [Path]
DEBUG: ParameterBinding Information: 0 :         BIND arg [C:\\] to param [Path] SKIPPED
DEBUG: ParameterBinding Information: 0 :     Parameter [Path] PIPELINE INPUT ValueFromPipelineByPropertyName NO COERCION
DEBUG: MemberResolution Information: 0 :     Lookup
DEBUG: MemberResolution Information: 0 :         "Path" NOT present in type table.
DEBUG: MemberResolution Information: 0 :         Adapted member: not found.
DEBUG: ParameterBinding Information: 0 :     Parameter [StackName] PIPELINE INPUT ValueFromPipelineByPropertyName NO COERCION
DEBUG: MemberResolution Information: 0 :     Lookup
DEBUG: MemberResolution Information: 0 :         "StackName" NOT present in type table.
DEBUG: MemberResolution Information: 0 :         Adapted member: not found.
DEBUG: ParameterBinding Information: 0 :     Parameter [LiteralPath] PIPELINE INPUT ValueFromPipelineByPropertyName NO COERCION
DEBUG: MemberResolution Information: 0 :     Lookup
DEBUG: MemberResolution Information: 0 :         "LiteralPath" NOT present in type table.
DEBUG: MemberResolution Information: 0 :         Adapted member: not found.
DEBUG: MemberResolution Information: 0 :     Lookup
DEBUG: MemberResolution Information: 0 :         Found PSObject instance member: PSPath.
DEBUG: ParameterBinding Information: 0 :     BIND arg [Microsoft.PowerShell.Core\FileSystem::C:\] to parameter [LiteralPath]
DEBUG: ParameterBinding Information: 0 :         BIND arg [Microsoft.PowerShell.Core\FileSystem::C:\] to param [LiteralPath] SUCCESSFUL
DEBUG: ParameterBinding Information: 0 : MANDATORY PARAMETER CHECK on cmdlet [Set-Location]
DEBUG: ParameterBinding Information: 0 : CALLING EndProcessing
DEBUG: ParameterBinding Information: 0 : CALLING EndProcessing

Как видите, PowerShell отказывается от привязки C:\ к Set-Location s -Path параметру, так как каким-то образом более подходящим является привязка значения свойства PSPath к -LiteralPath?!

Причина этого является то, что параметр -LiteralPath имеет псевдоним PSPath, что можно увидеть, покопав бит с помощью Get-Command:

PS C:\> (Get-Command Set-Location).Parameters['LiteralPath'] |Select Aliases

Aliases
-------
{PSPath}

Реальная причина почему конвейерные привязки для провайдера Командлеты реализованы следующим образом:

  1. Привязка "нативного" представления строки поставщика напрямую к Path может иметь непредвиденные последствия, связанные с globbing
    • Get-Item -Path 'a[bcd]' и Get-Item -LiteralPath 'a[bcd]' - это два дико разных запроса, например
  2. Привязка к значению PSPath, определенному поставщиком, означает, что мы можем переключить местоположение в другой провайдер без потери автоматов c привязка:
    • ie. PS Cert:\> $aFile |Get-Content просто работает
...