# --------------------------------------------------------------------------- ### # --------------------------------------------------------------------------- param([int]$count=1, [switch]$collectionMethod, [array]$inputObject=$null) BEGIN { if ($args -eq '-?') { @" Usage: Select-Random [[-Count] ] [-inputObject] (from pipeline) [-?] Parameters: -Count : The number of elements to select. -inputObject : The collection from which to select a random element. -collectionMethod : Collect the pipeline input instead of using reservoir -? : Display this usage information and exit Examples: PS> $arr = 1..5; Select-Random $arr PS> 1..10 | Select-Random -Count 2 "@ exit } else { $rand = new-object Random if ($inputObject) { # Write-Output $inputObject | &($MyInvocation.InvocationName) -Count $count } elseif($collectionMethod) { Write-Verbose "Collecting from the pipeline " [Collections.ArrayList]$inputObject = new-object Collections.ArrayList } else { $seen = 0 $selected = new-object object[] $count } } } PROCESS { if($_) { if($collectionMethod) { $inputObject.Add($_) | out-null } else { $seen++ if($seen -lt $count) { $selected[$seen-1] = $_ } ## For each input element $n there is a $count/$n chance that it becomes part of the result. elseif($rand.NextDouble() -lt ($count/$seen)) { ## For the ones previously selected, there's a 1/$n chance of it being replaced $selected[$rand.Next(0,$count)] = $_ } } } } END { if (-not $inputObject) { ## DO ONCE: (only on the re-invoke, not when using -inputObject) Write-Verbose "Selected $count of $seen elements." Write-Output $selected # foreach($el in $selected) { Write-Output $el } } else { Write-Verbose ("{0} elements, selecting {1}." -f $inputObject.Count, $Count) foreach($i in 1..$Count) { Write-Output $inputObject[$rand.Next(0,$inputObject.Count)] } } }