{"id":87853,"date":"2020-08-18T20:07:37","date_gmt":"2020-08-18T20:07:37","guid":{"rendered":"https:\/\/www.red-gate.com\/simple-talk\/?p=87853"},"modified":"2023-10-09T13:29:50","modified_gmt":"2023-10-09T13:29:50","slug":"how-to-use-parameters-in-powershell-part-ii","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/sysadmin\/powershell\/how-to-use-parameters-in-powershell-part-ii\/","title":{"rendered":"How to Use Parameters in PowerShell Part II"},"content":{"rendered":"<p><strong>The series so far:<\/strong><\/p>\n<ol>\n<li><a href=\"https:\/\/www.red-gate.com\/simple-talk\/sysadmin\/powershell\/how-to-use-parameters-in-powershell\/\">How to Use Parameters in PowerShell Part I<\/a><\/li>\n<li><a href=\"https:\/\/www.red-gate.com\/simple-talk\/sysadmin\/powershell\/how-to-use-parameters-in-powershell-part-ii\/\">How to User Parameters in PowerShell Part II<\/a><\/li>\n<\/ol>\n\n<p>In a <a href=\"https:\/\/www.red-gate.com\/simple-talk\/sysadmin\/powershell\/how-to-use-parameters-in-powershell\/\">previous article<\/a>, I wrote about how to use parameters within your PowerShell scripts. It turns out that it was the most popular article I\u2019ve written so far for Simple-Talk. I appreciate all the votes and page views. However, as I was writing my article on <a href=\"https:\/\/www.red-gate.com\/simple-talk\/sysadmin\/powershell\/how-to-add-help-to-powershell-scripts\/\">Adding Help to Your PowerShell Scripts<\/a>, I found myself diving deeper into how you can use parameters. I realized I had barely scratched the topic of parameters and PowerShell, hence this article.<\/p>\n<p>A bit of this will be a recap from that article on help, but I will then expand upon parameter usage and passing in PowerShell. Even then, I suspect I will not cover every possible detail. PowerShell is a deep and rich scripting language that I\u2019m still learning more about every day.<\/p>\n<h2>Boolean vs Switch<\/h2>\n<p>In my previous article on Adding Help, I gave an example of both <code>Boolean<\/code> and <code>switch<\/code>. I will very quickly recap them here.<\/p>\n<p>This script uses a <code>Boolean<\/code> parameter.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">param([boolean]\u00a0$help\u00a0)\r\n#\r\n#\u00a0Author:\u00a0Greg\u00a0D.\u00a0Moore\r\n#\u00a0Date:\u00a02020-02-18\r\n#\u00a0Version:\u00a01.0\r\n#\u00a0Show\u00a0boolean\u00a0help\r\n#\r\nif\u00a0($help\u00a0-eq\u00a0$true)\r\n{\r\n\u00a0\u00a0\u00a0\u00a0write-host\u00a0\"This\u00a0is\u00a0help\u00a0for\u00a0this\u00a0program.\u00a0It\u00a0does\u00a0nothing.\u00a0Hope\u00a0that\u00a0helps.\"\r\n}\r\nelse\r\n{\r\n\u00a0\u00a0\u00a0\u00a0write-host\u00a0\"Do\u00a0nothing.\"\r\n}<\/pre>\n<p>This script uses switch which you can compare to the previous script.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">param([switch]\u00a0$help\u00a0)\r\n#\r\n#\u00a0Author:\u00a0Greg\u00a0D.\u00a0Moore\r\n#\u00a0Date:\u00a02020-02-18\r\n#\u00a0Version:\u00a01.0\r\n#\u00a0Show\u00a0switch\u00a0help\r\n#\r\nif\u00a0($help)\r\n{\r\n\u00a0\u00a0\u00a0\u00a0write-host\u00a0\"This\u00a0is\u00a0help\u00a0for\u00a0this\u00a0program.\u00a0It\u00a0does\u00a0nothing.\u00a0Hope\u00a0that\u00a0helps.\"\r\n}\r\nelse\r\n{\r\n\u00a0\u00a0\u00a0\u00a0write-host\u00a0\"Do\u00a0nothing.\"\r\n}<\/pre>\n<p>They both act in very similar fashions except you cannot assign an actual value to a <code>switch<\/code> datatype. If it\u2019s not included on the command line when calling the script, it\u2019s treated as <em>false<\/em>. If it\u2019s included on the command line, regardless of what you try to assign to it, it will be treated as <em>true<\/em>.<\/p>\n<p>If you create the above script and save it as <em>Switch_help.ps1<\/em> or download it from <a href=\"https:\/\/github.com\/stridergdm\/SimpleTalk_PowerShell-Scripts\/tree\/master\/More%20Parameters%20and%20Help\">here<\/a>, you can play with trying to pass different values to the <code>\u2013help<\/code> parameter. You will find they all give the same results.<\/p>\n<h2>Parameter Definitions<\/h2>\n<p>With that out of the way, I want to recap how to define a parameter and build upon it. Start with the script below (note all scripts are available on <a href=\"https:\/\/github.com\/stridergdm\/SimpleTalk_PowerShell-Scripts\/tree\/master\/Parameters%20Part%20II\">Github<\/a>.).<\/p>\n<p>Save it as <em>simplest.ps1<\/em>.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">param($foo)\r\n    Write-host $foo <\/pre>\n<p>Run it like this:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">.\\simplest.ps1 -foo BAR <\/pre>\n<p>You should get:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"605\" height=\"19\" class=\"wp-image-87854\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2020\/08\/word-image-16.png\" \/><\/p>\n<p>This is just as you\u2019d expect and is about the simplest script you can write with a parameter.<\/p>\n<p>Now save the following script as <em>simplest_bad.ps1<\/em>.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">write-host \"before parameter!\"\r\nparam($foo)\r\n    Write-host $foo <\/pre>\n<p>If you save this and try to run it, you should get the following error:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"836\" height=\"155\" class=\"wp-image-87855\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2020\/08\/word-image-17.png\" \/><\/p>\n<p>This example shows that the param keyword has to be the first line in a script. (Note when discussing functions, this changes a bit. I most likely will cover this in a future article).<\/p>\n<p>In my first article on parameters and in the examples above with <code>$help<\/code>, I explicitly defined the datatype for a parameter. Generally, I prefer doing so for parameters. Below is a short script to illustrate this:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">param($foo)\r\n    Write-host $foo.GetType().Name <\/pre>\n<p>Save that as <em>simplest_gettype.ps1<\/em> and then run it with various data types.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"715\" height=\"342\" class=\"wp-image-87856\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2020\/08\/word-image-18.png\" \/><\/p>\n<p>For the most part, the datatype makes make sense. PowerShell is generally pretty good at guessing the data type. However, it\u2019s important to notice that <code>$true<\/code> is considered as a <code>Boolean<\/code> and <em>true<\/em> is considered a string. If you absolutely need to check if the user entered a <code>$true<\/code> or <code>$false<\/code> value, I highly recommend the use of <code>Boolean<\/code> (or <code>switch<\/code>) as shown at the start of this article.<\/p>\n<p>As the above example shows, you can pass an object to a script. This can be done a couple of ways that may be useful.<\/p>\n<p>Save the following script as <em>Passing_Object.ps1<\/em>.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">param ($foo=@{firstname='';lastname=''})\r\nwrite-host $foo.firstname\r\nwrite-host $foo.lastname<\/pre>\n<p>&nbsp;<\/p>\n<p>Run as follows:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"813\" height=\"58\" class=\"wp-image-87857\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2020\/08\/word-image-19.png\" \/><\/p>\n<p>You can also define an object first and pass that. For example, if you define an object first and pass that to your script, it will work also:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"805\" height=\"108\" class=\"wp-image-87858\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2020\/08\/word-image-20.png\" \/><\/p>\n<p>As seen in my article on Help, besides defining the datatype for a parameter, you can also force a parameter to be mandatory. You can also provide default values for a parameter.<\/p>\n<p>Save the following script as <em>Default_Example_1.ps1<\/em>:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">param([parameter(mandatory)] [string] $dbserver )\r\nwrite-host \"You picked $dbserver!\" <\/pre>\n<p>If you run this in the PowerShell ISE, you will see:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"613\" height=\"68\" class=\"wp-image-87859\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2020\/08\/word-image-21.png\" \/><\/p>\n<p>In my help article, I had a slight variation on this. You may find that not only do you want to make a particular parameter mandatory, but you only want to allow specific values. Save the following script as <em>Default_Example_2.ps1<\/em>:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">param([parameter(mandatory)] [validateset(\"ProdDB_Server\",\"DevDB_Server\")] [string] $dbserver )\r\nwrite-host \"You picked $dbserver!\" <\/pre>\n<p>Now when you try to run it in the PowerShell ISE, you should see:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"716\" height=\"72\" class=\"wp-image-87860\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2020\/08\/word-image-22.png\" \/><\/p>\n<p>Note that in PowerShell ISE, the valid values are displayed. This is not necessarily true of all editors. If you enter an invalid value you will see something like:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1316\" height=\"131\" class=\"wp-image-87861\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2020\/08\/word-image-23.png\" \/><\/p>\n<p>It is possible to have multiple and different validation sets. I explore that a bit more in the <a href=\"https:\/\/www.red-gate.com\/simple-talk\/sysadmin\/powershell\/how-to-add-help-to-powershell-scripts\/\">help article<\/a>.<\/p>\n<h3>ValidateSet Caveat<\/h3>\n<p>Enter the script below and save it as <em>ValidateSet_Caveat_1.ps1<\/em>:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">param([parameter(mandatory)][validateset('Good','Bad')] $status) \r\nWrite-host \"Status is $status\"\r\n$status = 'Ugly'\r\nWrite-host \"Status is still $status\"\r\n$status = 'Good'\r\nWrite-host \"Status is now $status\" <\/pre>\n<p>Run it and select <em>Bad<\/em>:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"502\" height=\"81\" class=\"wp-image-87862\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2020\/08\/word-image-24.png\" \/><\/p>\n<p>You will get:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"957\" height=\"197\" class=\"wp-image-87863\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2020\/08\/word-image-25.png\" \/><\/p>\n<p>The error message explains the issue clearly.<\/p>\n<p>Save the following script as <em>ValidateSet_Caveat_2.ps1<\/em>:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">param([validateset('Lorca','Georgiou','Pike','Kirk')] $Captain, $color)\r\n[validateSet('red','yellow')] $alert = 'red'\r\n[validateSet('good','bad')] $status\r\nWrite-host \"Captain $Captain has declared $alert alert and our status is $status!\"\r\n$alert = $color\r\n$status = 'REALLY BAD'\r\nWrite-host \"Now Captain $Captain has declared $alert alert and our status is $status!\" <\/pre>\n<p>Note the <code>$Captain<\/code> parameter is no longer mandatory. This script should show several interesting details about the use of <code>ValidateSet<\/code>.<\/p>\n<p>Run the following first:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">.\\ValidateSet_Caveat_2.ps1 -color yellow <\/pre>\n<p>Your result will be:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"620\" height=\"39\" class=\"wp-image-87864\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2020\/08\/word-image-26.png\" \/><\/p>\n<p>Note that while you provided options for the set, since it wasn\u2019t mandatory, you weren\u2019t prompted to enter a Captain\u2019s name. In addition, even though you did define a <code>ValidateSet<\/code> for <code>$status<\/code>, it wasn\u2019t used. As a result, in the first message, no <code>$status<\/code> is shown, and in the second message, a status is shown that wasn\u2019t part of the <code>ValidateSet<\/code>.<\/p>\n<p>Now if you decide you want to be the Captain of a starship, you might try something like:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">.\\ValidateSet_Caveat_2.ps1 -color yellow -Captain Moore <\/pre>\n<p>That only results in:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"953\" height=\"162\" class=\"wp-image-87865\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2020\/08\/word-image-27.png\" \/><\/p>\n<p>This result makes sense because you\u2019re trying to assign a value to <code>$Captain<\/code> at the same time it\u2019s declared, but you\u2019re also telling PowerShell what the valid values are and your name isn\u2019t one of them.<\/p>\n<p>Now try<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">.\\ValidateSet_Caveat_2.ps1 -color black -Captain Pike <\/pre>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"948\" height=\"148\" class=\"wp-image-87866\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2020\/08\/word-image-28.png\" \/><\/p>\n<p>Evidently, all knowledge of the Spore Drive has been declared top secret, and you can\u2019t have a black alert. But you can set a standard alert color.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">  .\\ValidateSet_Caveat_2.ps1 -color yellow -Captain Pike <\/pre>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"686\" height=\"39\" class=\"wp-image-87867\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2020\/08\/word-image-29.png\" \/><\/p>\n<p>When using <code>ValidateSet<\/code>, keep in mind that it only is effective if you assign a valid value at the time you declare the variable. Otherwise, any value can be used (as shown by the <code>$status<\/code> in the above script).<\/p>\n<p>The above examples are useful and applicable if you are running your scripts and typing in the parameters by hand, but, what if you want to run a script and pass it data from another source.<\/p>\n<h2>Pipelined Parameters<\/h2>\n<p>Most PowerShell cmdlets let you use the pipe | symbol to pass data. For example, run the following script:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">Get-Service | ogv <\/pre>\n<p>You should see a window similar to the following show up:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"651\" height=\"515\" class=\"wp-image-87868\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2020\/08\/word-image-30.png\" \/><\/p>\n<p>You might be tempted to do something like:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">\"test\" | .\\simplest.ps1 <\/pre>\n<p>You will find that nothing happens, but this is simple to fix.<\/p>\n<p>Save the following script as <em>Piped_Variable.ps1<\/em>:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">param([parameter(ValueFromPipeline)] $piped1)\r\n    Write-host $piped1 <\/pre>\n<p>First, you can run it as follows:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"542\" height=\"45\" class=\"wp-image-87869\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2020\/08\/word-image-31.png\" \/><\/p>\n<p>It works as you\u2019d expect.<\/p>\n<p>Now, try this:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"510\" height=\"39\" class=\"wp-image-87870\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2020\/08\/word-image-32.png\" \/><\/p>\n<p>It also works as you\u2019d expect, but what if you want to pass in multiple values? You could try:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"564\" height=\"42\" class=\"wp-image-87871\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2020\/08\/word-image-33.png\" \/><\/p>\n<p>That didn\u2019t work as you might hope.<\/p>\n<p>Have no fear. PowerShell does have a way of handling this. At first, the solution will look more complicated than you might need, but I think you\u2019ll quickly agree that the solution is fairly useful.<\/p>\n<p>Save the following script as <em>Piped_Variable_2.ps1<\/em>:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">param([parameter(ValueFromPipeline)] $piped2)\r\nbegin  #Note the begin block is optional!\r\n{\r\n    Write-host \"Will only run once at the start!\"\r\n}\r\nProcess  #This is the part that does all the work\r\n{ \r\n    Write-host $piped2\r\n}\r\nend   #Note that the end block is also optional!\r\n{\r\n    Write-Host \"Will only run at the end\"\r\n} <\/pre>\n<p>Run it like this:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">\"foo\", \"bar\" | .\\Piped_Variable_2.ps1 <\/pre>\n<p>You will see the following:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"295\" height=\"73\" class=\"wp-image-87872\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2020\/08\/word-image-34.png\" \/><\/p>\n<p>This does exactly what you would expect and want: it runs the begin block once at the start, and the end block once at the end, but the Process block runs multiple times as expected. Below is a more useful example:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">param([parameter(ValueFromPipeline)] $addends)\r\nbegin  #Note the begin block is optional!\r\n{\r\n    $sum=0\r\n}\r\nProcess  #This is the part that does all the work\r\n{ \r\n    $sum+=$addends\r\n}\r\nend   #Note that the end block is also optional!\r\n{\r\n    Write-Host \"The sum of your numbers is $sum\"\r\n} <\/pre>\n<p>Save the above script as <em>Piped_Addition.ps1<\/em>and run it as:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">1, 5, 67 | .\\Piped_Addition.ps1 <\/pre>\n<p>You should get the following as a result:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"263\" height=\"23\" class=\"wp-image-87873\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2020\/08\/word-image-35.png\" \/><\/p>\n<p>You may be curious as to what happens if you try to pass in variables in the standard manner, i.e. after the cmdlet:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">.\\Piped_Addition.ps1 -addends 4 <\/pre>\n<p>This will work as expected:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"266\" height=\"20\" class=\"wp-image-87874\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2020\/08\/word-image-36.png\" \/><\/p>\n<p>However, you may be a bit surprised when you run this:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">.\\Piped_Addition.ps1 -addends 4,5 <\/pre>\n<p>It doesn\u2019t work.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"883\" height=\"105\" class=\"wp-image-87875\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2020\/08\/word-image-37.png\" \/><\/p>\n<p>When you pass in parameters to that function, PowerShell treats the 4,5 as an object as the error suggests.<\/p>\n<p>You could write the above piped addition program as:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">param( $addends)\r\n$sum=0\r\nforeach ($addend in $addends)\r\n{\r\n    $sum+=$addend\r\n}\r\nWrite-Host \"The final value is $sum\" <\/pre>\n<p>Save it as <em>Nonpiped_addition.ps1<\/em> and then run it as:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">.\\Nonpiped_addition.ps1 4,5 <\/pre>\n<p>You will get:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"215\" height=\"29\" class=\"wp-image-87876\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2020\/08\/word-image-38.png\" \/><\/p>\n<p>What if you want to be able to handle the user doing either? Your first attempt will probably look something like the following:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">param([parameter(ValueFromPipeline)] $addends)\r\nbegin  #Note the begin block is optional!\r\n{\r\n    $sum=0\r\n    if ($addends.count -gt 0)\r\n    {\r\n write-host \"Values are not piped!\" \r\n        $piped = $false\r\n    }\r\n    else\r\n    {\r\n        $piped = $true\r\n        Write-Host \"Values are piped!\"\r\n    }\r\n}\r\nProcess  #This is the part that does all the work\r\n{ \r\n    if ($piped)\r\n        {\r\n            $sum+=$addends\r\n        }\r\n    else\r\n        {\r\n            foreach ($addend in $addends)\r\n            {\r\n                $sum+=$addend\r\n            }\r\n        }\r\n}\r\nend   #Note that the end block is also optional!\r\n{\r\n    Write-Host \"The sum of your numbers is $sum\"\r\n} <\/pre>\n<p>Save it as <em>Piped_Addition_2.ps1<\/em> and run it like this:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">2,3 | .\\Piped_Addition_2.ps1 <\/pre>\n<p>You will get:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"265\" height=\"35\" class=\"wp-image-87877\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2020\/08\/word-image-39.png\" \/><\/p>\n<p>Supply the parameters like this:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">.\\Piped_Addition_2.ps1 4,3 <\/pre>\n<p>You will get:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"277\" height=\"41\" class=\"wp-image-87878\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2020\/08\/word-image-40.png\" \/><\/p>\n<p>If you try to send the parameters both ways:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">  4,4 | .\\Piped_Addition_2.ps1 4,3 <\/pre>\n<p>This does not work. You can\u2019t tell PowerShell to accept a parameter as both piped AND non-piped.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1726\" height=\"253\" class=\"wp-image-87879\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2020\/08\/word-image-41.png\" \/><\/p>\n<p>However, one of the things that I continue to find amazing about PowerShell is that the authors gave a lot of thought about how as a programmer I might want to do things AND to keep things simple. You might already be thinking that could be a simpler way to do the above and there is. In fact, an earlier example came close to solving the problem.<\/p>\n<p>Save the following script as <em>Piped_Addition_3.ps1.<\/em><\/p>\n<pre class=\"lang:ps theme:powershell-ise\">param([parameter(ValueFromPipeline)] $addends)\r\nProcess \r\n{ \r\n    \r\n    foreach ($addend in $addends)\r\n    {\r\n        $sum+=$addend\r\n    }\r\n    Write-Host \"In Process block: Total = $sum\"\r\n} <\/pre>\n<p>Run it with the following input:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">3,5,4 | .\\Piped_Addition_3.ps1 <\/pre>\n<p>You will get the following results:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"267\" height=\"60\" class=\"wp-image-87880\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2020\/08\/word-image-42.png\" \/><\/p>\n<p>This is what you would expect from the original piped addition example, but what happens if you run the following?<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">.\\Piped_Addition_3.ps1 -addends 4,8,1 <\/pre>\n<p>You will get:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"268\" height=\"19\" class=\"wp-image-87881\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2020\/08\/word-image-43.png\" \/><\/p>\n<p>Note that since the <code>Write-Host<\/code> is outside of the foreach loop, you only see it once.<\/p>\n<p>It\u2019s worth taking time to understand what exactly is happening here.<\/p>\n<p>When you send piped input to a script (or a function), the <code>Process<\/code> block gets called for each individual value passed to it. This means <code>$addends<\/code> consists of a single value in the foreach loop. In the first example, <code>Process<\/code> gets called three times because there are three separate values piped in: 3,5, and 4.<\/p>\n<p>When passing the parameters by name, you are actually passing in an object of type <code>System.Array<\/code>, and <code>Process<\/code> gets called just once (because there\u2019s only one <code>System.Array<\/code> being passed to it). However, the <code>foreach<\/code> gets called three times because the <code>System.Array<\/code> consists of three values: 4,8, and 1.<\/p>\n<p>This becomes obvious if you add one line to the above script and resave it as <em>Piped_Addition_4.ps1<\/em> and run it:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">param([parameter(ValueFromPipeline)] $addends)\r\nProcess \r\n{ \r\n    $addends.gettype() # Let's reveal the datatype here!\r\n    foreach ($addend in $addends)\r\n    {\r\n        $sum+=$addend\r\n    }\r\n    Write-Host \"In Process block: Total = $sum\"\r\n}<\/pre>\n<p>&nbsp;<\/p>\n<p>While <em>Piped_Addition_2.ps1<\/em> may seem like the obvious way to go, once you realize how the parameters are being passed, you should realize why <em>Piped_Addition_3.ps1<\/em> works and is far simpler to write. You will also notice for simplicity\u2019s sake, I eliminated the <code>begin<\/code> and <code>end<\/code> blocks since they weren\u2019t necessary.<\/p>\n<h3>Multiple Piped Parameters<\/h3>\n<p>The above example is useful if you want to pass in a variable number of parameters for the same purpose; for example, you want to pipe in two different parameters.<\/p>\n<p>Your first attempt might look like this:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">param([parameter(ValueFromPipeline)] [string] $name, [parameter(ValueFromPipeline)] [string] $Provider) \r\nprocess\r\n{\r\n    Write-Host \"The name is: $name and provider is $Provider\"\r\n} <\/pre>\n<p>Save this as <em>Piped_ByName_1.ps1<\/em>and run it as:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">\"bob\", \"ted\" | .\\Piped_ByName_1.ps1 <\/pre>\n<p>You\u2019ll get:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"338\" height=\"40\" class=\"wp-image-87882\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2020\/08\/word-image-44.png\" \/><\/p>\n<p>Which makes sense as this is the behavior you saw with the named addition examples above. It passes each value into the <code>Process<\/code> block, and even though you asked for two values, it only read one from the pipeline at a time.<\/p>\n<p>You might try:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">  \"bob,mary\", \"ted\" | .\\Piped_ByName_1.ps1 <\/pre>\n<p>But that\u2019s no better:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"428\" height=\"39\" class=\"wp-image-87883\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2020\/08\/word-image-45.png\" \/><\/p>\n<p>It might dawn on you to try to pass in an object:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">  @{name='Greg';provider='YES'} | .\\Piped_ByName_1.ps1 <\/pre>\n<p>But that\u2019s no better either.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"790\" height=\"21\" class=\"wp-image-87884\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2020\/08\/word-image-46.png\" \/><\/p>\n<p>Before giving up entirely though, try the following:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">get-psdrive | .\\Piped_ByName_1.ps1 <\/pre>\n<p>Your results will look similar to:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"454\" height=\"288\" class=\"wp-image-87885\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2020\/08\/word-image-47.png\" \/><\/p>\n<p>The fact that you could pass in the output from a cmdlet and get something semi-useful hopefully piqued your curiosity. Before I give the complete solution, you should run this code:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">Get-PSDrive | get-member <\/pre>\n<p>You will see the following:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"941\" height=\"327\" class=\"wp-image-87886\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2020\/08\/word-image-48.png\" \/><\/p>\n<p>I\u2019ve highlighted two lines since that\u2019s what you want in your script.<\/p>\n<p>Save the following script as <em>Piped_ByName_2.ps1<\/em>:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">param([parameter(ValueFromPipeLineByPropertyName)] [string] $name, [parameter(ValueFromPipeLineByPropertyName)] [System.Management.Automation.ProviderInfo] $Provider) \r\nprocess\r\n{\r\nWrite-Host \"The PSDrive name is: $name and provider is $($Provider.Name)\" \r\n } <\/pre>\n<p>You will notice that now the parameters use <code>ValueFromPipeLineByPropertyName<\/code> instead of <code>ValuefromPipeline<\/code> and that the datatype for <code>$Provider<\/code> matches what <code>get-member<\/code> provided.<\/p>\n<p>Run this command:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">get-psdrive | .\\Piped_ByName_2.ps1 <\/pre>\n<p>You will get:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"748\" height=\"379\" class=\"wp-image-87887\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2020\/08\/word-image-49.png\" \/><\/p>\n<p>Note you can still call the script with named parameters:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">.\\Piped_ByName_2.ps1 -name C -Provider ($provider=(get-psdrive c)).Provider <\/pre>\n<p>That may seem like a trivial example since you\u2019re hardcoding the name of the drive, but you could also do something like this:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">$drive=\"env\"\r\n.\\Piped_ByName_2.ps1 -name $drive -Provider ($provider=(get-psdrive $drive)).Provider <\/pre>\n<p>You\u2019ll get this back:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"487\" height=\"21\" class=\"wp-image-87888\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2020\/08\/word-image-50.png\" \/><\/p>\n<p>In an earlier article on <a href=\"https:\/\/www.red-gate.com\/simple-talk\/sysadmin\/powershell\/how-to-add-help-to-powershell-scripts\/\">Help<\/a>, I showed how using the <code>\u2013Full<\/code> or <code>-Showwindow<\/code> parameter would provide a lot more detail. This is particularly useful if you\u2019re trying to write a script and want to know how cmdlets can handle parameters. It will allow you to see what the names of properties are of other cmdlets so that you can use them in the pipeline to pass to your own cmdlets. In theory, you can take the named property of one cmdlet and pass it to one that you write. Note, however, that this is not always accurate.<\/p>\n<p>Save the following script as <em>Piped_byName_3.ps1:<\/em><\/p>\n<pre class=\"lang:ps theme:powershell-ise\">param([parameter(ValueFromPipeLineByPropertyName)] [string] $name, [parameter(ValueFromPipeLineByPropertyName)] [System.Management.Automation.ProviderInfo] $Provider,\r\n[parameter(ValueFromPipeLineByPropertyName)] $free, [parameter(ValueFromPipeLineByPropertyName)] [System.Nullable[long]] $MaximumSize)\r\nprocess\r\n{\r\n    if ($free -ne $null)\r\n    {\r\n        Write-Host \"The PSDrive name is: $name and provider is $($Provider.Name) and free space is $([math]::round($($free\/1GB),2)) GB out of $MaximumSize\"\r\n    }\r\n    else\r\n    {\r\n        Write-Host \"The PSDrive name is: $name and provider is $($Provider.Name)\"\r\n    }\r\n} <\/pre>\n<p>Run this as:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">Get-PSDrive | .\\Piped_ByName_3.ps1 <\/pre>\n<p>You will get something like:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"872\" height=\"120\" class=\"wp-image-87889\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2020\/08\/word-image-51.png\" \/><\/p>\n<p>You\u2019ll note it doesn\u2019t show the maximum size.<\/p>\n<p>While the help suggests you should be able to get the maximum size of a drive from get-psdrive, the reality is you can\u2019t. To prove that run:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">Get-PSDrive C | format-list * <\/pre>\n<p>You\u2019ll see that it returns data for Used, Free, and more, but not for the Maximum size. I think the easiest solution would be to add up Used and Free space and display that. I leave that as an exercise for you to figure out.<\/p>\n<p>I do want to draw your attention to one detail in PowerShell that I absolutely love: the fact that you can divide by 1GB (or even 1MB and 1TB) <code>$($free\/1GB)<\/code> works just as you\u2019d expect!<\/p>\n<h2>Mixing Pipelined and Passed Parameters<\/h2>\n<p>As a final script, I will partially contradict something I said above. I noted you couldn\u2019t pass in the parameter both via pipeline and as a passed parameter. That\u2019s not quite true. You can\u2019t pass in the same parameter both ways, but you can combine the usage. Below is an example:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">param([parameter(ValueFromPipeLineByPropertyName)] [string] $name, [parameter(ValueFromPipeLineByPropertyName)] [System.Management.Automation.ProviderInfo] $Provider,\r\n[parameter(ValueFromPipeLineByPropertyName)] $free, $buymore)\r\nprocess\r\n{\r\n    if ($free -ne $null)\r\n    {\r\n        Write-Host \"The PSDrive name is: $name and provider is $($Provider.Name) and free space is $([math]::round($($free\/1GB),2)) GB\"\r\n        if ($([math]::round($($free\/1GB),2)) -lt $buymore)\r\n        {\r\n            write-host \"==================&gt; Time to think about upgrading! $name\" -ForegroundColor Red\r\n        }\r\n    }\r\n} <\/pre>\n<p>Save this as <em>Check-FreeDisk.ps1<\/em> and run it as before:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">Get-PSDrive | .\\Check-FreeDisk.ps1 <\/pre>\n<p>It will pretty much run as you might expect, though in this case, I\u2019ve changed it slightly only to show actual storage devices.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"710\" height=\"90\" class=\"wp-image-87890\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2020\/08\/word-image-52.png\" \/><\/p>\n<p>Now try running:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">Get-PSDrive | .\\Check-FreeDisk.ps1 -buymore 100 <\/pre>\n<p>You should see something like:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"712\" height=\"114\" class=\"wp-image-87891\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2020\/08\/word-image-53.png\" \/><\/p>\n<p>Try running the code without the named parameter:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">Get-PSDrive | .\\Check-FreeDisk.ps1 100 <\/pre>\n<p>You will get very different results from what you expect!<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"734\" height=\"88\" class=\"wp-image-87892\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2020\/08\/word-image-54.png\" \/><\/p>\n<p>Basically, PowerShell is capturing the first passed parameter and using that! Fortunately this is an easy fix, simply move the <code>$buymore<\/code> parameter to the start of the list of parameters.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">param( $buymore, [parameter(ValueFromPipeLineByPropertyName)] [string] $name, [parameter(ValueFromPipeLineByPropertyName)] [System.Management.Automation.ProviderInfo] $Provider,\r\n[parameter(ValueFromPipeLineByPropertyName)] $free)\r\nprocess\r\n{\r\n    if ($free -ne $null)\r\n    {\r\n        Write-Host \"The PSDrive name is: $name and provider is $($Provider.Name) and free space is $([math]::round($($free\/1GB),2)) GB\"\r\n        if ($([math]::round($($free\/1GB),2)) -lt $buymore)\r\n        {\r\n            write-host \"==================&gt; Time to think about upgrading! $name\" -ForegroundColor Red\r\n        }\r\n    }\r\n} <\/pre>\n<p>Save this as <em>Check-FreeDisk_2.ps1<\/em> and run it:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">Get-PSDrive | .\\Check-FreeDisk_2.ps1 <\/pre>\n<p>You\u2019ll get what you expect:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"710\" height=\"90\" class=\"wp-image-87893\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2020\/08\/word-image-55.png\" \/><\/p>\n<p>Try both of these examples:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">Get-PSDrive | .\\Check-FreeDisk_2.ps1 -buymore 100 \r\nGet-PSDrive | .\\Check-FreeDisk_2.ps1 100 <\/pre>\n<p>Each one will result in:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"712\" height=\"114\" class=\"wp-image-87894\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2020\/08\/word-image-56.png\" \/><\/p>\n<p>This is most likely what you want. In general, put parameters that you don\u2019t necessarily expect a user to specifically name first. Note this can obviously get more complicated when you want to allow the same parameter to be passed by the pipeline or as part of calling the cmdlet (as in the addition examples above).<\/p>\n<h2>Conclusion<\/h2>\n<p>When I started this article, I thought it would be a sequel and conclusion to my previous article. However, as I dove deeper, I realized I\u2019m still haven\u2019t touched upon everything there is to know about Parameters, including using parameters in functions, the use of cmdletbinding, how to work with some of the default parameters that PowerShell offers such as <code>\u2013verbose<\/code>, <code>-erroraction<\/code>, etc. I suspect there\u2019s at least one more article in the works.<\/p>\n<p>Thanks again for your support and hopefully this article will approach the popularity of the first.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>PowerShell is a basic skill any administrator working in Windows or Azure should know. After writing his first article about PowerShell parameters, Greg Moore realized that there is even more to talk about. This article covers using pipelined parameters and more. &hellip;<\/p>\n","protected":false},"author":319367,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[53,35],"tags":[],"coauthors":[61343],"class_list":["post-87853","post","type-post","status-publish","format-standard","hentry","category-featured","category-powershell"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/87853","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/319367"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=87853"}],"version-history":[{"count":4,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/87853\/revisions"}],"predecessor-version":[{"id":87901,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/87853\/revisions\/87901"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=87853"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=87853"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=87853"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=87853"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}