Получение выходных исполняемых файлов в power shell

Tomas M

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.

Получение выходных исполняемых файлов в power shell

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

  1. Create a new working directory and save it to a variable
   
  1. 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 
  1. Create the PowerShell script which the service runs

This loop checks for notepad every 5 sec and kills it if it finds it

  
  1. 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.ps1

Save 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)
:/>  Swz 1 94v 0 e301791 блок питания схема

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@IP
Start-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.StartProcessCommand

What 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.

mklement0's user avatar

67 gold badges672 silver badges861 bronze badges

asked Aug 7, 2023 at 10:47

Callum Cooper's user avatar

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 -o is unquoted, Start-Process interprets 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 -OutVariable and -OutBuffer for -o in this case. Thus, prefix -outv would have avoided the ambiguity, for instance. Also note that some parameters have unambiguous short aliases, such as -ov for -OutVariable.

  • More fundamentally, trying to pass multiple pass-through arguments individually to Start-Process causes 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-Process expects 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.
:/>  Как убрать ограничение скорости интернета в Windows 10? - блог про компьютеры и их настройку

answered Aug 7, 2023 at 14:07

mklement0's user avatar

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 $info, to capture the information-stream output.

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-Command solution above wouldn’t capture them.

    • Arguably, however, the use of -OutVariable should implicitly act like the request to capture output from external programs too; see GitHub issue #5758 for a discussion.
  • 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.
  • 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.
# 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 -OutVariable for external-program calls has been suggested in GitHub issue #4332, with syntax such as 2>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

INPUTS​

None

You cannot pipe objects to this function.