{"id":9781,"date":"2012-04-22T00:01:00","date_gmt":"2012-04-22T00:01:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2012\/04\/22\/the-problem-with-powershell-positional-parameters\/"},"modified":"2012-04-22T00:01:00","modified_gmt":"2012-04-22T00:01:00","slug":"the-problem-with-powershell-positional-parameters","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/the-problem-with-powershell-positional-parameters\/","title":{"rendered":"The Problem with PowerShell Positional Parameters"},"content":{"rendered":"<p><b>Summary<\/b>: In this blog, Microsoft Scripting Guy, Ed Wilson, talks about problems that can arise when using Windows PowerShell positional parameters.\nMicrosoft Scripting Guy, Ed Wilson, is here. Today is the final day of judging for the 2012 Scripting Games. The judges have made a magnificent effort these last few days to get the final scripts graded. The leaderboard has changed on a minute-by-minute basis for the last several days, and I know from twitter that many of you have been following the leaderboard more closely than University of Kentucky basketball fans followed the NCAA Final Four Tournament games.\nIn yesterday&rsquo;s blog, <a href=\"http:\/\/blogs.technet.comhttps:\/\/devblogs.microsoft.com\/scripting\/when-you-should-use-powershell-aliases\/\" target=\"_blank\">When You Should Use PowerShell Aliases<\/a>,<i> <\/i>I discussed the problems that indiscriminate alias usage creates.\nOne of the main problems with using Windows PowerShell aliases, even at the Windows PowerShell console, is that the code is much less readable. The same problem exists with positional parameters, parameter aliases, and partial parameters.<\/p>\n<h2>Understanding positional parameters<\/h2>\n<p>Positional parameters make Windows PowerShell commands shorter because you do not have to do as much typing, and some of the parameter names are rather long. But the problem is that unless you really know what a cmdlet does, and how it does it, you might not know what is actually going on. An example is the following command.<\/p>\n<p style=\"padding-left: 30px\">S C:&gt; copy c:1 c:3\nSo what does this command do? Well, it might copy the contents of the c:3 folder to the c:1 folder. Or it might copy the contents of the c:1 folder to the c:3 folder. For that matter, what is the copy command? The copy command is an alias for the Copy-Item cmdlet. Now, what is the first parameter? Is the parameter name source original, path, target, destination, or what? As a matter of fact, the first parameter is path. The second parameter is destination. To find this sort of information you need to use the <b>Get-Help<\/b> cmdlet with the <i>Full <\/i>switch. Each parameter entry includes information that states if the parameter is required, positional, or whatever. The following output displays the <i>Path <\/i>and the <i>Destination <\/i>parameter information.<\/p>\n<p style=\"padding-left: 30px\">-Path &lt;string[]&gt;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp; Specifies the path to the items to copy.<\/p>\n<p style=\"padding-left: 30px\">&nbsp;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp; Required?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; true<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp; Position?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp; Default value<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp; Accept pipeline input?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; true (ByValue, ByPropertyName)<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp; Accept wildcard characters?&nbsp; False<\/p>\n<p style=\"padding-left: 30px\">-Destination &lt;string&gt;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; Specifies the path to the location where the items are to be copied.<\/p>\n<p style=\"padding-left: 30px\">&nbsp;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; Required?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; false<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; Position?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; Default value<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; Accept pipeline input?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; true (ByPropertyName)<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; Accept wildcard characters?&nbsp; false<\/p>\n<h2>Understanding partial parameters<\/h2>\n<p>Another way of speeding up working with parameters is to use partial parameter names. For example, many cmdlets have a parameter named <i>ComputerName. <\/i>Now, this is a lot of typing. It is especially unfortunate because the <b>Get-WmiObject<\/b> cmdlet does not accept <i>ComputerName <\/i>positionally. Therefore, the following command fails.<\/p>\n<p style=\"padding-left: 30px\">PS C:&gt; gwmi win32_bios localhost<\/p>\n<p style=\"padding-left: 30px\">Get-WmiObject : Invalid query<\/p>\n<p style=\"padding-left: 30px\">At line:1 char:5<\/p>\n<p style=\"padding-left: 30px\">+ gwmi &lt;&lt;&lt;&lt;&nbsp; win32_bios localhost<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; + CategoryInfo&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : InvalidOperation: (:) [Get-WmiObject], ManagementExce<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp; ption<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; + FullyQualifiedErrorId : GetWMIManagementException,Microsoft.PowerShell.Comman<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp; ds.GetWmiObjectCommand\nThis does not mean that you are limited to typing the entire <i>ComputerName <\/i>parameter name each time you want to connect to a remote computer. You only need to type enough of the parameter so that it will distinguish it from other parameters that also start with the letter <b>C<\/b><i>.<\/i> One easy way to see what will work is to simply run the command and look at the error message. In the following output, you can see that there are three parameters on the <b>Get-WmiObject<\/b> cmdlet that begin with the letter <b>C<\/b>. The first is <i>Class, <\/i>the second one is <i>Credential, <\/i>and the last parameter is <i>ComputerName. <\/i><\/p>\n<p style=\"padding-left: 30px\">PS C:&gt; gwmi win32_bios -c localhost<\/p>\n<p style=\"padding-left: 30px\">Get-WmiObject : Parameter cannot be processed because the parameter name &#8216;c&#8217; is ambi<\/p>\n<p style=\"padding-left: 30px\">guous. Possible matches include: -Class -Credential -ComputerName.<\/p>\n<p style=\"padding-left: 30px\">At line:1 char:5<\/p>\n<p style=\"padding-left: 30px\">+ gwmi &lt;&lt;&lt;&lt;&nbsp; win32_bios -c localhost<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; + CategoryInfo&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : InvalidArgument: (:) [Get-WmiObject], ParameterBindin<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp; gException<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; + FullyQualifiedErrorId : AmbiguousParameter,Microsoft.PowerShell.Commands.GetW<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp; miObjectCommand\nBased on the error message, you can safely use <i>co <\/i>as the partial parameter for <i>ComputerName. <\/i>This technique is shown here.<\/p>\n<p style=\"padding-left: 30px\">PS C:&gt; gwmi win32_bios -co localhost<\/p>\n<p style=\"padding-left: 30px\">SMBIOSBIOSVersion : 8BET47WW (1.27 )<\/p>\n<p style=\"padding-left: 30px\">Manufacturer&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : LENOVO<\/p>\n<p style=\"padding-left: 30px\">Name&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : Default System BIOS<\/p>\n<p style=\"padding-left: 30px\">SerialNumber&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : R9FPY3P<\/p>\n<p style=\"padding-left: 30px\">Version&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : LENOVO &ndash; 1270\nConsider the following issues if you use partial parameter completion:<\/p>\n<ul>\n<li>Partial parameters are hard to read and to understand. For example, the <i>co <\/i>that was discovered to work with the <b>Get-WmiObject<\/b> cmdlet does not look like <i>ComputerName <\/i>at all.<\/li>\n<li>The same partial parameter does not always work in all cmdlets that may use that parameter. For example, there could be partial parameter conflicts in other cmdlets that would necessitate using <i>Com <\/i>or even <i>Comp<\/i>. Of course <i>Comp <\/i>begins to look a little more like <i>ComputerName, <\/i>and therefore, it begins to be more readable.<\/li>\n<li>Partial parameters are not guaranteed to work the same way&mdash;even for the same cmdlets between versions. Because new parameters get added to existing cmdlets between versions, it can destroy previous working partial parameter names. This is not a compatibility issue because we do not guarantee that partial parameter names will ever work.<\/li>\n<\/ul>\n<p>Because of the potential problems involved in working with partial parameters, it is general a good thing to avoid using them&mdash;even from the Windows PowerShell console line. Besides, when you have typed enough to make the partial parameter unique enough to use, a simple press of the Tab key completes the parameter anyway.<\/p>\n<h2>Understanding parameter aliases<\/h2>\n<p>Now we are back to the problem of aliases. However, there are a few caveats. The first is that in Windows PowerShell&nbsp;2.0 parameter aliases are not documented. The way most people learn about parameter aliases is by looking at the code from someone who has learned about the parameter alias from someone else. In my Hey, Scripting Guy! Blog, <a href=\"http:\/\/blogs.technet.com\/b\/heyscriptingguy\/archive\/2011\/01\/15\/weekend-scripter-discovering-powershell-cmdlet-parameter-aliases.aspx\" target=\"_blank\">Discovering PowerShell Cmdlet Parameter Aliases<\/a>, I wrote some code that discovers parameter aliases and then writes the resulting aliases to a text file. The script takes a long time to run because there are many cmdlets, and many of these cmdlets have as many as 20 parameter aliases documented on them. Tab expansion does not help here, and <b>Get-Help<\/b> does not help either. The only way to find all of the parameter aliases is to read my blog&mdash;so I guess that means they are documented now.\nThe good thing about parameter aliases is that they are consistent among all cmdlets that use a particular parameter. Therefore, there is a parameter alias for <i>ComputerName <\/i>that is defined as <i>cn. <\/i>Anywhere you have <i>ComputerName <\/i>in a cmdlet, you can use <i>cn <\/i>instead. The advantage is that it is just as short as the <i>co <\/i>that we discovered would work for <i>ComputerName, <\/i>but with the advantage that <i>cn <\/i>actually makes sense.<\/p>\n<h2>Best practices around parameters<\/h2>\n<p>In a script, you should always use complete parameter names because with full parameter names, you actually know what the code is doing and it is more readable. You should avoid partial parameter names, and positional parameters for the same reason. Using the <i>cn <\/i>parameter alias is one that can safely be utilized because it makes sense, and it will be everywhere that the parameter itself resides. Because it cannot be deleted or overwritten (like cmdlet aliases can), the question of reliability does not come up.\nWhen you are working interactively at the Windows PowerShell console, it is generally best to avoid positional parameters because they are very confusing, and it is easy to get them wrong. Is the target or the destination the first parameter? For simple cmdlets, such as <b>Get-Process <\/b>or <b>Get-Service <\/b>where the default parameter is <i>Name<\/i>, the positional use is fine, makes sense, and has little chance of error. The big problem with positional parameters comes into play where a cmdlet positionally accepts multiple parameters.\nWith partial parameters, the big problems are readability and the fact that they may not be consistent from version to version or even from cmdlet to cmdlet. Coupled with the fact that when you have a unique parameter, you can simply press the Tab key to avoid the problem altogether, partial parameters make little sense. If shortness of command is what you seek, you should find the parameter aliases and use them.\nI invite you to follow me on <a href=\"http:\/\/bit.ly\/scriptingguystwitter\" target=\"_blank\">Twitter<\/a> and <a href=\"http:\/\/bit.ly\/scriptingguysfacebook\" target=\"_blank\">Facebook<\/a>. If you have any questions, send email to me at <a href=\"http:\/\/blogs.technet.commailto:scripter@microsoft.com\" target=\"_blank\">scripter@microsoft.com<\/a>, or post your questions on the <a href=\"http:\/\/bit.ly\/scriptingforum\" target=\"_blank\">Official Scripting Guys Forum<\/a>. See you tomorrow. Until then, peace.<\/p>\n<p><b>Ed Wilson, Microsoft Scripting Guy<\/b>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Summary: In this blog, Microsoft Scripting Guy, Ed Wilson, talks about problems that can arise when using Windows PowerShell positional parameters. Microsoft Scripting Guy, Ed Wilson, is here. Today is the final day of judging for the 2012 Scripting Games. The judges have made a magnificent effort these last few days to get the final [&hellip;]<\/p>\n","protected":false},"author":596,"featured_media":87096,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[331,3,4,61,45],"class_list":["post-9781","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-best-practices","tag-scripting-guy","tag-scripting-techniques","tag-weekend-scripter","tag-windows-powershell"],"acf":[],"blog_post_summary":"<p>Summary: In this blog, Microsoft Scripting Guy, Ed Wilson, talks about problems that can arise when using Windows PowerShell positional parameters. Microsoft Scripting Guy, Ed Wilson, is here. Today is the final day of judging for the 2012 Scripting Games. The judges have made a magnificent effort these last few days to get the final [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/9781","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/users\/596"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/comments?post=9781"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/9781\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media\/87096"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media?parent=9781"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=9781"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=9781"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}