I have a web UI that allows writing Powershell scripts. Later this script is being sent to the backend and executed.
In this post, I will focus how to execute the Powershell inside c#.
First of all you need to add to you project "System.Management.Automation" reference. If you are not sure where to take it from, just open windows PowerShell windows and type
[psobject].assembly.location
The output is the exact location of the DLL.
In my program, the purpose of the PowerShell is to give the user the ability
to manipulate the data of some DataTable object. For this purpose the program
will person 3 operations.
1. Create DataTable
2. Pass it to Powershell
3. Change the DataTable from inside the PowerShell
4. Return the DataTable
Create DataTable
DataTable dt = new DataTable(); dt.Columns.Add("ID",typeof(Int32)); DataRow dr = dt.NewRow(); dr["ID"] =22; dt.Rows.Add(dr);
Create a Powershell object and pass this DataTable to it
InitialSessionState iss = InitialSessionState.CreateDefault(); Runspace rs = RunspaceFactory.CreateRunspace(iss); rs.Open(); string powershell = @"Param([system.Data.DataTable]$dt) [system.Data.DataRow]$row = $dt.NewRow(); $row.ID = 3; $dt.Rows.Add($row); return ,[system.Data.DataTable]$dt; "; //here is the catch "," using (PowerShell powerShellInstance = PowerShell.Create()) { powerShellInstance.Runspace = rs; powerShellInstance.AddScript(powershell); powerShellInstance.AddParameter("dt", dt); DataTable outDt = null; Collection<PSObject> PSOutput = powerShellInstance.Invoke();
Note the Powershell parameter. It expects to get the DataTable . After this the script adds a new record into the DataTable.
This problematic point that took me some time to figure is how to return the DataTable.
The "," sign before [system.Data.DataTable]$dt; is not a misstake.
If you don't put it the script will return System.Data.DataRow!!! object.
You actually need "," to specify that you are returning the collection of DataRows
What is left now is to read the content of the output. You can check if there are some errors
and actually read the output DataTable
//catch the errors foreach (var err in powerShellInstance.Streams.Error) { var ex = err.Exception?.Message; }
//catch the output foreach (PSObject pSObject in PSOutput) { outDt = (DataTable)pSObject.ImmediateBaseObject; } }
If we check the "outDt" is debugger, we will see row with a value "3" that we added in the
Powershell script
Datatable created by Powershell manipulation |
P.S. Point of concern. I am trying to figure out how I can secure the PowerShell
script from harming my backend. I could not find a way in PowerShell to restrict my
PowerShell access to my file system. To solve this problem, I wrapped the whole
code in a custom restricted AppDomain.
No comments:
Post a Comment