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."
.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 the feature request in GitHub issue #2993.
In C# code:
In PSCmdlet
-derived cmdlets:[1]
Use GetUnresolvedProviderPathFromPSPath()
to translate a PS-drive-based path into a native-drive-based path[2] unresolved, which means that, aside from translating the drive part:
Use GetResolvedProviderPathFromPSPath()
to resolve a PS-drive-based path to a native-drive-based one, which means that, aside from translating the drive part:
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] In PowerShell code, these methods can also be accessed via $ExecutionContext.SessionState.Path
, e.g. $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath('temp:/')
, using the automatic $ExecutionContext
variable.
[2] 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.