Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / PowerShell

Retrieving data from executed commands in PowerShell in C#

5.00/5 (4 votes)
15 Jun 2022CPOL3 min read 14K  
How to create a dynamic object in C # containing the results of a command executed in PowerShell.
How to quickly create a record class in C # containing the output values of a PowerShell command

Introduction

C # allows you to execute PowerShell commands from within. The results of such a command are passed to a single PSObject or a collection of such objects. In turn, PSObject may have a collection of members, each of which has an individual name and value.

When executing a PowerShell command, these results are typically presented in a table as text strings by default. After formatting with the fl command, we get a view of each pair of properties in the form of name: value as text.

In this article, I present how easy translate PSObjects to object of a class defined by a programmer with the appropriate properties.

Preliminary assumptions

Each PSObject represents a PowerShell command result record containing a specific number of values for that command and also with specific names. Values have types specific to a given command as well.

Result record types and descriptions of their structures are of course available in Microsoft's documentation, but this information is not easy to find due to the number of PowerShell commands and the mere availability of documentation.

However, we can easily work out the structure of the result records that interest us.

Using PowerShell itself:

We execute the command we are interested in with the fl modifier. Ideally, the command should return a single record, not a collection.

Get-Process lsass | fl

Collection of values displayed

Id           : 836
Handles: 2078
CPU       : 16.625
SI           : 0
Name    : lsass

informs us that the result record has 5 values named sequentially Id, Handles, CPU, SI and Name. The current values in text are displayed on the right side of each name.

When using C#

after getting PSObject with PowerShell.Invoke we have the same effect using:

C#
foreach (var member in PSObject.Members)
{ 
     Console.WriteLine (member.Name + ":" + member.Value.ToString ());
}

Now you would have to define a result record class for the Get-Process command:

C#
public class ProcessItem
{
   public string Id {get; set;}      = string.Empty;
   public string Handles {get; set;} = string.Empty;
   public string CPU {get; set;}     = string.Empty;
   public string SI {get; set;}      = string.Empty;
   public string Name {get; set;}    = string.Empty;
}

Clue

Now we should equip our class with a method that would extract values from PSObject members and insert them into the appropriate class properties.

The easiest way would be to look at the members of PSObject and match the name of each to the name of the class property. When we find a suitable name for the property, we enter the value in text form.

C++
Id = member["Id"].Value.ToString();
Handles = member["Handles"].Value.ToString();
CPU = member["CPU"].Value.ToString();
SI = member["SI"].Value.ToString();
Name = member["Name"].Value.ToString();

However, such an enumeration is not very pretty. What if we have a class with several dozen (or more) properties?

At each class in C #, you can browse its properties by getting the name given to the property by the programmer in the form of a text string. 

There is a method

C#
Class_Name.GetType().GetProperties()

returning a collection of properties where you can access both the name and the value modification.

From here, we can easily automate the search in PSObject of values appropriate for a specific property.

C#
foreach (var prop in MyClass.GetType().GetProperties())
{
      prop.SetValue(MyClass, pso.Members[prop.Name].Value.AsString());
}

Please note that in our defined class, which is to reflect the properties of the PowerShell command result record, we do not have to put all the properties, only those of interest. The PSObject member parsing method will pick only those we've defined without spending any time on the rest.

Code

Below I present an example result record class with a value parsing procedure. the procedure is a bit more elaborate so as not to generate an error if some values are null in the result record. 

You can easily change this code snippet to the class required for your project.

C#
//The class name may be changed in order to match a PowerShell command.

public class ResultRecordItem
{
      //We can add here the next values shown as a result of the PowerShell command and remove unnecessary ones.
      //Property types MUST be text or we need to be able to detect the type and use the correct converter in the parsing procedure.

      public string Name {get; set;} = string.Empty;

      public string Status {get; set;} = string.Empty;

      public string GUID {get; set;} = string.Empty;

      public ResultRecordItem() {}

      public ResultRecordItem(PSObject pso)
      {
          foreach (var prop in this.GetType().GetProperties())
          {
             prop.SetValue(this, (pso.Members[prop.Name].IsNull() ? "" : pso.Members[prop.Name].Value.AsString()));
          }

          //Here we can add procedures to transform the read values.
          //Or creating new text values based on those already obtained.
      }
}

History

Version 1, written on June 15, 2022.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)