'How to escape the following regex, so its usable in PowerShell?
As far as I know, there is no way in PowerShell to execute an exe with parameters specified in a variable and direct the return of the exe into a variable. Therefore I am currently writing a small function to make this possible. But now I am stuck at the point that the parameters have to be passed individually when calling with &. (This is not necessary for all programs, but some programs cause problems if you pass all parameters as a string in a variable) Therefore I want to use a split to write the parameters passed to my function into an array. And then pass the array with the parameters in my exe call.
For this I have the following regex:
[^\s"']+|"([^"]*)"|'([^']*)'
This regex allows that single and double quotes are taken into account when passing parameters and that a text with spaces inside them is not split.
But unfortunately I don't have the slightest idea how to best escape this regex so that it doesn't cause any problems in the PowerShell script.
Here then still my function to make it a little easier to understand:
The function executes the file passed in the $Path parameter with the parameters from the $Arguments. Before the execution i try to split the $Arguments with the regex. As return of the function, you get an object with the ExitCode and the output of the executed file. Here you can see my attempt, but the quotes cause problems with the following code.
function Invoke-Process ($Path,$Arguments){
[PsObject[]] $ReturnValue = @()
$Params=$Arguments -split([regex]::escape([^\s"']+|"([^"]*)"|'([^']*)'))
$ExCode = 0
try {
$ProcOutput = & $Path $Params | out-string
}catch{
$ProcOutput = "Failed: $($_.Exception.Message)"
$ExCode = 1
}
$ReturnValue += [PsObject]@{ ExitCode = $ExCode; Output = $ProcOutput}
Return $ReturnValue
}
The function is called as follows:
$ExePath = "C:\arcconf\arcconf.exe"
$ExeParams = "getconfig 1"
$Output = Invoke-Process $ExePath $ExeParams
I hope you can understand my problem. I am also open to other ways of writing the function.
Greetings
Solution 1:[1]
Mathias R. Jessen's helpful answer answers your immediate question well.
Taking a step back:
there is no way in PowerShell to execute an exe with parameters specified in a variable and direct the return of the exe into a variable
No: PowerShell does support both of those things:
$output = someExternalProgram ...captures the stdout output from an external program in variable$output; use redirection2>&1to also capture stderr output; use>$nullor2>$nullto selectively discard stdout or stderr output - see this answer for details.someExternalProgram $someVariable ...passes the value of variable$someVariableas an argument to an external program; if$someVariableis an array (collection) of values, each element is passed as a separate argument. Instead of a variable reference, you may also use the output from a command or expression, via(...); e.g.,someExternalProgram (1 + 2)passes3as the argument - see this answer for details.Note: An array's elements getting passed as individual arguments only happens for external programs by default; to PowerShell-native commands, arrays are passed as a whole, as a single argument - unless you explicitly use splatting, in which case you must pass
@someVariablerather than$someVariable. For external programs,@someVariableis effectively the same as$someVariable. While array-based splatting also works for PowerShell-native commands, for passing positional arguments only, the typical and more robust and complete approach is to use hashtable-based splatting, where the target parameters are explicitly identified.A general caveat that applies whether or not you use variables or literal values as arguments: Up to at least PowerShell 7.2.x, passing empty-string arguments or arguments with embedded
"chars. to external programs is broken - see this answer.
With the above in mind you can rewrite your function as follows, which obviates the need for - ultimately brittle - regex parsing:
function Invoke-Process {
# Split the arguments into the executable name / path and all
# remaining arguments.
$exe, $passThruArgs = $args
try {
# Call the executable with the pass-through arguments.
# and capture its *stdout* output.
$output = & $exe @passThruArgs
$exitCode = $LASTEXITCODE # Save the process' exit code.
} catch {
# Note: Only If $exe is empty or isn't a valid executable name or path
# does a trappable statement-terminating error occur.
# By contrast, if the executable can be called in principle, NO
# trappable error occurs if the process exit code is nonzero.
$exitCode = 127 # Use a special exit code
$output = $_.ToString() # Use the exception message
}
# Construct and output a custom object containing
# the captured stdout output and the process' exit code.
[pscustomobject] @{
ExitCode = $exitCode
Output = $output
}
}
Sample calls:
Invoke-Process cmd /c 'echo hi!'
# Equivalent, using an array variable for the pass-through arguments.
$argsForCmd = '/c', 'echo hi!'
Invoke-Process cmd @argsForCmd
Note:
Since
Invoke-Processis a PowerShell command, splatting (@argsForCmd) is necessary here in order to pass the array elements as individual arguments, which inside the function are then reflected in the automatic$argsvariable variable.The automatic
$argsvariable is only available in simple functions, as opposed to advanced ones, which behave like cmdlets and therefore automatically support additional features, such as common parameters; to make your function and advanced one, replace the line$exe, $passThruArgs = $argsat the top of the function with the following:
[CmdletBinding()]
param(
[Parameter(Mandatory)]
[string] $exe,
[Parameter(ValueFromRemainingArguments)]
[string[]] $passThruArgs
)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
