What is the proper way to receive a file as a parameter when writing a C# cmdlet? So far I just have a property LiteralPath (aligning with their parameter naming convention) that is a string. This is a problem because you just get whatever is typed into the console; which could be the full path or could be a relative path.
Using Path.GetFullPath(string) doesn’t work. It thinks I’m currently at ~, I’m not. Same problem occurs if I change the property from a string to a FileInfo.
EDIT: For anyone interested, this workaround is working for me:
SessionState ss = new SessionState();
Directory.SetCurrentDirectory(ss.Path.CurrentFileSystemLocation.Path);
LiteralPath = Path.GetFullPath(LiteralPath);
LiteralPath is the string parameter. I’m still interested in learning what is the recommended way to handle file paths that are passed as parameters.
EDIT2: This is better, so that you don’t mess with the users current directory, you should set it back.
string current = Directory.GetCurrentDirectory();
Directory.SetCurrentDirectory(ss.Path.CurrentFileSystemLocation.Path);
LiteralPath = Path.GetFullPath(LiteralPath);
Directory.SetCurrentDirectory(current);
This is a surprisingly complex area, but I have a ton of experience here. In short, there are some cmdlets that accept win32 paths straight from the System.IO APIs, and these typically use a -FilePath parameter. If you want to write a well behaved “powershelly” cmdlet, you need -Path and -LiteralPath, to accept pipeline input and work with relative and absolute provider paths. Here’s an excerpt from a blog post I wrote a while ago:
Paths in PowerShell are tough to understand [at first.] PowerShell Paths – or PSPaths, not to be confused with Win32 paths – in their absolute forms, they come in two distinct flavours:
FileSystem::c:\temp\foo.txtc:\temp\foo.txtIt’s very easy to get confused over provider-internal (The
ProviderPathproperty of a resolvedSystem.Management.Automation.PathInfo– the portion to the right of::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:Now, let’s look at this again:
FileSystem::c:\temp\foo.txttemp:\foo.txtA 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:
LiteralPathpath parameter aliased toPSPathPathparameter (which will resolve wildcards / glob)Point number three is especially important. Also, obviously
LiteralPathandPathshould 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:
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):
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$driveis not$null(your current location might be provider-qualified in which case$drivewill be$null) then you should use$drive.name + ":\" + $drive.CurrentLocation + "\" + "foo.txt"to get a drive-qualified PSPath.Quickstart C# Skeleton
Here’s a skeleton of a C# provider-aware cmdlet to get you going. It has built in checks to ensure it has been handed a FileSystem provider path. I am in the process of packaging this up for NuGet to help others get writing well-behaved provider-aware Cmdlets:
Cmdlet Development Guidelines (Microsoft)
Here is some more generalized advice that should help you out in the long run:
http://msdn.microsoft.com/en-us/library/ms714657%28VS.85%29.aspx