PowerShell – The Patchwork of Paths, PSPaths and ProviderPaths

Paths in PowerShell are tough to understand [at first.] PowerShell Paths - or PSPaths, not to be confused with Win32 paths - in their absolute forms, come in two distinct flavours:

  • Provider-qualified: FileSystem::c:\temp\foo.txt
  • Drive-qualified: c:\temp\foo.txt

It's very easy to get confused over provider-internal (The ProviderPath property of a resolved PathInfo – and the bold portion of the provider-qualified path above) and drive-qualified paths since they look the same if you look at the default FileSystem provider drives. That is to say, the PSDrive has the same name (C) as the native backing store, the windows filesystem (C). So, to make it easier for yourself to understand the differences, create yourself a new PSDrive:

ps c:\> new-psdrive temp filesystem c:\temp\
ps c:\> cd temp:
ps temp:\>

Now, let's look at this again:

  • Provider-qualified: FileSystem::c:\temp\foo.txt
  • Drive-qualified: temp:\foo.txt

A bit easier this time to see what’s different this time. The bold text to the right of the provider name is the ProviderPath.

So, your goals for writing a generalized provider-friendly Cmdlet (or advanced function) that accepts paths are:

  • Define a LiteralPath path parameter aliased to PSPath
  • Define a Path parameter (which will resolve wildcards / glob)
  • Assume you are receiving PSPaths, NOT native provider-paths

Point number three is especially important. Also, obviously LiteralPath and Path should belong in mutually exclusive parameter sets.

Relative Paths

A good question is: how do we deal with relative paths being passed to a Cmdlet. As you should assume all paths being given to you are PSPaths,  let’s look at what the Cmdlet below does:

ps temp:\> write-zip -literalpath foo.txt

The command should assume foo.txt is in the current drive, so this should be resolved immediately in the ProcessRecord or EndProcessing block like (using the scripting API here to demo):

$provider = $null;
$drive = $null
$providerPath = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath("foo.txt", [ref]$provider, [ref]$drive)

Now you everything you need to recreate the two absolute forms of PSPaths, and you also have the native absolute ProviderPath. To create a provider-qualified PSPath for foo.txt, use $provider.Name + “::” + $providerPath. If $drive is not null (your current location might be provider-qualified in which case $drive will be null) then you should use $drive.name + ":\" + $drive.CurrentLocation + "\" + "foo.txt" to get a drive-qualified PSPath.

Have fun!

blog comments powered by Disqus

About the author

Irish, PowerShell MVP, .NET/ASP.NET/SharePoint Developer, Budding Architect. Developer. Montrealer. Opinionated. Montreal, Quebec.

Month List

Page List