Using BorderAround emits "True" to the console.
$range = $sum_wksht.Range('B{0}:G{0}' -f ($crow))
$range.BorderAround(1, -4138)
This can be overcome by using one of the following.
$wasted = $range.BorderAround(1, -4138)
[void]$range.BorderAround(1, -4138)
Why is this needed? Am I not creating the range correctly? Is there a better workaround?
It is needed, because the
BorderAround
method has a return value and, in PowerShell, any command or expression...
that outputs (returns) data is implicitly output to the (success) output stream, which by default goes to the host, which is typically the console window (terminal) in which a PowerShell session runs.That is, the data shows in the console/terminal, unless it is:
$var = ...
)... | ...
; the last pipeline segment's command may or may not produce output itself)... >
)or any combination thereof.
That is:
is (more efficient) shorthand for:
(Explicit use of
Write-Output
is rarely needed.)Since you don't want that output, you must suppress it, for which you have several options:
$null = ...
[void] (...)
... > $null
... | Out-Null
$null = ...
may be the best overall choice, because:[void] = (...)
does that too, but often requires you to enclose the rest of the statement in(...)
for syntactic reasons; e.g.,[void] 1 + 2
doesn't work as intended, only[void] (1 + 2)
$null = Get-AdUser ...
) and expression output (e.g.,$null = $range.BorderAround(1, -4138)
).Conversely, avoid
... | Out-Null
, because it is generally much slower (except with expression output in PowerShell Core).However, if you need to silence all output streams - not just the success output, but also errors, verbose output, ... - you must use
*> $null
Why does PowerShell produce output implicitly?
As a shell, PowerShell's output behavior is based on streams, as in traditional shells such as
cmd.exe
or Bash. (While traditional shells have 2 output streams - stdout and stderr - PowerShell has 6, so as to provide more sophisticated functionality - see about_Redirection.)A cmdlet, script, or function can write to the output streams as often as it wants, and such output is usually instantly available for display but notably also to potential consumers, which enables the streaming, one-by-one processing that the pipeline provides.
This contrasts with traditional programming languages, whose output behavior is based on return values, typically provided via the
return
keyword, which conflates output data (the return value) with flow control (exit the scope and return to the caller).return
statement to act the same, but it doesn't:return <val>
is just syntactic sugar for<val>; return
, i.e., implicit output of<val>
followed by an unconditional return of control to the caller; notably, the use ofreturn
does not preclude generation of output from earlier statements in the same scope.Unlike traditional shells, PowerShell doesn't require an explicit write-to-the-output stream command in order to produce output:
While PowerShell does have a counterpart to
echo
, namelyWrite-Output
, its use is rarely needed.Write-Output
is useful is preventing enumeration of a collection on output with-NoEnumerate
, or to use common parameter-OutVariable
to both output data and capture it in a variable (which is generally only needed for expressions, because cmdlets and advanced functions / scripts themselves support-OutVariable
).The implicit output behavior:
is generally a blessing:
[IO.Path]::GetExtension('foo.txt')
and[math]::Pow(2, 32)
- and see its output (akin to the behavior of a REPL).can occasionally be a pitfall:
for users accustomed to the semantics of traditional programming languages.
due to the potential for accidental pollution of the output stream from statements that one doesn't expect to produce output, such as in your case; a more typical example is the
.Add()
method of the[System.Collections.ArrayList]
class unexpectedly producing output.Example:
The above yields the following:
This demonstrates the streaming aspect of the behavior:
Get-HexNumber
's output is available to theForEach-Object
cmdlet call as it is being produced, not afterGet-HexNumber
has exited.