Advanced Function Optional Parameter Problem

This topic contains 4 replies, has 4 voices, and was last updated by Profile photo of Istvan Szarka Istvan Szarka 2 years, 5 months ago.

  • Author
    Posts
  • #16331
    Profile photo of Istvan Szarka
    Istvan Szarka
    Participant

    Hello,

    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:
    
    [CmdletBinding()]
    param(
          [Parameter(Mandatory,
                ValueFromPipeline,
                ValueFromPipelineByPropertyName)]
          [string[]]
          $VMName,
    
          [Parameter(ValueFromPipeline,
                ValueFromPipelineByPropertyName)]
          [AllowEmptyString()]
          [AllowNull()]
          [string]
          $SwitchName,
    
    #And so on
    )
    
    PROCESS
    {
            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
             }
    }
    
  • #16332
    Profile photo of Don Jones
    Don Jones
    Keymaster

    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.

  • #16333
    Profile photo of Bjorn Houben
    Bjorn Houben
    Member

    How do you call the function?

  • #16334
    Profile photo of Dave Wyatt
    Dave Wyatt
    Moderator

    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.

  • #16337
    Profile photo of Istvan Szarka
    Istvan Szarka
    Participant

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

You must be logged in to reply to this topic.