1

I am trying to simplify a script I wrote by creating some functions, however, I can't seem to get them to work the way I want.

An example function will accept 2 or more parameters but only return 1 value. When I do this, it is returning every value, which in this case are all the parameters (2 in this case) which are passed to the function.

I understand from some research that Powershell returns more than is explicitly called on, which is a little confusing, so I have tried some suggestions about assigning those other values to $null but to no avail.

My function and its result when run looks like the following:

function postReq($path, $payload) {
    Write-Host $path
}

postReq($url, $params)

> [path value (is correct)] [$payload (shouldn't be included here)]
mklement0
  • 382,024
  • 64
  • 607
  • 775
vin_Bin87
  • 318
  • 8
  • 18
  • @mklement0 I don't think this should be considered a duplicate. While the question elicits similar answers to "how do I pass multiple parameters into a function in Powershell", that's not what the user is asking, and this honestly is how many new users to Powershell perceive how functions calls work (especially because it's how method calls work). – codewario Dec 03 '19 at 03:55
  • @BendertheGreatest, given what answer the OP accepted, it looks like the confusion was exactly the same as in the linked post: mistakenly expecting `postReq($url, $params)` to pass _two distinct_ arguments, rather than what is actually passed: a single, array-valued argument (both of whose elements are printed to the console with `Write-Host`, space-separated). – mklement0 Dec 03 '19 at 04:02

2 Answers2

2

Your syntax in how you are calling a function is not correct semantically. You write:

postReq($url, $params)

But that is not the correct syntax in PowerShell. (It's valid syntactically, but not semantically.) In PowerShell, functions are called without ( and ) and without ,, as in:

postReq $url $params

When you use ( ), you are passing a single argument to your function.

Bill_Stewart
  • 22,916
  • 4
  • 51
  • 62
  • That was absolutely it. Thanks so much. I am coming from Ruby and Javascript so that just seems so foreign to do it like that. Thanks for clearing that up! – vin_Bin87 Dec 02 '19 at 19:18
1

Solution

You're not invoking the function how you think you are. PowerShell functions are called without parentheses and the argument delimiter is whitespace, not a comma. Your function call should look like this:

postReq $url $params

What is wrong with using traditional C#-like syntax?

Calling it like you are above as postReq($url, $params) has two undesired consequences here:

  1. The parentheses indicate a sub-expression, the code in the parentheses will run first before the outer code and be treated as a single argument. If you are familiar with solving algebraic equations, the order of operations is the same as in PEMDAS - parentheses first.

  2. Whitespace (), and NOT commas (,) are the argument delimiter to Powershell functions. However, the commas do mean something in Powershell syntax - they signify a collection. [1, 2, 3, 4] is functionally the same as 1, 2, 3, 4 in Powershell. In your case above, you are rolling both parameters into a single array argument of [$url, $params], which the stream-writing cmdlets will do an array join with a , as the delimiter in the rendered string.

But what about object instance and static methods?

This can be confusing to some because object instance and class (RE: static) methods ARE called with the traditional C#-like syntax, where you DO need the parentheses to indicate parameter values, and commas are the delimiter. For example:

([DateTime]::Now).ToString()

returns the current local time, and runs the ToString() method on the returned DateTime object. If you used one of its overloads as shown below, you would separate each argument with a , and regardless of whether you need to pass in arguments or not, you still must specify the outer parentheses:

OverloadDefinitions
-------------------
string ToString()
string ToString(string format)
string ToString(System.IFormatProvider provider)
string ToString(string format, System.IFormatProvider provider)
string IFormattable.ToString(string format, System.IFormatProvider formatProvider)
string IConvertible.ToString(System.IFormatProvider provider)

If you were to omit the parentheses on the empty parameter overload above, you would get the preceding output showing the overload definitions, unlike the behavior when calling functions with no argument.

It's a little odd, but I remember that in any programming language, functions and methods are similar, but distinct, and it's no different in Powershell other than functions and methods are less alike than they are in other languages. I find a good rule of thumb for this is:

Invoke methods with C# syntax and functions with shell syntax.

mklement0
  • 382,024
  • 64
  • 607
  • 775
codewario
  • 19,553
  • 20
  • 90
  • 159