Advanced Function Optional Parameter Problem


I’ve written an advanced function that creates one or more VMs. I have a mandatory parameter and many optional, with some default values.
The problem is with the optional parameters that have no default values.
For example, there is a SwitchName parameter that is optional and has no default value, because I don’t always want a new VM to connect to a switch.
However, if I don’t supply any value to it, I get this error, even if I use [AllowEmptyString()] and [AllowNull()] in the PARAM block:

New-VM : Cannot validate argument on parameter 'SwitchName'. The argument is null or empty. Provide an argument that is not null or empty, and then try the command again.

I want the VMs to connect to a switch only if I supply the name of a switch, otherwise I don’t want them to connect anywhere. How can I do this?
These are the relevant snippets from my code (sorry for the formatting, it gets messed up whatever I do):

#Some of the parameters:



#And so on

        foreach ($name in $VMName)
                $params = @{Name                          = $name
                                         MemoryStartupBytes = $MemoryStartupBytes
                                         Generation                  = 2
                                         NewVHDPath             = "$VHDFolder\$name\$name.vhdx"
                                         NewVHDSizeBytes    = $VHDSizeBytes
                                         BootDevice                  = $BootDevice
                                         ComputerName         = $ComputerName
                                         Path                              = $VMFolder
                                         SwitchName               = $SwitchName}
                New-VM @params

                $params = @{VMName                              = $name
                                          DynamicMemoryEnabled = $true
                                          MinimumBytes                    = $MemoryMinimumBytes
                                          ComputerName                 = $ComputerName}
                Set-VMMemory @params

You need to put some logic in your script to not provide the SwitchName parameter is $SwitchName is null.

if ($SwitchName) { $params.Add('SwitchName',$SwitchName) }

Something along those lines.

The [AllowNull()] means YOUR FUNCTION will accept a null value from $SwitchName. That doesn’t mean New-VM will do so.

How do you call the function?

The problem is probably when you pass a null / empty value to the New-VM cmdlet, based on what I can see so far. You’d need to construct your $params hashtable so that only the defined parameters are in it when you call New-VM. Something like this:

$params = @{
    Name               = $name
    MemoryStartupBytes = $MemoryStartupBytes
    Generation         = 2
    NewVHDPath         = "$VHDFolder\$name\$name.vhdx"
    NewVHDSizeBytes    = $VHDSizeBytes
    BootDevice         = $BootDevice
    ComputerName       = $ComputerName
    Path               = $VMFolder
if ($SwitchName) { $params['SwitchName'] = $SwitchName }
New-VM @params

Also, you’ll want to get away from using ValueFromPipeline in combination with String parameters. Any object can be represented as a string, which will give you some crazy results when you start trying to pipe objects to this function. Based on what I see so far, ValueFromPipelineByPropertyName should be all you need.

Thank you a lot, it works! I haven’t encountered this amazing technique yet.
Thank you for the advice on pipeline imput too!