- PVSM.RU - https://www.pvsm.ru -
Еще с выходом в свет Windows Vista2008 администраторы столкнулись с маленькой, но неприятной проблемой: оповещение об истечении срока действия пароля стало сиротливо появляться в самом неприметном углу экрана. И это вместо окна прямо по центру, как было раньше!
Отсюда и смена паролей в последний момент, под аккомпанемент отказов доступа; и негодование, почему вдруг перестал работать VPN, и что с этим делать в командировке. Конечно, не проблема года, но явление назойливое и неприятное. Поэтому разбираемся, как его одолеть.
В статье «Excel вместо PowerShell: запросы к AD и системные отчеты [1]» я рассказывал, как вытащить информацию из Active Directory при помощи Excel. Благодаря этому механизму всегда можно получить отчет о сроках действия пользовательских паролей. В современных доменах для этого существует атрибут msDS-UserPasswordExpiryTimeComputed, который находится в классе user.
При помощи Power Query мы можем легко получить подобную табличку:
Отчет о сроках действия пароля в MS Excel.
Теперь, если добавить формулу вида
=ЕСЛИ([@[msDS-UserPasswordExpiryTimeComputed]]<ТДАТА();"Пароль просрочен!";ЕСЛИ([@[msDS-UserPasswordExpiryTimeComputed]]-5<ТДАТА();"Пароль скоро закончится!";"ОК"))
в соседний столбец, то мы получим таблицу уже такого вида:
Делаем отчет более наглядным.
Осталось только добавить правила раскрашивания ячеек на основе их содержимого, и будет совсем красиво:
И еще более наглядным.
При настройке автоматического обновления данных можно смотреть в таблицу и готовиться к заявкам от пользователей. Или поручить аккаунт-менеджеру (да, где-то есть такие специальные люди) обзванивать сотрудников.
Попробуем использовать в качестве аккаунт-менеджера PowerShell.
По счастью, получать данные из Active Directory можно не только через Excel, но и при помощи любимых скриптовых языков вроде PowerShell.
Для начала получим список пользователей и их адресов таким запросом:
$users = Get-ADUser -filter {Enabled -eq $True -and PasswordNeverExpires -eq $False -and PasswordLastSet -gt 0} `
-Properties "Name", "EmailAddress", "msDS-UserPasswordExpiryTimeComputed" | ` Select-Object -Property "Name", "EmailAddress", `
@{Name = "PasswordExpiry"; Expression = {[datetime]::FromFileTime($_."msDS-UserPasswordExpiryTimeComputed").tolongdatestring() }}
Как видно, по этому запросу я получаю только тех пользователей, которые соответствуют трем критериям:
В результате мы получим таблицу значения с именем пользователя, его адресом и датой истечения пароля. Для удобства задаем три варианта времени предупреждения ― за 7, за 3 и за 1 день:
$SevenDayWarnDate = (get-date).adddays(7).ToLongDateString()
$ThreeDayWarnDate = (get-date).adddays(3).ToLongDateString()
$OneDayWarnDate = (get-date).adddays(1).ToLongDateString()
Теперь, сравнивая эти три переменные со значением $user.PasswordExpiry, мы сможем посылать соответствующие уведомления. Напомню, что отправка e-mail производится при помощи командлета Send-MailMessage.
Но не обязательно уведомлять пользователей исключительно по почте ― можно использовать материал «Еще не бот, но уже что-то ― получаем уведомления от Zabbix в мессенджеры [2]» и отсылать уведомления по любому другому каналу связи.
С полным листингом скрипта, который можно запускать ежедневно при помощи планировщика, можно ознакомиться под спойлером.
Import-Module ActiveDirectory
#Создаем пороги срабатывания уведомлений
$SevenDayWarnDate = (get-date).adddays(7).ToLongDateString()
$ThreeDayWarnDate = (get-date).adddays(3).ToLongDateString()
$OneDayWarnDate = (get-date).adddays(1).ToLongDateString()
#Настройка текста сообщений
$MailSender = " Бот-Напоминалка <bot@domain.com>"
$Subject = 'Внимание! Срок действия Вашего пароля заканчивается'
$EmailStub1 = 'Я бот-напоминалка. Ваш пароль закончится'
$EmailStub2 = 'через'
$EmailStub3 = 'дней'
$EmailStub4 = '. Пожалуйста, заблаговременно измените свой пароль. Обратитесь в службу технической поддержки, если вы испытываете трудности со сменой пароля.'
$SMTPServer = 'smtp.domain.com'
#Получаем пользователей
$users = Get-ADUser -filter {Enabled -eq $True -and PasswordNeverExpires -eq $False -and PasswordLastSet -gt 0 } `
-Properties "Name", "EmailAddress", "msDS-UserPasswordExpiryTimeComputed" | Select-Object -Property "Name", "EmailAddress", `
@{Name = "PasswordExpiry"; Expression = {[datetime]::FromFileTime($_."msDS-UserPasswordExpiryTimeComputed").tolongdatestring() }}
#Проверяем сроки действия и отправляем уведомления.
foreach ($user in $users) {
if ($user.PasswordExpiry -eq $SevenDayWarnDate) {
$days = 7
$EmailBody = $EmailStub1, $user.name, $EmailStub2, $days, $EmailStub3, $SevenDayWarnDate, $EmailStub4 -join ' '
Send-MailMessage -To $user.EmailAddress -From $MailSender -SmtpServer $SMTPServer -Subject $Subject -Body $EmailBody
}
elseif ($user.PasswordExpiry -eq $ThreeDayWarnDate) {
$days = 3
$EmailBody = $EmailStub1, $user.name, $EmailStub2, $days, $EmailStub3, $ThreeDayWarnDate, $EmailStub4 -join ' '
Send-MailMessage -To $user.EmailAddress -From $MailSender -SmtpServer $SMTPServer -Subject $Subject `
-Body $EmailBody
}
elseif ($user.PasswordExpiry -eq $oneDayWarnDate) {
$days = 1
$EmailBody = $EmailStub1, $user.name, $EmailStub2, $days, $EmailStub3, $OneDayWarnDate, $EmailStub4 -join ' '
Send-MailMessage -To $user.EmailAddress -From $MailSender -SmtpServer $SMTPServer -Subject $Subject -Body $EmailBody
}
else {}
}
Теперь пользователи предупреждены, и остается надеяться на их ответственность. Рассмотрим еще один вариант уведомления.
Можно вернуть на экран сообщение об истекающем сроке пароля через логон-скрипт или программу в автозагрузке. К сожалению, по понятным причинам этот вариант не подойдет для пользователей, работающих с доменными сервисами удаленно.
Приведу пример простого скрипта на PowerShell, подсунутого в автозагрузку групповыми политиками:
$user= Get-ADUser -Identity $env:username -Properties 'msDS-UserPasswordExpiryTimeComputed','PasswordNeverExpires'
if ( -not $user.'PasswordNeverExpires') {
$diff=(new-timespan -start (get-date) -end ([datetime]::FromFileTime($user."msDS-UserPasswordExpiryTimeComputed"))).Days
if ($diff -lt 7) {
$msgBoxInput = [System.Windows.MessageBox]::Show("Ваш пароль истекает через "+ $diff + " дней!`nПерейти к диалогу смены пароля?","Внимание!","YesNo","Warning")
switch ($msgBoxInput) {
'Yes' {
cmd /c "explorer shell:::{2559a1f2-21d7-11d4-bdaf-00c04f60b9f0}"
}
'No' { }
}
}
}
Строка запуска explorer shell:::{2559a1f2-21d7-11d4-bdaf-00c04f60b9f0} ― это запуск интерфейса «Безопасность Windows». После выхода Windows 2012 он исчез из меню «Пуск» и стал доступен только при нажатии Ctrl+Alt+Del или Ctrl+Alt+End в случае подключения по RDP.
Окно уведомления.
Для ценителей под спойлером старая версия скрипта.
#Include <AD.au3>
#include <Date.au3>
_AD_Open()
$array=_AD_GetPasswordInfo()
if $array[9] <> "" then
$t=_DateDiff ( "d", _NowCalc(), $array[9] )
if $t < 7 Then
$a=MsgBox ( 4, "Внимание!", "Срок действия вашего пароля истекает через " &$t &" дней."&@crlf&"Перейти к диалогу смены пароля?" )
if $a=6 then
Run("explorer shell:::{2559a1f2-21d7-11d4-bdaf-00c04f60b9f0}")
sleep(1000)
endif
endif
endif
_AD_Close()
Простой реализации помогает функция _AD_GetPasswordInfo() из библиотеки AD.au3 [3]. Она выдает массив значений с информацией о пароле, в том числе и временем его истечения.
После внедрения этого механизма какие-либо проблемы с просроченными паролями перестали появляться.
Если инфраструктура Active Directory у вас не развернута ― например, в случае отдельного терминального сервера, ― то решение тоже существует, пусть и чуть более сложное.
Для этого нам понадобится чуть-чуть магии WMI и любимый скриптовый язык. Вернемся к примерам на PowerShell:
#Имя компьютера.
$Computer = $env:computername
#Имя пользователя
$UserName = $env:username
#Дельта в днях
$Days = 2
$User = [ADSI]"WinNT://$Computer/$UserName,user"
$Flags = $User.UserFlags.psbase.Value
#Проверка существования срока жизни пароля.
If ($Flags -band 65536)
{
"Пароль никогда не имеет срока действия"
}
Else
{
#Конвертируем время в дни.
$AgeDays = $User.PasswordAge.psbase.Value / 86400
$MaxAge = $User.MaxPasswordAge.psbase.Value / 86400
If ($AgeDays -gt $MaxAge)
{
"Пароль просрочен"
}
Else
{
If (($AgeDays + $Days) -gt $MaxAge)
{
"Пароль будет просрочен через $Days дней"
}
Else
{
"Все в порядке"
}
}
}
При должной доработке такой скрипт может уведомлять пользователей при регулярном запуске или при входе в систему.
Уже давно я задумывался о смысле существования срока жизни пароля. С одной стороны, это хорошо и безопасно, с другой ― постоянное придумывание новых паролей приводит к забыванию этих самых паролей и, как следствие, к стикерам на мониторе и под клавиатурой.
Поэтому все больше мне близка практика, когда пользователи сами придумывают пароли, но при этом регулярно проводится аудит их творчества путем атаки по словарю утилитами вроде L0phtCrack [4]. Обязательным остается только требование к длине паролей (вспоминая известную картинку от xkcd [5]).
Так можно и людям жизнь облегчить, и избежать защитной реакции на «закручивание гаек» в виде чудесных сочетаний вроде Qwerty123. Ну, а что ― система не ругается, а ИБ эта ваша… понапридумывали тут.
Кстати, а у вас есть аккаунт-менеджер или какая-нибудь модно-молодежная практика смены паролей?
Автор: Tri-Edge
Источник [6]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/powershell/279725
Ссылки в тексте:
[1] Excel вместо PowerShell: запросы к AD и системные отчеты: https://habr.com/company/pc-administrator/blog/350582/
[2] Еще не бот, но уже что-то ― получаем уведомления от Zabbix в мессенджеры: https://habr.com/company/pc-administrator/blog/353652/
[3] AD.au3: https://www.autoitscript.com/forum/topic/106163-active-directory-udf/
[4] L0phtCrack: http://www.l0phtcrack.com
[5] xkcd: https://xkcd.com/936/
[6] Источник: https://habr.com/post/358082/?utm_campaign=358082
Нажмите здесь для печати.