A quick an easy but still (at least for me) useful article for this month.
Have you ever needed to run a PowerShell script from a .Net application? Pretty easy you would say and I fully agree. But what I was really needing was to retrieve all the outputs (from Write-Host or Write-Output statements) and any errors reported by the script. Do I get your attention now?
This is exactly what will be shown here in this article.
The downloadable code
This month’s downloadable demo solution contains both VB and C# projects. The solution was created using Visual Studio 2017 but can be used in most older versions as well.
Building the UI
As you can see in figure 1, the UI is very simple:
The font of the textbox containing the results has been set to Courier New. Because it is a monospace/fixed font, it makes it just easier to read when the script returns a table.
Figure 1: The demo app in action
The code
I really hope you are not expecting anything fancy here, or else you will be very disappointed!
In fact, I will just reuse a component that has always been around. I have even written an article on this component back in 2003. Can you guess which one? It is our friend the Process component.
The code is going to say to this component to run the PowerShell.exe process, using the script passed as the arguments. Finally, the StandardOutput and StandardError properties are read after the process has completed to retrieve the outputs and the errors (if any).
Here is the full code:
Private Sub btnExecute_Click(sender As Object, e As EventArgs) Handles btnExecute.Click txtResults.Clear() Dim script As String = txtScript.Text Dim objProcess As New System.Diagnostics.Process() objProcess.StartInfo.FileName = "powershell.exe" objProcess.StartInfo.Arguments = script objProcess.StartInfo.RedirectStandardOutput = True objProcess.StartInfo.RedirectStandardError = True objProcess.StartInfo.UseShellExecute = False objProcess.StartInfo.CreateNoWindow = True objProcess.Start() Dim output As String = objProcess.StandardOutput.ReadToEnd() Dim errors As String = objProcess.StandardError.ReadToEnd() txtResults.Text += "Output:" + Environment.NewLine txtResults.Text += "-------" + Environment.NewLine txtResults.Text += output + Environment.NewLine txtResults.Text += Environment.NewLine txtResults.Text += "Errors:" + Environment.NewLine txtResults.Text += "-------" + Environment.NewLine txtResults.Text += errors + Environment.NewLine End Sub
private void button1_Click(object sender, EventArgs e) { txtResults.Clear(); string script = txtScript.Text; System.Diagnostics.Process process = new System.Diagnostics.Process(); process.StartInfo.FileName = @"powershell.exe"; process.StartInfo.Arguments = script; process.StartInfo.RedirectStandardOutput = true; process.StartInfo.RedirectStandardError = true; process.StartInfo.UseShellExecute = false; process.StartInfo.CreateNoWindow = true; process.Start(); string output = process.StandardOutput.ReadToEnd(); string errors = process.StandardError.ReadToEnd(); txtResults.Text += "Output:" + Environment.NewLine; txtResults.Text += "-------" + Environment.NewLine; txtResults.Text += output + Environment.NewLine; txtResults.Text += Environment.NewLine; txtResults.Text += "Errors:" + Environment.NewLine; txtResults.Text += "-------" + Environment.NewLine; txtResults.Text += errors + Environment.NewLine; }
In your application, the script will probably not come from a textbox but since it is nothing more then a string passed to the Arguments property, it can come from anywhere like a database or an existing PowerShell script file that you read into a string.
Running the application
If you are using my downloadable demo and you try to run it, the script textbox is already filled with a simple script to demonstrate the various kind of outputs that we can get.
As you can see, all the outputs from Write-Host are shown (which can be very useful to debug). Even the errors are shown.
Another mechanism
The Process component is not the only mechanism that will have your .Net application runs PowerShell code. You could also have used the System.Management.Automation component instead. It is different in the way that you cannot provide a full script one shot like we did here.
But is worth looking at to see if there could be something in there more useful to your specific case.
Conclusion
I told you it was easy. Nothing magics here. Just a few properties correctly used and more than useful results are spit out.
This is another proof that the .Net framework was well written since its inception!