Store Arguments and Variables And Use With Command - powershell

I am re-writing the Write-Progress function to work better with my script and to accomplish this I am joining all the arguments into a string and then trying to use it on the command however it is not working.
Function
Function Update-Progress {
Param (
[String] $Activity,
[Bool] $Completed,
[String] $CurrentOperation,
[Int] $ID,
[Int] $ParentID,
[Int] $PercentComplete,
[Int] $SecondsRemaining,
[Int] $SourceID,
[String] $Status
)
If ($htDisplay.WriteProgress.Enable -EQ $True -AND $htDisplay.WriteProgress.StopWatch.Elapsed.TotalMilliseconds -ge 500) {
$Parameters = New-Object System.Text.StringBuilder
IF (isNull($Activity)) { Write-Error "Activity is Required" } Else { $Null = $Parameters.Append("-Activity `"$Activity`"") }
IF (!(isNull($Completed))) { $Null = $Parameters.Append(" -Completed") }
IF (!(isNull($CurrentOperation))) { $Null = $Parameters.Append(" -CurrentOperation `"$CurrentOperation`"") }
IF (!(isNull($ID))) { $Null = $Parameters.Append(" -ID `"$ID`"") }
IF (!(isNull($ParentID))) { $Null = $Parameters.Append(" -ParentID `"$ParentID`"") }
IF (!(isNull($PercentComplete))) { $Null = $Parameters.Append(" -PercentComplete `"$PercentComplete`"") }
IF (!(isNull($SecondsRemaining))) { $Null = $Parameters.Append(" -SecondsRemaining `"$SecondsRemaining`"") }
IF (!(isNull($SourceID))) { $Null = $Parameters.Append("-SourceID `"$SourceID`"") }
IF (!(isNull($Status))) { $Null = $Parameters.Append(" -Status `"$Status`"") }
"Write-Progress $Parameters"
Write-Progress $Parameters
$htDisplay.WriteProgress.StopWatch.Reset()
$htDisplay.WriteProgress.StopWatch.Start()
}
}
Command Calling Function
Update-Progress -ID 1 -Activity "Preloading threads" -Status "Starting Job $($htConfig.MultiThread.Jobs.count)"
Error - The Progress bar displays
-Activity "Preloading Threads" -ID "1" -Status "Starting Job #"
Write-Host of the exact command shows the following so the syntax is correct, just need to figure out how to process the variable as all the parameters instead of just the activity param.
Write-Progress -Activity "Preloading threads" -ID "1" -Status "Starting Job 2"

to accomplish this I am joining all the arguments into a string and then trying to use it on the command however it is not working.
That's a terrible idea - use splatting with the $PSBoundParameters automatic variable instead - it already contains everything you need:
Function Update-Progress {
Param (
[String] $Activity,
[Bool] $Completed,
[String] $CurrentOperation,
[Int] $ID,
[Int] $ParentID,
[Int] $PercentComplete,
[Int] $SecondsRemaining,
[Int] $SourceID,
[String] $Status
)
If ($htDisplay.WriteProgress.Enable -EQ $True -AND $htDisplay.WriteProgress.StopWatch.Elapsed.TotalMilliseconds -ge 500) {
Write-Progress #PSBoundParameters
$htDisplay.WriteProgress.StopWatch.Reset()
$htDisplay.WriteProgress.StopWatch.Start()
}
}
I would probably go for a Switch rather than Bool for boolean parameters. You can grab the exact Param block from the original command with:
[System.Management.Automation.ProxyCommand]::GetParamBlock($(Get-Command Write-Progress))
And end up with getting input validation and positional parameters corresponding to what Write-Process expects:
Function Update-Progress {
param(
[Parameter(Mandatory=$true, Position=0)]
[string]${Activity},
[Parameter(Position=1)]
[ValidateNotNullOrEmpty()]
[string]${Status},
[Parameter(Position=2)]
[ValidateRange(0, 2147483647)]
[int]${Id},
[ValidateRange(-1, 100)]
[int]${PercentComplete},
[int]${SecondsRemaining},
[string]${CurrentOperation},
[ValidateRange(-1, 2147483647)]
[int]${ParentId},
[switch]${Completed},
[int]${SourceId}
)
If ($htDisplay.WriteProgress.Enable -EQ $True -AND $htDisplay.WriteProgress.StopWatch.Elapsed.TotalMilliseconds -ge 500) {
Write-Progress #PSBoundParameters
$htDisplay.WriteProgress.StopWatch.Reset()
$htDisplay.WriteProgress.StopWatch.Start()
}
}

Ok, Thanks to someone else here I have found the answer. It was inline expansion and I needed to use a hash table variable.
Source: Inline expansion of powershell variable as cmdlet parameter?
Function Update-Progress {
Param (
[String] $Activity,
[Bool] $Completed,
[String] $CurrentOperation,
[Int] $ID,
[Int] $ParentID,
[Int] $PercentComplete,
[Int] $SecondsRemaining,
[Int] $SourceID,
[String] $Status
)
If ($htDisplay.WriteProgress.Enable -EQ $True -AND $htDisplay.WriteProgress.StopWatch.Elapsed.TotalMilliseconds -ge 500) {
IF (isNull($Activity)) { Write-Error "Activity is Required" } Else { $Parameters = #{ Activity=$Activity } }
IF (!(isNull($Completed))) { $Parameters += #{ Completed=$Completed } }
IF (!(isNull($CurrentOperation))) { $Parameters += #{ CurrentOperation=$CurrentOperation } }
IF (!(isNull($ID))) { $Parameters += #{ ID=$ID} }
IF (!(isNull($ParentID))) { $Parameters += #{ ParentID=$ParentID } }
IF (!(isNull($PercentComplete))) { $Parameters += #{ PercentComplete=$PercentComplete } }
IF (!(isNull($SecondsRemaining))) { $Parameters += #{ SecondsRemaining=$SecondsRemaining } }
IF (!(isNull($SourceID))) { $Parameters += #{ SourceID=$SourceID } }
IF (!(isNull($Status))) { $Parameters += #{ Status=$Status } }
Write-Progress #Parameters
$htDisplay.WriteProgress.StopWatch.Reset()
$htDisplay.WriteProgress.StopWatch.Start()
}
}

Related

Is it possible to have [Nullable[bool]] in a bool[] in PowerShell

Is it possible to have [Nullable[bool]] in a bool[] in PowerShell? I tried different solution, approaches but fail to get proper $null, $true, $false for a parameter? Also it seems that [cmdletbinding] changes how things works as well.
enum BoolNull {
null = $null
true = $true
false = $false
}
function Test-Array0 {
param (
[bool[]] $thisValue
)
if ($thisValue -eq $null) {
Write-Output 'Null found'
}
}
function Test-Array1 {
param (
[bool[]] $thisValue
)
foreach ($value in $thisValue) {
if ($value -eq $null) {
Write-Output 'Null found'
}
}
}
function Test-Array2 {
[CmdletBinding()]
param (
[bool[]] $thisValue
)
if ($thisValue -eq $null) {
Write-Output 'Null found'
}
}
function Test-Array {
[CmdletBinding()]
param (
[AllowEmptyCollection()] [AllowNull()][ValidateSet($null, $true, $false)] $thisValue
)
if ($thisValue -eq $null) {
Write-Output 'Null found'
}
}
# this works
function Test-Test {
[CmdletBinding()]
param (
[nullable[bool]] $thisValue
)
if ($thisValue -eq $null) {
Write-Output 'Null found'
}
}
function Test-Array5 {
param (
[boolnull[]] $thisValue
)
foreach ($value in $thisValue) {
if ($value -eq 'null') {
Write-Output 'Null found'
}
}
}
Test-Array0 -thisValue $null #this works
Test-Array -thisValue $null # this doesn't work
Test-Array -thisValue $null, $null, $true # this doesn't work
Test-Array1 -thisValue $null
Test-Array2 -thisValue $null # this
Test-Test -thisValue $null # this works
Test-Array5 -thisValue null, true, null # this works but is completely useless
This is a limitation of the bool type. When you strictly-type the parameter, it can only take $true, $false, 0, and 1. In order to achieve what you want, you can use a [ValidateSet] attribute:
[CmdletBinding()]
param(
[Parameter(Position = 0, Mandatory)]
[ValidateSet($null, $true, $false)]
[object] $ThisValue
)
As a side-note, there used to be a bug with powershell (might still be present) where comparing $null on the right side will cause nothing to be returned, causing logic to fall out of the statement, so it's best to compare on the left:
if ($null -eq $ThisValue) {
After testing your example, I was unable to replicate your problem, however:
function Test-Nullable {
[CmdletBinding()]
param(
[nullable[bool]] $Value
)
if ($null -eq $Value) {
'Yes'
} else {
$Value
}
}
and in array format:
function Test-Nullable {
[CmdletBinding()]
param(
[nullable[bool][]] $Value
)
foreach ($bool in $Value) {
if ($null -eq $bool) {
'Yes'
} else {
$bool
}
}
}
Test-Nullable 5, 3, $null, $true, $false, 0
True
True
Yes
True
False
False

Powershell v3-5: Out-Grid View Truncated Data

I'm working on a PS script (v5 on the machine I'm using) that uses Invoke-WebRequest to grab information from a web address and returns the results.
When attempting to pipe my output to Out-GridView with more than 9 results, the column containing data lists "..." on the 10th line.
I've tried doing several types of joins, and am just wondering if I need to have my result in a specific type to avoid having this effect (hashtable maybe?)
Checking MS forums has only yielded results about joining on line-end's, which doesn't seem to help in this case.
The pages I'm querying are simple HTML showing the output of .txt files, however the .Content property of my Invoke-WebRequest query seems to be one long string.
Here's my code thus far:
[cmdletBinding(
DefaultParameterSetName='FileWithURIs'
)]
Param(
[Parameter(ParameterSetName='FileWithURIs',
Mandatory=$true
)]
[ValidateNotNull()]
[ValidateNotNullOrEmpty()]
[ValidateScript({
if(-Not ($_ | Test-Path) ){
throw "File or folder does not exist"
}
if(-Not ($_ | Test-Path -PathType Leaf) ){
throw "The Path argument must be a file. Folder paths are not allowed."
}
if($_ -notmatch "(\.txt)"){
throw "The file specified in the path argument must be of type txt"
}
return $true
})]
[String]$FileWithURIs,
[Parameter(ParameterSetName='SingleURI',
Mandatory=$True)]
[ValidateNotNull()]
[ValidateNotNullOrEmpty()]
[ValidateScript({
if($_.StartsWith("http://") -eq $false -and $_.StartsWith("https://" -eq $false))
{
throw "User specified URI must start with http:// or https://"
}
else
{
return $true
}
})]
[String]$URI,
[Switch]$ViewAsGrid
)
BEGIN
{
Function Check-CustomType()
{
if("TrustAllCertsPolicy" -as [type])
{
Out-Null
}
else
{
Set-CustomType
}
}
Function Set-CustomType()
{
add-type #"
using System.Net;
using System.Security.Cryptography.X509Certificates;
public class TrustAllCertsPolicy : ICertificatePolicy {
public bool CheckValidationResult(
ServicePoint srvPoint, X509Certificate certificate,
WebRequest request, int certificateProblem) {
return true;
}
}
"#
$script:newCertPolicy = [System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
}
Function Evaluate-URIs()
{
if($URI)
{
Get-Blocklist -ListURI $URI
}
elseif($FileWithURIs)
{
$lines = Get-Content $FileWithURIs
foreach($line in $lines)
{
Get-Blocklist -ListURI $line
}
}
}
Function Create-Table()
{
$script:tabName = "ResultTable"
# Create Table object
$script:table = New-Object System.Data.DataTable “$script:tabName”
# Create first column
$script:col1 = New-Object System.Data.DataColumn SiteName,([string])
$script:table.columns.add($script:col1)
}
Function Add-RowToTable($Value)
{
# Create new row
$newRow = $script:table.NewRow()
# Add value to row
$newRow.SiteName = $Value
# Add row to table
$script:table.Rows.Add($newRow)
}
Function Get-Blocklist($ListURI)
{
try
{
$query = Invoke-WebRequest -Uri "$ListURI"
if($ViewAsGrid)
{
Create-Table
$content = #($query.Content.Split("`r`n"))
foreach($entry in $content)
{
Add-RowToTable -Value $entry
}
$script:table | Out-GridView -Title "Blocklist for $ListURI"
}
else
{
Write-Host "`nBlocklist for $ListURI " -ForegroundColor Yellow -NoNewline
Write-Host "`n`n$($query.Content | Sort -Descending)"
}
}
catch [Exception]
{
Write-Host "`nUnable to connect to resource " -ForegroundColor Yellow -NoNewline
Write-Host "$ListURI" -ForegroundColor Red
Write-Host "`nERROR: $($Error[0].Exception)"
}
}
Function Run-Stack()
{
Check-CustomType
Evaluate-URIs
}
}
PROCESS
{
Run-Stack
}
END { Write-Host "`nEnd of script" }
The idea is to only use Out-GridView if a single, user-entered address is the input. Otherwise it just becomes console output.
Any help would be appreciated!

How to reuse/extend functions on Powershell?

I'm trying to develop 2 functions with Powershell. The first, will check my database status (online/offline). The second function should loop on the first function until a certain state is achieve.
function Get-DBStatus
{
<# .. removed help section for brevity .. #>
[CmdletBinding()]
[OutputType([System.Object])]
param
(
[Parameter(Mandatory = $true)]
[String]$ServerName,
[Parameter(Mandatory = $true)]
[String]$ServerUser,
[Parameter(Mandatory = $true)]
[String]$ServerPassword,
[Parameter(Mandatory = $true)]
[String]$DatabaseName,
)
try
{
$params = #{ ... }
$dbStatus = Invoke-SqlConnection #params | Where-Object {$_.Name -match $AltDBName }
}
catch
{
Write-Error -Message ('An error has occured while ...')
}
if ([String]::IsNullOrEmpty($dbStatus) -eq $false)
{
$dbStatus
}
# <<< function Get-DbStatusOnlyIf
# <<< same parameters as the function above
# <<< get the desired status as a new parameter
# <<< loop the function above until the desired status is achieved or a timeout is reached
}
I'm new to Powershell and I think I shouldn't repeat myself rewriting the same parameters from the first function into the second one since they're dependent. However, I might be wrong, thus the question.
Thank you for your assistance!
You have to rewrite this parameters on your second function and pass them through or add another paramter to your first function that will do the looping. I would go with the second solution.
Try something like that
function Get-DBStatus {
<# .. removed help section for brevity .. #>
[CmdletBinding()]
[OutputType([System.Object])]
param
(
[Parameter(Mandatory = $true)]
[String]$ServerName,
[Parameter(Mandatory = $true)]
[String]$ServerUser,
[Parameter(Mandatory = $true)]
[String]$ServerPassword,
[Parameter(Mandatory = $true)]
[String]$DatabaseName,
$WaitForStatus, #or something like that
[int]$Timeout=10
)
do {
try {
#$params = #{ ... }
$dbStatus = Invoke-SqlConnection #params | Where-Object {$_.Name -match $AltDBName }
}
catch {
Write-Error -Message ('An error has occured while ...')
return
}
if ([String]::IsNullOrEmpty($dbStatus) -eq $false) {
if ($WaitForStatus){
if ($dbStatus -eq $WaitForStatus) {
$dbStatus
$EndLoop = $true
}
else {
Write-Host -NoNewline "." #only for test
Start-Sleep -Seconds 1
$Timeout -= 1
}
}
else{
$dbStatus
$EndLoop = $true
}
}
}
until ($EndLoop -or $Timeout -eq 0)
}
or with recursion
function Get-DBStatus {
<# .. removed help section for brevity .. #>
[CmdletBinding()]
[OutputType([System.Object])]
param
(
[Parameter(Mandatory = $true)]
[String]$ServerName,
[Parameter(Mandatory = $true)]
[String]$ServerUser,
[Parameter(Mandatory = $true)]
[String]$ServerPassword,
[Parameter(Mandatory = $true)]
[String]$DatabaseName,
$WaitForStatus, #or something like that
[int]$timeout = 3
)
if ($WaitForStatus) {
$start = Get-Date
while (((get-date) - $start).TotalSeconds -lt $timeout) {
$res = Get-DBStatus -ServerName $ServerName -ServerUser $ServerUser -ServerPassword $ServerPassword -DatabaseName $DatabaseName
if ($WaitForStatus -eq $res) {
return $res
}
Start-Sleep -Seconds 1
}
}
else {
try {
$params = #{ ... }
$dbStatus = Invoke-SqlConnection #params | Where-Object {$_.Name -match $AltDBName }
}
catch {
Write-Error -Message ('An error has occured while ...')
}
if ([String]::IsNullOrEmpty($dbStatus) -eq $false) {
$dbStatus
}
}
}

Powershell - calling unmanaged Function CreateProfile crashes Powershell.exe

When calling a unmanaged piece of code with pinvoke -- createprofile. The Powershell.exe process crashes after the call to the method in the unmanaged code. The profile is created successfully.
Why this would happen? My code is below:
function CreateProfile
{
param([String]$UserSid, [String]$UserName, [system.uint32]$ProfilePath)
Add-Type -TypeDefinition '
using System;
using System.Runtime.InteropServices;
public static class PInvoke {
[DllImport("userenv.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern int CreateProfile( [MarshalAs(UnmanagedType.LPWStr)] String pszUserSid, [MarshalAs(UnmanagedType.LPWStr)] String pszUserName, [Out][MarshalAs(UnmanagedType.LPWStr)] System.Text.StringBuilder pszProfilePath, uint cchProfilePath);
}
'
$pszProfilePath = new-object -typename System.Text.StringBuilder
[int]$results = [PInvoke]::CreateProfile($UserSid, $UserName, $pszProfilePath, $ProfilePath)
}
$stringbuff = new-object system.text.stringbuilder(260)
[system.uint32]$a =$stringbuff.capacity
$sid = ((get-aduser -id 'brtestlocaluser').sid.value)
CreateProfile -usersid $sid -username 'brtestlocaluser' -ProfilePath $a
Finally was able to figure this out. Calling it in another means seemed to fix this issue.
function Register-NativeMethod
{
[CmdletBinding()]
[Alias()]
[OutputType([int])]
Param
(
# Param1 help description
[Parameter(Mandatory=$true,
ValueFromPipelineByPropertyName=$true,
Position=0)]
[string]$dll,
# Param2 help description
[Parameter(Mandatory=$true,
ValueFromPipelineByPropertyName=$true,
Position=1)]
[string]
$methodSignature
)
$script:nativeMethods += [PSCustomObject]#{ Dll = $dll; Signature = $methodSignature; }
}
function Add-NativeMethods
{
[CmdletBinding()]
[Alias()]
[OutputType([int])]
Param($typeName = 'NativeMethods')
$nativeMethodsCode = $script:nativeMethods | ForEach-Object { "
[DllImport(`"$($_.Dll)`")]
public static extern $($_.Signature);
" }
Add-Type #"
using System;
using System.Text;
using System.Runtime.InteropServices;
public static class $typeName {
$nativeMethodsCode
}
"#
}
function New-ProfileFromSID {
[CmdletBinding()]
[Alias()]
[OutputType([int])]
Param
(
# Param1 help description
[Parameter(Mandatory=$true,
ValueFromPipelineByPropertyName=$true,
Position=0)]
[string]$UserName,
[string]$domain = ''
)
$methodname = 'UserEnvCP2'
$script:nativeMethods = #();
if (-not ([System.Management.Automation.PSTypeName]$methodname).Type)
{
Register-NativeMethod "userenv.dll" "int CreateProfile([MarshalAs(UnmanagedType.LPWStr)] string pszUserSid,`
[MarshalAs(UnmanagedType.LPWStr)] string pszUserName,`
[Out][MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszProfilePath, uint cchProfilePath)";
Add-NativeMethods -typeName $methodname;
}
$sb = new-object System.Text.StringBuilder(260);
$pathLen = $sb.Capacity;
Write-Verbose "Creating user profile for $Username";
#$SID= ((get-aduser -id $UserName -ErrorAction Stop).sid.value)
if($domain)
{
$objUser = New-Object System.Security.Principal.NTAccount($domain, $UserName)
$strSID = $objUser.Translate([System.Security.Principal.SecurityIdentifier])
$SID = $strSID.Value
}
else
{
$objUser = New-Object System.Security.Principal.NTAccount($UserName)
$strSID = $objUser.Translate([System.Security.Principal.SecurityIdentifier])
$SID = $strSID.Value
}
Write-Verbose "$UserName SID: $SID"
try
{
$result = [UserEnvCP2]::CreateProfile($SID, $Username, $sb, $pathLen)
if($result -eq '-2147024713')
{
$status = "$userName already exists"
write-verbose "$username Creation Result: $result"
}
elseif($result -eq '-2147024809')
{
$status = "$username Not Found"
write-verbose "$username creation result: $result"
}
elseif($result -eq 0)
{
$status = "$username Profile has been created"
write-verbose "$username Creation Result: $result"
}
else
{
$status = "$UserName unknown return result: $result"
}
}
catch
{
Write-Error $_.Exception.Message;
break;
}
$status
}

Can you combine CmdletBinding with unbound parameters?

(Powershell 5)
I have the following coalesce function:
(UPDATE: Removed the "optimized" continue call in the process block.)
function Find-Defined {
begin {
$ans = $NULL;
$Test = { $_ -ne $NULL };
}
process {
if ( $ans -eq $NULL ) {
$ans = $_ |? $Test | Select -First 1;
}
}
end {
if ( $ans -ne $NULL ) {
return $ans;
}
else {
$Args `
|% { if ( $_ -is [Array] ) { $_ |% { $_ } } else { $_ } } `
|? $Test `
| Select -First 1 `
| Write-Output `
;
}
}
}
And this works plenty well for me, on command lines like the following:
$NULL, $NULL, 'Legit', 1, 4 | Find-Defined;
$NULL, $NULL | Find-Defined $NULL, #( $NULL, 'Value' ), 3;
$NULL, $NULL | Find-Defined $NULL $NULL 3 4;
You may notice that I encapsulated the decision logic in a ScriptBlock variable. This was because I wanted to parameterize it and I started out trying this.
[CmdletBinding()]param( [ScriptBlock] $Test = { $_ -ne $NULL } );
However, the minute I added CmdletBinding I started to get errors. The binding wanted to try to cast everything in the argument section as a ScriptBlock, so I added
[CmdletBinding(PositionalBinding=$False)]
And then it complained that the unbound arguments couldn't be bound, and so I added:
param( [parameter(Mandatory=$False,Position=0,ValueFromRemainingArguments=$True)][Object[]] $Arguments ...
And whatever I did afterwards added a new error. If I removed the $Test parameter, just localizing it to see what I could do, then I started getting the error I had when developing the first generation:
The input object cannot be bound to any parameters for the command either
because the command does not take pipeline input or the input and its
properties do not match any of the parameters that take pipeline input.
... even though I had a process block.
In the end simply removing the param statement, put it back to its flexible function that I liked.
I still would like to broaden this function to accept both a ScriptBlock test and unbound parameters (as well as Common parameters like -Verbose, if that's possible). That way I could have a general algorithm for string coalescing as well:
$Test = { -not [string]::IsNullOrEmpty( [string]$_ ) };
$NULL,$NULL,'','' | Find-Defined -Test $Test $NULL,'','This should be it' 'Not seen'
Am I missing something?
I believe this solve the problem you are trying to solve, but with a bit of a different implementation. When using CmdletBinding everything must be declared. So you need one parameter for the pipeline input and one for the "unbound" parameters.
Based on you question I wrote these test cases:
Describe 'Find-Defined' {
it 'should retun Legit' {
$NULL, $NULL, 'Legit', 1, 4 | Find-Defined | should be 'Legit'
}
it 'should retun Value' {
$NULL, $NULL | Find-Defined $NULL, #( $NULL, 'Value' ), 3 | should be 'Value'
}
it 'should retun 3' {
$NULL, $NULL | Find-Defined $NULL $NULL 3 4 | should be '3'
}
it 'Should return "This should be it"' {
$Test = { -not [string]::IsNullOrEmpty( [string]$_ ) };
$NULL,$NULL,'','' | Find-Defined -Test $Test $NULL,'','This should be it' 'Not seen' | should be 'This should be it'
}
}
Here is my solution, which passes all of the above cases.
function Find-Defined {
[CmdletBinding()]
param (
[ScriptBlock] $Test = { $NULL -ne $_},
[parameter(Mandatory=$False,ValueFromPipeline =$true)]
[Object[]] $InputObject,
[parameter(Mandatory=$False,Position=0,ValueFromRemainingArguments=$True)]
[Object[]] $Arguments
)
begin {
$ans = $NULL;
function Get-Value {
[CmdletBinding()]
param (
[ScriptBlock] $Test = { $_ -ne $NULL },
[parameter(Mandatory=$False,Position=0,ValueFromRemainingArguments=$True)]
[Object[]] $Arguments,
$ans = $NULL
)
$returnValue = $ans
if($null -eq $returnValue)
{
foreach($Argument in $Arguments)
{
if($Argument -is [object[]])
{
$returnValue = Get-Value -Test $Test -Arguments $Argument -ans $returnValue
}
else
{
if ( $returnValue -eq $NULL ) {
$returnValue = $Argument |Where-Object $Test | Select-Object -First 1;
if($null -ne $returnValue)
{
return $returnValue
}
}
}
}
}
return $returnValue
}
}
process {
$ans = Get-Value -Test $Test -Arguments $InputObject -ans $ans
}
end {
$ans = Get-Value -Test $Test -Arguments $Arguments -ans $ans
if ( $ans -ne $NULL ) {
return $ans;
}
}
}