Powershell: Strange Get-Random Input-Object parameter behaviour

Created on 2 May 2017  路  6Comments  路  Source: PowerShell/PowerShell

Steps to reproduce

Get-Random -InputObject @('zzz', 'aaa', '')
Get-Random @('zzz', 'aaa', '')

Expected behavior

InputObject parameter position value is 1, so these command should work the same way and return one of the array elements.

Actual behavior

While the second command works, first command produces error:

Get-Random : Cannot validate argument on parameter 'InputObject'. The argument is null or empty. Provide an argument th
at is not null or empty, and then try the command again.
At line:1 char:25
+ Get-Random -InputObject @('zzz', 'aaa', '')
+                         ~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidData: (:) [Get-Random], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.GetRandomCommand

Environment data

> $PSVersionTable
Name                           Value
----                           -----
SerializationVersion           1.1.0.1
PSRemotingProtocolVersion      2.3
BuildVersion                   3.0.0.0
WSManStackVersion              3.0
PSVersion                      6.0.0-alpha
CLRVersion
PSEdition                      Core
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
GitCommitId                    v6.0.0-alpha.18

Name                           Value
----                           -----
PSVersion                      5.1.15063.138
PSEdition                      Desktop
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
BuildVersion                   10.0.15063.138
CLRVersion                     4.0.30319.42000
WSManStackVersion              3.0
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
Issue-Bug Resolution-Fixed WG-Engine

Most helpful comment

I'm also thinking that removing [ValidateNotNullOrEmpty] is the right thing and shouldn't have any negative side effects. I'll submit a PR.

All 6 comments

I'm seeing this behaviour too.

$DomainListSource = "https://raw.githubusercontent.com/opendns/public-domain-lists/master/opendns-top-domains.txt"
$domainlistMaster = (Invoke-RestMethod -useBasicParsing -uri $domainListSource) -split "`n"
Get-Random $domainlistMaster -Count 50 
Get-Random : Cannot validate argument on parameter 'InputObject'. The argument is null or empty. Provide an argument that is not null or empty, and then try the command again.

Name                           Value                                                                                                                                                                                 
----                           -----                                                                                                                                                                                 
PSVersion                      5.0.10586.117                                                                                                                                                                         
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}                                                                                                                                                               
BuildVersion                   10.0.10586.117                                                                                                                                                                        
CLRVersion                     4.0.30319.42000                                                                                                                                                                       
WSManStackVersion              3.0                                                                                                                                                                                   
PSRemotingProtocolVersion      2.3                                                                                                                                                                                   
SerializationVersion           1.1.0.1                                                                                                                                                                               

This is a nasty bug in parameter binding.

@SteveL-MSFT @daxian-dbw @mklement0 for information.

This isn't an issue in the parameter binder. The default parameter set is for -Maximum, not -InputObject. InputObject has [ValidateNotNullOrEmpty] whereas Maximum does not. This attribute also checks if the collection contains $null (or empty string which is equivalent for strings). And this is what's causing the error message. Removing that attribute "fixes" this issue. Would need to think through any side effects. Since that parameter is mandatory, you can't pass in $null anyways.

@benny-gold: Your example is missing the -InputObject parameter for reproducing the symptom; as an aside: given that the list you're retrieving by definition has no line-internal spaces, the better command to use is $domainlistMaster = -split (Invoke-RestMethod -useBasicParsing -uri $domainListSource), which bypasses the problem.

@SteveL-MSFT:

  • Removing the ValidateNotNullOrEmpty strikes me as the right thing to do, because there is no reason to prevent pulling random elements from collections only because they happen to have empty elements.

    • Perhaps the intent was to prevent passing an empty _scalar_ (e.g., Get-Random -InputObject $null), but (a) with an [object[]]-typed parameter that emptiness check is invariably also applied to the _elements_ of the array individually; and (b), even an empty scalar isn't worth preventing, if it is explicitly passed (which is by definition the case here, given that the parameter is mandatory), so not only should [ValidateNotNullOrEmpty] be removed, [AllowNull] should be added.

As for what parameter is bound with a _positional_ argument:

  • Due to trickery in GetRandomCommand.cs -Maximum is _ultimately not_ bound if its argument is an _array_: the code checks for an array-valued argument and, if so, assigns to InputObject instead.

  • The upshot is:

    • Using an array _positionally_ accidentally _bypasses_ the ValidateNotNullOrEmpty validation attribute, because the argument is _initially_ bound to -Maximum, which doesn't have this attribute; therefore, it is only positional use with an array that currently - accidentally - exhibits the desired behavior.

    • The trickery enables questionable commands such as Get-Random -Maximum (1..10) -Count 3, which is effectively the same as Get-Random -InputObject (1..10) -Count 3

I'm also thinking that removing [ValidateNotNullOrEmpty] is the right thing and shouldn't have any negative side effects. I'll submit a PR.

:tada:This issue was addressed in #10644, which has now been successfully released as v7.0.0-preview.5.:tada:

Handy links:

Was this page helpful?
0 / 5 - 0 ratings