PowerShell - Start-Process and Cmdline Switches - command-line

I can run this fine:
$msbuild = "C:\WINDOWS\Microsoft.NET\Framework\v3.5\MSBuild.exe"
start-process $msbuild -wait
But when I run this code (below) I get an error:
$msbuild = "C:\WINDOWS\Microsoft.NET\Framework\v3.5\MSBuild.exe /v:q /nologo"
start-process $msbuild -wait
Is there a way I can pass parameters to MSBuild using start-process? I'm open to not using start-process, the only reason I used it was I needed to have the "command" as a variable.
When I have
C:\WINDOWS\Microsoft.NET\Framework\v3.5\MSBuild.exe /v:q /nologo
on a line by itself, how does that get handled in Powershell?
Should I be using some kind of eval() kind of function instead?

you are going to want to separate your arguments into separate parameter
$msbuild = "C:\WINDOWS\Microsoft.NET\Framework\v3.5\MSBuild.exe"
$arguments = "/v:q /nologo"
start-process $msbuild $arguments

Using explicit parameters, it would be:
$msbuild = 'C:\WINDOWS\Microsoft.NET\Framework\v3.5\MSBuild.exe'
start-Process -FilePath $msbuild -ArgumentList '/v:q','/nologo'
EDIT: quotes.

Warning
If you run PowerShell from a cmd.exe window created by Powershell, the 2nd instance no longer waits for jobs to complete.
cmd> PowerShell
PS> Start-Process cmd.exe -Wait
Now from the new cmd window, run PowerShell again and within it start a 2nd cmd window:
cmd2> PowerShell
PS> Start-Process cmd.exe -Wait
PS>
The 2nd instance of PowerShell no longer honors the -Wait request and ALL background process/jobs return 'Completed' status even thou they are still running !
I discovered this when my C# Explorer program is used to open a cmd.exe window and PS is run from that window, it also ignores the -Wait request.
It appears that any PowerShell which is a 'win32 job' of cmd.exe fails to honor the wait request.
I ran into this with PowerShell version 3.0 on windows 7/x64

I've found using cmd works well as an alternative, especially when you need to pipe the output from the called application (espeically when it doesn't have built in logging, unlike msbuild)
cmd /C "$msbuild $args" >> $outputfile

Unless the OP is using PowerShell Community Extensions which does provide a Start-Process cmdlet along with a bunch of others. If this the case then Glennular's solution works a treat since it matches the positional parameters of pscx\start-process : -path (position 1) -arguments (positon 2).

Related

Get return of cmd.exe exit

I develop a PowerShell application. I use for example
Start-Process "cmd.exe" "/c some_command"
#rest of the source code
But when I run this, it is not waiting for cmd.exe to close before executing the rest of the source code.
How can I get cmd.exe "exit event" return to continue to run my PowerShell script?
Or other way to sleep PowerShell script while cmd.exe is running?
I found the answer is to use -wait
Start-Process "cmd.exe" "/c some_command" -wait
You can invoke CMD directly from PowerShell:
cmd.exe /c some_command
In case the executable is provided as a string rather than a bare word you must prefix the statement with the call operator (otherwise using the operator is optional):
& 'cmd.exe' /c some_command
This kind of invocation automatically runs synchronously.
Start-Process invocation is asynchronous by default. You can change the behaviour to synchronous by adding the parameter -Wait.
In addition to using -Wait, you could also check the exit code to verify command success:
[int]$ExitCode = (Start-Process "cmd.exe" "/c some_command" -Wait).ExitCode
# Check exit code
if ($ExitCode -ne 0) {
throw "Something went wrong.
}
This is useful for debugging and checking cmd success.

Calling another executable and capturing output

Using a PowerShell script I'm trying to execute SqlPackage.exe to update a database. The problem is that it spawns a new CMD window and I can't capture the output effectively.
Here is my script:
&$SqlPackage "/Action:Script", "/SourceFile:$($Environment.PackageFile)", "/Profile:$($Environment.PublishProfile)", "/OutputPath:$($Environment.ScriptFile)";
where SqlPackage = "SQLPackage\SqlPackage.exe";.
Strangely when I execute the script on a Windows 2008 R2 web server the output is inline with the PowerShell output, which is ideally what I want. On my Windows 7 machine it spawns a new CMD window.
How can I route the output to the PowerShell window all the time, or at least pipe to another file?
Edit
Full solution with waiting for process to finish:
$p = Start-Process $SqlPackage -ArgumentList #("/Action:Script", "/SourceFile:$($Environment.PackageFile)", "/Profile:$($Environment.PublishProfile)", "/OutputPath:$($Environment.ScriptFile)") -NoNewWindow -Wait -Passthru
$p.WaitForExit()
You should be able to get the result you are looking for if you use Start-Process with the -NoNewWindow parameter:
Start-Process $SqlPackage -ArgumentList #("/Action:Script", "/SourceFile:$($Environment.PackageFile)", "/Profile:$($Environment.PublishProfile)", "/OutputPath:$($Environment.ScriptFile)") -NoNewWindow
If you need to direct the output to a file you can also use the -RedirectStandardOutput / -RedirectStandardError parameters of Start-Process

Invoke-Expression Not Running Command

I am pulling in a text file that was previously created that simply lists the KB numbers for all currently installed Windows Updates. I am trying to pull this file in and call wusa.exe and pass it the KB number to perform an uninstallation.
$a = Get-Content c:\hotfixid.txt
foreach ($kb in $a) {
$command = 'cmd /c wusa.exe /uninstall /kb:' + $kb.Trim().Substring(2) + ' /quiet /norestart'
#Write-Host $command
Write-Host "Currently uninstalling $kb"
Invoke-Expression -Command:$command
}
If I use
Write-Host $command
and copy that directly to a run dialog box in Windows, it completes successfully.
What happens when I run it in a PowerShell script is that it only outputs the Write-Host portions one after the other in about 2 seconds. I do not see any command windows opening and I don't see it actually DOING anything. I am running the PowerShell script 'As Administrator' with an unrestricted execution policy. I have also tried adding 'runas' to the $command to call the CMD window each time with administrative privileges and it made no difference. Calling it via Invoke-Command as well makes no difference.
PowerShell can run most commands directly w/o too much trouble.
Using Invoke-Expression just complicates matters, as does Invoke-Command or Start-Process, because you need to get the quoting right, and pass the arguments in a slightly unnatural way.
You can even skip running cmd.exe most of the time.
Try the following:
wusa.exe /uninstall "/kb:$($kb.Trim().Substring(2))" /quiet /norestart

Debugging a Powershell start-process line

I'm using Powershell's standard ISE to develop a script that, among other things, calls start-process using a pre-defined filepath. Here is the code:
$MSTEST ="C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE\MSTEST.EXE"
$TESTSETTING="D:\Source\Test\DEV\FIREBIRD\QA\LoadTesting\WebTests\perfvsctlr2.testsettings"
$TESTCONTAINER1="D:\Source\Infinity\DEV\FIREBIRD\QA\LoadTesting\WebTests\Test.AppFx.LoadTesting.Test\LoadTestDefs\Test_Interactive_Peak_Workload.loadtest"
start-process $MSTEST -ArgumentList "/Testsetting: $TESTSETTING /Testcontainer: $TESTCONTAINER1 /resultsfile: $RESULTSFILE"
When I pass the variables and then try to manually execute the start-process line from the Powershell prompt it simply opens a window and closes it without displaying the error. So far I've used the -NoNewWindow argument and tried calling Powershell from the Run line with the -noexit argument. So far, no luck.
How is $RESULTSFILE defined?
You shouldn't have a space after the colon (and you generally have to look out for spaces in any of your arguments. You don't seem to have any, but spaces in arguments require proper quoting).
You can get the error message from Start-Process by calling it with some extra arguments (the line below produces an error on purpose):
Start-Process $MSTEST -ArgumentList "\testcontainer: file" -wait -NoNewWindow -RedirectStandardError err -RedirectStandardOutput out

Run powershell in new window

I would like to run new powershell window with parameters. I was trying to run following:
powershell -Command "get-date"
but everything happens in same console. Is there a simple way to do this?
To open a new PowerShell Window from PowerShell:
Start-Process PowerShell
Or my personal favorite:
Start-Process PowerShell -WindowStyle Maximized
Then you could typeGet-Datewithout having to deal with the -ArgumentList's tendency to close itself. I still haven't found a way to open a new PowerShell process with the -ArgumentList Parameter, without it immediately closing after it runs. For Instance:
Start-Process PowerShell -ArgumentList "Get-Date"
or simply
Start-Process PowerShell -ArgumentList Get-Date
Will Close Immediately after running the process.
In order to get it to wait before closing you could add:
Start-Process PowerShell -ArgumentList 'Get-Date; Read-Host "Press Enter"'
Since the -Wait Parameter seems to do nothing at all in this case.
FYI - PowerShell Suggested Syntax is actually:
Start-Process -FilePath "powershell.exe"
But since PowerShell is a standard Windows Application in the %SystemRoot%\system32 Environment Variables the command line(s) should recognize a simple
Powershell
Command
Use the start command. In a CMD prompt, try:
start powershell -noexit -command "get-date"
For Start/Run (or Win+r) prompt, try:
cmd /c start powershell -noexit -command "get-date"
The -noexit will tell Powershell to, well, not to exit. If you omit this parameter, the command will be executed and you are likely to just see a glimpse of a Powershell window. For interactive use, this is a must. For scripts it is not needed.
Edit:
start is an internal command for CMD. In Powershell it is an alias for Start-Process. These are not the same thing.
As for why the window is black, that's because the shortcut for Powershell.exe is configured to set the background blue.
To call a PowerShell (PS) script in a second terminal window without exiting, you can use a script similar to:
Start-Process PowerShell -ArgumentList "-noexit", "get-date"
or if you need to run another script from a specific location:
Start-Process PowerShell -ArgumentList "-noexit", "-command .\local_path\start_server.ps1"