Освоение команды Import-Csv и других команд для работы с CSV в PowerShell

Команды PowerShell Export-Csv и Import-Csv позволяют администраторам импортировать CSV-файлы с помощью цикла foreach, использовать Export-Csv для добавления CSV-файлов и экспорта массивов в файл CSV, а также многое другое.

В этой статье вы узнаете о многих общих сценариях, в которых можно использовать PowerShell для управления CSV-файлами, таких как:

  • Чтение CSV-файлов с помощью PowerShell
  • Сохранение CSV-файлов с помощью PowerShell
  • Форматирование вывода перед запуском Export-CSV
  • Добавление к CSV
  • Добавление различий в существующий файл
  • Export-CSV и строка #TYPE

Если вы не знакомы с внутренним устройством файлов CSV, это текстовые файлы, которые следуют стандартному формату, буквально разделяя значения в таблице запятыми. Вы можете создать файл CSV в PowerShell с помощью командлета Export-Csv и направить в него один или несколько объектов.

Нижеприведенная команда находит первые два запущенных процесса и передает сгенерированные объекты командлету Export-Csv. Затем командлет Export-Csv создает файл CSV с именем processes.csv в корне диска системы (скорее всего C:\).

PS51> Get-Process | Select-Object -First 2 | Export-CSV -Path "$env:SystemDrive\processes.csv"

Теперь откройте файл processes.csv с помощью Блокнота. Вы увидите "Name","SI","Handles","VM" в верхней части как заголовки. Вы также увидите #TYPE System.Diagnostics.Process, что сейчас может не иметь особого смысла. Не беспокойтесь, мы рассмотрим эту строку в этой статье.

Чтение файлов CSV с помощью Import-Csv

Хотите больше советов, подобных этому? Посетите мой личный блог PowerShell.

PowerShell имеет несколько команд, позволяющих читать текстовые файлы. Эти команды – это Get-Content и Import-Csv. Каждая из этих двух команд технически считывает файл одинаковым образом. Но Import-Csv идет на шаг дальше. Import-Csv понимает внутреннюю структуру не только текстового файла, но и CSV-файла.

Поскольку файл CSV следует определенной схеме, Import-Csv понимает эту схему CSV. Эта команда не только считывает текстовый файл с диска, но и преобразует строки в CSV-файле в объекты PowerShell.

Несоответствующие CSV-файлы

Обычно данные CSV разделены запятыми, но бывают случаи, когда CSV (технически уже не CSV на этом этапе) имеет данные, разделенные другим разделителем. Эти разделители иногда являются табуляцией или, возможно, точкой с запятой.

Если у вас есть CSV-файл с другим разделителем, вы можете использовать параметр Delimiter. Этот параметр указывает Import-Csv не искать запятые, что он делает по умолчанию, а искать другое значение.

Например, если у вас есть файл, разделенный табуляцией, вы можете прочитать файл следующим образом:

PS51> Import-Csv -Path tab-separated-data.csv -Delimiter "`t"

Добавление заголовков

A common Import-Csv parameter is Header. This parameter lets you specify the property names of the objects created by this cmdlet.

По умолчанию cmdlet Import-Csv будет рассматривать верхнюю строку CSV-файла как заголовки. Затем он преобразует эти значения в свойства каждой строки (объекта). Но если у вас есть CSV-файл без строки заголовка, вы можете использовать параметр Header, чтобы определить его самостоятельно.

Параметр Header предотвращает использование Import-CSV вашей первой строки в качестве заголовка и также экономит вам головную боль от необходимости вручную открывать CSV-файл для добавления заголовков.

Чтобы продемонстрировать это поведение, откройте блокнот и скопируйте/вставьте текст ниже. Этот текст представляет собой набор данных из трех строк и двух столбцов.

a,1
b,2
c,3

Сохраните файл с текстом как test.csv. Не забудьте включить расширения типов файлов или заключить файл в кавычки, чтобы случайно не сохранить его с расширением файла .csv.txt!

Теперь используйте Import-CSV, чтобы прочитать недавно созданный CSV-файл без параметра Header и проверьте результат.

PS51> Import-Csv .\test.csv

a 1
---
b 2
c 3

Обратите внимание, что здесь использована первая строка в качестве свойств объекта. A и 1 не являются “метками”, которые вы хотите использовать для свойств объекта. A, b и c – это буквы, в то время как 1, 2 и 3 – это числа. Вам нужно определить их с использованием параметра Header, как показано ниже:

PS51> Import-Csv .\test.csv -Header "Letter", "Number"

Letter Number
------ ------
a      1
b      2
c      3

Сохранение файлов CSV с помощью PowerShell

Если вам нужно создать или сохранить файл CSV из объектов PowerShell, вы можете также поступить по-другому. В то время как cmdlet Import-Csv “преобразует” файл CSV в объекты PowerShell, Export-Csv делает обратное. Этот cmdlet “преобразует” объекты PowerShell в файл CSV.

Сохранение файла CSV с помощью Export-Csv позволяет вам позже просматривать или использовать эти данные в других системах.

Например, я могу сохранить все выполняющиеся процессы на своем компьютере, направив вывод Get-Process в cmdlet Export-Csv.

PS51> Get-Process | Export-Csv -Path processes.csv

Cmdlet Export-Csv прост по своей природе, но есть несколько подводных камней, на которые стоит обратить внимание.

Форматирование вывода перед запуском Export-CSV

Как вы видели выше, Export-Csv сам по себе выполняет “сырое” преобразование. Он не добавляет никакого специального форматирования rich-text, цветов и т. д.

Один из наиболее распространенных подводных камней – попытка сделать вывод более приятным перед экспортом в CSV. Многие пользователи пытаются улучшить вид вывода перед экспортом в CSV. Но я собираюсь показать вам, что это может только ухудшить ситуацию.

Вы можете открыть CSV-файл в Microsoft Excel, выделить текст курсивом, жирным шрифтом, добавить цвета и многое другое. Однако, если вы сохраните файл как CSV (а не как книгу Excel), вся форматированная информация будет удалена. Файл CSV просто не достаточно “умный”.

Помните, что файлы CSV – это просто текстовые файлы, в которых значения разделены запятыми (или иногда табуляциями). Перенаправление вывода Import-Csv в командлет PowerShell Format-* не сработает ожидаемым образом.

Согласно документации Microsoft Export-Csv: “Не форматируйте объекты перед отправкой их в командлет Export-CSV. Если Export-CSV получает форматированные объекты, CSV-файл будет содержать свойства форматирования, а не свойства объекта.”

Почему так происходит?

Откройте окно PowerShell и создайте фиктивные данные. Давайте воспользуемся примером Get-Process, рассмотренным в первом разделе этой статьи. Но на этот раз присвойте вывод переменной. Затем направьте эти объекты процесса в командлет Format-Table.

PS51> $a = Get-Process
PS51> $a | Format-Table
Using Format-Table

Вы увидите, что с использованием Format-Table у вас теперь чистый таблицчатый вывод.

Теперь сохраните этот вывод в другую переменную.

PS51> $b = $a | Format-Table

Теперь просмотрите свойства переменных $a и $b с помощью командлета Get-Member. Этот командлет поможет вам понять, почему эти два кажущихся одинаковыми объекта не экспортируются в файл CSV одинаковым образом:

PS51> $a | Get-Member
System.Diagnostics.Process object type
PS51> $b | Get-Member
Format-Table‘s many object types

Результат напрямую от Get-Process возвращает: TypeName: System.Diagnostics.Process, тогда как результат от Format-Table совершенно отличается. Он возвращает множество различных типов с разными свойствами.

Если вы просмотрите $a и $b в консоли, вывод будет идентичным. Это поведение вызвано системой форматирования PowerShell.

Как это влияет на вывод Export-Csv?

PS51> $b | Export-Csv | Format-Table

Export-Csv считывает каждый объект “как есть”. Когда вы перенаправляете вывод на командлет Format-*, вы изменяете входные данные, которые получает Export-CSV. Это затем влияет на вывод, который сохраняется в вашем новом файле CSV.

Если вы собираетесь перенаправлять вывод на командлет Export-Csv, не используйте перенаправление вывода на какой-либо командлет Format-*.

Помните, что CSV-файлы ориентированы на данные, а не на форматирование.

Добавление данных в CSV-файл

Иногда вам может потребоваться добавить данные в существующий файл, а не создавать совершенно новый. По умолчанию Export-Csv перезапишет любой файл, указанный через параметр Path.

Если вам нужно добавить данные в CSV, используйте параметр Append.

Предположим, у вас есть цикл, в котором вы хотите сохранить каждый обработанный объект в CSV-файл. На каждой итерации у вас есть разный объект, который вы хотели бы сохранить в файл CSV. Поскольку вы вызываете Export-Csv повторно, он будет перезаписывать этот файл CSV, если вы не используете параметр Append. Без параметра Append вы получите только последний объект, что в большинстве случаев не является желаемым результатом.

Ниже приведен пример поиска первых пяти запущенных процессов. Затем происходит вход в цикл foreach PowerShell и запись свойств Name и ProductVersion в файл test.csv по одному за раз.

Get-Process | Select-Object -First 5 | Foreach-Object {
    $_ | Select-Object Name, ProductVersion | Export-CSV -Path C:\test.csv -Append
}

Без использования параметра Append вы увидите, что в файле CSV будет только пятый процесс.

Добавление Различий в файл CSV

Возможно только добавление различий свойств в существующий файл CSV с помощью Export-Csv. Это означает, что если столбцы строки CSV и объект для записи отличаются, тогда можно добавить их.

Чтобы добавить только различия в файл CSV, вам нужно использовать параметры Append и Force вместе. Согласно документации Microsoft “Когда параметры Force и Append объединены, объекты, содержащие несоответствующие свойства, могут быть записаны в файл CSV. В файл записываются только совпадающие свойства. Несоответствующие свойства отбрасываются.”

Для демонстрации создайте один объект с двумя свойствами; Name и Age.

PS51> $Content = [PSCustomObject]@{Name = "Johnny"; Age = "18"}

Теперь создайте другой объект с свойствами Name и Zip.

PS51> $OtherContent = [PSCustomObject]@{Name = "Joe"; Zip = "02195"}

Каждый объект имеет разные свойства.

Затем создайте CSV-файл из первого объекта, а затем попробуйте добавить в CSV второй объект без параметра Force. Вы получите ошибку.

PS51> $Content | Export-CSV -Path .\User.csv -NoTypeInformation
PS51> $OtherContent | Export-CSV -Path .\User.csv -NoTypeInformation -Append
Export-Csv without Force

Однако, если вы используете параметр Force, Export-Csv будет отлично работать.

PS51> $OtherContent | Export-CSV -Path .\User.csv -NoTypeInformation -Append -Force

Тем не менее, вы заметите, что столбец Zip отсутствует в CSV-файле. Используйте Force осторожно. Он может не дать ожидаемого результата.

PS51> Import-Csv -Path .\User.csv

Name   Age
----   ---
Johnny 18
Joe

Export-CSV и строка #TYPE

По умолчанию, если использовать Export-CSV без дополнительных параметров, в начале вашего CSV-файла будет включена строка #TYPE. Затем следует тип объекта, который Export-Csv получил.

#TYPE System.Diagnostics.Process

Большую часть времени эта строка на самом деле не полезна при обработке вывода. Эта строка присутствует только на случай, если вам нужно сохранить тип объекта, откуда взялись свойства и значения.

Чтобы удалить эту строку, используйте параметр NoTypeInformation. Этот параметр полностью удаляет эту строку из CSV.

Обратите внимание, что начиная с PowerShell Core, это больше не требуется.

Summary

Использование командлетов PowerShell Import-CSV и Export-CSV позволяет легко работать с файлами CSV. Эти два полезных командлета следует часто использовать при работе с объектами и файлами CSV.

Моя надежда заключается в том, что благодаря объяснениям и примерам, которые я предоставил здесь, вы сможете четко понимать ситуации, в которых можно использовать эти командлеты на вашу пользу.

Хотите больше подобных советов? Загляните на мой личный блог PowerShell.

Source:
https://adamtheautomator.com/import-csv/