Вернуть PSObject Powershell как DataTable в C#

Я написал скрипт Powershell, который читает файл CSV и возвращает предопределенную коллекцию из данных. Ниже приведен пример вывода указанного скрипта.

Count     Name
------   ------
  12      Rubies
   3      Pearls
  20      Emeralds

Я могу получить результаты в C#, сохранив его в PSObject следующим образом:

var shell = PowerShell.Create();
shell.Commands.AddScript("C:\\Scripts\\Powershell\\Get-MyData.ps1");
Collection<PSObject> results = shell.Invoke();

Теперь, когда я ожидаю отдельный объект, я могу получить каждое значение и назначить его переменным следующим образом:

foreach (PSObject psObject in results)
{
   localVariable = Convert.ToString(psObject.Properties["Name"].Value);
}

Однако у меня возникли проблемы с преобразованием этого решения в динамическое. То есть ожидается, что число строк будет различным. Так что я реализовал это раньше, когда источником является база данных SQL, использующая решение, аналогичное тому, которое опубликовано здесь, поэтому я предположил, что таблицы данных должны быть подходящим способом, но я не могу заставить его работать в этом сценарии. Есть идеи или предложения? Спасибо!

Примечание. Компонент скрипта Powershell здесь обязателен, так как он включает в себя другие механизмы для формулирования выходных данных, поэтому, хотя я мог просто читать из CSV-файла с использованием C#, это просто не вариант.

4 ответа

Решение

Из вашего вопроса я понял, что вы хотите иметь DataTable для дальнейшей обработки данных и использовать его в своей соответствующей коллекции.

Вы можете продолжить так:

DataTable dt=new DataTable();
dt.Colums.Add("Count");
dt.Colums.Add("Name");
foreach (PSObject psObject in results)
{
   foreach(PSPropertyInfo prop in psObject.Properties)
   {
     var count=prop.Name; 
     var name=prop.Value;
     //In other words generate output as you desire.
     dt.Rows.Add(count,name);
   }
}

Надеюсь, это полезно для вас.

Документы присутствуют: Док 1 и Док 2

Так как вы уже используете powershell для чтения файла csv, почему бы не продолжить?

Вы можете вызвать команду / скрипт powershell, чтобы повторить результаты вашего файла *.ps1, прежде чем вы начнете управлять им в C#.

Это довольно легко вызвать сценарий в C#, и вам не нужно создавать сценарий в виде файла. Вы можете просто отправить текст сценария напрямую и вызвать его.

может быть, вы даже можете объединить 2 аналогичных:

var shell = PowerShell.Create();
shell.Commands.AddScript("C:\\Scripts\\Powershell\\Get-MyData.ps1 | foreach {do-something $_}");
Collection<PSObject> results = shell.Invoke();

Обратите внимание, что я добавил канал после того, как возвращены результаты вашего скрипта. Помните, что AddScript очень похож на отправку текста в powershell.exe. Я передал этому файлу целые файлы сценариев из встроенных ресурсов.

Используйте Linq:

IEnumerable<dynamic> dynamicResults = from item in results                                     
                                      select new { Name = item.Name, Count = item.Count };

Затем установите myDataGrid.ItemsSource = dynamicResults;

Обнаружил, что мне нужно сделать что-то подобное, и создал это более общее решение для PS, возвращающего PSObject[], используя ответ @Nabeel Khan в качестве отправной точки.

      public DataTable PSObjectCollectionToDataTable(PSObject psObj)
{
    DataTable dt = new DataTable();
    IList collection = (IList)psObj.BaseObject; //turn this obj into an iList so we can loop it
    foreach (PSObject psRow in collection)
    {
        DataRow dtRow = dt.Rows.Add();
        foreach (var prop in psRow.Properties)
        {
            var name = prop.Name;
            var val = prop.Value;
            var type = val.GetType();
            //check if the table has the psobj's column
            if (!(dt.Columns.Contains(name)))
            {
                dt.Columns.Add(name, type); //if the table does not have the correct columns yet, add them
            }
            dtRow[name] = val;
        }
    }
    return dt;
}

Обратите внимание, что вам нужно будет включить следующие ссылки в начало вашего кода.

      using System.Data;
using System.Collections;
Другие вопросы по тегам