Start process, wait for it, and throw away all output - powershell

I'd like to do this in PowerShell:
myprogram.exe arg1 arg2 >nul 2>nul
How does it work? There are like a million options to start processes in PowerShell, it's impossible to know the right one you need at a time.

nul is a special device (see this answer on SuperUser for instance) that's available in CMD, but not in PowerShell. In PowerShell you can use $null instead. Starting with PowerShell v3 you can use *> to redirect all output streams, but since you want to redirect output from an external program there should only be output on STDOUT and STDERR (Success and Error output stream in PowerShell terms), so >$null 2>$null should be fine.
A notable difference between CMD and PowerShell is that PowerShell doesn't include the current working directory in the PATH (the list of directories that is searched when you call a program/script without a path). If you want to run myprogram.exe from the current directory you need to prepend it with the path to the current directory (./).
You may also want to use the call operator (&). Although it's not required in this particular case I consider using it good practice. If you specify the command as a string (for instance because the path or filename contains spaces, or you want to use a variable instead of a literal) you MUST use the call operator, otherwise the statement would throw an error.
Something like this
& ./myprogram.exe arg1 arg2 >$null 2>$null
or like this
& ./myprogram.exe arg1 arg2 *>$null
should work.

Related

Avoid Line break at end of cmd output?

when I use this command pwsh -c echo hello in cmd I get the following output:
C:\>pwsh -c echo hello
hello
C:\>
I do not get that line break at the end
when I run it on powershell:
PS C:\> pwsh -c echo hello
hello
PS C:\>
So I think the problem is in cmd. I know this is not such a problem and have an easy fix but I have some programs uses cmd to access powershell and removing that line break is not that fun.
So is there any fix to prevent cmd to add that line ?
Mofi has provided the crucial pointers in comments:
When executing a command interactively, cmd.exe unconditionally appends a a newline (line break) to the command's output, presumably for readability and perhaps also to ensure that the next prompt always starts on a new line.
This applies irrespective of what that command is. In other words: It doesn't matter that your command happens to be a PowerShell command.
However, that trailing newline does not become part of the command's output, therefore programmatic processing of a command's output is not affected, such as when you redirect > to a file or process the output lines one by one with for /f.
In other words: for programmatic processing you need not remove the trailing newline, because it isn't part of the actual command output.
Conversely, if you really need to in effect suppress the trailing newline for display, you'll have to modify the command's output - if that is even an option - so that the output itself doesn't end in a newline, as shown in this SuperUser answer for cmd.exe's own echo command; for PowerShell, you could do pwsh -c Write-Host -NoNewLine hello.
Edge case:
When capturing output from a batch file that is running without #echo off (or with echo on) - in which case the trailing newlines do become part of the output - you can filter out empty lines by piping to findstr /r /v /c:"^$" (as also shown in the linked answer); e.g.
foo.cmd | findstr /r /v /c:"^$"
However, note that all empty lines are filtered out this way - potentially including actual empty lines in the output from commands executed by the batch file.
If preventing that is required, a more sophisticated approach is required, which, however (a) relies on the standard prompt string (e.g., C:\>) being used and (b) can still yield false positives:
foo.cmd | powershell -nop -c "#($Input) -join \"`n\" -replace '\n(?=[a-z]:\\.*?>)'"
Finally note that if you execute the above commands without capturing or redirecting their output, their overall output in the cmd.exe console will again have a trailing newline.

Passing a semicolon as a parameter to a .bat file from both cmd and PowerShell

This question seems to be rather simple, but even after searching the web for a couple of hours, I was not able to find a solution...
I have a batch file test.bat
set MY_VARIABLE=%~1
echo %MY_VARIABLE%
The point is that I want to call this programm with a semicolon as input parameter, i.e.,
.\test.bat ";",
from both cmd and Windows PowerShell. While this works fine from cmd, PowerShell does not seem to get anything as an input. Is there any way to make this work for both simultaneously?
This is because of command line syntax. The semicolon is one of multiple delimiters, that split the command line into words: a;b would be interpreted as two separate arguments a (%1) and b (%2).
Therefore, quotes are required. Since Powershell uses quotes for string literals (Powershell does its own re-quoting behind the scenes when passing arguments), you need to include them in the string:
.\test.bat '";"'
# or
.\test.bat "`";`""
Or as #mklement0 pointed out, the stop-parsing symbol --% would also be an option:
.\test.bat --% ";"
Note that this is specific to Powershell syntax.
In CMD, this will suffice:
test.bat ";"

Cannot pass asterisk character to external command via powershell

I cannot pass an asterisk character to external command using powershell
I use following a line like
& .\args.bat #("-arg1", "-arg2", "*.test.com")
where args.bat just dumps passed arguments
#ECHO off
ECHO The %~nx0 script args are...
for %%I IN (%*) DO ECHO %%I
And instead of passing "*.test.com" it lookups up current directory for files matching pattern "*.test.com" and sends list of them to args.bat
That can be seen if you use "*" instead of "*.test.com"
I've also tried back tick character to escape asterisk, but it didn't help
In my case using asterisk is required as I'm passing it to makecert.exe to create wildcard domain certificate
Please help
I'm not seeing that. As a test I created args.bat like so:
'pause' > args.bat
Then executed it:
& .\args.bat #("-arg1", "-arg2", "*.ps1")
When I look in task manager at the command line for that cmd.exe, I see:
It must be something the batch file is doing because PowerShell is doing nothing to your *. BTW I used *.ps1 because the directory I executed from had a ton of ps1 files in it.
If you are PS 3.0 or higher you can use "stop parsing operator" --%. See help about_parsing for details.

What is correct syntax with depend parameter flag in Windows Powershell?

I am using Windows PoweShell to submit jobs to a high performance cluster, and I'm having a problem with the depend parameter flag. I cannot post the actual code as it would probably get me in trouble at work so here's the gist:
job add $jobid /scheduler:xxxxx /name:task1 /workdir:M:\dir foo.exe "foo" -logfile task1.log
job add $jobid /scheduler:xxxxx /name:task2 /workdir:M:\dir foo.exe "foo" -logfile task2.log
job add $jobid /scheduler:xxxxx /name:task3 \depend:task1,task2 /workdir:M:\dir foo.exe "foo" -logfile task1.log
The problem occurs when it hits task2 in \depend:task1,task2. If I skip task2 and remove it from the depend statement, then everything is fine. Maybe I need some sort of brackets or whatnot to indicate that I'm giving a list, rather than a single parameter, to the depend flag.
What's the proper syntax for this?
I'm going out on a limb here, but task1,task2 is most likely interpreted as a PowerShell array and /depend probably doesn't accept that as input (or just the first array element). Try putting the list in double quotes:
job add $jobid /scheduler:xxxxx /name:task3 /depend:"task1,task2" ...
or using the magic parameter (if you're using PowerShell v3 or newer):
job add $jobid --% /scheduler:xxxxx /name:task3 /depend:task1,task2 ...

How do I pass an equal sign when calling a batch script in Powershell?

We have a batch file that invokes our MSBuild-based build process. Syntax:
build App Target [ Additional MSBuild Arguments ]
Internally, it does this:
msbuild.exe %1.msbuild /t:%2 %3 %4 %5 %6 %7 %8 %9
Which results in calls to MSBuild that look like this:
msbuild.exe App.msbuild /t:Target
When any argument contains the equal sign, =, Powershell completely removes it. My batch script never sees it. This does not happen with the standard cmd.exe command prompt.
For example, if I call
build App Target "/p:Property=Value"
this is what gets passed to MSBuild:
msbuild.exe App.msmbuild /t:Target /p:Property Value
I expected this:
msbuild.exe App.msbuild /t:Target "/p:Property=Value"
I've tried the Powershell escape character, the standard Command Prompt escape character, and even stuff I made up:
build App Target "/p:Property=Value"
build App Target '/p:Property=Value'
build App Target /p:Property^=Value
build App Target /p:Property`=Value
build App Target /p:Property==Value
None of it works. What do I do to get the equal sign to not be stripped out or removed?
I've seen this before and have found a way to trick it out. I wish I could explain what's going on in particular with the '=' but I cannot. In your situation I'm fairly certain the following will work if you want to pass properties to msbuild:
build App Target '"/p:Property=Value"'
When echoed, this produces the following:
msbuild.exe App.msbuild /t:Target "/p:Property=Value"
With PowerShell 3 you can use --% to stop the normal parsing powershell does.
build --% App Target "/p:Property=Value"
I don't know if there's an easier answer (I think not) but you can solve the problem by using .Net's process class to invoke cmd.exe. Here's an example:
# use .NET Process class to run a batch file, passing it an argument that contains an equals sign.
# This test script assumes the existence of a batch file "c:\temp\test.bat"
# that has this content:
# echo %1
# pause
$cmdLine = $cmdLine = '/c c:\temp\test.bat "x=1"'
$procStartInfo = new-object System.Diagnostics.ProcessStartInfo("cmd", $cmdLine )
$proc = new-object System.Diagnostics.Process
$proc.StartInfo = $procStartInfo
$proc.Start();
Have you tried single quotes to force a literal interpretation?
Or:
cmd /c 'msbuild.exe App.msbuild /t:Target "/p:Property=Value"'
It seems that only single-quote around double-quote might be the best for multiple scenario around windows environment.
Following link from MS shows its support(or limitation) of equal sign
http://support.microsoft.com/kb/35938
It is specific to Batch Files but it likely affect lots of other MS shell products.
The answer is that %2 becomes "/p:property" and %3 becomes "value".
Make this work in your batch file by using BOTH %2 and %3 and insert an = sign between them:
msbuild.exe %1.msbuild /t:%2=%3 %4 %5 %6 %7 %8 %9
and do not use the quote chars on the command line call. Use:
build App Target /p:property=value
For additional args with = signs just keep pairing them up.
I had the same issue with a simple batch file to run youtube-dl where the URL I pass has an = sign in it.
solved as :
#echo off
REM YTDL audio only
echo %1=%2
youtube-dl -f bestaudio --extract-audio --audio-format mp3 --audio-quality 0 %1=%2