Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Conditionally piping to Out-Null

Tags:

powershell

I'm writing a PowerShell script to msbuild a bunch of solutions. I want to count how many solutions build successfully and how many fail. I also want to see the compiler errors, but only from the first one that fails (I'm assuming the others will usually have similar errors and I don't want to clutter my output).

My question is about how to run an external command (msbuild in this case), but conditionally pipe its output. If I'm running it and haven't gotten any failures yet, I don't want to pipe its output; I want it to output directly to the console, with no redirection, so it will color-code its output. (Like many programs, msbuild turns off color-coding if it sees that its stdout is redirected.) But if I have gotten failures before, I want to pipe to Out-Null.

Obviously I could do this:

if ($SolutionsWithErrors -eq 0) {
    msbuild $Path /nologo /v:q /consoleloggerparameters:ErrorsOnly
} else {
    msbuild $Path /nologo /v:q /consoleloggerparameters:ErrorsOnly | Out-Null
}

But it seems like there's got to be a way to do it without the duplication. (Okay, it doesn't have to be duplication -- I could leave off /consoleloggerparameters if I'm piping to null anyway -- but you get the idea.)

There may be other ways to solve this, but for today, I specifically want to know: is there a way to run a command, but only pipe its output if a certain condition is met (and otherwise not pipe it or redirect its output at all, so it can do fancy stuff like color-coded output)?

like image 666
Joe White Avatar asked Jun 07 '15 13:06

Joe White


1 Answers

You can define the output command as a variable and use either Out-Default or Out-Null:

# set the output command depending on the condition
$output = if ($SolutionsWithErrors -eq 0) {'Out-Default'} else {'Out-Null'}

# invoke the command with the variable output
msbuild $Path /nologo /v:q /consoleloggerparameters:ErrorsOnly | & $output

UPDATE

The above code loses MSBuild colors. In order to preserve colors and yet avoid duplication of code this approach can be used:

# define the command once as a script block
$command = {msbuild $Path /nologo /v:q /consoleloggerparameters:ErrorsOnly}

# invoke the command with output depending on the condition
if ($SolutionsWithErrors -eq 0) {& $command} else {& $command | Out-Null}

is there a way to run a command, but only pipe its output if a certain condition is met (and otherwise not pipe it or redirect its output at all, so it can do fancy stuff like color-coded output)?

There is no such a way built-in, more likely. But it can be implemented with a function and the function is reused as such a way:

function Invoke-WithOutput($OutputCondition, $Command) {
    if ($OutputCondition) { & $Command } else { $null = & $Command }
}

Invoke-WithOutput ($SolutionsWithErrors -eq 0) {
    msbuild $Path /nologo /v:q /consoleloggerparameters:ErrorsOnly
}
like image 69
Roman Kuzmin Avatar answered Nov 09 '22 02:11

Roman Kuzmin