How to run a CmdLet from a Process class?

I want to run a CmdLet (in particular Write-Output) from a Process class, but I am getting a The system cannot find the file specified. error. Which makes sense, as Write-Output is not a file:

using (Process process = new Process()) {
  process.StartInfo.FileName = "Write-Output";
  process.StartInfo.Arguments = "hello";
  await process.WaitForExitAsync();

But, how could I use this correctly? I want to grab hello from standardoutput later and return it.

>Solution :

The Process class runs executables native to the OS. A commandlet is not an executable to the OS, but a concept of PowerShell ("inside" PowerShell). You have to invoke PowerShell, then make it run the commandlet you need.

But first you need to decide (you didn’t say in the question) if you want to use Windows PowerShell or PowerShell (core). The Windows PowerShell is installed in "%windir%\System32\WindowsPowerShell\v1.0\powershell.exe". PowerShell (Core) is installed in various locations. On my system I have it (installed) in C:\Program Files\PowerShell\7-preview\pwsh.exe. YMMV, for more details on the different PowerShell Versions check this.

The command line won’t differ, so I use pwsh.exe as an example.

process.StartInfo.FileName = "<path>\pwsh.exe";
process.StartInfo.Arguments = "-Command \"Write-Output 'Hello'\""

Redirecting/reading the output of PowerShell invoked like this does not differ from doing this for any other command. There are already lots of Q&A about this on SO (for example this one).

One more thing. For any nontrivial use, I would think about running the commandlet inside your own process. You can host powershell in your own application. Certainly more advanced, but might be worth it, if you need to run specific PowerShell commands a lot.

Leave a Reply