Invoke-Command with parameters (exe file)

Rather simple example I would think - but the Microsoft documentation does not help.
So this is my 3rd version of this simple thing.

My goal is to run an EXE with a lot of command line parameters from power shell.
The specific command is CMAKE… My powershell script snippit looks like this


# GENERATE cmake cmd line arguments in a list.
$ALIST=@()
$ALIST += "-G""Eclipse CDT4 - Unix Makefiles"""
$ALIST += "-DCONFIG_APP_NAME=${APP_NAME}"
$ALIST += "-B"
$ALIST += "${THIS_BUILD_DIR}"
$ALIST += "-S"
$ALIST += "."
Invoke-command "cmake" -ArgumentList $ALIST | Tee-object -file-path $THIS_CMAKE_LOG_FILENAME 

When I run this (step through the code) using the ISE…
I get this error message, I don’t understand why.

Invoke-Command : Parameter set cannot be resolved using the specified named parameters.
At C:\Work\supervisor\common\tools\sc_windows\cmake_common.ps1:36 char:1
+ Invoke-command "cmake" -ArgumentList $ALIST | Tee-object -file-path $ ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [Invoke-Command], ParameterBindingException
    + FullyQualifiedErrorId : AmbiguousParameterSet,Microsoft.PowerShell.Commands.InvokeCommandCommand

I am getting frustrated, i have also tried a giant long string - the string works if I copy/paste the string into the cmd.exe window…
ie: the command line would be:

cmake -G"Eclipse CDT4 - Unix Makefiles" -DNAME=VALUE -B c:\some\dir -S .

There are about 10 examples on the Rather USELESS example site: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/invoke-command?view=powershell-7.4

It does not even show an example of running an EXE with parameters.
It only shows executing a POWER SHELL command thing only.

I’ve not used Invoke-Command for running non-Powershell things. I think you might want to investigate Start-Process, Invoke-Expression or the Call operator
https://ss64.com/ps/call.html

I disagree with this advice. Unless you have a specific reason to, don’t involve any additional process/command. OP says he calls it in CMD like this

cmake -G"Eclipse CDT4 - Unix Makefiles" -DNAME=VALUE -B c:\some\dir -S .

And there is no reason to make it any more complicated than this in powershell. Meaning you just call the executable directly. Now if it does have spaces in the path, you will need to use the call operator, but for your example it should not be needed. Simply try the same in powershell.

cmake -G"Eclipse CDT4 - Unix Makefiles" -DNAME=VALUE -B c:\some\dir -S .

You may have to add quotes around each argument. If you want to “paramaterize” the arguments, I would use splatting for this.

$argumentlist = "-G",
                "Eclipse CDT4 - Unix Makefiles",
                "-DCONFIG_APP_NAME=${APP_NAME}",
                "-B",
                "${THIS_BUILD_DIR}",
                "-S",
                "."

cmake @argumentlist

If you do need the first argument to be one, just escape the inner quotes

$argumentlist = "-G`"Eclipse CDT4 - Unix Makefiles`"",
                "-DCONFIG_APP_NAME=${APP_NAME}",
                "-B",
                "${THIS_BUILD_DIR}",
                "-S",
                "."

cmake @argumentlist

As FYI - There’s more I’m trying to do

a) Capture both STDOUT and STDERR into ONE - not separate files.
(All examples I see are separate files, i want one file)
It is important that both are together - intermingled and a single file.

  1. I need both STDOUT and STDERR - (a) on the console and (b) in a single file.
    combined as above.

  2. Detect a failure (exit condition) so I can stop processing with a REASONABLE error message (specifically not the way powershell pukes on an error)

  3. I need to be in a specific working directory when the to is run.

  4. I need to provide a MODIFIED path environment when executing the command.
    The existing (previous) PATH variable must remain as it was before this command.
    (WHY? I have about 6 different tool chains on my machine, each tool chain wants to be the exclusive tool set in the PATH otherwise things just go south in bad ways, the solution is to set the PATH in the script when we execute the tools)

Also - how would I use “splating” and designate some @arguments for “Invoke-command” - verses arguments for the child process.

There does not seem to be a way to do that other then with the -arguments option

You can still use Tee-Object running it natively, so nothing should change there. For native executables error handling you can use

$ErrorActionPreference = 'Stop'

$argumentlist = "-G`"Eclipse CDT4 - Unix Makefiles`"",
                "-DCONFIG_APP_NAME=${APP_NAME}",
                "-B",
                "${THIS_BUILD_DIR}",
                "-S",
                "."

try{
    cmake @argumentlist | Tee-object -file-path $THIS_CMAKE_LOG_FILENAME
}
catch{
    # An error occurred, handle it how you would like here. 
    # The error details will be in $_ as well as the last entry in $error
    # You can also use $LastExitCode to determine the disposition
}

You may need to combine streams depending how cmake outputs stdout/stderr. If you still see errors (red text) written to the screen instead of your catch code, add 2>&1 like this

$ErrorActionPreference = 'Stop'

$argumentlist = "-G`"Eclipse CDT4 - Unix Makefiles`"",
                "-DCONFIG_APP_NAME=${APP_NAME}",
                "-B",
                "${THIS_BUILD_DIR}",
                "-S",
                "."

try{
    cmake @argumentlist 2>&1 | Tee-object -file-path $THIS_CMAKE_LOG_FILENAME
}
catch{
    # An error occurred, handle it how you would like here. 
    # The error details will be in $_ as well as the last entry in $error
    # You can also use $LastExitCode to determine the disposition
}

If you insist on going out of process, I would recommend Start-Process

$processParams = @{
    FilePath     = 'cmake.exe'

    ArgumentList = "-G",
                    "Eclipse CDT4 - Unix Makefiles",
                    "-DCONFIG_APP_NAME=${APP_NAME}",
                    "-B",
                    "${THIS_BUILD_DIR}",
                    "-S",
                    "."

    PassThru     = [switch]::Present

    Wait         = [switch]::Present
}
try{
    $result = Start-Process @processParams -ErrorAction Stop 

    if($result.ExitCode -eq 0){
        # process executed successfully
    }
    else{
        # process completed with error condition
    }
}
catch{
    # process had a terminating error
}

$result | Tee-object -file-path $THIS_CMAKE_LOG_FILENAME

As an FYI for others - I gave up on this entire method.

Instead, I create a text file (aka: BATCH script)

I focused 100% instead on creating a simple BATCH file.
The BATCH file does all redirection, everything - it just works.

Then I Execute the BATCH FILE no parameter quoting etc in powershell.

The added advantage is: I can manually re-run the batch file to debug things.

I could go into a RANT about how this powershell works - it might well work for a windows data center - but for normal things you might need to [in my world] - it is horrible.

You can create a simple powershell script too. Glad you got your task completed.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.