.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:
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.