However, GUI application has one more thing that may not be desirable when launched using a console: GUI. There is a way to hide that window, but it forces using Start-Process command (or at least this is the only way I am aware of) which separates the script from the process output:
# not a GUI app, but does the trick
$proc = Start-Process -FilePath "podman" `
-ArgumentList stats `
-NoNewWindow -PassThru
$proc.StandardOutput -eq $null # stream is null!Start-Process offers a way to redirect output to a file using -RedirectStandardOutput parameter, while this works we lose the opportunity to filter and react to output as it is being produced. But, as it often is, this can be solved with another level of indirection:
This wrapper function forwards output to a temporary file which will be removed once the process exists or the script is aborted. While in progress, file content will be checked and forwarded once a second.
I agree, this is not an everyday script and probably for the better. So far it has been applied in two cases: running installer and reading error output (Console.Error.WriteLine) of Terminal.Gui application.

Red or blue pill
If you are in the same rabbit-hole as I was of setting up a Windows Service of any form of looping script, there’s two pills you can choose from:
A wrapper executable that can run any executable as a Windows service, in a permissive license.
Naturally as someone who enjoys coding with hand grenades, I took the Blue Pill and here’s how that story went:
The Blue Pill
- Create a new working directory and save it to a variable
- Download the latest WinSW-x64.exe to the working directory
# Get the latest WinSW 64-bit executable browser download url # Download it to the newly created working directory - Create the PowerShell script which the service runs
This loop checks for notepad every 5 sec and kills it if it finds it
- Construct the .XML file
Just edit the id, name, description and startarguments
This service runs a custom PowerShell script. -NoLogo -file C:\Path\To\Script\Invoke-PowerShellServiceScript.ps1Save the .xml, in this example I saved it as PowerShell_Service.xml
# if not already, step into the workingdirectory# Install the service # Make sure powershell.exe's executionpolicy is Bypass Conclusion
Running a PowerShell script as a service on any windows machine isn’t that complicated thanks to WinSW. It’s a great choice if you don’t want to get deeper into the process of developing windows services (it’s kind of a fun rabbit-hole though).
I recommend reading docs of WinSW.
Some things to consider:
- The service will run PowerShell 5.1 as System
- Meaning the executionpolicy must be supporting that usecase (bypass as local machine will do)
- The script in this example is just a demo of a loop, but anything you can think of that loops will do here
- Starting the Service requires elevated rights in this example
- If you get the notorious
The service did not respond to the start or control request in a timely fashion, you have my condolences (This is a very general error msg that has no clear answer by itself it seems)
Good luck have fun, happy coding
/Emil
I am currently trying to get a command that I know works in CLI to run through a PowerShell Ise script but it will not allow me to run it as it is picking up a part of the command as a parameter.
Start-Process ssh -o KexAlgorithms=diffie-hellman-group14-sha1 Username@IPStart-Process : Parameter cannot be processed because the parameter name 'o' is ambiguous. Possible matches include: -OutVariable -OutBuffer.
At line:1 char:30
+ Start-Process ssh -o KexAlgorithms=diffie-hellman-group14- ...
+ ~~ + CategoryInfo : InvalidArgument: (:) [Start-Process], ParameterBindingException + FullyQualifiedErrorId : AmbiguousParameter,Microsoft.PowerShell.Commands.StartProcessCommandWhat is supposed to happen is the cli should pop up and allow me to access a switch which as i have stated earlier works when I manually input it into Cli.
67 gold badges672 silver badges861 bronze badges
asked Aug 7, 2023 at 10:47
As Mathias notes, you must quote the list of arguments to pass through to ssh:
# Note the '...' around the entire list of pass-through arguments.
# Use "..." if you need string interpolation.
# Use *embedded* "..." quoting for arguments that contain spaces, for instance.
Start-Process ssh '-o KexAlgorithms=diffie-hellman-group14-sha1 Username@IP'There are two problems with your approach:
Because
-ois unquoted,Start-Processinterprets it as one of its parameter names.Thus, pass-through arguments that happen to look like PowerShell parameters, must be quoted, e.g. – if passed individually (which isn’t advisable; see next point) –
'-o'.As for the error you saw:
PowerShell’s “elastic syntax” allows you to use parameter-name prefixes for brevity, so you don’t have to type / tab-complete the full parameter name.
However, such a prefix must be unambiguous; if it isn’t, PowerShell complains and lists the candidate parameter names, such as
-OutVariableand-OutBufferfor-oin this case. Thus, prefix-outvwould have avoided the ambiguity, for instance. Also note that some parameters have unambiguous short aliases, such as-ovfor-OutVariable.
More fundamentally, trying to pass multiple pass-through arguments individually to
Start-Processcauses a syntax error:It is best to specify all pass-through arguments as a single, quoted string, using embedded double-quoting, if necessary.
- This answer explains the syntax problem in detail, but the short of it is that
Start-Processexpects pass-through arguments via a single argument, passed to its-ArgumentList(-Args) parameter, which is the 2nd positional parameter. - This answer explains why – even though you can specify the pass-through arguments individually as the elements of an array (
,-separated), a long-standing bug makes the single-string approach preferable.
- This answer explains the syntax problem in detail, but the short of it is that
answered Aug 7, 2023 at 14:07
67 gold badges672 silver badges861 bronze badges
Mathias R. Jessen has provided the crucial pointer:
The self-chosen variable you designate as the target of one of the common -*Variable parameters, such as the common -OutVariable (-ov) parameter, -ErrorVariable (-ev), and -InformationVariable (-iv), must be specified by name only, i.e. without the $ prefix:
Therefore, in order to capture success output in variable $out, use -OutVariable out, not -OutVariable .$out
Analogously, use -iv info (-InformationVariable info), not -iv , to capture the information-stream output.$info
To capture (non-terminating) errors in, say, variable $err, use -ErrorVariable err
(or -ev err).
What -OutVariable $out, for instance, does is to use the value of variable $out as the name of the target variable, and if $out isn’t defined, the reference evaluates to $null, which is the same as not specifying a target variable for -OutVariable, i.e. the parameter has no effect – which is what you saw.
Note that PowerShell has no concept of return codes; PowerShell commands produce output via its system of output streams.
Additionally, there is an abstract success indicator in the form of the automatic $? variable, which contains $false if at least one error occurred in the most recently executed command, and $true otherwise.
Error details must be gleaned from the error records (objects) emitted via the error output stream (whose number is 2), and are also logged session-wide in the automatic $Error variable.
Optional reading: How to capture output from commands that don’t support common parameters:
For other commands except external (native) programs, you can wrap the call in a Invoke-Command call and use the latter’s common parameters; e.g.:
# Define a simple (non-advanced) function that emits both success
# and error output.
function SimpleFunc { 'hi!' # same as: Write-Output 'hi!' Write-Error 'err' # emit a non-terminating error
}
# Wrap the call in Invoke-Command and use the latter's common parameters.
# The output streams are passed through, and the success-output / error stream
# content is recorded in $out / $err
Invoke-Command -OutVariable out -ErrorVariable err { SimpleFunc }Self-chosen variable $out now contains 'hi!' and self-chosen variable $err contains an error record with message 'err'.
For external (native) programs, there is only a suboptimal solution:
Unless the output streams of external programs – stdout and stderr – are explicitly redirected or captured, PowerShell passes them straight through to the host (terminal). Therefore, the
Invoke-Commandsolution above wouldn’t capture them.- Arguably, however, the use of
-OutVariableshould implicitly act like the request to capture output from external programs too; see GitHub issue #5758 for a discussion.
- Arguably, however, the use of
You can force this capturing to happen simply by piping the external-program call to
Write-Output(which effectively just relays the output lines), but only stdout output is by default passed through the pipeline.- Note that this may surface character-encoding issues that wouldn’t necessarily surface in direct-to-host output: capturing involves decoding the output streams based on
[Console]::OutputEncoding, which must match the actual encoding used by the external program – see this answer for background information.
- Note that this may surface character-encoding issues that wouldn’t necessarily surface in direct-to-host output: capturing involves decoding the output streams based on
In order to also capture stderr output, you must redirect it into the success stream, using
2>&1, but this invariably means that you can only capture the combination of the stdout and stderr streams, in a single variable, passed to-OutVariable- However, because PowerShell records stderr lines wrapped in
[ErrorRecord]instances, you can separate the stream output afterwards, using the intrinsic.Where()method, as shown below.
- However, because PowerShell records stderr lines wrapped in
# Capture the *combined* stdout and stderr output in $outAndErr
Invoke-Command -OutVariable outAndErr { cmd /c 'ver & dir nosuch' 2>&1 | Write-Output
}
# Now split the captured lines into those that come from stdout vs. stderr.
$out, $err = $outAndErr.Where({ $_ -is [string] }, 'Split')$out, $err = ( cmd /c 'ver & dir nosuch' 2>&1 ).Where({ $_ -is [string] }, 'Split')Possibly providing a mechanism analogous to
-OutVariablefor external-program calls has been suggested in GitHub issue #4332, with syntax such as2>variable:err
PARAMETERS
-LoadLoggedOnUserEnvironmentVariables
Accept pipeline input
Accept wildcard characters
-ContinueOnError
Continue if an error is encountered.
Default is: $true.
Accept pipeline input
Accept wildcard characters
CommonParameters
DESCRIPTION
Environment variable changes that take place during script execution are not visible to the current PowerShell session.
Use this function to refresh the current PowerShell session with all environment variable settings.
SYNTAX
NOTES
This function has an alias: Refresh-SessionEnvironmentVariables
OUTPUTS
None. This function does not return objects.
SYNOPSIS
Updates the environment variables for the current PowerShell session with any environment variable changes that may have occurred during script execution.
EXAMPLES
EXAMPLE 1



