Sometimes a PowerShell script gets called with arguments containing spaces and enclosed by double-quotes,
to ensure the string is interpreted as one single argument. A problem arises when the argument is empty and the double-quotes are passed containing nothing. PS sees the command line as non-empty, and tries to form an argument value from it. Except the double-quotes are stripped away, leaving an empty string as an argument value. Of course PS cannot actually use the empty value, so we want to validate command line arguments to disallow empty strings.
See the calling Cmd script, and the PS source, both commented. Tests 4 and 5 show the benefit of the function that scans the $args[] array and returns the first valid/non-empty argument.
Question: why can the function not be coded with just one ForEach loop?
Args.CMD:
@Echo Off
CD /D "%~dp0" & Rem Change to the folder where this script lives
CLS
Echo.
Rem PS script name is the same as this Cmd script
Set Script=%~n0.PS1
Rem Parameters of each call here are TestNumber, ExpectedExitCode, Argument1, Argument2
Rem Test 0: Try with zero arguments; expected exit code is 1
Call :TryMe 0 1
Rem Test 1: Try with non-useful arguments; expected exit code is 2
Call :TryMe 1 2 "" ""
Rem Test 2: Try with valid arguments, single words; expected exit code is 0
Call :TryMe 2 0 ArgOne ArgTwo
Rem Test 3: Try with valid arguments, multiple words; expected exit code is 0
Call :TryMe 3 0 "Arg One" "Arg Two"
Rem Test 4: Try with mixed arguments, single words; expected exit code is 0
Call :TryMe 4 0 "" ArgTwo
Rem Test 5: Try with mixed arguments, multiple words; expected exit code is 0
Call :TryMe 5 0 "" "Arg Two"
Echo All Done.
Pause
GoTo :EOF
:TryMe
Set TstNbr=%1
Set ExpCod=%2
Set Args12=%3 %4
Echo Test %TstNbr% of 5: PowerShell.EXE -F %Script% %Args12%
PowerShell.EXE -F %Script% %Args12%
Echo ErrorLevel is [%ErrorLevel%], expected was [%ExpCod%]
Pause
Echo.
GoTo :EOF
Args.ps1:
Set-StrictMode -Version 3.0 # disallow implicit variables
function ArgNonEmtFstGet( $arrArgs ) { # get the first non-empty argument
ForEach( $strArgs In $arrArgs ) { # <=== why is this double-indirection needed?
ForEach( $strArg In $strArgs ) { # scan all argument strings
$intArgLen = $strArg.Length # get length of current argument-string
If( $intArgLen -gt 0 ) { Return $strArg } # first time length is greater than zero, quit scanning and pass that argument back to caller
} # done scanning
} # <=== why is this double-indirection needed?
"" # when we finished scanning and did not return early, return a non-crashing value
} # ArgNonEmtFstGet
# Step 0: show we are alive
"Arg count: " + $args.Length # emit how many strings exist that *could be* arguments
# Step 1: look for any argument at all
If( $args.Length -eq 0 ) { # when there are zero strings that look like arguments
Write-Output "Putative argument required." # emit error message for 'no strings found'
Exit( 1 ) # abort with exit code
} # done with no strings found that *could be* arguments
"First putative argument: [" + $args[0] + "]" # emit the first argument-looking string
# Step 2: look for an argument that is actually meaningful
$strArg = ArgNonEmtFstGet( $args ) # get the first non-empty argument; that is our input
If( $strArg -eq "" ) { # when it is not a usable argument
Write-Output "Non-empty argument required." # emit error message for 'no real arguments found'
Exit( 2 ) # abort with exit code
} # done with no usable arguments found
"First non-empty argument: [$strArg]" # emit the first valid argument; this is our input
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…