How to access a PSDrive from System.IO.File calls?

陌路散爱 提交于 2020-02-22 06:29:27

问题


I'm writing a c# cmdlet which copies files from one location to another (similar to rsync). It even supports ToSession and FromSession.

I'd like it to work with PSDrives that use the Filesystem provider but it currently throws an error from System.IO.File.GetAttributes("psdrive:\path")

I'd really like to use calls from System.IO on the PSDrive.

How does something like copy-item do this?

I've performed a search for accessing PSDrives from c# and have returned no results.

This is the equivalent of my code

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

returns

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

回答1:


.NET knows nothing about PowerShell drives (and typically also has a different working directory), so conversion to a filesystem-native path is necessary:

In PowerShell code:

Use Convert-Path to convert a PowerShell-drive-based path to a native filesystem path that .NET types understand:

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

By default (positional argument use) and with -Path, Convert-Path performs wildcard resolution; to suppress the latter, use the -LiteralPath parameter.

Caveat: Convert-Path only works with existing paths. Lifting that restriction is the subject of this feature request on GitHub.


In C# code:

In PSCmdlet-derived cmdlets:

  • Use GetUnresolvedProviderPathFromPSPath() to translate a PS-drive-based path into a native-drive-based path[1]unresolved, which means that, aside from translating the drive part:

    • the existence of the path is not verified (but the drive name must exist)
    • and no wildcard resolution is performed.
  • Use GetResolvedProviderPathFromPSPath() to resolve a PS-drive-based path to a native-drive-based one, which means that, aside from translating the drive part:

    • wildcard resolution is performed, yielding potentially multiple paths or even none.
    • literal path components must exist.
  • Use the CurrentProviderLocation() method with provider ID "FileSystem" to get the current filesystem location's path as a System.Management.Automation.PathInfo instance; that instance's .Path property and .ToString() method return the PS form of the path; use the .ProviderPath property to get the native representation.

Here's a simple ad-hoc compiled cmdlet that exercises both methods:

# 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

You can test it as follows:

# 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

If your current directory is C:\Temp and it happens to contain text files a.txt and b.txt, you'll see the following output:

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] If a PS drive (created with New-PSDrive) referenced in the input path is defined in terms of a UNC path, the resulting native path will be a UNC path too.



来源:https://stackoverflow.com/questions/58721850/how-to-access-a-psdrive-from-system-io-file-calls

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!