What I want is a combo of a switch parameter and a string parameter.
Where there are 3 scenarios (not just 2):
- -log not given
- -log given, default filename
- -log filename given
All these states could exist, but I think powershell prevents them.
You can get the first 2 with a [switch]
parameter.
You can get 1 and 3 with a [string]$log = 'default'
But I see no way to get all 3.
One use-case is simple and commonplace. I want to either turn a log file on or off, and either let the script use a default logfile or provide my own. Simple. Easy. But I can't figure out how. (I can figure out several workarounds, but no direct way in the language as currently defined.)
One might think that [AllowNull()]
would allow -log
with no value, but it does not. It only allows -log $null
(as called from powershell; called from other contexts, who knows?) (And anyway powershell turns the null into an empty string)
Another way to state this is that while powershell permits Mandatory and non-Mandatory parameters, all parameter values are Mandatory (if the parameter is provided and is not a switch) and there's no way to turn that off.
I believe the following code would work if powershell would not object to the parameters given. But powershell does in fact object (throws an error).
Function Test-Func {
Param(
[string]$log = 'default_logfile.log'
)
$do_log = 'uninit'
if ($PSBoundParameters.ContainsKey('log')) {
$do_log = $true
'-log provided' | Tee-Object -Append $log
}
else {
$do_log = $false
'-log not provided' # no Tee-Object
}
$msg = "log='$log'"
$msg
if ($do_log) {
$msg | Out-File -Append $log
}
}
'1'
Test-Func
'2'
Test-Func -log 'myfile.log'
'3'
Test-Func -log # Error: Test-Func : Missing an argument for parameter 'log'.
# I want it to use the default_logfile in this case.
Above code produces the output:
1
-log not provided
log='default_logfile.log'
2
-log provided
log='myfile.log'
3
Test-Func : Missing an argument for parameter 'log'. Specify a parameter of type 'System.String' and try again.
At F:\tech\windows_10\powershell\args_arguments_parameters_example_advanced_no_value_post.ps1:26 char:11
+ Test-Func -log # Error: Test-Func : Missing an argument for ...
+ ~~~~
+ CategoryInfo : InvalidArgument: (:) [Test-Func], ParameterBindingException
+ FullyQualifiedErrorId : MissingArgument,Test-Func
and myfile.log
contains:
-log provided
log='myfile.log'
and default_logfile.log
is not created.
EDIT:
The duplicate question has a thorough discussion on this. Contemplates a syntax of -log:value
using the :
char like a switch.
Why?
Because otherwise if parameter values were optional, how would you tell if the next string is a parameter value to -log
or a value for the next parameter, as this code shows.
Function Test-Func {
Param(
[string]$log = 'default_logfile.log'
,
[string]$confounding_param
)
$do_log = 'uninit'
if ($PSBoundParameters.ContainsKey('log')) {
$do_log = $true
'-log provided' | Tee-Object -Append $log
}
else {
$do_log = $false
'-log not provided' # no Tee-Object
}
$msg = "log='$log' confounding_param='$confounding_param'"
$msg
if ($do_log) {
$msg | Out-File -Append $log
}
}
'1'
Test-Func
'2'
Test-Func -log 'myfile.log'
'3'
Test-Func -log # Error: Test-Func : Missing an argument for parameter 'log'.
# I want it to use the default_logfile in this case.
'4'
Test-Func -log 'confounding param string' # how can you tell if the next param is a value of -log or the next param
'5'
Test-Func -log -confounding_param 'confounding param string' # this is how can you tell but then the named param is mandatory in this case which is not ideal
$whoops_logfile = 'confounding param string'
if (Test-Path $whoops_logfile) {
dir $whoops_logfile
del -Verbose $whoops_logfile
}
produces the output:
1
-log not provided
log='default_logfile.log' confounding_param=''
2
-log provided
log='myfile.log' confounding_param=''
3
Test-Func : Missing an argument for parameter 'log'. Specify a parameter of type 'System.String' and try again.
At F:\tech\windows_10\powershell\args_arguments_parameters_example_advanced_no_value_post.ps1:28 char:11
+ Test-Func -log # Error: Test-Func : Missing an argument for ...
+ ~~~~
+ CategoryInfo : InvalidArgument: (:) [Test-Func], ParameterBindingException
+ FullyQualifiedErrorId : MissingArgument,Test-Func
4
-log provided
log='confounding param string' confounding_param=''
5
Test-Func : Missing an argument for parameter 'log'. Specify a parameter of type 'System.String' and try again.
At F:\tech\windows_10\powershell\args_arguments_parameters_example_advanced_no_value_post.ps1:33 char:11
+ Test-Func -log -confounding_param 'confounding param string' # this ...
+ ~~~~
+ CategoryInfo : InvalidArgument: (:) [Test-Func], ParameterBindingException
+ FullyQualifiedErrorId : MissingArgument,Test-Func
Directory: C:\Users\techuser199
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 10/21/2024 9:46 PM 534 confounding param string
VERBOSE: Performing the operation "Remove File" on target "C:\Users\techuser199\confounding param string".