Creating a PowerShell Command that Process Paths using Visual Studio Code

Writing functions that need to process paths in PowerShell and do everything that PowerShell users expect can be tricky.  Here are some of the features that folks expect for a fictitious function called “Edit-File” (well, there *is* an Edit-File command in PSCX) :

PS C:\> Edit-File –Path C:\foo.txt, C:\bar.txt # do you handle an array of paths
PS C:\> Edit-File –Path C:\*.txt # do you support wildcards
PS C:\> Edit-File –Path ..\foo.txt # do you support relative paths
PS C:\> Edit-File –Path ~\foo.txt # do you resolve paths with ~ in them
PS C:\> Edit-File –LiteralPath C:\foo[1].txt # do you support literal paths
PS C:\> Get-ChildItem . -Recurse *.txt | Edit-File # do you support piping from Get-ChildItem

In addition to these, do you test if the path exists and give a good error message?  Do you support “ShouldProcess”?  Is the Path parameter set as the default parameter set?

In order to make the creation of path processing functions easier, we have created some productivity and example code snippets in the PowerShell extension for Visual Studio Code.  Let’s get started by scaffolding out an empty cmdlet style function using the “cmdlet” productivity snippet e.g.:

Path1

Now that we have an empty cmdlet function (aka advanced function) scaffolded, lets add two parameters – Path and LiteralPath:

Path2

No we have both a Path and a LiteralPath parameter.  They are defined in different parameter sets: Path and LiteralPath.  You can change those parameter set names as appropriate for your function.

The Path parameter validates input, declares support for wildcards and sets its type to “[string[]]”.  This means the user can specify more than one path when using the Path parameter.  Also note that pipeline input support has been set up and the parameter is declared as a positional (position 0) parameter.  Change or remove the positional property as necessary for your function.

The LiteralPath parameter also validates input and declares an alias of “PSPath”.  This is crucial, along with setting ValueFromPipelineByPropertyName to true, to enable this function to be able to handle pipeline input from commands like Get-ChildItem.  This parameter is also set to position 0.  Again, change or remove this property as necessary for your function.

We have the two parameters configured.  It’s not rocket science but not as simple as one might hope.  Now we need to drop in some script to process the values applied to these two parameters.  What follows is use of an “example” snippet – “ex-path processing for wildcards allowed” – from the PowerShell extension for VS Code.  This is one particular way of implementing the script to process both of these parameters, which is why this snippet is in the example category:

Path3

Wow!  That’s a good bit of script but it is necessary for both robust handling of paths that might be relative, contain wildcards (for the Path parameter) or special characters like “~” and for providing good errors when the path doesn’t exist.  BTW there may be times when “by definition” the path doesn’t exist e.g. you’re writing a New-ProjectFile function.  For that scenario, see the snippet “ex-path processing for non-existing paths”.

OK let’s test the script above and see how it works:

Path4

When you open the PowerShell extension’s Examples folder “~\.vscode\extensions\ms-vscode.PowerShell-0.4.1\Examples” you will see the following files:

* PathProcessing.Tests.ps1
* PathProcessingNonExistingPaths.ps1
* PathProcessingNoWildcards.ps1
* PathProcessingWildcards.ps1

The first file is a Pester test to ensure the snippets used to create the other three files, processes paths correctly.  If you have this folder open, press Ctrl+Shift+T to run the Pester tests in the first file.  You should see these results:

Path5

Please take these snippets for a spin.  If you find any issues or have suggestions, please submit them to the extension’s GitHub project.

This entry was posted in PowerShell, PowerShellEditorServices, VSCode. Bookmark the permalink.

Leave a comment