Как получить доступ к PSDrive из вызовов System.IO.File?

Я пишу командлет С#, который копирует файлы из одного места в другое (аналогично rsync). Он даже поддерживает ToSession и FromSession.

Я бы хотел, чтобы он работал с PSDrive, которые используют поставщика файловой системы, но в настоящее время он выдает ошибку из System.IO.File.GetAttributes("psdrive:\path")

Я бы очень хотел использовать вызовы из System.IO на PSDrive.

Как что-то вроде copy-item делает это?

Я выполнил поиск доступа к PSDrives из С# и не дал результатов.

Это эквивалент моего кода

new-psdrive -name mydrive -psprovider filesystem  -root \\aserver\ashare -Credential domain\user
$attributes=[system.io.file]::GetAttributes("mydrive:\path\")

возвращается

Exception calling "GetAttributes" with "1" argument(s): "The given path's format is not supported."

person silicontrip    schedule 06.11.2019    source источник


Ответы (1)


.NET ничего не знает о дисках PowerShell (и, как правило, также имеет другой рабочий каталог), поэтому преобразование в собственный для файловой системы путь необходимо:

В коде PowerShell:

Используйте Convert-Path для преобразования PowerShell путь на основе диска к собственному пути файловой системы, который понимают типы .NET:

$attributes=[System.IO.File]::GetAttributes((Convert-Path "mydrive:\path\"))

По умолчанию (использование позиционного аргумента) и с -Path, Convert-Path выполняет разрешение подстановочных знаков; для подавления последнего используйте параметр -LiteralPath.

Предупреждение: Convert-Path работает только с существующими путями. Снятие этого ограничения является предметом этого запроса функции на GitHub.


В коде C#:

В командлетах, производных от PSCmdlet:

  • Используйте GetUnresolvedProviderPathFromPSPath() для перевода PS путь на основе диска в путь на основе собственного диска[1] неразрешенный, что означает, что помимо перевода части диска:

    • the existence of the path is not verified (but the drive name must exist)
    • и нет разрешения подстановочных знаков.
  • Используйте GetResolvedProviderPathFromPSPath() для преобразовать путь на основе диска PS в путь на основе собственного диска, что означает, что помимо перевода части диска:

    • wildcard resolution is performed, yielding potentially multiple paths or even none.
    • литеральные компоненты пути должны существовать.
  • Используйте метод CurrentProviderLocation() с поставщиком ID "FileSystem" для получения текущего пути к файловой системе как экземпляра System.Management.Automation.PathInfo; свойство .Path этого экземпляра и метод .ToString() возвращают PS-форму пути; используйте свойство .ProviderPath, чтобы получить собственное представление.

Вот простой специально скомпилированный командлет, который использует оба метода:

# Compiles a Get-NativePath cmdlet and adds it to the session.
Add-Type @'
    using System;
    using System.Management.Automation;
    [Cmdlet("Get", "NativePath")]
    public class GetNativePathCommand : PSCmdlet {

        [Parameter(Mandatory=true,Position=0)]
        public string PSPath { get; set; }

        protected override void ProcessRecord() {
            WriteObject("Current directory:");
            WriteObject("  PS form:      " + CurrentProviderLocation("FileSystem"));
            WriteObject("  Native form:  " + CurrentProviderLocation("FileSystem").ProviderPath);
            //
            WriteObject("Path argument in native form:");
            WriteObject("  Unresolved:");
            WriteObject("    " + GetUnresolvedProviderPathFromPSPath(PSPath));
            //
            WriteObject("  Resolved:");
            ProviderInfo pi;
            foreach (var p in GetResolvedProviderPathFromPSPath(PSPath, out pi))
            {
              WriteObject("    " + p);
            }
        }
    }
'@ -PassThru | % Assembly | Import-Module

Вы можете протестировать его следующим образом:

# Create a foo: drive whose root is the current directory.
$null = New-PSDrive foo filesystem .

# Change to foo:
Push-Location foo:\

# Pass a wildcard path based on the new drive to the cmdlet
# and have it translated to a native path, both unresolved and resolved;
# also print the current directory, both in PS form and in native form.
Get-NativePath foo:\*.txt

Если ваш текущий каталог C:\Temp и он содержит текстовые файлы a.txt и b.txt, вы увидите следующий вывод:

Current directory:
  PS form:      foo:\
  Native form:  C:\Temp\
Path argument in native form:
  Unresolved:
    C:\Temp\*.txt
  Resolved:
    C:\Temp\a.txt
    C:\Temp\b.txt

[1] Если диск PS (созданный с помощью New-PSDrive), указанный во входном пути, определен в терминах пути UNC, результирующий собственный путь также будет путем UNC.

person mklement0    schedule 06.11.2019
comment
@MarkHeath: Ах, я пропустил, что вы хотели звонить из C# - пожалуйста, смотрите мое обновление. Обратите внимание, что оба метода SDK и Convert-Path возвращают путь UNC только в том случае, если входной путь основан на диске PS, корневой каталог которого был определен как путь UNC — по крайней мере, это то, что я вижу в WinPS v5.1/PowerShell Core 7.0. .0-предварительный просмотр.5. - person mklement0; 06.11.2019