#powershell
#powershell
Вопрос:
После извлечения данных из SQL в powershell у меня есть набор данных. Как мне преобразовать это в массив?
$data.tables | gm
дает мне TypeName: System.Data.DataSet
Если я запрашиваю информацию из таблицы, которую я извлек, я получаю:
$data.Tables | fl
ServerName : Server10
SamAccount : Admin-Server10
но $data доступен только для чтения. Я не планирую выполнять обратную запись в базу данных, но хочу иметь возможность работать с данными и изменять их, находясь в памяти.
Мне нужен строковый массив, содержащий эти значения.
Конечно, я мог бы сделать:
$x = "" | select servername,SamAccount
$x.Servername = $data.tables.servername
но должен быть более простой способ. Извлеченный мной набор данных содержит более 100 столбцов.
Есть ли способ преобразовать это просто в массив строк (или как бы он ни назывался).. Строка, в которой я могу получить доступ к элементам данных внутри нее?
Я хочу иметь возможность использовать:
write-host "$($x.servername)"
и получить Server10
Кстати, в наборе данных всего 1 строка данных.. Просто много столбцов.
Комментарии:
1. Похоже, что для начала это не массив из-за одной строки. Потому что это не так. Если вы помещаете свой набор данных в ‘объект’ Powershell (переменную) и выполняете $data[0], что он возвращает?
Ответ №1:
По сути, вам нужно развернуть все, чтобы перейти от многомерного массива к одномерному массиву. Путь для перехода от набора данных к одной строке:
DataSet -> DataTableCollection -> DataTable -> DataRowCollection -> DataRow
Что такое:
$DataTableCollection = $DataSet.Tables #Get the Tables
$DataTable = $DataTableCollection[0] #Only need the first Table
$DataRowCollection = $DataTable.Rows #Get the Rows
$DataRow = $DataRowCollection[0] #Only need the first Row
Или, для упрощенного однострочного:
$Row = $DataSet.Tables[0].Rows[0]
Затем это позволяет вам получить доступ к свойствам, как вы ожидаете.
$Row.ServerName = "asdf"
Комментарии:
1. Это позволяет ему легко ссылаться на вещи, но его данные настроены только для чтения, поэтому он не может манипулировать никакими значениями, что и было целью его сообщения.
2. Это объясняет, как получить доступ к повторным данным, но все равно не позволяет мне манипулировать ими. Если я устал
$DataSet.Tables[0].Rows[0].servername = "Test"
, он все равно терпит неудачу.3. Нет. Не используйте
$DataSet.Tables[0].Rows[0].servername
, потому что да, набор данных доступен только для чтения. Присвойте строку$Row
переменной и используйте DataRow, поскольку она не доступна только для чтения.
Ответ №2:
Вы можете создать объект для каждой строки, а затем заполнить их значения на основе столбцов таблицы. Это даст вам PSCustomObject для каждой строки со свойствами, на которые вы можете ссылаться и изменять.
$MyArray = ForEach($Row in $Data.Tables[0].Rows){
$Record = New-Object PSObject
ForEach($Col in $Data.Tables[0].Columns.ColumnName){
Add-Member -InputObject $Record -NotePropertyName $Col -NotePropertyValue $Row.$Col
}
$Record
}
Когда это будет сделано $MyArray
, появится массив пользовательских объектов, с которыми вы можете работать сколько угодно.
Комментарии:
1. Возможно, я упускаю что-то простое. Используя ваш код точно так, как написано, когда я набираю $myArray, я вижу подтипы. Но если я попытаюсь сделать
$MyArray.servername = "dd"
это, он не сможет сказать, что свойство не может быть найдено для объекта.2. Это потому
$MyArray
, что это массив объектов. Вы можете удалить[array]
из первой строки или ссылаться на объект в массиве по индексу$MyArray[0].servername = "dd"
3. Проверил это, без ссылки [array], это именно то, что я пытался сделать. Спасибо.. У вас 26 КБ (на данный момент), поэтому баллы могут мало что значить, но они ваши. Даже значения внутри нового объекта сохраняют там типы. (строка против логического значения). Отлично, спасибо..
Ответ №3:
Ответ, данный администратором, правильный. Вот другой, значительно более быстрый способ (если мы говорим о тысячах строк), который только один раз перебирает имена столбцов и сохраняет объекты в arraylist
Сначала получите все имена свойств
[string[]]$Properties = @()
Foreach($col in $DataSet.Tables[0].Columns) {
$Properties = $col;
}
Затем добавьте все строки как PSCustomObject (с именами столбцов из набора данных) в arraylist:
$arrayList = New-Object System.Collections.ArrayList
Foreach($row in $DataSet.Tables[0]) {
$arrayList.Add(($row | Select-Object $Properties)) > $null;
}