Автоматизация с помощью PowerShell, на примере взаимодействия Outlook и Active Directory

от автора

PowerShell — это средство автоматизации разработанное и выпущенное Microsoft в 2006 году на замену Командной строке и её батникам, помимо всего функционала cmd — Powershell обзавелась собственным скриптовым языком с поддержкой классов, объектов, переменных и т.д. По сути с её помощью можно обращаться ко всему функционалу Windows и Windows Server как к объектам и выполнять с ними действия. В статье я расскажу свой опыт, как автоматизировал создание пользователей в домене из писем-заявок в Outlook на удаленном сервере AD.

Планировщик задач

Планировщик задач

Все запланированные задачи в Windows можно посмотреть в «Планировщике задач», автоматизировать Windows возможно как с его помощью, так и чисто на Powershell, чтобы вывести все текущие задачи необходимо выполнить:

Get-ScheduledJob 

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

Get-ChildItem $HOME\AppData\Local\Microsoft\Windows\PowerShell\ScheduledJobs

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

$Условие = New-JobTrigger -Daily -At 12AM  Register-ScheduledJob -Name NewAD_User -ScriptBlock {######} -Trigger $Условие

Рассмотрим как происходит взаимодействие с Outlook, и сразу отмечу что для выполнения действий с почтой, необходимо закрыть открытое приложение, иначе команды не будут выполняться.

#Завершение Outlook Get-Process | Where-Object {$_.ProcessName -eq "OUTLOOK"} | Stop-Process  Start-Sleep -Seconds 10  # Создание объекта Outlook $outlook = New-Object -ComObject Outlook.Application  # Получение коллекции папок $folders = $outlook.Session.Folders.Item("###Ваш адрес почты####").Folders  # Выбор папки "Входящие" $Входящие = $folders.Item("Входящие")  $Исполнено = $folders.Item("Исполнено")  # Получение последнего письма $Письма = $Входящие.Items | Sort-Object ReceivedTime -Descending

В данном коде я получаю сортированный по дате список писем из папки «Входящие» и адрес папки «Исполнено» куда я планирую перемещать письма после выполнения скрипта.

foreach ($Письмо in $Письма) {  $lines = $Письмо.Body -split "`n"  #Условие чтения письма if ($lines[0].Substring(0, 29) -ne "Заявка в IT - Новый сотрудник") {continue}   $Дата_заявки = $lines[0].Substring(32).Trim() $Фамилия = $lines[2].Substring(18).Trim() $Имя = $lines[4].Substring(4).Trim() $Отчество = $lines[6].Substring(9).Trim() $Отдел = $lines[8].Substring(6).Trim() $Должность = $lines[10].Substring(10).Trim() $Организация = $lines[12].Substring(12).Trim() $Подразделение = $lines[14].Substring(14).Trim() $Номер_телефона = $lines[16].Substring(15).Trim() $Мобильный_телефон = $lines[18].Substring(18).Trim() $Имя_пользователя_для_копирования_групп = $lines[20].Substring(29).Trim()

В данном фрагменте начинается цикл который проходит по каждому письму, преобразует в список строк и получает значения из него, в начале я добавил простую проверку на случай если на выделенный почтовый ящик попадет случайное письмо. Далее самое важное — создание учетки, и в моем случае контакта, на удаленном сервере, для этого используется команда Invoke-Command:

$Сессия = New-PSSession -ComputerName ###Сетевое имя или IP-адресс компа###
$Переменные = Invoke-Command -Session $Сессия -ScriptBlock {  param(####Все ваши переменные через запятую###)   команды на удаленном компе   return Переменные которые вернуться в массив обьектов "$Переменные" } -ArgumentList ###Переменные через запятую которые вы передали в параметры###

Переменная «$Переменные» примет, после выполнения команды на удаленном компьютере, переменные, указанные в return — они понадобятся для отправления письма-отчета.

Далее я преобразую имя и фамилию в логин, проверяю однофамильцев и при необходимости добавляю в логин цифру (Функция транслита в конце статьи в полном листинге)

#Транслит имени function global:Translit {} - Функция принимает кирилицу и возвращает латиницу   $count = 0  #---------------Получаем список пользователей AD-----------------  $adUsers = Get-ADUser -Filter * -Properties UserPrincipalName  #---------------------Создание логина---------------------------  #чтобы транслейтить имя надо написать: $Транслит = Translit($имя) $Имя_пользователя = Translit($Имя[0] + "." + $Фамилия) $Отображаемое_имя = "$Фамилия $Имя"   #---------------Проверка на однофамильцев----------------- while ($adUsers.SamAccountName -like "*$Имя_пользователя*") {        $count = $count + 1    $Имя_пользователя = Translit($Имя[0] + $count + "." + $Фамилия)    $Отображаемое_имя = "$Фамилия $Имя $count"  #---------------Создание почты на основе логина-----------------  $Эл_почта = $Имя_пользователя + "@mail" 

Теперь самое важное — создание учетной записи и контакта, Powershell не даст просто присвоить учетной записи пароль, для этого строку необходимо сначала преобразовать в защищенную.

#Пользователь $Пароль = ConvertTo-SecureString -String "###Пароль###" -AsPlainText -Force New-ADUser -SamAccountName "$Имя_пользователя" -UserPrincipalName "$Имя_пользователя" -Name $Отображаемое_имя -DisplayName $Отображаемое_имя -GivenName "$Имя" -Surname "$Фамилия" -Title "$Должность" -Mobile "$Мобильный_телефон" -OfficePhone "$Номер_телефона" -EmailAddress "$Эл_почта" -Department "$Отдел" -Company "$Организация" -AccountPassword $Пароль -Enabled $true -Path "OU=ТЕСТ,DC=domen,DC=local"  #Контакт New-ADObject -Name "$Отображаемое_имя" -Type Contact -Path "OU=ТЕСТ_КОНТАКТЫ,OU=ТЕСТ,DC=domen,DC=local" -OtherAttributes @{DisplayName = $Отображаемое_имя; GivenName = "$Имя"; Sn = "$Фамилия"; Mobile = "$Мобильный_телефон"; Mail = "$Эл_почта";telephoneNumber = "444"; Title = "$Должность"; Department = "$Отдел"; Company = "$Организация"}

Теперь копируем для пользователя группы безопасности, для этого в заявке из последней строки берётся логин учетки для копирования, которая содержится в том же контейнере

$Исходные_группы = Get-ADUser $Имя_пользователя_для_копирования_групп -Properties MemberOf | Select-Object -ExpandProperty MemberOf foreach ($группы in $Исходные_группы) {     Add-ADGroupMember -Identity $группы -Members $Имя_пользователя }

На этом действия на сервере заканчиваются, закрываем скобки, и переходим в локальную сессию, в качестве отчета я отправлю письмо-ответ на адрес отправителя, для этого получаем переменные из объекта сессии и составляем письмо, после чего перемещаем письмо в папку «Исполнено».

#Получение значений из сессии  $Имя_учетки = $Переменные.GetValue(0) $Почта = $Переменные.GetValue(1)  #Ответное письмо $Ответ = $Письмо.ReplyAll() $Ответ.Body = @" $Фамилия $Имя $Отчество $Отдел $Должность $Организация $Имя_учетки $Почта $Мобильный_телефон $Номер_телефона "@ $Ответ.Send( ) $Письмо.Move($Исполнено)

После завершения цикла, закрываем сессию с сервером и закрываем Outlook, через 10 секунд чтобы письма успели отправиться.

#Завершение сессии Remove-PSSession -Session $Сессия  #Завершение Outlook Start-Sleep -Seconds 10 Get-Process | Where-Object {$_.ProcessName -eq "OUTLOOK"} | Stop-Process

Образец моей заявки:

Заявка в IT - Новый сотрудник от 12.04.2024 10:34:49 Описание: Фамилия: Жданов Имя: Дмитрий Отчество: Юрьевич Отдел: Служба Качества Должность: Контролер пищевой продукции Организация: АО "Агрофирма "Бунятино" Подразделение: - Номер телефона: Мобильный телефон: - Пользователь для копирования:

Полный листинг кода:

  #----------------Создание сессии------------------------  $Сессия = New-PSSession -ComputerName ServerAD  #-------------------------Чтение почты-----------------------------  #Завершение Outlook Get-Process | Where-Object {$_.ProcessName -eq "OUTLOOK"} | Stop-Process  Start-Sleep -Seconds 10  # Создание объекта Outlook $outlook = New-Object -ComObject Outlook.Application  # Получение коллекции папок $folders = $outlook.Session.Folders.Item("auto-user@agro-holding.ru").Folders  # Выбор папки "Входящие" $Входящие = $folders.Item("Входящие")  $Исполнено = $folders.Item("Исполнено")  # Получение последнего письма $Письма = $Входящие.Items | Sort-Object ReceivedTime -Descending   #-------------------------Рабочий алгоритм-----------------------------  #Получение значений переменных из письма foreach ($Письмо in $Письма) {  $lines = $Письмо.Body -split "`n"  #Условие чтения письма if ($lines[0].Substring(0, 29) -ne "Заявка в IT - Новый сотрудник") {continue}   $Дата_заявки = $lines[0].Substring(32).Trim() $Фамилия = $lines[2].Substring(18).Trim() $Имя = $lines[4].Substring(4).Trim() $Отчество = $lines[6].Substring(9).Trim() $Отдел = $lines[8].Substring(6).Trim() $Должность = $lines[10].Substring(10).Trim() $Организация = $lines[12].Substring(12).Trim() $Подразделение = $lines[14].Substring(14).Trim() $Номер_телефона = $lines[16].Substring(15).Trim() $Мобильный_телефон = $lines[18].Substring(18).Trim() $Имя_пользователя_для_копирования_групп = $lines[20].Substring(29).Trim()   #---------------Основная команда создания пользователя на удаленном сервере-----------------  $Переменные = Invoke-Command -Session $Сессия -ScriptBlock { param($Фамилия, $Имя, $Отчество, $Отдел, $Должность, $Организация, $Подразделение, $Номер_телефона, $Мобильный_телефон, $Имя_пользователя_для_копирования_групп)  #---------------Функция транслита----------------- #Транслит имени function global:Translit { param([string]$inString) $Translit = @{ [char]'а' = "a" [char]'А' = "a" [char]'б' = "b" [char]'Б' = "b" [char]'в' = "v" [char]'В' = "v" [char]'г' = "g" [char]'Г' = "g" [char]'д' = "d" [char]'Д' = "d" [char]'е' = "e" [char]'Е' = "e" [char]'ё' = "yo" [char]'Ё' = "yo" [char]'ж' = "zh" [char]'Ж' = "zh" [char]'з' = "z" [char]'З' = "z" [char]'и' = "i" [char]'И' = "i" [char]'й' = "j" [char]'Й' = "j" [char]'к' = "k" [char]'К' = "k" [char]'л' = "l" [char]'Л' = "l" [char]'м' = "m" [char]'М' = "m" [char]'н' = "n" [char]'Н' = "n" [char]'о' = "o" [char]'О' = "o" [char]'п' = "p" [char]'П' = "p" [char]'р' = "r" [char]'Р' = "r" [char]'с' = "s" [char]'С' = "s" [char]'т' = "t" [char]'Т' = "t" [char]'у' = "u" [char]'У' = "u" [char]'ф' = "f" [char]'Ф' = "f" [char]'х' = "h" [char]'Х' = "h" [char]'ц' = "c" [char]'Ц' = "c" [char]'ч' = "ch" [char]'Ч' = "ch" [char]'ш' = "sh" [char]'Ш' = "sh" [char]'щ' = "sch" [char]'Щ' = "sch" [char]'ъ' = "" [char]'Ъ' = "" [char]'ы' = "y" [char]'Ы' = "y" [char]'ь' = "" [char]'Ь' = "" [char]'э' = "e" [char]'Э' = "e" [char]'ю' = "yu" [char]'Ю' = "yu" [char]'я' = "ya" [char]'Я' = "ya" } $outCHR="" foreach ($CHR in $inCHR = $inString.ToCharArray()) { if ($Translit[$CHR] -cne $Null ) {$outCHR += $Translit[$CHR]} else {$outCHR += $CHR} } Write-Output $outCHR }   $count = 0  #---------------Получаем список пользователей AD-----------------  $adUsers = Get-ADUser -Filter * -Properties UserPrincipalName  #---------------------Получение логина---------------------------  #чтобы транслейтить имя надо написать: $Транслит = Translit($имя) $Имя_пользователя = Translit($Имя[0] + "." + $Фамилия) $Отображаемое_имя = "$Фамилия $Имя"   #---------------Проверка на однофамильцев----------------- while ($adUsers.SamAccountName -like "*$Имя_пользователя*") {        $count = $count + 1    $Имя_пользователя = Translit($Имя[0] + $count + "." + $Фамилия)    $Отображаемое_имя = "$Фамилия $Имя $count" }  #---------------Создание почты на основе логина-----------------  $Эл_почта = $Имя_пользователя + "@почта"  #---------------------Добавиление в AD-----------------------------  #Пользователь $Пароль = ConvertTo-SecureString -String "пароль" -AsPlainText -Force New-ADUser -SamAccountName "$Имя_пользователя" -UserPrincipalName "$Имя_пользователя" -Name $Отображаемое_имя -DisplayName $Отображаемое_имя -GivenName "$Имя" -Surname "$Фамилия" -Title "$Должность" -Mobile "$Мобильный_телефон" -OfficePhone "$Номер_телефона" -EmailAddress "$Эл_почта" -Department "$Отдел" -Company "$Организация" -AccountPassword $Пароль -Enabled $true -Path "OU=ТЕСТ,DC=bun,DC=local"   #Контакт New-ADObject -Name "$Отображаемое_имя" -Type Contact -Path "OU=ТЕСТ_КОНТАКТЫ,OU=ТЕСТ,DC=bun,DC=local" -OtherAttributes @{DisplayName = $Отображаемое_имя; GivenName = "$Имя"; Sn = "$Фамилия"; Mobile = "$Мобильный_телефон"; Mail = "$Эл_почта";telephoneNumber = "444"; Title = "$Должность"; Department = "$Отдел"; Company = "$Организация"}   #-----------Копируем группы пользователя из контейнера-------------  $Исходные_группы = Get-ADUser $Имя_пользователя_для_копирования_групп -Properties MemberOf | Select-Object -ExpandProperty MemberOf foreach ($группы in $Исходные_группы) {     Add-ADGroupMember -Identity $группы -Members $Имя_пользователя }  #-----------Возвращение переменных из сессии для ответного письма-------------  return $Имя_пользователя, $Эл_почта, $Фамилия, $Имя, $Отчество, $Отдел, $Должность, $Организация, $Подразделение, $Номер_телефона, $Мобильный_телефон, $Имя_пользователя_для_копирования_групп  } -ArgumentList $Фамилия, $Имя, $Отчество, $Отдел, $Должность, $Организация, $Подразделение, $Номер_телефона, $Мобильный_телефон, $Имя_пользователя_для_копирования_групп  #Получение значений из сессии  $Имя_учетки = $Переменные.GetValue(0) $Почта = $Переменные.GetValue(1)  #Ответное письмо $Ответ = $Письмо.ReplyAll() $Ответ.Body = @" $Фамилия $Имя $Отчество $Отдел $Должность $Организация $Имя_учетки $Почта $Мобильный_телефон $Номер_телефона "@ $Ответ.Send( ) $Письмо.Move($Исполнено)  }  #Завершение Outlook Start-Sleep -Seconds 10 Get-Process | Where-Object {$_.ProcessName -eq "OUTLOOK"} | Stop-Process  #Завершение сессии Remove-PSSession -Session $Сессия 

Надеюсь вам помогла моя статья, я постарался максимально понятно разделить код на составные части чтобы его части можно было поменять на собственные.


ссылка на оригинал статьи https://habr.com/ru/articles/813279/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *