Linux has have stty -echo which make off typing so it is not echoed back to user.
So basically what you're typing is not seen on the shell.
Is there way to do the same in powershell?
As it turns out, your intent was to suppress echoing of commands provided via stdin to the PowerShell CLI (powershell.exe for Windows PowerShell, pwsh for PowerShell (Core) 7+):
To do so, use -Command - (-c -), which - like -File - (-f -, the default behavior) - accepts (independent) commands one by one via stdin, but - unlike -File - - neither prints a prompt string nor echoes the command provided:
With -Command -:
# OK: Just the piped command's *output* prints.
PS> 'Get-Date' | powershell.exe -Command -
Friday, September 3, 2021 10:08:07 AM
With -File -:
# Pseudo-interactive behavior:
# The piped command's output is:
# * *preceded by* the prompt string as well as the input command.
# * *followed by* another rendering of the prompt string.
PS> 'Get-Date' | powershell.exe -File -
PS C:\Users\jdoe> Get-Date
Friday, September 3, 2021 10:09:44 AM
PS C:\Users\jdoe>
Note: In the examples above, a single command is provided via stdin (via the pipeline), and since no more stdin input is provided, the PowerShell process exits. However, in scenarios where you keep stdin open, you'll be able to feed commands - one by one - to the PowerShell process indefinitely.
Caveat: Both -File - and -Command - exhibit problematic, pseudo-interactive behavior; notably, a command spanning multiple lines must be terminated with two newlines; see GitHub issue #3223 for details.
Note:
Providing neither -Command - nor -File - is essentially the same as -File -, except that a copyright message is also printed on startup (which can be suppressed separately with -NoLogo); in short: ... | powershell -NoLogo is the same as
... | powershell -File -
To provide a predictable execution environment and to avoid extra overhead, consider preceding -File / -Command with -NoProfile, which bypasses the loading of PowerShell's profile files.
As for a general stty -echo equivalent (the POSIX-mandated stty utility is available on Unix-like platforms, not on Windows):
This commands operates on the terminal, not the shell that happens to run in it.
A POSIX-compatible shell such as bash does not try to reset the terminal to its previous state after issuing this command, so input typed by the user indeed remains invisible through the end of the session or until the terminal is reset.
By contrast, PowerShell (the cross-platform v7+ edition that runs on Unix-like platforms) does reset the terminal after running each command, so running stty -echo is, in effect, a no-op.
In other words: you cannot achieve the same effect in PowerShell, on any platform (at least as of PowerShell 7.2)
On a loosely related note (prompted by a misreading of the question's intent), the following discusses:
How to hide or mask interactive user input solicited via the Read-Host cmdlet:
There is no built-in PowerShell feature (as of v7.2) that hides what the user types, but if the intent is simply to mask user input, so as to hide sensitive information being typed, such as a password, you have two options - both of which mask each character typed printing * instead:
Use Read-Host -AsSecureString:
$$valueEnteredSecure = Read-Host -AsSecureString -Prompt 'Enter your password'
Note that this outputs a System.Security.SecureString instance (which provides limited security on Windows, and virtually none on Unix-like platforms), which you can convert back to a regular string as follows:
$valueEntered = [System.Net.NetworkCredential]::new('', $valueEnteredSecure).Password
In PowerShell (Core) 7.0+, you can alternatively use (though note the simpler 7.1+ solution further below):
$valueEntered = ConvertFrom-SecureString $valueEnteredSecure -AsPlainText
PowerShell (Core) 7.1+ now supports a -MaskInput parameter that exhibits the same UI behavior, but directly returns a regular string:
# PowerShell 7.1+
$valueEntered = Read-Host -MaskInput -Prompt 'Enter your password'
If truly suppressing the display of all characters typed by the user is a must, you'll have to create a custom solution that uses $host.ui.RawUI.ReadKey('NoEcho') in a loop:
Here's a simple implementation, which you can call as
$valueEntered = Read-HostSilent -Prompt 'Enter your password', for instance:
function Read-HostSilent {
param([string] $Prompt)
if ($Prompt) { Write-Host -NoNewline "${Prompt}: " }
$entered = $null; $done = $false
do {
$key = $host.ui.RawUI.ReadKey('NoEcho')
switch ($key.VirtualKeyCode) {
# Backspace
8 { if ($entered.Length -gt 1) { $entered = $entered.Substring(0, $entered.Length-1) } }
# Enter
13 { $done = $true; break }
default {
if ($key.Character) { # printable?
$entered += $key.Character
}
}
}
} while (-not $done)
$entered # output
}
Related
Apologize for the noob question but I did hours of research but still so confused...
The problem:
In powershell we can write this:
$i = 'hello'
echo $i # hello
easy. But:
powershell -c "$j = 'hello'; echo $j"
won't work and it throws error at our face.
The question: what is the error, and what is the correct grammar to use powershell -NoP -NonI -c "//..."? I see quite a few scripts written in this format. I even wonder if it is a linux thing...? but we are talking about powershell right?...
Any help would be appreciated.
It depends on where are you executing the command.
Inside cmd.exe this will work, because the commands don't render special meaning to cmd. But in powershell it will fail because of the special characters, use powershell -c '$j = ''hello''; echo $j' instead.
Also -c,-NoP etc. are parameters of powershell.exe:
PowerShell[.exe] [-PSConsoleFile <file> | -Version <version>]
[-NoLogo] [-NoExit] [-Sta] [-Mta] [-NoProfile] [-NonInteractive]
[-InputFormat {Text | XML}] [-OutputFormat {Text | XML}]
[-WindowStyle <style>] [-EncodedCommand <Base64EncodedCommand>]
[-ConfigurationName <string>]
[-File <filePath> <args>] [-ExecutionPolicy <ExecutionPolicy>]
[-Command { - | <script-block> [-args <arg-array>]
| <string> [<CommandParameters>] } ]
PowerShell[.exe] -Help | -? | /?
-PSConsoleFile
Loads the specified Windows PowerShell console file. To create a console
file, use Export-Console in Windows PowerShell.
-Version
Starts the specified version of Windows PowerShell.
Enter a version number with the parameter, such as "-version 2.0".
-NoLogo
Hides the copyright banner at startup.
-NoExit
Does not exit after running startup commands.
-Sta
Starts the shell using a single-threaded apartment.
Single-threaded apartment (STA) is the default.
-Mta
Start the shell using a multithreaded apartment.
-NoProfile
Does not load the Windows PowerShell profile.
-NonInteractive
Does not present an interactive prompt to the user.
-InputFormat
Describes the format of data sent to Windows PowerShell. Valid values are
"Text" (text strings) or "XML" (serialized CLIXML format).
-OutputFormat
Determines how output from Windows PowerShell is formatted. Valid values
are "Text" (text strings) or "XML" (serialized CLIXML format).
-WindowStyle
Sets the window style to Normal, Minimized, Maximized or Hidden.
-EncodedCommand
Accepts a base-64-encoded string version of a command. Use this parameter
to submit commands to Windows PowerShell that require complex quotation
marks or curly braces.
-ConfigurationName
Specifies a configuration endpoint in which Windows PowerShell is run.
This can be any endpoint registered on the local machine including the
default Windows PowerShell remoting endpoints or a custom endpoint having
specific user role capabilities.
-File
Runs the specified script in the local scope ("dot-sourced"), so that the
functions and variables that the script creates are available in the
current session. Enter the script file path and any parameters.
File must be the last parameter in the command, because all characters
typed after the File parameter name are interpreted
as the script file path followed by the script parameters.
-ExecutionPolicy
Sets the default execution policy for the current session and saves it
in the $env:PSExecutionPolicyPreference environment variable.
This parameter does not change the Windows PowerShell execution policy
that is set in the registry.
-Command
Executes the specified commands (and any parameters) as though they were
typed at the Windows PowerShell command prompt, and then exits, unless
NoExit is specified. The value of Command can be "-", a string. or a
script block.
If the value of Command is "-", the command text is read from standard
input.
If the value of Command is a script block, the script block must be enclosed
in braces ({}). You can specify a script block only when running PowerShell.exe
in Windows PowerShell. The results of the script block are returned to the
parent shell as deserialized XML objects, not live objects.
If the value of Command is a string, Command must be the last parameter
in the command , because any characters typed after the command are
interpreted as the command arguments.
To write a string that runs a Windows PowerShell command, use the format:
"& {<command>}"
where the quotation marks indicate a string and the invoke operator (&)
causes the command to be executed.
-Help, -?, /?
Shows this message. If you are typing a PowerShell.exe command in Windows
PowerShell, prepend the command parameters with a hyphen (-), not a forward
slash (/). You can use either a hyphen or forward slash in Cmd.exe.
EXAMPLES
PowerShell -PSConsoleFile SqlSnapIn.Psc1
PowerShell -version 2.0 -NoLogo -InputFormat text -OutputFormat XML
PowerShell -ConfigurationName AdminRoles
PowerShell -Command {Get-EventLog -LogName security}
PowerShell -Command "& {Get-EventLog -LogName security}"
# To use the -EncodedCommand parameter:
$command = 'dir "c:\program files" '
$bytes = [System.Text.Encoding]::Unicode.GetBytes($command)
$encodedCommand = [Convert]::ToBase64String($bytes)
powershell.exe -encodedCommand $encodedCommand
-NoP is no profile means not load powershell profile.
-NonI is to run non-interactive session.
-c execute command/scriptblock and exit.
I would like to run command mkdir C:\Temp\555 in Powershell via a Base64-encoded string.
This code should work
$4 = "bWtkaXIgQzpcVGVtcFw1NTU="
$code = [Text.Encoding]::Utf8.GetString([Convert]::FromBase64String($4))
powershell $code
but if i convert $code to ASCII, how can I run it like that, because this one won't work:
$4 = "bWtkaXIgQzpcVGVtcFw1NTU="
$code = [char]091+[char]084+[char]101+[char]120+[char]116+[char]046+[char]069+[char]110+[char]099+[char]111+[char]100+[char]105+[char]110+[char]103+[char]093+[char]058+[char]058+[char]085+[char]116+[char]102+[char]056+[char]046+[char]071+[char]101+[char]116+[char]083+[char]116+[char]114+[char]105+[char]110+[char]103+[char]040+[char]091+[char]067+[char]111+[char]110+[char]118+[char]101+[char]114+[char]116+[char]093+[char]058+[char]058+[char]070+[char]114+[char]111+[char]109+[char]066+[char]097+[char]115+[char]101+[char]054+[char]052+[char]083+[char]116+[char]114+[char]105+[char]110+[char]103+[char]040+[char]036+[char]052+[char]041+[char]041
powershell $code
because the last code doesn't work while the first one does, any help please?
Note: This answer addresses common use cases first; for a discussion of what you tried, see the bottom section.
Note: If you just want to execute commands stored in a string from inside a PowerShell session, without needing to run commands in a child process, use Invoke-Expression, but do note that Invoke-Expression should generally be avoided:
Note: For illustrative purposes, I'm substituting command Get-Date -UFormat "%s" for your original command, mkdir "C:\Temp\555". This Get-Date command prints the current point in time as a Unix timestamp, i.e., an integer denoting the seconds since 1 Jan 1970, midnight UTC; e.g., 1565229614 for Wednesday, August 7, 2019 10:00:13 PM ETD.
$cmd = 'Get-Date -UFormat "%s"'
Invoke-Expression $cmd # Execute the string $cmd as code.
If you control construction of the commands, it's better to store pieces of code as script blocks ({ ... }) inside a PowerShell session:
$cmd = { Get-Date -UFormat "%s" } # create a script block
& $cmd # execute the script block
How to pass a complex command to a PowerShell child process via its CLI, using the -EncodedCommand parameter:
From outside PowerShell, use the -EncodedCommand parameter, which requires a Base64 encoding of the bytes of a UTF-16LE-encoded string ("Unicode"-encoded), not of a UTF-8-encoded one:
# Get the Base64-encoding of the bytes that make up the UTF-16LE
# ("Unicode") encoding of string 'Get-Date -UFormat "%s"'
# Assigns the following to $base64Cmd:
# 'RwBlAHQALQBEAGEAdABlACAALQBVAEYAbwByAG0AYQB0ACAAIgAlAHMAIgA='
$base64Cmd =
[System.Convert]::ToBase64String(
[System.Text.Encoding]::Unicode.GetBytes(
'Get-Date -UFormat "%s"'
)
)
powershell -EncodedCommand $base64Cmd # executes: Get-Date -UFormat "%s"
Note: The above assumes Windows PowerShell. If you're using PowerShell Core, use pwsh instead of powershell.
Specifying the System. component in PowerShell type literals explicitly is optional; e.g., [System.Text.Encoding] can be shortened to [Text.Encoding].
From inside PowerShell, there's no need to pass a Base64-encoded string via -EncodedCommand explicitly, because PowerShell does that implicitly when you simply pass the code to execute as a script block({ ... }):
powershell { Get-Date -UFormat "%s" } # -command (-c) parameter implied
Note:
You cannot refer to the caller's variables in a script block, but you can pass arguments to it via the -args parameter; e.g.:
powershell { Get-Date -UFormat $args[0] } -args '%s'.
Behind the scenes, the appropriate Base64 encoding is performed, and the encoded command is passed to -EncodedCommand, as follows:
# The command to execute:
$cmd = 'Get-Date -UFormat "%s"'
# Obtain a Base64-encoded version of the command from the bytes of its
# UTF-16LE encoding.
$base64Cmd = [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($cmd))
# Pass the result to the -EncodedCommand parameter:
powershell -EncodedCommand $base64Cmd -inputFormat xml -outputFormat xml
Note:
-inputFormat xml -outputFormat xml are automatically added when you pass a script block to the (possibly positionally implied) -Command / -c parameter.
They trigger CLIXML serializing of the arguments passed to as well as the output from the CLI call.
This serialization is the same as the one used by PowerShell's remoting / background-job infrastructure and has two benefits:
PowerShell's output streams are preserved (whereas passing a string -Command merges all output into the single standard stdout stream).
Arguments and output are passed and received as objects (rather than as text only, as happens when you pass a string -Command), albeit with the same limitations on type fidelity as in remoting - see this answer for more information.
The equivalent of using -args to pass arguments to a script block is to pass an explicitly Base64-encoded argument list to -encodedArguments (-ea):
This parameter - undocumented as of this writing - additionally requires serializing the argument list to XML (CLIXML format) before Base64-encoding the result, as demonstrated in this answer.
As for what you tried:
Your 1st command works, because you're passing a decoded plain-text version of the mkdir command to powershell.exe, which implicitly binds to the -Command parameter and is executed as a command in the new PowerShell session.
As an aside: pwsh, PowerShell Core's CLI, now defaults to -File, so -Command (or -c) would have to be used explicitly.
Your 2nd command does not work, because $code now contains the plain text of the Base64-decoding command from your 1st command.
That command references variable $4, which the new PowerShell instance you're creating knows nothing about.
However, instead of trying to defer the decoding of the Base64-encoded mkdir command to the new PowerShell session, it makes much more sense to pass the Base64-encoded command directly to the new session (if a new session is even needed, see above), via -EncodedCommand.
However, -EncodedCommand requires a Base64 encoding based on UTF-16LE, not UTF-8 - see above for how to produce such an encoding explicitly (if needed).
If you're given a UTF-8-based Base64 encoding, you can translate it into a UTF-16LE-based one as follows:
# UTF-8-based Base64-encoding
$4 = "bWtkaXIgQzpcVGVtcFw1NTU="
# Decode to plain text.
$plainTextCode = [Text.Encoding]::Utf8.GetString([Convert]::FromBase64String($4))
# Re-encode to Base64 via UTF-16 ("Unicode"):
$utf16Base64Command = [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($plainTextCode))
# Pass to powershell.exe via -EncodedCommand
powershell -EncodedCommand $code
A string can be executed as a script through the CommandInvocationIntrinsics class method InvokeScript.
powershell $executioncontext.InvokeCommand.InvokeScript($code)
See InvokeScript Method for more information.
I'm new in windows environment. How can I execute the following powershell command from cmd "hello gourav how are you1" | Out-File filename -append
Open cmd from Run and execute powershell /? to know all the options you have.
PowerShell[.exe] [-PSConsoleFile <file> | -Version <version>]
[-NoLogo] [-NoExit] [-Sta] [-Mta] [-NoProfile] [-NonInteractive]
[-InputFormat {Text | XML}] [-OutputFormat {Text | XML}]
[-WindowStyle <style>] [-EncodedCommand <Base64EncodedCommand>]
[-ConfigurationName <string>]
[-File <filePath> <args>] [-ExecutionPolicy <ExecutionPolicy>]
[-Command { - | <script-block> [-args <arg-array>]
| <string> [<CommandParameters>] } ]
PowerShell[.exe] -Help | -? | /?
-PSConsoleFile
Loads the specified Windows PowerShell console file. To create a console
file, use Export-Console in Windows PowerShell.
-Version
Starts the specified version of Windows PowerShell.
Enter a version number with the parameter, such as "-version 2.0".
-NoLogo
Hides the copyright banner at startup.
-NoExit
Does not exit after running startup commands.
-Sta
Starts the shell using a single-threaded apartment.
Single-threaded apartment (STA) is the default.
-Mta
Start the shell using a multithreaded apartment.
-NoProfile
Does not load the Windows PowerShell profile.
-NonInteractive
Does not present an interactive prompt to the user.
-InputFormat
Describes the format of data sent to Windows PowerShell. Valid values are
"Text" (text strings) or "XML" (serialized CLIXML format).
-OutputFormat
Determines how output from Windows PowerShell is formatted. Valid values
are "Text" (text strings) or "XML" (serialized CLIXML format).
-WindowStyle
Sets the window style to Normal, Minimized, Maximized or Hidden.
-EncodedCommand
Accepts a base-64-encoded string version of a command. Use this parameter
to submit commands to Windows PowerShell that require complex quotation
marks or curly braces.
-ConfigurationName
Specifies a configuration endpoint in which Windows PowerShell is run.
This can be any endpoint registered on the local machine including the
default Windows PowerShell remoting endpoints or a custom endpoint having
specific user role capabilities.
-File
Runs the specified script in the local scope ("dot-sourced"), so that the
functions and variables that the script creates are available in the
current session. Enter the script file path and any parameters.
File must be the last parameter in the command, because all characters
typed after the File parameter name are interpreted
as the script file path followed by the script parameters.
-ExecutionPolicy
Sets the default execution policy for the current session and saves it
in the $env:PSExecutionPolicyPreference environment variable.
This parameter does not change the Windows PowerShell execution policy
that is set in the registry.
-Command
Executes the specified commands (and any parameters) as though they were
typed at the Windows PowerShell command prompt, and then exits, unless
NoExit is specified. The value of Command can be "-", a string. or a
script block.
If the value of Command is "-", the command text is read from standard
input.
If the value of Command is a script block, the script block must be enclosed
in braces ({}). You can specify a script block only when running PowerShell.exe
in Windows PowerShell. The results of the script block are returned to the
parent shell as deserialized XML objects, not live objects.
If the value of Command is a string, Command must be the last parameter
in the command , because any characters typed after the command are
interpreted as the command arguments.
To write a string that runs a Windows PowerShell command, use the format:
"& {<command>}"
where the quotation marks indicate a string and the invoke operator (&)
causes the command to be executed.
-Help, -?, /?
Shows this message. If you are typing a PowerShell.exe command in Windows
PowerShell, prepend the command parameters with a hyphen (-), not a forward
slash (/). You can use either a hyphen or forward slash in Cmd.exe.
EXAMPLES
PowerShell -PSConsoleFile SqlSnapIn.Psc1
PowerShell -version 2.0 -NoLogo -InputFormat text -OutputFormat XML
PowerShell -ConfigurationName AdminRoles
PowerShell -Command {Get-EventLog -LogName security}
PowerShell -Command "& {Get-EventLog -LogName security}"
# To use the -EncodedCommand parameter:
$command = 'dir "c:\program files" '
$bytes = [System.Text.Encoding]::Unicode.GetBytes($command)
$encodedCommand = [Convert]::ToBase64String($bytes)
powershell.exe -encodedCommand $encodedCommand
Maybe a bit off-topic but this does the same trick without powershell (i.e. directly from cmd prompt):
echo Your text >>filename
simple
#ECHO off
SET LONG_COMMAND=^
if ($true)^
{^
$Resolution=Get-DisplayResolution;^
Write-Host $Resolution;^
}
START Powershell -noexit -command %LONG_COMMAND%
with return
#echo off
set "psCommand="[Environment]::GetFolderPath('DesktopDirectory')""
for /f "usebackq delims=" %%I in (`powershell %psCommand%`) do set "folder=%%I"
echo DesktopDirectory = %folder%
you can use powershell.exe in cmd to execute powershell command.
powershell.exe "your command"
like
powershell.exe "\"hello gourav how are you1\" | Out-File filename -append"
And you can enter interact interface in powershell using powershell directly
Quick question. I am trying to write the following PowerShell script, but I would like it to fit on a single line:
$app = New-Object -comobject Excel.Application
$wb1 = $app.Workbooks.Open("C:\xampp\upload_files\Launchpad.xlsm")
$app.Run("Refresh")
$wb1.Close($false)
$app.Quit()
The pseudo-code would look something like this:
$app = New-Object -comobject Excel.Application AND $wb1 = $app.Workbooks.Open AND "C:\xampp\upload_files\Launchpad.xlsm") AND $app.Run("Refresh") AND $wb1.Close($false) AND $app.Quit()
The reason I want to fit on a line is because I would like to insert the arguments directly in the 'arguments' box of Windows Task Scheduler. The reason for this is that for some reason scripts have been disabled (e.g. I cannot call a .ps1 file...)
I know this will still work, as I already have a "one liner" PS script running. What would the syntax look like??
Kind regards,
G.
Powershell statements can be separated with semicolons:
$app = New-Object -COM 'Excel.Application'; $wb1 = $app.Workbooks.Open("..."); ...
The PowerShell executable takes a -Command parameter that allows you to specify a command string for execution in PowerShell:
powershell.exe -Command "stmnt1; stmnt2; ..."
To run this via Task Scheduler you'd put powershell.exe into the "program" field and -Command "stmnt1; stmnt2; ..." into the "arguments" field of the task.
However, as #alroc said: you should verify why script execution has been restricted. If it's just the default setting you can simply change it by running Set-ExecutionPolicy RemoteSigned or override it by adding -ExecutionPolicy ByPass to a PowerShell command line. However, if the setting is enforced by policy changing/bypassing the setting will fail, and you could get into quite some trouble for violating company policies.
Here is a solution that you might use if the script is not that easy to convert, but you are on Windows running at least PowerShell V5.
It converts the code into Base64 and uses PowerShell.exe with the parameter -encodedCommand to pass the encodedCommand as string.
$command = Get-Content .\YourPowerShellFileContainingTheCode.ps1 -raw
# Get-Content may require "-encoding utf8" or other encodings depending on your file
$encodedCommand = [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($command))
Write-Output "Text for application:"
Write-Output "PowerShell.exe" ""
Write-Output "Text for argurments:"
Write-Output "-encodedCommand $encodedCommand"
It would look like this, but with a much larger command:
Text for application:
PowerShell.exe
Text for argurments:
-encodedCommand SABvACAASABvACAASABvACwAIABzAHQAYQBjAGsAbwB2AGUAcgBmAGwAbwB3AA==
Sometimes, the answer is "no". This turns out not to be a question, but more of a cri de coeur (OK, just complaining).
The Team Foundation Server 2010 PowerShell snap-in exports a cmdlet called Get-TfsPendingChange, which does what it sounds like.
If there are no pending changes, Get-TfsPendingChange echoes "There are no pending changes." on standard output. I never asked it to. The following attempts at suppressing that output all fail:
$pcs = $(Get-TfsPendingChange -Server $server "$/foo/bar" -User $env:USERNAME -r ) | out-null;
$($pcs = Get-TfsPendingChange -Server $server "$/foo/bar" -User $env:USERNAME -r ) | out-null;
$pcs = Get-TfsPendingChange -Server $server "$/foo/bar" -User $env:USERNAME -r | out-null;
I'm not getting errors, but the text output is not redirected. What IS redirected, is the normal successful output of the cmdlet, in the case where there are pending changes for it to return. The ONLY output you can suppress is the useful output. If there are zero pending changes, you get text garbage via stdout. If there are any actual pending changes, that stream (of objects, not text) can be redirected to the null device, but that's worse than useless.
So it appears that text on stdout is a side effect from this cmdlet, not the cmdlet's output, and it cannot be redirected in PowerShell. The PowerShell redirect operators > and |, without the fileno specifiers (2 in PS2, 2, 3, 4, 5, and * in PS3/PS4), work on the object stream, which is not stdout. This would be fine if stdout had been replaced by this new object stream concept (or if some genius on the TFS team hadn't decided that cmdlets should spew random text noise in all directions as a side effect).
The garbage output definitely is on stdout, not stderr. I can redirect the standard output of the whole script to nul when I run it from cmd.exe, and that works as expected, because duh:
c:\>powershell .\tfstest.ps1 > nul
However, I do not want to suppress all the output from the entire script. Just the output from one snapin cmdlet. It's not the end of the world, but it's irritating to have random stuff that I call echoing garbage I have no control over. The script otherwise works correctly (see UPDATE).
One workaround would be to prefix everything I want to echo on stdout with some arbitrary string (say "KLUDGEPREFIX"), and run the whole mess from a batch file which pipes the PowerShell script's output through find /v KLUDGEPREFIX and then through a PowerShell fragment that strips off the prefix from each line.
Instead, I'm going to write the rest of the script around the problem so it looks like what they get is what I intended, because, in fact, I was going to tell them they didn't have any pending changes anyhow. It's been a valuable exercise, however, in terms of getting my head inside PowerShell.
UPDATE: This script turned out to be fragile, unreliable, glacially slow, and impossible to run on any computer but the one where I originally wrote it.
I replaced it with a Perl script that took 1/10 the time to write, executed 10 times as fast, and does the same task better without any foolishness. PS and the TFS PS snap-in are great ideas but they both need a lot of work before they'll be ready for release.
I'm not familiar with Team Foundation Server, but most likely the cmdlet writes to the host rather than one of the output streams. Output to the host cannot be redirected in PowerShell, but if you run a PowerShell script in CMD the host output goes to STDOUT (as does the success output stream) and can be redirected there.
Demonstration:
PS C:\> cat .\test.ps1
Write-Host 'foo'
PS C:\> .\test.ps1 | Out-Null
foo
PS C:\> .\test.ps1 >$null
foo
PS C:\> & cmd.exe /c powershell.exe -File .\test.ps1
foo
PS C:\> & cmd.exe /c powershell.exe -File .\test.ps1 `>nul
PS C:\> & cmd.exe /c powershell.exe -File .\test.ps1 >$null
PS C:\> _
if you add 2 in front of the > it will only redirect error. likewise with 1 for non errors (stdout). So if you want all stdout, but not stderr to go away you can type
$pcs = Get-TfsPendingChange -Server $server "$/foo/bar" -User $env:USERNAME -r 1> $null
$null can be used as an equivalent to /dev/null. your code probably creates the file "nul" on disk.