I have the below code line, in a script that iterates through things to install from a repository. Some things have arguments, some don't. Have come across one that doesn't, and trying to avoid having the same command more or less duplicated (along with all the error checking, etc) in a for...else command. Is there anyway to have start-process work with a $null/empty variable specified after -argumentlist
that I am not thinking about?
for($i=0; $i -lt $Installs.count; $i++)
{
$Arguments = $($Installs[$i].path)
start-process -filepath $Path -argumentlist $Arguments -wait
}
Your symptom suggests that you're using Windows PowerShell (the legacy, ships-with-Windows, Windows-only edition of PowerShell whose latest and last version is 5.1), where Start-Process
's -ArgumentList
parameter inexplicably doesn't accept $null
, @()
(an empty array / enumerable) or ''
(the empty string).
Fortunately, this unhelpful constraint has been removed in PowerShell (Core) 7, which now interprets any of these inputs as the signal to pass no arguments, i.e. to behave the same as if -ArgumentList
hadn't been specified at all.
However, the splatting technique described in Santiago's answer alone is not enough for a robust solution:
Start-Process
bug that won't be fixed (see GitHub issue #5565) unfortunately requires use of embedded double-quoting around arguments that contain spaces, e.g. -ArgumentList '-foo', '"bar baz"'
Therefore, use the following:
for ($i = 0; $i -lt $Installs.count; $i++)
{
# Create a hashtable for splatting that originally just contains
# a value for the -FilePath and -Wait parameters.
$splat = @{
FilePath = $Path
Wait = $true
}
# Only add an 'ArgumentList' entry if an install path was given.
if ($installPath = $Installs[$i].Path) {
# Enclose the install path in "..." if it contains a space.
$splat.ArgumentList =
($installPath, "`"$installPath`"")[$installPath -match ' ']
}
Start-Process @splat
}
Note:
The ($installPath = $Installs[$i].Path)
conditional:
Assigns the value of $Installs[$i].Path
to helper variable $installPath
...
... and - due to enclosure of the assignment in (...)
) - outputs the assigned value, which is then tested using implicit to-Boolean coercion:
The value is assumed to be a string, and PowerShell coerces any nonempty string to $true
, so that if ($Installs[$i].Path)
is in effect shorthand for if ('' -ne $Installs[$i].Path)
($installPath, "`"$installPath`"")[$installPath -match ' ']
is an approximation of a ternary conditional, that is, in effect, short for:
if ($installPath -match ' ') { "`"$installPath`"" } else { $installPath }
; see this answer for details.
$installPath -match ' ' ? "`"$installPath`"" : $installPath