0

I am trying to run a PowerShell command and having problems with it. Here is the code:

PowerShell ps = PowerShell.Create();
ps.AddScript("ipfs 'pin ls'");
var result = await ps.InvokeAsync();
string response = "";
foreach (var entry in result)
{
    response += entry.BaseObject.ToString() + "/";
}

What am I doing wrong? Thanks

faremax
  • 11
  • 2
  • 3
    As far as I can tell, `ipfs` is not a Powershell cmdlet, it's a command line executable. Why are you using the Powershell runtime to call it? `Process.Start` with output capture will do the same without the overhead. The daemon might even have an API that would let you do whatever `pin ls` does (enumerates pins?) without going through the CLI client. – Seva Alekseyev May 04 '22 at 21:50
  • SevaAlekseyev's comment is worth heeding; if you still want to use PowerShell with the [`ipfs` command line](https://docs.ipfs.io/install/command-line), please clarify which problem, specifically, you're experiencing - and whether you've verified that the same command works in an interactive PowerShell session. – mklement0 May 04 '22 at 22:47
  • The reason I am using PowerShell is because according to IPFS installation instructions it must be done in PowerShell. The installation involves creating PowerShell profiles that the application is using. II do not get any errors and if I simply change the line to ps.AddScript("ipfs"); it will run correctly and I am getting a response. So it's a matter of passing those additional arguments. Yes same command works when ran in PowerShell – faremax May 05 '22 at 14:24
  • @Seva. I am trying to use Process.Start but getting an error that it can't find a folder. Seems like the process is looking at the wrong path: C:\windows\system32\config\systemprofile\.ipfs when in reality that folder is located at C:\Users\Administrator\.ipfs – faremax May 05 '22 at 14:35
  • So does `ipfs 'pin ls'` work as intended in an interactive PowerShell session? Note that when you use `.AddScript()`, any errors that occur during execution of the PowerShell code do _not_ surface _as exceptions_ in your C# program; instead, you must examine the `.Streams.Error` collection (`.HadErrors` is a Boolean that indicates whether any errors occurred) - see [this answer](https://stackoverflow.com/a/69051991/45375) for details. – mklement0 May 05 '22 at 15:14
  • @Seva. Ok I was able to get it to work. Thank you for putting me on the right path. – faremax May 05 '22 at 15:17
  • 1
    @mklement0 Yes it does. Even through I was able to get it to work using Process I still want to get the PowerShell working as well. Let me see what errors it returns. Will update. Thanks – faremax May 05 '22 at 15:19

1 Answers1

0

First of all, I would highly recommend to ask more than just "This is my code; What am I doing wrong?".

For instance:

  • Which NuGet package with which version have you installed to use PowerShell within C#? (There are quite a few...)
  • What does the error say? (DLL not found? PS-Execution-Policy denying the execution? ...)
  • Which additional using statements have you added in your code?

As a well-intentioned advice:
You can (and probably should) read the guidelines for asking questions here.
(Poorly asked questions often gets closed.)


Nonetheless, this is what I did:
Copied your code and pasted it in VS 2022, installed the Package System.Management.Automation (7.2.3) and tried to build and debug it with .NET 6.0.

Then this error came up:
System.Management.Automation.Runspaces.PSSnapInException:
"Cannot load PowerShell snap-in Microsoft.PowerShell.Diagnostics because of the following error: Could not load file or assembly 'X:\TestProject\bin\Debug\net6.0-windows\runtimes\win\lib\net6.0\Microsoft.PowerShell.Commands.Diagnostics.dll'.

[Solution]
To sum up, I had to install the following NuGet packages, just for stopping the application complaining about missing DLLs:

  • System.Management.Automation (7.2.3) (already mentioned above)
  • Microsoft.PowerShell.Commands.Diagnostics (7.2.3)
  • Microsoft.PowerShell.ConsoleHost (7.2.3)
  • Microsoft.PowerShell.Commands.Utility (7.2.3)
  • Microsoft.PowerShell.Commands.Management (7.2.3)
  • Microsoft.WSMan.Management (7.2.3)

Finally, the application did not crash.

However, the output was empty.
So I executed ipfs 'pin ls' directly from PowerShell and I got an error. ("ipfs not recognized as a name of a cmdlet, method or script.")

Then I changed the command to something, PowerShell should know:

  • dir (as an alias of Get-ChildItem): Worked.
  • ipconfig (short-term for C:\Windows\System32\ipconfig.exe): Worked.

What I did not experience in this case, but in the past:
If there shows up an error concerning the execution policy, you could execute the following command:

// Create instance
var PsInstance = PowerShell.Create();
// Allow execution of any scripts for the current user
// (does not require administrator privileges)
var policy = PsInstance.AddCommand("Set-ExecutionPolicy")
               .AddArgument("Unrestricted")
               .AddParameter("Scope", "CurrentUser")
               .Invoke();
// Wipe the command pipeline to avoid executing the previous command
// everytime .Invoke() will be invoked.
PsInstance.Commands.Clear();
// continue with your code here...

Besides the PowerShell topic:
If ipfs is an executable, I would recommend to directly invoke it using Process.Start with additional parameters, as Seva Alekseyev already commented below your question.
In my option, it would be a much better solution with way less overhead and dependencies and much better performance, since you will get rid of PowerShell as an additional (and unnecessary) layer between your code and the third party application.
(I hope you get what I mean.)

In case you want to keep this design for e.g. reading ps1 files and dynamically loading and executing them in your PowerShell session (what is absolutely valid), then I would highly recommend to protect the ps1 files for unauthorized modifications, especially if your application will be executed with administrator privileges. The easiest way might be ACLs on file system level, I guess.

Edgar.Bro
  • 121
  • 1
  • 1
  • 4
  • The reason I am using PowerShell is because according to IPFS installation instructions it must be done in PowerShell. The installation involves creating PowerShell profiles that the application is using. II do not get any errors and if I simply change the line to ps.AddScript("ipfs"); it will run correctly and I am getting a response. So it's a matter of passing those additional arguments. – faremax May 05 '22 at 14:11