Powershell: Functions with switches that include arguments - function

So I'm trying to write a script that uses switch parameters and I also need arguments to go along with them. So for instance,
Function Foo ($X, $Z, [switch]$Y, $Yarg, [switch]$K, $Karg){
if($Y){
$Yup = $Yarg
}
if($K){
$Y = $Karg
}Else{$Y = 42}
$X + $Z / $Yup
}
Essentialy I want to ask if the switch is there, then if it's there I want it to use the $Yarg variable, currently when I do that I get an error saying the switch can only be a boolean value. Then the rest of the code fails. Any ideas?

My assumption is that Y and K are mutually exclusive parameter sets, and X and Z are common to both, and mandatory. If neither -Y nor -K are specified, the default will be -Y. I'm using the alternate parameter declaration syntax here for clarity:
function Foo(
[cmdletbinding(defaultparametersetname="setY")]
param(
[parameter(mandatory=$true)]
$X,
[parameter(mandatory=$true)]
$Y
[parameter(parametersetname="setY")]
[switch]$Y,
[parameter(parametersetname="setY", mandatory=$true)]
$YArg,
[parameter(parametersetname="setK")]
[switch]$K,
[parameter(parametersetname="setK", mandatory=$true)]
$KArg,
)
# do work
)
I'm hoping the syntax should be obvious.

So what I am intending on doing is making a function where you enter variables like so
foo x z -y yarg -k karg
Primarily wanting the -y yarg type variable entry.
For me to be able to do this I thought I needed to use a switch, but really I just needed unmandatory parameters.
function Foo(
[cmdletbinding(defaultparametersetname="setY")]
param(
[parameter(mandatory=$true, position=0)]
$X,
[parameter(mandatory=$true, position=1)]
$Z
[parameter(mandatory=$false)]
$Y,
[parameter(mandatory=$false)]
$K
)
# do work
)
That seemed easier, and it works!

Related

Can I make one parameter mandatory based on the _value_ of a different parameter?

If param One is set to bbb then I want to make param Two mandatory. Is it possible to do this with parameter sets somehow or will I just have to add this logic to the script itself?
Example idea of what I need:
param (
[Parameter(Mandatory, ParameterSetName = 'default')]
[ValidateSet(“aaa”, ”bbb”, ”ccc”, "ddd")]
[String]
$One,
[Parameter(ParameterSetName = 'default')]
[ValidateScript( { $One -eq 'bbb'; THEN MAKE THIS PARAM MANDATORY! })]
[String]
$Two
)
The value of $One seems to not be set yet as I tried doing this and one.txt is empty
[ValidateScript( { $One > One.txt; $true })]
Edit
While there is DynamicParam{} that looks like its only if you have begin,process,end, etc setup. This is a simple function that I don't want to add that to it. Also DynamicParam seems to require a bizarre amount of boilerplate code to work
Edit
It looks like DynamicParam is the only way, but I think it crazy. It's weird and not readable, but I'd still prefer Powershell to handle validation for me.
Doing it myself though is still pretty simple:
if ($One -eq 'bbb' -and -not $Two) {
ThrowError Param Two required when One set to $One
}
Use the default value for parameter -Two to enforce the desired logic, via an if statement that uses Throw:
param (
[Parameter(Mandatory, ParameterSetName = 'default')]
[ValidateSet('aaa', 'bbb', 'ccc', 'ddd')]
[String]
$One,
[Parameter(ParameterSetName = 'default')]
[String]
$Two = $(if ($One -eq 'bbb') { Throw "-Two must be passed if -One equals 'bbb'." })
)
"-One: $One; -Two: $Two"
Note: Emulating a (conditionally) mandatory parameter with Throw means that the behavior differs from a regular Mandatory parameter in that the latter prompts when a value isn't given.
A solution based on validation attributes would be preferable, but validation attributes aren't designed for cross-parameter validation, and no particular order of their evaluation is guaranteed.
The above solution relies on the fact that default values are evaluated after explicitly passed arguments have been bound.
The much more verbose alternative is to use a dynamic parameter, as shown in Wasif Hasan's answer, relies on the same timing, though it does have the advantage of exhibiting normal prompt-for-a-missing-mandatory-value behavior.
As of this writing, Wasif's answer doesn't work as posted, so here's a working solution; note how the use of DynamicParam syntactically requires (at least one of) the begin, process and end blocks.
# Syntax requires PSv5+:
using namespace System.Management.Automation
param(
[Parameter(Mandatory, ParameterSetName='default')]
[ValidateSet('aaa', 'bbb', 'ccc', 'ddd')]
[String]$One
)
# Define parameter -Two *dynamically*, so that its Mandatory property
# can be based on the specific value of the already-bound static -One parameter.
DynamicParam {
# Create a the dictionary of dynamic parameters.
$dict = [RuntimeDefinedParameterDictionary]::new()
# Define and add the -Two parameter
$paramName = 'Two'
$dict.Add(
$paramName,
[RuntimeDefinedParameter]::new(
$paramName,
[string],
[ParameterAttribute] #{
ParameterSetName = 'default'
# *Conditionally* make the parameter mandatory, depending on the value
# of the already-bound static -One parameter.
Mandatory = $One -eq 'bbb'
}
)
)
# Return the dictionary
return $dict
}
begin {
# NOTE: Dynamic parameter values do not become local variables the way
# they do for static parameters; the value must be accessed via the
# automatic $PSBoundParameters dictionary.
$Two = $PSBoundParameters['Two']
"-One: $One; -Two: $Two"
}
You are looking for dynamic parameters: Conditional PowerShell parameters
param(
[String]$One
)
DynamicParam {
# Create a parameter dictionary
$runtimeParams = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
# Populate it with parameters, with optional attributes
$attribs = New-Object System.Collections.ObjectModel.Collection[System.Attribute]
$mandatoryAttrib = New-Object System.Management.Automation.ParameterAttribute
$mandatoryAttrib.Mandatory = ($one -eq "bbb")
$attribs.Add($mandatoryAttrib)
$param = New-Object System.Management.Automation.RuntimeDefinedParameter('Two', String, $attribs)
}
Begin {
# If desired, move dynamic parameter values to variables
$ParameterName = $PSBoundParameters['Two']
}
# Do like regular
Without process block it will work.

passing a parameter in a function, the second parameter is always null [duplicate]

If I have a function which accepts more than one string parameter, the first parameter seems to get all the data assigned to it, and remaining parameters are passed in as empty.
A quick test script:
Function Test([string]$arg1, [string]$arg2)
{
Write-Host "`$arg1 value: $arg1"
Write-Host "`$arg2 value: $arg2"
}
Test("ABC", "DEF")
The output generated is
$arg1 value: ABC DEF
$arg2 value:
The correct output should be:
$arg1 value: ABC
$arg2 value: DEF
This seems to be consistent between v1 and v2 on multiple machines, so obviously, I'm doing something wrong. Can anyone point out exactly what?
Parameters in calls to functions in PowerShell (all versions) are space-separated, not comma separated. Also, the parentheses are entirely unneccessary and will cause a parse error in PowerShell 2.0 (or later) if Set-StrictMode -Version 2 or higher is active. Parenthesised arguments are used in .NET methods only.
function foo($a, $b, $c) {
"a: $a; b: $b; c: $c"
}
ps> foo 1 2 3
a: 1; b: 2; c: 3
The correct answer has already been provided, but this issue seems prevalent enough to warrant some additional details for those wanting to understand the subtleties.
I would have added this just as a comment, but I wanted to include an illustration--I tore this off my quick reference chart on PowerShell functions. This assumes function f's signature is f($a, $b, $c):
Thus, one can call a function with space-separated positional parameters or order-independent named parameters. The other pitfalls reveal that you need to be cognizant of commas, parentheses, and white space.
For further reading, see my article Down the Rabbit Hole: A Study in PowerShell Pipelines, Functions, and Parameters. The article contains a link to the quick reference/wall chart as well.
There are some good answers here, but I wanted to point out a couple of other things. Function parameters are actually a place where PowerShell shines. For example, you can have either named or positional parameters in advanced functions like so:
function Get-Something
{
Param
(
[Parameter(Mandatory=$true, Position=0)]
[string] $Name,
[Parameter(Mandatory=$true, Position=1)]
[int] $Id
)
}
Then you could either call it by specifying the parameter name, or you could just use positional parameters, since you explicitly defined them. So either of these would work:
Get-Something -Id 34 -Name "Blah"
Get-Something "Blah" 34
The first example works even though Name is provided second, because we explicitly used the parameter name. The second example works based on position though, so Name would need to be first. When possible, I always try to define positions so both options are available.
PowerShell also has the ability to define parameter sets. It uses this in place of method overloading, and again is quite useful:
function Get-Something
{
[CmdletBinding(DefaultParameterSetName='Name')]
Param
(
[Parameter(Mandatory=$true, Position=0, ParameterSetName='Name')]
[string] $Name,
[Parameter(Mandatory=$true, Position=0, ParameterSetName='Id')]
[int] $Id
)
}
Now the function will either take a name, or an id, but not both. You can use them positionally, or by name. Since they are a different type, PowerShell will figure it out. So all of these would work:
Get-Something "some name"
Get-Something 23
Get-Something -Name "some name"
Get-Something -Id 23
You can also assign additional parameters to the various parameter sets. (That was a pretty basic example obviously.) Inside of the function, you can determine which parameter set was used with the $PsCmdlet.ParameterSetName property. For example:
if($PsCmdlet.ParameterSetName -eq "Name")
{
Write-Host "Doing something with name here"
}
Then, on a related side note, there is also parameter validation in PowerShell. This is one of my favorite PowerShell features, and it makes the code inside your functions very clean. There are numerous validations you can use. A couple of examples are:
function Get-Something
{
Param
(
[Parameter(Mandatory=$true, Position=0)]
[ValidatePattern('^Some.*')]
[string] $Name,
[Parameter(Mandatory=$true, Position=1)]
[ValidateRange(10,100)]
[int] $Id
)
}
In the first example, ValidatePattern accepts a regular expression that assures the supplied parameter matches what you're expecting. If it doesn't, an intuitive exception is thrown, telling you exactly what is wrong. So in that example, 'Something' would work fine, but 'Summer' wouldn't pass validation.
ValidateRange ensures that the parameter value is in between the range you expect for an integer. So 10 or 99 would work, but 101 would throw an exception.
Another useful one is ValidateSet, which allows you to explicitly define an array of acceptable values. If something else is entered, an exception will be thrown. There are others as well, but probably the most useful one is ValidateScript. This takes a script block that must evaluate to $true, so the sky is the limit. For example:
function Get-Something
{
Param
(
[Parameter(Mandatory=$true, Position=0)]
[ValidateScript({ Test-Path $_ -PathType 'Leaf' })]
[ValidateScript({ (Get-Item $_ | select -Expand Extension) -eq ".csv" })]
[string] $Path
)
}
In this example, we are assured not only that $Path exists, but that it is a file, (as opposed to a directory) and has a .csv extension. ($_ refers to the parameter, when inside your scriptblock.) You can also pass in much larger, multi-line script blocks if that level is required, or use multiple scriptblocks like I did here. It's extremely useful and makes for nice clean functions and intuitive exceptions.
You call PowerShell functions without the parentheses and without using the comma as a separator. Try using:
test "ABC" "DEF"
In PowerShell the comma (,) is an array operator, e.g.
$a = "one", "two", "three"
It sets $a to an array with three values.
Function Test([string]$arg1, [string]$arg2)
{
Write-Host "`$arg1 value: $arg1"
Write-Host "`$arg2 value: $arg2"
}
Test "ABC" "DEF"
If you're a C# / Java / C++ / Ruby / Python / Pick-A-Language-From-This-Century developer and you want to call your function with commas, because that's what you've always done, then you need something like this:
$myModule = New-Module -ascustomobject {
function test($arg1, $arg2) {
echo "arg1 = $arg1, and arg2 = $arg2"
}
}
Now call:
$myModule.test("ABC", "DEF")
and you'll see
arg1 = ABC, and arg2 = DEF
Because this is a frequent viewed question, I want to mention that a PowerShell function should use approved verbs (Verb-Noun as the function name).
The verb part of the name identifies the action that the cmdlet performs. The noun part of the name identifies the entity on which the action is performed. This rule simplifies the usage of your cmdlets for advanced PowerShell users.
Also, you can specify things like whether the parameter is mandatory and the position of the parameter:
function Test-Script
{
[CmdletBinding()]
Param
(
[Parameter(Mandatory=$true, Position=0)]
[string]$arg1,
[Parameter(Mandatory=$true, Position=1)]
[string]$arg2
)
Write-Host "`$arg1 value: $arg1"
Write-Host "`$arg2 value: $arg2"
}
To pass the parameter to the function you can either use the position:
Test-Script "Hello" "World"
Or you specify the parameter name:
Test-Script -arg1 "Hello" -arg2 "World"
You don't use parentheses like you do when you call a function within C#.
I would recommend to always pass the parameter names when using more than one parameter, since this is more readable.
If you don't know (or care) how many arguments you will be passing to the function, you could also use a very simple approach like;
Code:
function FunctionName()
{
Write-Host $args
}
That would print out all arguments. For example:
FunctionName a b c 1 2 3
Output
a b c 1 2 3
I find this particularly useful when creating functions that use external commands that could have many different (and optional) parameters, but relies on said command to provide feedback on syntax errors, etc.
Here is a another real-world example (creating a function to the tracert command, which I hate having to remember the truncated name);
Code:
Function traceroute
{
Start-Process -FilePath "$env:systemroot\system32\tracert.exe" -ArgumentList $args -NoNewWindow
}
If you try:
PS > Test("ABC", "GHI") ("DEF")
you get:
$arg1 value: ABC GHI
$arg2 value: DEF
So you see that the parentheses separates the parameters
If you try:
PS > $var = "C"
PS > Test ("AB" + $var) "DEF"
you get:
$arg1 value: ABC
$arg2 value: DEF
Now you could find some immediate usefulness of the parentheses - a space will not become a separator for the next parameter - instead you have an eval function.
I don't see it mentioned here, but splatting your arguments is a useful alternative and becomes especially useful if you are building out the arguments to a command dynamically (as opposed to using Invoke-Expression). You can splat with arrays for positional arguments and hashtables for named arguments. Here are some examples:
Note: You can use positional splats with external commands arguments with relative ease, but named splats are less useful with external commands. They work, but the program must accept arguments in the -Key:Value format as each parameter relates to the hashtable key/value pairs. One example of such software is the choco command from the Chocolatey package manager for Windows.
Splat With Arrays (Positional Arguments)
Test-Connection with Positional Arguments
Test-Connection www.google.com localhost
With Array Splatting
$argumentArray = 'www.google.com', 'localhost'
Test-Connection #argumentArray
Note that when splatting, we reference the splatted variable with an # instead of a $. It is the same when using a Hashtable to splat as well.
Splat With Hashtable (Named Arguments)
Test-Connection with Named Arguments
Test-Connection -ComputerName www.google.com -Source localhost
With Hashtable Splatting
$argumentHash = #{
ComputerName = 'www.google.com'
Source = 'localhost'
}
Test-Connection #argumentHash
Splat Positional and Named Arguments Simultaneously
Test-Connection With Both Positional and Named Arguments
Test-Connection www.google.com localhost -Count 1
Splatting Array and Hashtables Together
$argumentHash = #{
Count = 1
}
$argumentArray = 'www.google.com', 'localhost'
Test-Connection #argumentHash #argumentArray
Function Test([string]$arg1, [string]$arg2)
{
Write-Host "`$arg1 value: $arg1"
Write-Host "`$arg2 value: $arg2"
}
Test("ABC") ("DEF")
I don't know what you're doing with the function, but have a look at using the 'param' keyword. It's quite a bit more powerful for passing parameters into a function, and makes it more user friendly. Below is a link to an overly complex article from Microsoft about it. It isn't as complicated as the article makes it sound.
Param Usage
Also, here is an example from a question on this site:
Check it out.
I stated the following earlier:
The common problem is using the singular form $arg, which is incorrect. It should always be plural as $args.
The problem is not that. In fact, $arg can be anything else. The problem was the use of the comma and the parentheses.
I run the following code that worked and the output follows:
Code:
Function Test([string]$var1, [string]$var2)
{
Write-Host "`$var1 value: $var1"
Write-Host "`$var2 value: $var2"
}
Test "ABC" "DEF"
Output:
$var1 value: ABC
$var2 value: DEF
Function Test {
Param([string]$arg1, [string]$arg2)
Write-Host $arg1
Write-Host $arg2
}
This is a proper params declaration.
See about_Functions_Advanced_Parameters.
And it indeed works.
You can pass parameters in a function like this also:
function FunctionName()
{
Param ([string]$ParamName);
# Operations
}

Use Alias only for parameters in function

How can i use alias only when i call my cmdlet function ?
This is my code
Function Deploy-Citrix {
[cmdletBinding(SupportsShouldProcess=$True)]
Param(
[Parameter(Mandatory=$true)]
[Alias("component")]
[ValidateNotNullOrEmpty()]
[string]$componentparam,
[Parameter(Mandatory=$true)]
[Alias("ip")]
[ValidateNotNullOrEmpty()]
[string]$ipaddressparam,
)
In this case for the second parameter for example, i can use the alias -ip but i can also use -ipaddressparam.
Deploy-citrix -componentparam "toto" -ipaddressparam "172.22.0.100"
Deploy-citrix -component "toto" -ip "172.22.0.100"
I can use both, but i want to disable the first one, i want to have alias only.
I know i can rename my variable, but i don't want to touch them in the whole script.
How can i achieve that?
I'm using Powershell V4.0
Thanks
If your goal is disallow the long form, you have no choice but to rename the parameter and remove the alias.
To minimize changes to your script, you can create a variable inside the function, e.g.
Function Deploy-Citrix {
[cmdletBinding(SupportsShouldProcess=$True)]
Param(
[Parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[string]$ip)
$ipaddressparam = $ip
...

Two function parameters getting collapsed into one?

I ran into some strange behavior writing a .ps1 script. I wrote a function that takes two parameters, but for some reason the second parameter was always null.
Upon closer inspection, it seems like my two parameters are somehow getting collapsed into the first one.
Given the following script, I would have expected, one line of output showing ...
function Foo($first, $second) {
echo $first
}
$x = "..."
$y = "why?"
Foo($x, $y)
But when I run this script, I get
...
why?
Is there some PowerShell syntax I don't know about that I'm accidentally (mis-)using?
Do not use parens around your arguments and don't use commas to separate arguments. Invoke your functions just like you would any other PowerShell command - using space separated arguments e.g.:
foo $x $y
When you put parens around ($x, $y) PowerShell passes that as a single expression/argument, in this case an array containing two items to the first parameter ($x) of your function. You can use Strict-Mode -Version Latest to warn you when you do this e.g.:
114> function foo($x,$y){}
115> foo(3,4)
116> Set-StrictMode -Version latest
117> foo(3,4)
The function or command was called as if it were a method. Parameters should be separated by
spaces. For information about parameters, see the about_Parameters Help topic.
At line:1 char:1
+ foo(3,4)
+ ~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : StrictModeFunctionCallWithParens
Is there some PowerShell syntax...that I'm accidentally (mis-)using?
Yes, you are not calling your function properly. In PowerShell, function calls do not use parenthesis or have their arguments separated by commas.
Instead, you would call Foo like so:
Foo $x $y
See a demonstration below:
PS > function Foo($first, $second) {
>> echo $first
>> }
>>
PS > $x = "..."
PS > $y = "why?"
PS > Foo $x $y
...
PS >
PS > function Foo($first, $second) {
>> echo "$first and $second"
>> }
>>
PS > Foo $x $y
... and why?
PS >
In case you are wondering, your current code has PowerShell interpreting ($x, $y) as a single argument to Foo: a two-item array. Thus, it assigns this array to $first and $null to $second:
PS > function Foo($first, $second) {
>> echo "Type of `$first: $($first.Gettype())"
>> echo "`$second is `$null: $($second -eq $null)"
>> }
>>
PS > $x = "..."
PS > $y = "why?"
PS > Foo($x, $y)
Type of $first: System.Object[]
$second is $null: True
PS >
The "," is used differently in powershell than in other programming languages. Here it is the array constructor.
(1,2,3).GetType() # System.Object[]
(,'element').GetType() # System.Object[]
Because you havent specified a datatype on your parameters the powershell assumes it is dealing with plain old System.Objects (the superclass of all classes). It then takes the array and assigns it to the first input parameter because it is the only one in this line. It can do that because an array is, by extension, also a System.Object.
Also, the old synthax for defining functions is not recommended anymore:
function foo ( $first, $second ) {}
When writing this, the powershell interpreter would internally convert this into an advanced function:
function foo {
PARAM(
[Parameter(Position=1)]
[object]$first,
[Parameter(Position=2)]
[object]$second
)
BEGIN { <# Do stuff here #> }
PROCESS { <# Do stuff here #> }
END { <# Do stuff here #> }
}
foo -first 'first' -second 'second'
foo 'first' 'second'
Causing unneeded overhead.
I hope that clears it up a little :)

PowerShell : use parameter validation without throwing exception

I'd like to call a PowerShell script this way :
script.ps1 -path mypath\to\files\ -days 6 -hours 0
To validate the command line arguments, I can either do it by hand, either rely on the param syntax :
Param (
[Parameter(Mandatory=$true )] [string] $path,
[Parameter(Mandatory=$false)] [int] $days,
[Parameter(Mandatory=$false)] [int] $hours
)
If I use the param syntax :
the param definition must be the first line in the script (excluding comments). Okay, not a problem for me
in case of incorrect parameters, I can't catch the error (for example to display a custom error message)
I'd like to display a custom error message when the script is called with wrong parameters.
Is it possible, and how, to catch the exception in case of parameter error ?
So okay, it is not possible to use param AND to catch the related exceptions.
The examples are for functions (simple and advanced) but the same idea should work for scripts with param as well:
# Simple function.
# Everything not declared in `param` goes to $args.
# If $args is not empty then there are "invalid" parameters or "unexpected" arguments
function test {
param (
[string]$path,
[int]$days,
[int]$hours
)
# check $args and throw an error (in here we just write a warning)
if ($args) { Write-Warning "Unknown arguments: $args" }
}
Or
# Advanced function.
# For an advanced function we can use an extra argument $args
# with an attribute `[Parameter(ValueFromRemainingArguments=$true)]`
function test {
param (
[Parameter(Mandatory=$true )] [string] $path,
[Parameter(Mandatory=$false)] [int] $days,
[Parameter(Mandatory=$false)] [int] $hours,
[Parameter(ValueFromRemainingArguments=$true)] $args
)
# check $args and throw an error (in this test we just write a warning)
if ($args) { Write-Warning "Unknown arguments: $args" }
}
The following test:
# invalid parameter
test -path p -invalid -days 5
# too many arguments
test -path p 5 5 extra
in both cases produces the same output:
WARNING: Unknown arguments: -invalid
WARNING: Unknown arguments: extra
A possible workaround is to wrap your actual function in another one. Something similar to a private/public relation. Example:
function Example-Private
{
[CmdletBinding()]
Param
(
[ValidateNotNullOrEmpty()]
[string]$Arg1,
[ValidateNotNullOrEmpty()]
[string]$Arg2
)
# Do what you need
}
function Example-Public
{
[CmdletBinding()]
Param
(
[string]$Arg1,
[string]$Arg2
)
try
{
Example-Private $Arg1 $Arg2
}
catch
{
# Display a user-friendly message, save exception into a log file, etc.
}
}
If you are working on a module you could take a look here how to export your public functions and hide the private ones: Export Powershell Functions
In the Begin block you can always do further validation on the parameters but if the parameter is wrong, I think you wouldn't want to continue execution. That is, you'd want to throw a terminating error. Here's an example:
param (
[Parameter(Mandatory=$true )] [string] $path,
[Parameter(Mandatory=$false)] [int] $days,
[Parameter(Mandatory=$false)] [int] $hours
)
Begin {
if ($hours -lt 0 -or $hours -gt 23) {
throw "Hours parameter must be between 0 and 23"
}
}
That said, I'm not sure that's any better than using PowerShell's built-in parameter validation functionality e.g.:
param (
[Parameter(Mandatory=$true )] [string] $path,
[Parameter(Mandatory=$false)] [int] $days,
[Parameter(Mandatory=$false)]
[ValidateRange(0,23)]
[int]
$hours
)
you can do that with the param syntax, if you add a string-type dummy-parameter with the property "ValueFromRemainingArguments".
Then you can check this dummy-parameter in your script and take appropriate actions, e.g.:
Param(
[Parameter(Mandatory=$false)]
[SWITCH]$myparam1,
[Parameter(Mandatory=$false)]
[SWITCH]$myparam2,
[parameter(Mandatory=$false,ValueFromRemainingArguments=$true)]
[STRING]$dummy
)
if ($dummy -eq anythingYouDontLike) throwAMessageOrSomething.