Show a Help message (Syntax) instead of an error when no parameters specified

I wrote a script to retrieve VM metrics from VMware vCenter.

A user needs to provide 2 arguments/parameters. One is the vCenter server and the other is 1 of the following : Single VM name or a file containing a list of VMs.

The script works fine, but if someone tries to run this script at the PS console without providing any arguments, it throws an exception. (shown below)

Questions :

  1. Is the exception pointing to an issue I don't know ?
  2. I would rather, the user be shown the Syntax instead of an exception. Is that possible ?
[CmdletBinding()]

Param (

<span class="pun">[</span><span class="typ">Parameter</span><span class="pun">(</span> <span class="typ">Mandatory</span> <span class="pun">=</span><span class="pln"> $true</span><span class="pun">,</span> <span class="typ">ParameterSetName</span> <span class="pun">= </span><span class="str">'List'</span> <span class="pun">)]</span>
<span class="pun">[</span><span class="typ">Parameter</span><span class="pun">(</span> <span class="typ">Mandatory</span> <span class="pun">=</span><span class="pln"> $true</span><span class="pun">,</span> <span class="typ">ParameterSetName</span> <span class="pun">= </span><span class="str">'OneVM'</span> <span class="pun">)]</span>
<span class="pun">[</span><span class="pln">string</span><span class="pun">]</span><span class="pln">$vCenterServer</span><span class="pun">,</span>

<span class="pun">[</span><span class="typ">Parameter</span><span class="pun">(</span> <span class="typ">Mandatory</span> <span class="pun">=</span><span class="pln"> $true</span><span class="pun">,</span> <span class="typ">ParameterSetName</span> <span class="pun">= </span><span class="str">'List'</span> <span class="pun">)]</span>
<span class="pun">[</span><span class="typ">ValidateNotNullOrEmpty</span><span class="pun">()]</span>
<span class="pun">[</span><span class="typ">ValidateScript</span><span class="pun">(</span> <span class="pun">{</span> <span class="typ">Test</span><span class="pun">-</span><span class="typ">Path</span> <span class="pun">-</span><span class="typ">LiteralPath</span><span class="pln"> $_ </span><span class="pun">-</span><span class="typ">Type</span> <span class="typ">Leaf</span> <span class="pun">})]</span>
<span class="pun">[</span><span class="pln">string</span><span class="pun">]</span><span class="pln">$vmListFile</span><span class="pun">,</span>

<span class="pun">[</span><span class="typ">Parameter</span><span class="pun">(</span> <span class="typ">Mandatory</span> <span class="pun">=</span><span class="pln"> $true</span><span class="pun">,</span> <span class="typ">ParameterSetName</span> <span class="pun">= </span><span class="str">'OneVM'</span> <span class="pun">)]</span>
<span class="pun">[</span><span class="pln">string</span><span class="pun">]</span><span class="pln">$MyVM

)


When I run this without providing arguments/parameters, here is what I see.

PS> c:\Temp\vCenter_RT_PerfData.ps1
C:\Temp\vCenter_RT_PerfData.ps1 : Parameter set cannot be resolved using the specified named parameters.
    + CategoryInfo          : InvalidArgument: (:) [vCenter_RT_PerfData.ps1], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : AmbiguousParameterSet,vCenter_RT_PerfData.ps1

Here is what I wish they would see.

SYNTAX
    C:\Temp\vCenter_RT_PerfData.ps1 -vCenterServer <String> -MyVM <String> [<CommonParameters>]

    C:\Temp\vCenter_RT_PerfData.ps1 -vCenterServer <String> -vmListFile <String> [<CommonParameters>]

Any suggestions on presenting this another/better way are also welcome.

You could use the help message parameter attribute in combination with mandatory to guide the user on what to input.

Otherwise you should drop mandatory and in your function check if there are no arguments and display the syntax help to them

Multiple parametersets are defined, you need to set a default parameterset to tell it the default parameters to ask for:

function Test-It {
    [CmdletBinding(DefaultParameterSetName = 'OneVM')]
    param (
        [Parameter( Mandatory = $true, ParameterSetName = 'List' )]
        [Parameter( Mandatory = $true, ParameterSetName = 'OneVM' )]
        [string]$vCenterServer,

        [Parameter( 
            Mandatory = $true, 
            ParameterSetName = 'List',
            HelpMessage="Enter path to vmlist file."
         )]
        [ValidateNotNullOrEmpty()]
        [ValidateScript( { Test-Path -LiteralPath $_ -Type Leaf })]
        [string]$vmListFile,

        [Parameter( 
            Mandatory = $true, 
            ParameterSetName = 'OneVM',
            HelpMessage="Enter the VM name"
        )]
        [string]$MyVM
    )
    begin{}
    process{}
    end{}
}

Test-It

However, the parameters are not normally how you would handle providing a file to a function. Use other cmdlets as examples for parameter names as something like ‘MyVM’ could be an Alias, but Name or VMName would be a better descriptive name:

function Test-It {
    [CmdletBinding()]
    param (
        [Parameter( 
            Mandatory = $true,
            HelpMessage="Enter the VCenter Server name"
        )]
        [string]$vCenterServer,

        [Parameter( 
            Mandatory = $true, 
            HelpMessage="Enter the VM name"
        )]
        [string[]]$VMName
    )
    begin{}
    process{
        foreach ( $vm in $vmname ) {
            Write-Verbose -Message ('Processing {0} on vcenter server {1}' -f $vm,$vCenterServer)
        }
    }
    end{}
}

Test-It -vCenterServer Server -VMName vm1,vm2 -Verbose

#or

$vms = Get-Content -Path C:\Script\vmlist.txt
Test-It -vCenterServer Server -VMName $vms -Verbose

Thank you Rob!

DefaultParameterSet did the trick.