Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Execute the powershell code with another method
#1
Hi,

I have a lot of Powershell script code in my collection and I want to call them in QM3,

In QM3 the cookbook, I found an example of executing a Powershell script, But it's not very convenient,

I found the C# code below that powershell scripts can also be executed successfully in Linqpad too

so, I want to define the code as a class in QM3, so that it is convenient to call the Powershell Multi-line commands or function
For example,  like this
----------------------------------------------
string code = """
dir c:\ |
? name -EQ windows
""";
var stdout;
var stderr;
PSrun(code, stdout, stderr);

string[] args = {1,2};
PSfun("sum", args, stdout, stderr);
----------------------------------------------

I'm just getting started with C # and can't implement these features
Thanks for any advice and help
david



The Dll needs to be referenced: 
C:\windows\assembly\GAC_MSIL\System.Management.Automation\1.0.0.0__31bf3856ad364e35\System.Management.Automation.dll
C# code: 
Code:
Copy      Help
 
class Program
{
static void Main(string[] args)
{

string Ps_code = "Get-Process | out-string";
Execute(Ps_code);
}

public static void Execute(string command)
{
using (var ps = PowerShell.Create())
{
var results = ps.AddScript(command).Invoke();
foreach (var result in results)
{
Console.WriteLine(result.ToString());
}

// report non-runspace-terminating errors, if any.
foreach (var error in ps.Streams.Error)
{
Console.Error.WriteLine("ERROR: " + error.ToString());
}
}
}
}


Call the Powershell function example:

Sum.ps1 
---------------------
function Sum
{
param([int]$first, [int]$second)
$result = $first + $second
return $result
}
Code:
Copy      Help
 
private static string script = File.ReadAllText(@"Path\Sum.ps1");
private static void CallPS1()
{
using (Runspace runspace = RunspaceFactory.CreateRunspace())
{
runspace.Open();

PowerShell ps = PowerShell.Create();
ps.Runspace = runspace;
ps.AddScript(script);
ps.Invoke();

ps.AddCommand("Sum").AddParameters(

new Dictionary<string, int>()
{
{"first", 5},
{"second", 4}
}
);

foreach (PSObject result in ps.Invoke())
{
Console.WriteLine("CallPS1()");
Console.WriteLine(result);
}
}
}
#2
Need NuGet package Microsoft.PowerShell.SDK. It contains 300+ files (full copy of PowerShell 7). I tested it, works, but the NuGet tool does not install several files. In the future I should fix it. Now I could give instructions how to install these manually, if you need. Then code could be like this:

C# code:
// script "PowerShell2.cs" /*/ nuget ps\Microsoft.PowerShell.SDK; /*/
using System.Management.Automation;

print.clear();

string code = "Get-Process | out-string";

var results = PS.Invoke(code);
foreach (var result in results) {
Console.WriteLine(result.ToString());
}

static class PS {
public static System.Collections.ObjectModel.Collection<PSObject> Invoke(string command) {
using (var ps = PowerShell.Create()) {
ps.AddScript(command);

var results = ps.Invoke();

// report non-runspace-terminating errors, if any.
foreach (var error in ps.Streams.Error) {
Console.Error.WriteLine("ERROR: " + error.ToString());
}

return results;
}
}
}
#3
Thanks for your help

Many times, I don't need to install Powershell7, it is enough to use Powershell5

I thought of another way, generate an exe program using the QM2 code below, Then call this program from QM3, No additional DLL files are required

Execution speed seems to be a little faster than using PsCmd2 command

Called in PS3 like this
--------------------------------------------------------
var commands = """
dir
Get-Process
""";
run.console("PSrun.exe", "{commands}");
--------------------------------------------------------

But two unresolved issues were encountered  Huh

Function PSrun
Code:
Copy      Help
;Todo1: Parse the received parameters

str pscode=
;Get-Process | out-string

CsScript x
x.SetOptions("references=System.Management.Automation.dll;System.Core.dll")
x.AddCode("")

str psout=x.Call("PS_Code.RunPs" pscode)

;Todo2: When an error occurs, an error message is output
;;;;;;;;and currently, when there is an error, it is returned as empty
out psout

#ret
using System;
using System.Management.Automation;

public class PS_Code
{
,public static void RunPs(string command)
,{
,,using (var ps = PowerShell.Create())
,,{
,,,var results = ps.AddScript(command).Invoke();
,,,foreach (var result in results)
,,,{
,,,,Console.WriteLine(result.ToString());
,,,}
,,,// report non-runspace-terminating errors, if any.
,,,foreach (var error in ps.Streams.Error)
,,,{
,,,,Console.Error.WriteLine("ERROR: " + error.ToString());
,,,}
,,}
,}
}
#4
Seeing as PowerShell and C# are both .NET languages, the interop here should be pretty easy and based on the exchange of rich .NET types instead of string output. For example, calling Get-Process should return an array of System.Diagnostics.Process objects that I can work with in my C# application.

Rather than calling PowerShell as an external program, using run.console, I think it would be better to host Windows PowerShell (or PowerShell 7, if you have the Microsoft.PowerShell.SDK installed ) in your C# application using the instructions provided by MSFT here: https://docs.microsoft.com/en-us/powersh...rshell-7.2

I think it would be great if QM3 had a PSRun command that abstracted away some of the complexity of hosting a PowerShell runspace. I wasn't able to get QM3 to work with Windows PowerShell 5.1 (maybe because they are based on different version of .NET?) nor could I get it working with PowerShell 7, presumably due to the missing files Gintaras mentioned. 

These 2 languages could really compliment each other in a product like QM3, so working with them together with little difficulty would be amazing.

@Gintaras - Speaking of interop between QM3 and PowerShell, do you know if it is possible to go the other way, calling QM3 from PowerShell. Something like this? That would be pretty cool too...
 
Code:
Copy      Help
Add-Type -Path "C:\PathTo\Au.dll" 

# Create object of CustomClass 
$folderObj = New-Object Au.folders 

# Calling getFolder method 
$tempFolder = $folderObj.getFolder("temp")
#5
Quote:Speaking of interop between QM3 and PowerShell, do you know if it is possible to go the other way, calling QM3 from PowerShell.

Yes, but not from the Windows PowerShell, because it uses .NET 4. Au.dll uses .NET 6, and they are incompatible. Install PowerShell 7. It does not have an ISE; for it can be used VSCode with PowerShell extension. Tested, works. Tested on Windows 11. Need Windows 8.1 or later.

Code:
Copy      Help
Add-Type –Path "C:\......\Au.dll"

[Au.dialog]::show('Au in PowerShell')
[Au.run]::it('notepad.exe')

Also add environment variable Au.Path = Au.dll folder path. After adding/removing/editing environment variables may need to restart apps or Windows to propagate the changes.


Forum Jump:


Users browsing this thread: 1 Guest(s)