Making a PowerShell Command Your Own

After you have been using PowerShell for a while, you’ll begin finding the need to create your own tools and commands. Often, your commands are centered on a PowerShell command that you want to adjust to meet your requirements. Perhaps you need to add a new parameter, modify an existing parameter, or take results from a command and combine them with something else. This can be a very tedious process if you attempt to build your own command from scratch. As you have probably surmised, I’m here to help. First, let’s look at two approaches on how to create your own PowerShell command.

Proxy Commands

A proxy command is often used to customize the behavior of a given cmdlet, often by removing parameters. This is most often done in scenarios where you have created a delegated and restricted remote-endpoint, and you not only want to limit what commands can be run, but also what parameters can be used. Often the proxy command uses the same name as the original command and passes parameters to it.

You can create a proxy function manually by first creating a CommandMetaData object.

This object is a snapshot of the command, its parameters, and settings.

Creating a CommandMetaData object in Windows PowerShell (Image Credit: Jeff Hicks)
Creating a CommandMetaData object in Windows PowerShell (Image Credit: Jeff Hicks)

This object has a method that will generate a proxy command.

The proxy code looks like this:

All you have to do is wrap it in a function scriptblock and modify as necessary. Personally, I like to clean up parameter definitions and remove the { } characters from the parameter variables.

Wrapper Functions

By contrast, a wrapper function typically focuses on a single cmdlet, but it can be customized to meet a specific need. For example, you might want to adjust parameters, or you might want to further process the results. Many of the tools you will build will most likely rely on wrapper functions.

Here is a wrapper function I wrote for Get-History.

I wanted something that would give me history but weed out the duplicates. However, I want my function to be as complete as possible with help and all of the same parameters as Get-History. But I don’t want to have to manually create all of that content. Instead, I make PowerShell do the work for me.

My Solution

I created a function I call Copy-Command, which grew out of earlier efforts to streamline the creation of proxy functions. You can use the ProxyCommand class to get other types of information from a command, where you can even grab individual elements if you wish.

Using the ProxyCommand class to grab individual elements in Windows PowerShell. (Image Credit: Jeff Hicks)
Using the ProxyCommand class to grab individual elements in Windows PowerShell. (Image Credit: Jeff Hicks)

This means that I can construct a new command on the fly, including copying the original help as a comment block.

Constructing a new command. (Image Credit: Jeff Hicks)
Constructing a new command. (Image Credit: Jeff Hicks)

I created Copy-Command, so I could easily create a wrapper command or a proxy function.

Another reason I wrote this is because I was having an issue creating proxy commands of the Active Directory cmdlets like Get-ADUser. It turns out that in those cmdlets many of the parameters are defined as dynamic parameters. These type of parameters are not detected when generating a proxy command. My solution was to retrieve the dynamic parameters from Get-Command and add them to my $cmd object, which would eventually be copied to my new command.

The function’s default behavior is to copy and paste the help as a comment, which you can then edit. If you prefer, you can tell the function to use the forwarded help links. The whole purpose of this command is to duplicate an existing command with minimal effort. The function works best in the ISE as your new command will automatically be opened in a new tab.

Our function in the PowerShell ISE. (Image Credit: Jeff Hicks)
Our function in the PowerShell ISE. (Image Credit: Jeff Hicks)

All I have to do now is refine the function to do what I need. All of the grunt work of typing help, parameters, and scriptblocks is automatically done for me.

I hope you’ll let me know what you think about this. If I’m doing something you don’t quite understand, please post a question in the comments. I will be using this in a number of upcoming articles to create new commands to solve a few problems. I hope you’ll stay tuned.

Related Topics:

  • PowerShell

    Don't have a login but want to join the conversation? Sign up for a Petri Account