
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 $Сессия
Надеюсь вам помогла моя статья, я постарался максимально понятно разделить код на составные части чтобы его части можно было поменять на собственные.
