Prof. Powershell

PowerShell Name Duplicates: When Commands Collide

Jeffrey Hicks shows you what to do when you have two commands with the same name.

As PowerShell continues to spread in the enterprise and more vendors (and the PowerShell community) begin offering cmdlet solutions, it is only a matter of time before you begin running into naming collisions. You might have a cmdlet called Get-CoolStuff from one vendor but someone else also creates a command called Get-CoolStuff. In PowerShell 3 when you run Get-CoolStuff, which command is going to run? Is it the one you want?

From my own experience I ran into this with virtual machine cmdlets. For the longest time I used PowerCLI to manage my VMware infrastructure. One cmdlet used frequently is Get-VM. But then I also started using the new Hyper-V module on Windows 8 and wouldn't you know it too has a command called Get-VM.

Back in the earlier days of PowerShell, some vendors realized there might be naming collisions so they prefixed their commands. The Quest Active Directory cmdlets are a great example. So all of their cmdlets have a QAD prefix to the noun like Get-QADUser. This prevents any conflicts with the Microsoft Get-ADUser. But not everybody does that. Using my Get-VM scenario here's the trouble.

I've loaded both the Hyper-V module and the VMware snapin. But PowerShell, only shows one command.

PS C:\> get-command get-vm

CommandType     Name                                     ModuleName
-----------     ----                                     ----------
Cmdlet          Get-VM                                   VMware.VimAutomation.Core

If I look at help for Get-VM or try to run it, this is the command that will run. But I can force Get-Command to show me all matching commands with –all.

PS C:\> get-command get-vm -all

CommandType     Name                                    ModuleName
-----------     ----                                    ----------
Cmdlet          Get-VM                                  hyper-v
Cmdlet          Get-VM                                  VMware.VimAutomation.Core

One way to run the Hyper-V version is to include the module name as a path. But this can get cumbersome to type.

PS C:\> hyper-v\get-vm | where {$_.state -eq 'running'} | hyper-v\stop-vm –asjob

Another option is to include your own prefix when importing the module.

PS C:\> import-module hyper-v -Prefix MY

Now I can more easily distinguish the commands.

PS C:\> get-command get-*vm

CommandType     Name                                       ModuleName
-----------     ----                                       ----------
Cmdlet          Get-MYVM                                   hyper-v
Cmdlet          Get-VM                                     VMware.VimAutomation.Core
PS C:\> (get-myvm).count
21

I should point out that ultimately since the Hyper-V module only runs in PowerShell 2, my solutions was to run the PowerCLI snapin in a separate PowerShell 2 session and keep virtualization management distinct.

Another option for avoiding naming collisions, but it only works with modules, is to skip importing and commands with conflicting names. For example, the PowerShell Community Extensions have a few commands like Get-Help and Unblock-File which conflict with Microsoft versions. Here's what a clean session looks like:

PS C:\> get-command get-help,unblock-file

CommandType     Name                                  ModuleName
-----------     ----                                  ----------
Cmdlet          Get-Help                              Microsoft.PowerShell.Core
Cmdlet          Unblock-File                          Microsoft.PowerShell.Utility

Then here's what happens after I import the community extensions.

PS C:\> import-module pscx
PS C:\> get-command get-help,unblock-file

CommandType     Name                                               ModuleName
-----------     ----                                               ----------
Function        Get-Help                                           pscx
Cmdlet          Unblock-File                                       pscx

I've "overwritten" the Microsoft commands. Instead I can do this:

PS C:\> import-module pscx -NoClobber

Now I still have the original Microsoft commands.

PS C:\> get-command get-help,unblock-file

CommandType     Name                                  ModuleName
-----------     ----                                  ----------
Cmdlet          Get-Help                              Microsoft.PowerShell.Core
Cmdlet          Unblock-File                          Microsoft.PowerShell.Utility

So if you run into conflicts there are several ways you can remedy the situation depending on your needs. And if you are developing your own advanced functions and modules I encourage you to plan ahead and give your commands unique, yet meaningful, names to will avoid this problem in the first place.

About the Author

Jeffery Hicks is an IT veteran with over 25 years of experience, much of it spent as an IT infrastructure consultant specializing in Microsoft server technologies with an emphasis in automation and efficiency. He is a multi-year recipient of the Microsoft MVP Award in Windows PowerShell. He works today as an independent author, trainer and consultant. Jeff has written for numerous online sites and print publications, is a contributing editor at Petri.com, and a frequent speaker at technology conferences and user groups.

comments powered by Disqus
Most   Popular