Обработка данных CSV с помощью Import-Csv и цикла ForEach в PowerShell

Вам приходилось выполнять одну и ту же задачу несколько раз? Например, создавать несколько пользователей Active Directory по одному, используя графический интерфейс? Или войти на сервер, чтобы удалить старые журналы из выбранных папок? Если ваш ответ – да, то знайте, что вы не одиноки. Пришло время овладеть командлетом PowerShell “Import-Csv” и циклом foreach.

Нет ничего плохого в ручных задачах; иногда это необходимо. Но когда речь идет о чтении и обработке файлов CSV, командлет PowerShell “Import-Csv” и цикл “ForEach” могут помочь.

Командлет PowerShell “Import-Csv” – отличный способ считывать данные из табличного источника, такого как файл CSV. Затем вы можете использовать цикл “ForEach” для перебора каждой строки данных CSV.

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

Если вы новичок в командлете “Import-Csv” и цикле “ForEach”, или если вам нужно освежить ваши знания, вы можете посетить эти ссылки, чтобы узнать больше.

Управление файлами CSV в PowerShell с помощью “Import-Csv” (цикл “foreach”)

Вернуться к основам: цикл “foreach” в PowerShell

Предварительные требования

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

  • A script editor such as Visual Studio Code, Atom, or Notepad++. Use whichever one you’re comfortable with.
  • Windows PowerShell 5.1 или PowerShell Core 6+
  • Доступ к Exchange Online (необязательно, если вы будете следовать примеру, связанному с Exchange Online).

Применение командлета Import-Csv и цикла ForEach

В следующих разделах приведены несколько примеров использования командлета Import-Csv и цикла ForEach, с которыми вы можете столкнуться в реальных сценариях. Хотя эти примеры импорта CSV foreach в PowerShell специфичны для каждой цели, важно понимать, что применяемая концепция и техника одинаковы.

Чтение и отображение записей из CSV

Возможно, самое простое использование командлетов Import-Csv и ForEach – это чтение записей из файла и их отображение в консоли. Анатомия CSV-файла аналогична базе данных. Он имеет заголовки столбцов, и каждая строка считается записью.

Например, ниже приведено содержимое файла с названием employee.csv, состоящего из трех столбцов – EmployeeID, Name, и Birthday, и четырех записей.

CSV containing employee records

Нижеприведенный код импортирует содержимое файла employee.csv, а затем передает импортированные данные в командлет ForEach-Object. Затем, ForEach-Object пройдет по каждой записи в импортированном CSV, чтобы отобразить объединенные значения в консоли. Скопируйте код ниже и сохраните его как list-employee.ps1.

Примечание: Тип цикла ForEach, использованный в приведенном ниже примере, – это командлет ForEach-Object. См. раздел “Командлет ForEach-Object” в этой статье.

Import-Csv .\employee.csv | ForEach-Object {
    Write-Host "$($_.Name), whose Employee ID is $($_.EmployeeID), was born on $($_.Birthday)."
}

После сохранения скрипта запустите его, вызвав его имя в PowerShell. При запуске скрипта вы должны увидеть вывод, аналогичный скриншоту ниже.

Imported CSV records displayed in the console

Поиск и отображение записей из CSV

В предыдущем примере вы узнали, как прочитать и отобразить все записи из CSV. В этом примере будет использован тот же файл CSV employee.csv, но на этот раз вы создадите функцию PowerShell для поиска EmployeeID в CSV.

Ниже приведен фрагмент кода PowerShell-функции с именем Find-Employee, у которой есть только один параметр. Имя параметра – EmployeeID, и он принимает значение идентификатора сотрудника для поиска в CSV.

Чтобы использовать эту функцию, ее необходимо импортировать в вашу сессию PowerShell. Есть два способа импортировать функцию Find-Employee в память:

  1. Скопировать и вставить нижеприведенный код в PowerShell.
  2. Сохранить скрипт как Find-Employee.ps1 и импортировать его с помощью техники dot-sourcing.

Примечание: тип ForEach-цикла, используемый в приведенном ниже примере, является оператором ForEach. См. раздел “Оператор foreach” в этой статье.

Function Find-Employee {
    param (
        # Параметр принимает идентификатор сотрудника для поиска.
        [Parameter(Mandatory)]
        $EmployeeID
    )

    # Импортируйте содержимое файла employee.csv и сохраните его в переменной $employee_list.
    $employee_list = Import-Csv .\employee.csv

    # Перебор всех записей в CSV
    foreach ($employee in $employee_list) {

        # Проверка, равен ли идентификатор текущей записи значению параметра EmployeeID.
        if ($employee.EmployeeID -eq $EmployeeID) {

            # Если EmployeeID найден, отобразите запись в консоли.
            Write-Host "$($employee.Name), whose Employee ID is $($employee.EmployeeID), was born on $($employee.Birthday)."
        }
    }
}

После импорта кода функции в сеанс PowerShell вызовите его, набрав имя функции следующим образом.

Find-Employee

Если функция запускается без использования параметра EmployeeID, она будет запрашивать значение EmployeeID для поиска. См. пример вывода ниже.

Function to search a CSV file for a specific record

Или же функцию можно запустить с указанным значением параметра EmployeeID во время выполнения, как показано ниже.

Find-Employee -EmployeeID 'E-2023'

Получение использования дискового пространства с нескольких серверов

Одной из обычных задач системных администраторов является мониторинг использования дискового пространства нескольких серверов. Вместо того чтобы входить в каждый сервер для проверки использования дискового пространства, вы можете создать список CSV со списком имен серверов, буквами дисков и пороговыми значениями. Затем, используя PowerShell, импортируйте файл CSV и переберите каждую строку для выполнения запроса.

Для создания скрипта, который получает информацию о использовании дискового пространства с удаленных серверов, сначала создайте список CSV со следующими заголовками:

  • servername – это имя сервера для запроса.
  • disk – это буква диска, информацию о использовании пространства которого нужно получить.
  • threshold – это определяет пороговое значение в ГБ. Если свободное пространство диска меньше этого значения, в отчете будет отображаться предупреждающий статус.

Приведенный ниже пример показывает, что в списке перечислены четыре записи. Ваш файл CSV будет отличаться в зависимости от количества серверов или дисков для чтения.

servername,disk,threshold
au-dc01,c,120
au-mail01,c,100
au-mail01,d,6
au-file01,c,120

После завершения работы с CSV сохраните файл как servers.csv. Это будет использоваться в качестве входного списка, который будет импортирован скриптом PowerShell.

Чтобы привести пример получения информации о использовании дискового пространства, скопируйте приведенный ниже код в редактор скриптов и сохраните его как diskReport.ps1. Скрипт должен быть сохранен в той же папке, где находится файл CSV.

$server_list = Import-Csv -Path .\servers.csv

foreach ($server in $server_list) {
    Get-WmiObject -Class Win32_logicaldisk -ComputerName ($server.servername) | `
        Where-Object { $_.DeviceID -match ($server.disk) } | `
        Select-Object `
    @{n = 'Server Name'; e = { $_.SystemName } }, `
    @{n = 'Disk Letter'; e = { $_.DeviceID } }, `
    @{n = 'Size (GB)'; e = { $_.Size / 1gb -as [int] } }, `
    @{n = 'Free (GB)'; e = { $_.FreeSpace / 1gb -as [int] } }, `
    @{n = 'Threshold (GB)'; e = { $server.Threshold } }, `
    @{n = 'Status'; e = {
            if (($_.FreeSpace / 1gb) -lt ($server.Threshold)) {
                return 'Warning'
            }
            else {
                return 'Normal'
            }
        }
    }
}

Выполняет следующие действия при запуске скрипта.

  • Импортирует файл CSV с именем servers.csv и сохраняет его в переменной $server_list.
  • Проходит по списку серверов, хранящемуся в переменной $server_list.
  • В каждой итерации цикла foreach текущая строка представлена переменной $server.
  • Получает информацию о диске с серверов с помощью командлета Get-WmiObject.
  • Выберите только соответствующие свойства для отображения.
    Имя сервера – Это имя системы, которая запрашивается.
    Буква диска – Буква, назначенная диску.
    Размер (ГБ) – Размер диска в ГБ
    Свободно (ГБ) – Размер свободного пространства в ГБ
    Порог (ГБ) – Установленный порог в ГБ
    Статус – Если значение Свободно (ГБ) меньше значения Порог (ГБ), возвращается статус «Предупреждение». В противном случае статус будет «Нормальный»

После сохранения файла сценария diskReport.ps1, он готов к запуску, вызывая его имя в PowerShell.

./diskReport.ps1

После выполнения ниже приведенный снимок экрана показывает результат выполнения сценария.

Disk space information gathered from multiple servers

Результат можно также экспортировать в CSV. Экспорт в CSV полезен, когда необходимо поделиться отчетом, поскольку экспортированный файл CSV можно отправить по электронной почте или загрузить на файловый ресурс или на сайт SharePoint. Обязательно ознакомьтесь с Export-Csv: The PowerShell Way to Treat CSV Files as First Class Citizens, если вам нужна дополнительная информация о экспорте в CSV.

Создание нескольких пользователей Active Directory

На этом этапе у вас уже должна быть надежная представление о том, как использовать Import-Csv и ForEach. В следующем примере ваше обучение идет дальше, добавляются командлеты New-ADUser и Get-ADUser.

Предположим, что вы получили файл CSV new_employees.csv, содержащий список новых сотрудников от отдела кадров. Каждая строка в файле CSV представляет одного сотрудника, которого необходимо принять на работу, и имеет следующие столбцы: FirstName, LastName, Department, State, EmployeeID и Office.

Имя пользователя должно быть производным от первой буквы имени сотрудника, объединенной с фамилией (например, bparr для пользователя Bob Parr).

CSV file containing new employees information for on-boarding

После сохранения файла CSV, ниже приведен скрипт, который использует Import-Csv для чтения файла CSV new_employees.csv. Затем он перебирает каждую строку, передавая значения в соответствующие параметры New-ADUser.

Import-Csv .\new_employees.csv | ForEach-Object {
    New-ADUser `
        -Name $($_.FirstName + " " + $_.LastName) `
        -GivenName $_.FirstName `
        -Surname $_.LastName `
        -Department $_.Department `
        -State $_.State `
        -EmployeeID $_.EmployeeID `
        -DisplayName $($_.FirstName + " " + $_.LastName) `
        -Office $_.Office `
        -UserPrincipalName $_.UserPrincipalName `
        -SamAccountName $_.SamAccountName `
        -AccountPassword $(ConvertTo-SecureString $_.Password -AsPlainText -Force) `
        -Enabled $True
}

После выполнения скрипта новые пользователи уже должны существовать в Active Directory. Однако хорошей практикой является подтверждение создания учетных записей пользователей.

Используя тот же файл CSV new_employees.csv в качестве справочника, ниже приведен скрипт, который выполняет импорт CSV и цикл для получения объектов ADUser, соответствующих тем, что указаны в списке.

Import-Csv .\new_employees.csv | ForEach-Object {
	Get-AdUser $_.SamAccountName
}

Добавление адреса прокси-электронной почты в почтовый ящик Office 365

В управлении почтовыми ящиками Office 365 запросы на добавление прокси-адресов для нескольких пользователей не редкость. Обычно в таких запросах администратор получает список пользователей и адрес электронной почты, который следует добавить, аналогично приведенному ниже примеру CSV.

The new_address.csv file contents

Примечание: Прежде чем выполнить любые командлеты Exchange Online в PowerShell, сначала необходимо войти в оболочку Управления Exchange Online.

Используя командлеты Import-Csv и цикл ForEach в сценарии PowerShell, список можно обработать за один раз. Ниже приведен пример такого сценария.

Сценарий ниже импортирует содержимое файла new_address.csv и сохраняет его в переменной $user_list. Затем, используя метод foreach(), PowerShell проходит по всему списку пользователей и использует значения username и email в каждой записи для добавления нового адреса электронной почты в каждый почтовый ящик.

$user_list = Import-Csv .\new_address.csv

$user_list.foreach(
    {
        Set-Mailbox -Identity $_.username -EmailAddresses @{add="$($_.email)"}
    }
)

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

Используя тот же CSV-файл new_address.csv в качестве справочника, можно проверить, были ли добавлены новые адреса, используя командлеты Import-Csv и цикл ForEach.

Сценарий ниже импортирует содержимое файла new_address.csv и сохраняет его в переменной $user_list. Затем, используя метод foreach(), PowerShell проходит по всему списку пользователей, чтобы проверить, существует ли новый адрес электронной почты в списке адресов прокси почтового ящика. Если найден, будет возвращено значение True; в противном случае результат будет False.

$user_list = Import-Csv .\new_address.csv

$user_list.foreach(
    {
        $emailObj = (Get-Mailbox -Identity $_.username).EmailAddresses
        if ($emailObj -contains $_.email) {
            Write-Host "$($_.username) --> $($_.email) --> TRUE"
        }
        else {
            Write-Host "$($_.username) --> $($_.email) --> FALSE"
        }
    }
)

Когда скрипт проверки запускается, результат должен выглядеть так, как показано на скриншоте ниже. Вы заметите, что в выводе ниже статус – все TRUE, что означает, что новые адреса электронной почты были успешно добавлены в каждый почтовый ящик.

Running the new email address verification

Отправка ежедневного прогноза погоды по списку рассылки

В этом примере предполагается, что у вас есть файл CSV, содержащий список адресов электронной почты подписчиков и их район или местоположение. Эти подписчики ожидают ежедневное письмо с прогнозом погоды на конкретный день для их местоположения. Посмотрите на пример CSV ниже с именем файла subscribers.csv.

Weather forecast subscribers list

CSV ниже содержит только двух подписчиков. Один в Лос-Анджелесе и один в Маниле.

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

  • Импортировать информацию об электронной почте и районе из файла subscribers.csv
  • Для каждого подписчика:
    – Загрузить изображение прогноза погоды на основе района подписчика с сайта https://wttr.in/
    – Отправить изображение прогноза погоды на адрес электронной почты подписчика.

Ниже приведен скрипт, выполняющий перечисленные выше действия. Вам нужно только изменить первые три переменные – $senderAddress, $smtpServer и $smtpPort. Затем скопируйте этот код и сохраните его как Send-WeatherInfo.ps1. См. комментарии перед каждым разделом скрипта, чтобы узнать больше о том, что делает код.

# НАЧАТЬ настройки SMTP здесь
$senderAddress = '<SENDER EMAIL ADDRESS HERE'
$smtpServer = '<SMTP RELAY SERVER HERE>'
$smtpPort = 25
# НАЧАТЬ настройки SMTP здесь

# Импорт списка электронных адресов подписчиков
$subscriber_list = Import-Csv .\subscribers.csv

# Получение прогноза погоды и отправка электронной почты
$subscriber_list.foreach(
    {
				
        # Создание URL для получения информации о погоде по региону
        $uri = ('<https://wttr.in/>' + $_.Area + '_u1F.png')
        # Получение изображения прогноза погоды для региона. Сохранение изображения как <AREA>.png
        $imageFile = (((Resolve-Path .\).Path) + "$($_.Area).png")
        Start-BitsTransfer $uri -Destination $imageFile

        # Создание объекта вложения
        $attachment = New-Object System.Net.Mail.Attachment -ArgumentList $imageFile
        $attachment.ContentDisposition.Inline = $true
        $attachment.ContentDisposition.DispositionType = "Inline"
        $attachment.ContentType.MediaType = "image/png"
        $attachment.ContentId = "weatherImage"

        # Создание сообщения
        $emailMessage = New-Object System.Net.Mail.MailMessage
        $emailMessage.From = $senderAddress
        $emailMessage.To.Add($_.Email)
        $emailMessage.Subject = ('Weather Forecast - ' + $_.Area)
        $emailMessage.IsBodyHtml = $true
        $emailMessage.Body = '<img src="cid:weatherImage">'
        $emailMessage.Attachments.Add($attachment)

        # Отправка сообщения
        Write-Output "Sending Weather Info to $($_.Email)"
				$smtp = New-Object Net.Mail.SmtpClient($smtpServer, $smtpPort)
        $smtp.Send($emailMessage)

        # Освобождение объектов
        $attachment.Dispose()
        $emailMessage.Dispose()
    }
)

После выполнения скрипта будет отправлено электронное письмо каждому подписчику, аналогичное примеру на скриншоте электронного письма ниже.

Weather forecast for Manila sent as an email to the subscriber
Weather forecast for Los Angeles sent as an email to the subscriber

Сводка

Нет ограничений для задач, в которых можно использовать Import-Csv и цикл ForEach. Пока задача включает список с разделенными столбцами, вы можете использовать эту мощную комбинацию.

В этой статье вы узнали, как CSV-файл подобен базе данных. Вы также узнали, как использовать Import-Csv для импорта данных и как ссылаться на значения во время итерации цикла ForEach.

I hope that with the many examples provided in this article, you now understand more of the Import-Csv and ForEach. And, that you would be able to use the knowledge you gained in this article in your administration and automation tasks.

Дополнительное чтение

Source:
https://adamtheautomator.com/import-csv-and-the-foreach-loop/