Несмотря на то, что Microsoft убрала требование регулярной смены пароли пользователей из своих рекомендаций безопасности, в большинстве on-prem доменов Active Directory включена политика, ограничивающая срок действия паролей пользователей. Часто пользователи забывают вовремя сменить свой пароль, срок действия которого истек, что вызывает лишние обращения в службы ИТ поддержки.
В этой статье мы рассмотрим, как узнать, когда истекает пароль учетной записи пользователя в домене и как заблаговременно напомнить пользователю о том, что ему нужно сменить свой пароль.
Как узнать срок действия пароля пользователя в Active Directory?
Срок действия пароля пользователя в домене определяется настройками парольной политики AD. Текущие настройки политики срока действия паролей в домене можно получить с помощью команды PowerShell:
Get-ADDefaultDomainPasswordPolicy|select MaxPasswordAge
В нашем примере максимальный срок действия пароля пользователя в домене – 60 дней.
В свойствах пользователя в Active Directory содержится только атрибут pwdLastSet, который содержит дату последней смены пароля ( можно посмотреть в консоли ADUC -> вкладка редактор атрибутов AD).
Узнать дату окончания срока действия пароля пользователя в домене можно с помощью PowerShell (требуется модуль AD PowerShell), который позволяет получить значение атрибута msDS-UserPasswordExpiryTimeComputed. Этот constructed-атрибут автоматически вычисляется на основании времени последней смены пароля и парольной политики:
Get-ADUser -Identity a.ivanov -Properties msDS-UserPasswordExpiryTimeComputed, PasswordLastSet, PasswordNeverExpires, PasswordExpired |Select-Object -Property Name,PasswordLastSet, PasswordNeverExpires, PasswordExpired,@{Name="ExpiryDate";Expression={[datetime]::FromFileTime($_."msDS-UserPasswordExpiryTimeComputed")}}
Командлет возвращает такие значения таких атрибутов:
- PasswordLastSet — время последней смены пароля;
- PasswordNeverExpires – возвращает True, если пароль пользователя никогда не устаревает (бессрочный пароль). Это один из битовых значений атрибута UserAccountControl);
- PasswordExpired – возвращает True, если пароль пользователя устарел;
- ExpiryDate – дата, когда истечет срок действия пароля
Вывести всех пользователей из определенного контейнера (OU) AD, срок действия пароля которых уже истек:
$Users = Get-ADUser -SearchBase 'OU=Users,OU=SPB,DC=corp,DC=winitpro,DC=ru' -filter {Enabled -eq $True -and PasswordNeverExpires -eq $False} -Properties msDS-UserPasswordExpiryTimeComputed, PasswordLastSet
$Users | select Name, @{Name="ExpirationDate";Expression= {[datetime]::FromFileTime($_."msDS-UserPasswordExpiryTimeComputed")}}, PasswordLastSet | where ExpirationDate -lt (Get-Date)
Политика оповещения об окончании срока действия пароля
В Windows можно включить параметр групповой политики, позволяющий оповещать пользователей о необходимости сменить пароль.
Политика называется Interactive logon: Prompt user to change password before expiration и находится в разделе GPO Computer Configuration -> Policies -> Windows Settings -> Security Settings -> Local Policies -> Security Options
По умолчанию эту политика включена на уровне локальной групповой политики Windows и уведомления начинают появляться за 5 дней до истечения срока действия пароля. Вы можете изменить количество дней, в течении которых должно появляться уведомление о смене пароля.
После включения этой политики, если пароль пользователя истекает, то при входе в трее Windows будет появляться уведомление о необходимости сменить пароль.
Consider changing your password Your password will expire in xx days.
Это сообщение появляется на несколько секунд и часто игнорируется пользователями. Поэтому вы можете добавить дополнительное всплывающее уведомление о необходимости смены пароля.
Вывести уведомление об истечении срока пароля с помощью PowerShell
Следующий PowerShell скрипт будет выводить всплывающее уведомление с предложением сменить пароль, если он истекает менее чем через 5 дней:
$DaysLeft = 5 try{ Add-Type -AssemblyName PresentationCore,PresentationFramework,WindowsBase,system.windows.forms } catch { Throw "Failed to load Windows Presentation Framework assemblies." } $curruser= Get-ADUser -Identity $env:username -Properties 'msDS-UserPasswordExpiryTimeComputed','PasswordNeverExpires' if ( -not $curruser.'PasswordNeverExpires') { $timediff=(new-timespan -start (get-date) -end ([datetime]::FromFileTime($curruser."msDS-UserPasswordExpiryTimeComputed"))).Days if ($timediff -lt $DaysLeft) { $msgBoxInput = [System.Windows.MessageBox]::Show("Ваш пароль истекает через "+ $timediff + " дней!`nХотите сменить пароль сейчас?","Внимание!","YesNo","Warning") switch ($msgBoxInput) { 'Yes' { $Console = quser | Select-String -Pattern ">"| Select-String -Pattern "console" -Quiet if ( $Console ) { Start-Process -FilePath powershell -ArgumentList "-command Set-ADAccountPassword -Identity $env:username ; pause" } else { cmd /c "C:\Windows\explorer.exe shell:::{2559a1f2-21d7-11d4-bdaf-00c04f60b9f0}" } } 'No' { } } } }
Если до истечения срока действия пароля пользователя осталось менее 5 дней, скрипт предложит пользователю сменить пароль. Если пользователь нажимает Да, выполняется проверка залогинен ли пользователь на консоль компьютера:
- В случае определения RDP сессий, пользователю отображается окно Windows Security, которое вы видите при нажатии Ctrl+Alt+Del или
Ctrl+Alt+End
(при RDP подключении). - Если сессия консольная, выводится окно командлета Set-ADAccountPassword, в котором можно сменить пароль.
Данный PowerShell скрипт можно запускать по расписанию через планировщик задач, поместить автозагрузку или запускать как logon скрипт групповых политик.
Однако это будет работать только на компьютерах, добавленных в домен Active Directory. Если пользователь подключается к домену через VPN (и вы не можете настроили запуск VPN до входа в Windows) или веб клиенты (типа OWA), он не увидит уведомления о приближении даты окончания срока действия пароля. В этом случае можно оповещать пользователей об истечении пароля по почте.
PowerShell: отправка почтовых уведомлений об истечении пароля на e-mail
С помощью PowerShell вы можете настроить отправку уведомлений на email пользователям о том, что срок действия их пароля истекает.
$Sender = "[email protected]"
$Subject = 'Внимание! Скоро истекает срок действия Вашего пароля!'
$BodyTxt1 = 'Срок действия Вашего пароля для'
$BodyTxt2 = 'заканчивается через '
$BodyTxt3 = 'дней. Не забудьте заранее сменить Ваш пароль. Если у вас есть вопросы, обратитесь в службу HelpDesk.'
$smtpserver ="smtp.domain.com"
$warnDays = (get-date).adddays(7)
$2Day = get-date
$Users = Get-ADUser -SearchBase 'OU=Users,DC=corp,DC=winitpro,DC=ru' -filter {Enabled -eq $True -and PasswordNeverExpires -eq $False} -Properties msDS-UserPasswordExpiryTimeComputed, EmailAddress, Name | select Name, @{Name ="ExpirationDate";Expression= {[datetime]::FromFileTime($_."msDS-UserPasswordExpiryTimeComputed")}}, EmailAddress
foreach ($user in $users) {
if (($user.ExpirationDate -lt $warnDays) -and ($2Day -lt $user.ExpirationDate) ) {
$lastdays = ( $user.ExpirationDate -$2Day).days
$EmailBody = $BodyTxt1, $user.name, $BodyTxt2, $lastdays, $BodyTxt3 -join ' '
Send-MailMessage -To $user.EmailAddress -From $Sender -SmtpServer $smtpserver -Subject $Subject -Body $EmailBody
}
}
Скрипт проверяет всех активных пользователей домена с истекающими паролями. За 7 дней до истечения пароля пользователю начинают отправляться письма на email адрес, указанный в AD (атрибут должен быть заполнен). Письма отправляются до тех пор, пока пароль не будет изменен или просрочен.
Данный PowerShell скрипт нужно запускать регулярно на любом компьютере/сервере домена (проще всего через Task Scheduler). Естественно, нужно на вашем SMTP сервере добавить IP адрес хоста, с которого рассылаются письма, в разрешенные отправители без аутентификации.
Последние официальные рекомендации — не включать функцию истечения паролей. Безопасности не прибавляет и даже наоборот — снижает. И геморроя прибавляет изрядно.
Дайте ссылку пожалуйста на официальную рекомендацию.
Здесь история вопроса: https://habr.com/ru/post/357406/
Здесь про рекомендации MS и некоторые разъяснения: https://habr.com/ru/company/globalsign/blog/457036/
Там же и ссылка на Technet есть.
Здесь больше интересна именно история вопроса — откуда это пошло и к чему в итоге пришло. MS здесь не выступает первоисточником но и они в итоге сейчас рекомендуют отказаться от этой практики.
Не плохо я и сама думала так.
Какой самый простой фторой фактор можно внедрить в ад?
cisco annyconnect
А теперь на секунду представьте на секунду — Вы в отпуске, а у пользователей истек срок действия паролей, естественно «у меня ничего не получилось», в итоге «работа простаивает, мне надо срочно» — уже нравится? Так можно делать когда все пользователи достаточно грамотные, чтобы разобраться самостоятельно, но, учитывая повальную экономию на всём — ситуация далеко не такая радостная.
Можно скрипт с аутентификацией по SMTP?
$emailSmtpServer = «mail_server»
$emailSmtpServerPort = «xxx»
$emailSmtpUser = «user_name_1»
$emailSmtpPass = «Password»
$emailFrom = «[email protected]»
$emailTo = «[email protected]»
$encoding = [System.Text.Encoding]::UTF8
нету таких команд, зачем вводить заблуждение людей ?
1)
Класс [System.Windows.MessageBox] будет работать только после добавления ассамблеи PresentationFramework через Add-Type. В противном случае будете получать ошибку «Unable to find type [System.Windows.MessageBox]». Соответственно это необходимо добавить в начале скрипта.
2)
cmd /c «explorer shell:::{2559a1f2-21d7-11d4-bdaf-00c04f60b9f0}» Не будет это работать в консольной сессии. Это работает при подключении к серверу по RDP
3)
Get-ADUser -filter * -properties Name, PasswordNeverExpires | where {$_.passwordNeverExpires -eq «true» }
Зачем делать -filter * и потом выбирать из этого массива?? лучше и быстрее использовать server-side фильтры Get-ADUser -filter ‘PasswordNeverExpires -eq True’
4) В начале в паре мест лишним берете свойство ‘CannotChangePassword’ и потом его не используете. Нужно убрать его, чтобы не отвлекало.
дальше уже стало неинтересно проверять. На мой взгляд необходимо доработать и проверять перед публикацией в будущем.
Подскажите, пожалуйста, по Вашему первому пункту: в какую часть скрипта (после каких команд или строк) нужно добавить асамблею «PresentationFramework через Add-Type», чтобы избавиться от ошибки Unable to find type [System.Windows.MessageBox]» ?! И если не сложно, то как будет выглядеть ПРАВИЛЬНЫЙ итоговый скрипт в данном случае?!
Добавил в скрипт строку
Add-Type -AssemblyName PresentationFramework
Погуглил, как на русскоязычных сайтах так и на буржуйских, а также поспрашивал на форумах по этому вопросу. В итоге получается следующая конструкция:
try{
Add-Type -AssemblyName PresentationCore,PresentationFramework,WindowsBase,system.windows.forms
} catch {
Throw «Failed to load Windows Presentation Framework assemblies.»
}
$curruser= Get-ADUser -Identity $env:username -Properties ‘msDS-UserPasswordExpiryTimeComputed’,’PasswordNeverExpires’
if ( -not $curruser.’PasswordNeverExpires’) {
$timediff=(new-timespan -start (get-date) -end ([datetime]::FromFileTime($curruser.»msDS-UserPasswordExpiryTimeComputed»))).Days
if ($timediff -lt 10) {
$msgBoxInput = [System.Windows.MessageBox]::Show(«Ваш пароль истекает через «+ $timediff + » дней!`nХотите сменить пароль сейчас?»,»Внимание!»,»YesNo»,»Warning»)
switch ($msgBoxInput) {
‘Yes’ {
cmd /c «explorer shell:::{2559a1f2-21d7-11d4-bdaf-00c04f60b9f0}»
}
‘No’ { }
}
}
}
Но, тут опять таки — вот эта строчка в скрипте:
[datetime]::FromFileTime($curruser.»msDS-UserPasswordExpiryTimeComputed»)
возвращает вам пустое значение, которое потом интерпретируется как 1 января 1601 года.
Прошу Вас помочь скорректировать указанную строку! Спасибо!
Попробуйте использовать такой блок:
$curruser= Get-ADUser -Identity $env:username -Properties ‘msDS-UserPasswordExpiryTimeComputed’,’PasswordNeverExpires’
if ( -not $curruser.’PasswordNeverExpires’) {
$timediff=(new-timespan -start (get-date) -end ([datetime]::FromFileTime($curruser."msDS-UserPasswordExpiryTimeComputed"))).Days
У меня все работает…
Если нет, после первой строки попробуйте вывести содержимое атрибута:
write-host $curruser."msDS-UserPasswordExpiryTimeComputed"
write-host ([datetime]::FromFileTime($curruser."msDS-UserPasswordExpiryTimeComputed"))
Возвращаются значения?
Здравствуйте!
Подскажите как сделать экспорт скрипта в файл, который указан в Вашей статье:
$Users = Get-ADUser -SearchBase ‘OU=Users,OU=SPB,DC=corp,DC=winitpro,DC=ru’ -filter {Enabled -eq $True -and PasswordNeverExpires -eq $False} -Properties msDS-UserPasswordExpiryTimeComputed, PasswordLastSet, CannotChangePassword
foreach($user in $Users){
if( [datetime]::FromFileTime($user.»msDS-UserPasswordExpiryTimeComputed») -lt (Get-Date)) {
$user.Name
}
}
Добавляю в начале
$lastday = ((Get-Date).AddDays(-1))
$filename = Get-Date -Format yyyy.MM.dd
$exportcsv=”c:\ps\expired_password_” + $filename + “.cvs”
В конце
Export-csv -path $exportcsv
Придется внутри цикла foreach собирать массив New-Object
Или можно добавлять данные в csv файл построчно:
$user |select-object name| Export-csv -path $exportcsv -append
У меня в итоге вот так получилось:
$filename = Get-Date -Format yyyy.dd.mm
$exportcsv=”c:\ps\expired_password_” + $filename + “.csv”
$Users = Get-ADUser -SearchBase ‘OU=xxx,DC=fmarket,DC=local’ -filter {Enabled -eq $True -and PasswordNeverExpires -eq $False} -Properties msDS-UserPasswordExpiryTimeComputed, PasswordLastSet, CannotChangePassword
foreach($user in $Users){
if( [datetime]::FromFileTime($user.»msDS-UserPasswordExpiryTimeComputed») -lt (Get-Date)) {
$user.Name
Export-csv -InputObject ($user | select DistinguishedName) -Path $exportcsv -Delimiter «;» -Encoding Unicode -NoTypeInformation -append -Force
}
}
Подскажите пжста, почему письма приходят в некорректной кодировке (вопросиками), такс написан на русском
Попробуйте задать кодировку UTF8 в скрипте:
.....
$EmailBody = $BodyTxt1, $user.name, $BodyTxt2, $lastdays, $BodyTxt3 -join ' '
$encoding = [System.Text.Encoding]::UTF8
Send-MailMessage -To $user.EmailAddress -From $Sender -SmtpServer $smtpserver -Subject $Subject -Body $EmailBody -Encoding $encoding
....
Здравствуйте пишу ваш скрипт
$Users = Get-ADUser -SearchBase ‘OU=Моя компания,DC=office,DC=local’ -filter {Enabled -eq $True -and PasswordNeverExpires -eq $False} -Properties msDS-UserPasswordExpiryTimeComputed, PasswordLastSet, CannotChangePassword $Users | select Name, @{Name=»ExpirationDate»;Expression= {[datetime]::FromFileTime ($_.»msDS-UserPasswordExpiryTimeComputed»)}}, PasswordLastSet
выдает ошибку
строка:1 знак:306
+ … Name=»ExpirationDate»;Expression= {[datetime]::FromFileTime ($_.»msDS …
+ ~
Непредвиденная лексема «(» в выражении или операторе.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : UnexpectedToken
что не так подскажите
Попробуйте отладить команду частями. Возможно какие-то символы неправильно скопировались с сайта (есть у WordPress такой глюк). Проверьте двойные кавычки, не больно быть елочек.
А можно изменить само сообщение о том, что «пароль не соответствует требованиям ИБ…»? Ну например, добавить сами требования в это сообщение?
Вы про какое сообщение?
Мне кажется тут достаточно настроить правильные доменные политики паролей, которые не дадут пользователю поставить слишком простой или старый пароль.
В строке по выгрузке срока действия паролей нужно убрать пробел перед скобкой FromFileTime ($_.»msDS-
+
Всем привет!
Подготовлен готовый механизм оповещения пользователей по ЭЛЕКТРОННОЙ ПОЧТЕ (за 14, 7, 2 дня) о скором окончании срока действия доменного пароля. Может кому-нибудь будет интересен данный механизм:
function notificationUser {
param (
[parameter(Mandatory=$true, Position=0)]
[string]$fullName,
[parameter(Mandatory=$true, Position=1)]
[string]$email,
[parameter(Mandatory=$true, Position=2)]
[string]$daysAwayFrom
)
$SubjectMail = «Через $daysAwayFrom дня(-ей) закончится срок действия вашего доменного пароля.»
$Body = @»
ТЕМА СООБЩЕНИЯ
«@
$paramSend = @{
‘from’= ‘УКАЖИТЕ ЛЮБОЕ ОТОБРАЖАЕМОЕ ИМЯ ОТПРАВИТЕЛЯ ‘
‘to’= ‘EMAIL’
‘subject’= $SubjectMail
‘body’=$Body
‘SMTPServer’= ‘SMTP-SERVER’
‘Encoding’ = [System.Text.Encoding]::UTF8
‘Port’ = ’25’
}
Send-MailMessage @paramSend
}
foreach ($user in (Get-ADUser -Server server -Filter {(Enabled -eq $True) -and (PasswordNeverExpires -eq $False) -and (mail -ne «null»)} -Properties msDS-UserPasswordExpiryTimeComputed, mail | Where-Object {($_.distinguishedName -like «*ЗДЕСЬ МОЖЕТЕ УКАЗАТЬ DN ОУШЕК, ЕСЛИ У ВАС ПОЛЬЗОВАТЕЛИ РАЗБРОСАНЫ ПО ДЕРЕВУ ДОМЕНУ») -or ($_.distinguishedName -like «*ЗДЕСЬ МОЖЕТЕ УКАЗАТЬ DN ОУШЕК, ЕСЛИ У ВАС ПОЛЬЗОВАТЕЛИ РАЗБРОСАНЫ ПО ДЕРЕВУ ДОМЕНУ»)})) {
$object = [PSCustomObject]@{
«fullName» = $user.Name
«email» = $user.mail
«daysAwayFrom» = (New-TimeSpan -Start $((Get-Date).Date) -End $(([datetime]::FromFileTime($user.’msDS-UserPasswordExpiryTimeComputed’)).Date)).TotalDays
}
switch($($object.daysAwayFrom))
{
’14’ {notificationUser -fullName $($object.fullName) -email $($object.email) -daysAwayFrom $($object.daysAwayFrom)}
‘7’ {notificationUser -fullName $($object.fullName) -email $($object.email) -daysAwayFrom $($object.daysAwayFrom)}
‘2’ {notificationUser -fullName $($object.fullName) -email $($object.email) -daysAwayFrom $($object.daysAwayFrom)}
}
}
Добрый день,
Подскажите пожалуйста, когда запрос:
Get-ADUser -Identity avivanov -Properties msDS-UserPasswordExpiryTimeComputed | select-object @{Name=»ExpirationDate»;Expression= {[datetime]::FromFileTime($_.»msDS-UserPasswordExpiryTimeComputed») }}
выполняю в консоли powershell выводиться результат запроса.
Но когда запрос сохраняю в файле ps1 и выполняю его, результат выполнения запроса — пустой.
В чем может быть причина?
Может кто-нибудь подсказать по этой программе?
*проблеме
Запускаете вручную из-под той же учетной записи, что и команду в консоли?
Или отрабатывает некий планировщик из-под другой учетной записи.
Проверил у себя — команда отрабатывает и в консоли и в консоли через скрипт. запускаю так:
PS C:\PS> .\test_ad_powershell.ps1
Запускаете вручную из-под той же учетной записи, что и команду в консоли? — Да
Запускаю так: на файле ps1 с запросом, правой кнопкой мыши->Выполнить с помощью PowerShell и результат пустой, но, скопировав содержимое ps1 файла в консоль PowerShell и нажав ввод, получаю искомый результат. Вот не могу понять в чем дело?
Понял вас. Нужно в скрипте указывать принудительный вывод в консоль:
import-module activedirectory
$a=Get-ADUser username1 -Properties msDS-UserPasswordExpiryTimeComputed | select-object @{Name="ExpirationDate";Expression= {[datetime]::FromFileTime($_."msDS-UserPasswordExpiryTimeComputed") }}
write-host $a
Read-Host -Prompt "Press any key to continue "
При таком запросе результат, при «Запускаю так: на файле ps1 с запросом, правой кнопкой мыши->Выполнить с помощью PowerShell», выводиться в виде: @{ExpirationDate=01.12.2021 00:00:00} — не очень красиво, т.к. со спец.символами @{}.
Сделал так, добавил вывод результата в виде списка, fl:
get-aduser -identity user -properties msds-userpasswordexpirytimecomputed | select-object @{name = «ExpirationDate»;expression = {[datetime]::fromfiletime($_.»msds-userpasswordexpirytimecomputed»)}} | fl
Write-Host -NoNewLine ‘Press any key to continue…’;
$null = $Host.UI.RawUI.ReadKey(‘NoEcho,IncludeKeyDown’);
Спасибо, за помощь.
Если нужно быстро продлить пароль пользователя, и не ставить галку password newer expires, воспользуйтесь командой:
Set-ADUser -Identity username -Replace @{pwdlastset="0"}
Set-ADUser -Identity username -Replace @{pwdlastset="-1"}
Команда сбросит счетчик пароля, пользователь сможет зайти на компьютер, а уведомление сменить пароль появится только в следующий период.
Добавил в скрипт проверку сеанса, консоль или RDP, для запуска соответствуещей процедуры смены пароля. Также вывод окна сделал через vbs так-как даже через (System.Windows.Forms.Form -property @{Topmost=$true}) вывод окна повер всех на Windows 7, в реализации через task, решить не удалось. Скрипт запускается через task(есть встроенные триггеры на вход, разблокировку, подключение к сеансу), команда «powershell -nologo -noninteractive -windowStyle hidden -command PasswordExpiriesEvent.ps1» для скрытого выполнения. Выполнение ctrl-alt-delete сделал через «(New-Object -COM Shell.Application).WindowsSecurity()», чтоб не запускать cmd, закоментил.
$ErrorActionPreference = "Stop"
Add-Type -AssemblyName Microsoft.VisualBasic
$curruser= Get-ADUser -Identity $env:username -Properties 'msDS-UserPasswordExpiryTimeComputed','PasswordNeverExpires'
if ( -not $curruser.'PasswordNeverExpires') {
$timediff=(new-timespan -start (get-date) -end ([datetime]::FromFileTime($curruser."msDS-UserPasswordExpiryTimeComputed"))).Days
if ($timediff -lt 180) {
$text = "Ваш пароль истекает через "+ $timediff + " дней!`nХотите сменить пароль сейчас?"
$msgboxtype = "YesNo,SystemModal,Information"
$title = "Внимание!"
$msgBoxInput = [Microsoft.VisualBasic.Interaction]::MsgBox($text,$msgboxtype,$title)
switch ($msgBoxInput) {
'Yes' {
$Console = quser | Select-String -Pattern ">"| Select-String -Pattern "console" -Quiet
if ( $Console ) {
Start-Process -FilePath powershell -ArgumentList "-command Set-ADAccountPassword -Identity $env:username ; pause"
}
else {
#cmd /c "C:\Windows\explorer.exe shell:::{2559a1f2-21d7-11d4-bdaf-00c04f60b9f0}"
(New-Object -COM Shell.Application).WindowsSecurity()
}
}
'No' { }
}
}
}
ЕЩЕ
Если кто подскажет как определить сеанс (RDP/Console) более изящно, а то получилось топорно 🙂 буду признателен. Опять же при выполнении скрипта как task, процедура получения сеанса через $env:SESSIONNAME не проходит, при выполнении как task данная переменная пуста.
Спасибо за дополнения. Я только непонял зачем нужно условие проверки консолььной сессии?
if ( $Console ) {
Start-Process -FilePath powershell -ArgumentList "-command Set-ADAccountPassword -Identity $env:username ; pause"
$env:SESSIONNAME при запуске через task будет пустым, т.к. по сути пользователь под которым запускается код не выполнил в ход
Если пользователь подключен к ПК через консоль то команда:
#cmd /c "C:\Windows\explorer.exe shell:::{2559a1f2-21d7-11d4-bdaf-00c04f60b9f0}"
(New-Object -COM Shell.Application).WindowsSecurity()
не сработает.
Можно в принципе не делать использовать смену всегда через команду powershell (Start-Process -FilePath powershell -ArgumentList «-command Set-ADAccountPassword -Identity $env:username ; pause»)
Что не так? Почему ошибка? как исправить?:
Get-ADUser : Объект каталога не найден
C:\Users\bovin_km\Desktop\PassworExpiryDate_1_test.ps1:11 знак:10
+ $Users = Get-ADUser -SearchBase ‘OU=Users,DC=corp,DC=avtodor-eng,DC=ru’ -filter …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (:) [Get-ADUser], ADIdentityNotFoundException
+ FullyQualifiedErrorId : ActiveDirectoryCmdlet:Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException,Microsoft.ActiveDirectory.Management.Commands.GetADUser
сам код:
#даже если здесь вставить:
Import-Module ActiveDirectory
$Sender = «[email protected]»
$From = «[email protected]»
$Subject = ‘Внимание! Скоро истекает срок действия Вашего пароля!’
$BodyTxt1 = ‘Срок действия Вашего пароля для’
$BodyTxt2 = ‘заканчивается через ‘
$BodyTxt3 = ‘дней. Не забудьте заранее сменить Ваш пароль используя ALT+CTRL+DEL, выберите «Сменить пароль…»; либо _https://mail.contoso.ru/ecp/?rfr=owa&owaparam=modurl%3D0&p=account. Не забудьте ввести новый пароль в настройках почты в мобильном телефоне.
Если у вас есть вопросы, обратитесь в службу HelpDesk.’
$smtpserver =»mail.contoso.ru»
$warnDays = (get-date).adddays(14)
$2Day = get-date
$Users = Get-ADUser -SearchBase ‘OU=Users,DC=corp,DC=contoso,DC=ru’ -filter {Enabled -eq $True -and PasswordNeverExpires -eq $False} -Properties msDS-UserPasswordExpiryTimeComputed, EmailAddress, Name | select Name, @{Name =»ExpirationDate»;Expression= {[datetime]::FromFileTime($_.»msDS-UserPasswordExpiryTimeComputed»)}}, EmailAddress
foreach ($user in $users) {
if (($user.ExpirationDate -lt $warnDays) -and ($2Day -lt $user.ExpirationDate) ) {
$lastdays = ( $user.ExpirationDate -$2Day).days
$EmailBody = $BodyTxt1, $user.name, $BodyTxt2, $lastdays, $BodyTxt3 -join ‘ ‘
Send-MailMessage -To $user.EmailAddress -From $Sender -SmtpServer $smtpserver -Subject $Subject -Body $EmailBody
}
}
ОТВЕТ:
для понимания зайти в AD, в свойствах контейнера в редакторе атрибутов посмотреть distinguishedName.
и без пробелов это все пишется (или копи-паст)
рабочий код:
$Sender = «[email protected]»
$From = «[email protected]»
$Subject = ‘Внимание! Скоро истекает срок действия Вашего пароля!’
$BodyTxt1 = ‘Срок действия Вашего пароля для’
$BodyTxt2 = ‘заканчивается через ‘
$BodyTxt3 = ‘дней. Не забудьте заранее сменить Ваш пароль используя ALT+CTRL+DEL, выберите «Сменить пароль…»; либо _https://mail.contoso.ru/ecp/?rfr=owa&owaparam=modurl%3D0&p=account. Не забудьте ввести новый пароль в настройках почты в мобильном телефоне.
Если у вас есть вопросы, обратитесь в службу HelpDesk.’
$smtpserver =»mail.contoso.ru»
$warnDays = (get-date).adddays(14)
$2Day = get-date
$Users = Get-ADUser -SearchBase ‘OU=Users,OU=Avtor_ENG,DC=corp,DC=contoso,DC=ru’ -filter {Enabled -eq $True -and PasswordNeverExpires -eq $False} -Properties msDS-UserPasswordExpiryTimeComputed, EmailAddress, Name | select Name, @{Name =»ExpirationDate»;Expression= {[datetime]::FromFileTime($_.»msDS-UserPasswordExpiryTimeComputed»)}}, EmailAddress
foreach ($user in $users) {
if (($user.ExpirationDate -lt $warnDays) -and ($2Day -lt $user.ExpirationDate) ) {
$lastdays = ( $user.ExpirationDate -$2Day).days
$EmailBody = $BodyTxt1, $user.name, $BodyTxt2, $lastdays, $BodyTxt3 -join ‘ ‘
Send-MailMessage -To $user.EmailAddress -From $Sender -SmtpServer $smtpserver -Subject $Subject -Body $EmailBody
}
}
А как добавить к -PasswordNeverExpires $false временный промежуток? Т. е. написать скрипт, чтоб, например, пароль сбрасывался через 30 дней?
Как вариант, можно создать для этого аккаунта отдельную Fine-Grained Password Policy
Или создать задание планировщика на DC..
При использовании кода
Get-ADUser -Identity user -Properties msDS-UserPasswordExpiryTimeComputed | select-object @{Name=»ExpirationDate»;Expression= {[datetime]::FromFileTime($_.»msDS-UserPasswordExpiryTimeComputed») }}
Возвращается значение:
ExpirationDate
—————
01.01.1601 3:00:00
У пользователя нет галки «Срок действия пароля неограничен».
Так же пользователю менялся пароль, но всё равно PasswordLastSet -скрипт выдаёт пустое поле (хотя в свойствах пользователя в редакторе атрибутов pwdLastSet заполнена корректно.
Подскажите пожалуйста в чём может быть проблема?
Вопрос отпал.
Если у кого-то такая же проблема, надо запускать не PowerShell, а «Модуль Active Directory для Windows PowerShell» в режиме администратора. Тогда всё работает корректно.
Добрый день,
А такой вот вопрос…
а как сдлать выводимый текст в писме столбиком?
сейчас всё что написано идёт одной строкой, а вот если надо разбить на предложения и обзацы?
ИСпользуйте HTML форматирование:
$EmailBody = @"
<p>$BodyTxt1 $user.name</p>
<p>$BodyTxt2, $lastdays, $BodyTxt3</p>
"@
+ в Send-MailMessage нужно добавьть параметр
-BodyAsHtml
Спасибо, получилось 🙂
Только теперь имя пользователя дублируется
Срок действия Вашего пароля для @{Name=Maksim Knyazev; ExpirationDate=03/09/2023 12:40:58; EmailAddress=Maksim.Knyazev@сервер.локал}.name
странно. как то ….
# Задаем параметры соединения с почтовым сервером
$MailFrom = «[email protected]»
$MailServer = «smtp.domain.ru»
$MailPort = «587»
$MailTo_adm = «[email protected]»
$MailUser = «[email protected]»
$MailPass = ConvertTo-SecureString -String «rdfgsdfgsfgsdfgwdxd» -AsPlainText -Force
$MailCred = New-Object System.Management.Automation.PSCredential $MailUser, $MailPass
# Отправить оповещение о создании учетной записи администраторам
Write-Host «-= Отправка информационного сообщения Администраторам =-» -ForegroundColor Green
Send-MailMessage -From $MailFrom -To $MailTo_adm -Subject $MailSubject -Body $MailBody -SmtpServer $MailServer -port $MailPort -Credential $MailCred -Encoding UTF8 -UseSsl -BodyAsHtml
Подскажите кто знает
как сделать, чтобы админу приходило уведомление, когда у пользователя блокируется учетка после неправильных вводом?
К событиям блокировки аккаунта 4740 и 4625 (https://winitpro.ru/index.php/2014/05/07/poisk-istochnika-blokirovki-uchetnoj-zapisi-polzovatelya-v-active-directory/) нужно привязать действие Attach Task to This Event (запуск скрипта, отправка письма — https://winitpro.ru/index.php/2015/04/02/triggery-sobytij-windows/)
Добрый день. Подскажите с условием. Мне нужно, чтобы скрипт отправлял сообщение только три дня до истечения учётной записи. В чем ошибка?
$UserNames = @(«user», «user», «user»)
$Days = 3
$ExpiringUsers = foreach ($UserName in $UserNames) {
$User = Get-ADUser $UserName -Properties AccountExpirationDate
if ((Get-Date).AddDays(-1) -le $User.AccountExpirationDate -and $User.AccountExpirationDate -ge (Get-Date).AddDays($Days)) {
$User | Select-Object Name, SamAccountName, @{
Name=’Expiration’
Expression={$User.AccountExpirationDate.Date.ToString(«yyyy-MM-dd»)}
}
}
}
if ($ExpiringUsers) {
$Body = «Срок действия учётных записей истекает`r`n»
$Body += $ExpiringUsers | ConvertTo-Html | Out-String
Вот это зачем условие?
(Get-Date).AddDays(-1) -le $User.AccountExpirationDate
Тогда тут останется только:
$User.AccountExpirationDate -le (Get-Date).AddDays($Days))
Ребята, Привет!
Огромное спасибо ВАМ за ваш ресурс, сколько я отсюда подчерпнул — не счесть.
Помогите, пожалуйста, чуть-чуть переделал скрипт отправки, но никак понять не могу в чем сейчас проблема.
$Server = «mail.mail.ru»
$Port = 587
$Username = «admin»
$Password = «admin123!»
$credential = New-Object System.Net.NetworkCredential ($Username, $Password)
$Sender = «[email protected]»
$Subject = ‘Tema Pisma’
$bodytxt1 = ‘skoro’
$bodytxt2 = ‘budet’
$bodytxt3 = ‘beda’
$warnDays = (get-date).adddays(7)
$ToDay = get-date
$Users = Get-ADUser -SearchBase ‘OU=Users,DC=mail,DC=ru’ -filter * -Properties msDS-UserPasswordExpiryTimeComputed, EmailAddress, Name, PasswordExpired, PasswordNeverExpires | Where-Object {($_.PasswordExpired -eq $false) -and ($_.Enabled -eq $True) -and ($_.PasswordNeverExpires -eq $false)} | select Name, @{Name =»ExpirationDate»;Expression= {[datetime]::FromFileTime($_.»msDS-UserPasswordExpiryTimeComputed»)}}, EmailAddress, PasswordExpired
foreach ($user in $users) {
if (($user.ExpirationDate -lt $warnDays) -and ($ToDay -lt $user.ExpirationDate) ) {
$lastdays = ($user.ExpirationDate -$ToDay).days
$EmailBody = $BodyTxt1, $user.name, $BodyTxt2, $lastdays, $BodyTxt3 -join ‘ ‘
Send-MailMessage -To $user.EmailAddress -From $Sender -SmtpServer $Server -port $Port -Credential $credential -Subject $Subject -Body $EmailBody
}
}
Ошибка
Send-MailMessage : Cannot process argument transformation on parameter ‘Credential’. userName
At C:\Users\admin\Desktop\testss.ps1:19 char:99
+ … ender -SmtpServer $Server -port $Port -Credential $credential -Subjec …
+ ~~~~~~~~~~~
+ CategoryInfo : InvalidData: (:) [Send-MailMessage], ParameterBindingArgumentTransformationException
+ FullyQualifiedErrorId : ParameterArgumentTransformationError,Microsoft.PowerShell.Commands.SendMailMessage
Разобрался.
Мб кому-то поможет, но приходят ?????? завтра буду копать.
$Server = «mail.mail.ru»
$Port = 25
$Username = «admin»
$Password = «admin123!»»
$secpasswd = ConvertTo-SecureString $password -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential ($username, $secpasswd)
$Sender = «[email protected]»
$Subject = ‘Tema Pisma’
$bodytxt1 = ‘skoro’
$bodytxt2 = ‘budet’
$bodytxt3 = ‘beda’
$warnDays = (get-date).adddays(7)
$ToDay = get-date
$Users = Get-ADUser -SearchBase ‘OU=Users,DC=mail,DC=ru’ -filter * -Properties msDS-UserPasswordExpiryTimeComputed, EmailAddress, Name, PasswordExpired, PasswordNeverExpires | Where-Object {($_.PasswordExpired -eq $false) -and ($_.Enabled -eq $True) -and ($_.PasswordNeverExpires -eq $false)} | select Name, @{Name =»ExpirationDate»;Expression= {[datetime]::FromFileTime($_.»msDS-UserPasswordExpiryTimeComputed»)}}, EmailAddress, PasswordExpired
foreach ($user in $users) {
if (($user.ExpirationDate -lt $warnDays) -and ($ToDay -lt $user.ExpirationDate) ) {
$lastdays = ($user.ExpirationDate -$ToDay).days
$EmailBody = $BodyTxt1, $user.name, $BodyTxt2, $lastdays, $BodyTxt3 -join ‘ ‘
#Send-MailMessage -To $user.EmailAddress -From $Sender -SmtpServer $Server -port $Port -Credential $credential -Subject $Subject -Body $EmailBody
Send-MailMessage -Credential $credential -To $user.EmailAddress -From $Sender -SmtpServer $Server -port $Port -Subject $Subject -Body $EmailBody
}
}
добавь к Send-MailMessage ключь -Encoding utf8
тогда будет нормально прихоходить нормально
Да, уже разобрался, спасибо.
$Sender = «[email protected]»
$Subject = ‘Внимание! Скоро истекает срок действия Вашего пароля!’
$BodyTxt1 = ‘Добрый день, ‘
$BodyTxt2 = ‘Срок действия Вашего пароля заканчивается через’
$BodyTxt3 = ‘дней’
$BodyTxt4 = ‘Не забудьте заранее сменить Ваш пароль. Если у вас есть вопросы, обратитесь в службу HelpDesk. ‘
$BodyTxt5 = »
$smtpserver =»kmgw.abc.ru»
$warnDays = (get-date).adddays(7)
$2Day = get-date
$Users = Get-ADUser -SearchBase ‘OU=04-Users,OU=_RU,DC=ABC,DC=ru’ -filter {Enabled -eq $True -and PasswordNeverExpires -eq $False} -Properties msDS-UserPasswordExpiryTimeComputed, EmailAddress, Name | select Name, @{Name =»ExpirationDate»;Expression= {[datetime]::FromFileTime($_.»msDS-UserPasswordExpiryTimeComputed»)}}, EmailAddress
foreach ($user in $users) {
if (($user.ExpirationDate -lt $warnDays) -and ($2Day -lt $user.ExpirationDate) ) {
$lastdays = ( $user.ExpirationDate -$2Day).days
$EmailBody = @»
$BodyTxt1 $($user.Name)
$BodyTxt2 $lastdays $BodyTxt3
$BodyTxt4
$BodyTxt5
Требования к паролям (Пароль должен содержать символы из трех следующих категорий):
Прописные буквы европейских языков (от A до Z, с диакритической меткой, греческим и кириллицем).
Строчные буквы европейских языков (от a до z, sharp-s, с диакритических знаков, греческий и кириллица).
Базовые 10 цифр (от 0 до 9).
Небукенно-цифровые символы (специальные символы): ‘-!»#$%&()*,./:;?@[]^_`{|}~+<=>
С уважением,
IT Team
«@
Send-MailMessage -To $user.EmailAddress -From $Sender -SmtpServer $smtpserver -Subject $Subject -Body $EmailBody -BodyAsHtml -Encoding utf8
}
}
Подскажите. у нас настроена как общая политика паролей так и (Fine-Grained Password Policy) . при выводе команды net user aaivanov /domain Password expires показывает 17.10.2024, но при запуске через
Get-ADUser -Identity avivanov -Properties msDS-UserPasswordExpiryTimeComputed | select-object @{Name=»ExpirationDate»;Expression= {[datetime]::FromFileTime($_.»msDS-UserPasswordExpiryTimeComputed») }} показывает 20.10.2023
я так понимаю что через Powershell выводиться более точная инфа ( так как в Fine-Grained Password Policy как раз и прописано 2 дня (Enforce Maximun password age)? или нет?
И подскажите на счёт Password changeable что это означет? Это когда юзер может сам себе менять пароль?
Скорее всего net user просто не умеет получаить информации о сроке действия пароля заданного через FGGP.
Password changeable — показывает, когда пользователь может сам сменить пароль (задается через minimum pasword age)
Доброго времени.
Подскажите пожалуйста как направить результаты вывода на почту?
то, что после:
Write-Host «$($user.sAMAccountName); осталось $lastdays дней: Сообщение отправлено» -BackgroundColor DarkGreen
****
if (($user.ExpirationDate -lt $warnDays) -and ($2Day -lt $user.ExpirationDate) ) {
$lastdays = ( $user.ExpirationDate -$2Day).days
$EmailBody = $BodyTxt1, $user.sAMAccountName, $BodyTxt2, $lastdays, $BodyTxt3, $BodyTxt4 -join, ‘ ‘
$encoding = [System.Text.Encoding]::UTF8
Send-MailMessage -To $user.EmailAddress -From $Sender -SmtpServer $smtpserver -Subject $Subject -Body $EmailBody -Encoding $encoding
Write-Host «$($user.sAMAccountName); сталось $lastdays дней: Сообщение отправлено» -BackgroundColor DarkGreen
Добрый день
а как можно настроить чтобы пароль истекал в 00:00 по времени
Ситуация такая что пользователи игнорируют оповещения на смену пароля и в течении рабочего дня у них пароль истекает,начальство требует чтобы пароли сбрасывались в полночь, чтобы сотрудник придя утром на работу при попытке логона выходило смена пароля
Добрый день, а не проще поднять веб интерфейс смены пароля по типу RD Web Access(Веб доступ к удаленным рабочим столам) из функционала Windows Server. Чтобы в ситуации когда у пользователя блокируется учетка, он знал что можно зайти на веб-страничку смены пароля и поменял его, тем самым разблокируя учетную запись, без участия администратора. И сделать этой страничке доступ извне, чтобы можно было заходить из любой сети и с любого устройства, например со смартфона.
Отличный у Вас план. Надёжный, как швейцарские часы. А главное — секьюрный )))
Это я про доступ извне, а не про RDWA.
У меня в напоминалке почтовой так и указывается: «Срок действия Вашего пароля для домена ***, пользователь: *** заканчивается через 7 дней. Не забудьте заранее сменить Ваш пароль. Это можно сделать перейдя по ссылке _https://***/».
Очень удобно, когда в сети несколько доменов и с каким-то из доменов работаешь только с веб-мордами или РДП
В теории наверное возможен скрипт, который пуляешь на исполнение в полночь и, если у юзера срок действия пароля меньше суток, но автоматом ставится галка «требовать смены пароля при следующем входе в систему». Но с реализацией не подскажу.
Cкрипт для вывода списка включенных учетных записей с неограниченным сроком действия пароля в active directory
# Подключение к Active Directory
Import-Module ActiveDirectory
# Получение всех включенных учетных записей с неограниченным сроком действия пароля
$users = Get-ADUser -Filter {Enabled -eq $true -and PasswordNeverExpires -eq $true} -Properties «SamAccountName», «Name», «PasswordNeverExpires»
# Вывод списка учетных записей
foreach ($user in $users) {
Write-Host «Имя пользователя: $($user.SamAccountName)»
Write-Host «Имя: $($user.Name)»
Write-Host «Неограниченный срок действия пароля: $($user.PasswordNeverExpires)»
Write-Host «»
}
Скрипт выдает ошибку
Send-MailMessage: C:\Scr\password_expired_email.ps1:19
Line |
19 | Send-MailMessage -To $users.EmailAddress -From $Sender -SmtpServer ma …
| ~~~~~~~~~~~~~~~~~~~
| Cannot validate argument on parameter 'To'. The argument is null, empty, or an
| element of the argument collection contains a null value. Supply a collection
| that does not contain any null values and then try the command again.
Send-MailMessage: C:\Scr\password_expired_email.ps1:19
Line |
19 | Send-MailMessage -To $users.EmailAddress -From $Sender -SmtpServer ma …
| ~~~~~~~~~~~~~~~~~~~
| Cannot validate argument on parameter 'To'. The argument is null, empty, or an
| element of the argument collection contains a null value. Supply a collection
| that does not contain any null values and then try the command again.
Send-MailMessage: C:\Scr\password_expired_email.ps1:19
Line |
19 | Send-MailMessage -To $users.EmailAddress -From $Sender -SmtpServer ma …
| ~~~~~~~~~~~~~~~~~~~
| Cannot validate argument on parameter 'To'. The argument is null, empty, or an
| element of the argument collection contains a null value. Supply a collection
| that does not contain any null values and then try the command again.
Хотя write-output $users.EmailAddress выводит список email адресов в чем может быть проблема?
$Sender = "test@"
$smtpServer = "mail.ru"
$smtpPort = 587
$smtpUsername = "test@"
$smtpPassword = ConvertTo-SecureString -String "" -AsPlainText -Force
$smtpCredential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $smtpUsername, $smtpPassword
$Subject = 'sadfasf'
$encoding = [System.Text.Encoding]::UTF8
$BodyTxt1 = 'adsf'
$BodyTxt2 = 'asdf '
$BodyTxt3 = 'adfs'
$warnDays = (get-date).adddays(180)
$2Day = get-date
$Users = Get-ADUser -SearchBase 'dc=temp, temp, temp' -filter {Enabled -eq $True -and PasswordNeverExpires -eq $False} -Properties msDS-UserPasswordExpiryTimeComputed, EmailAddress, Name | select Name, @{Name ="ExpirationDate";Expression= {[datetime]::FromFileTime($_."msDS-UserPasswordExpiryTimeComputed")}}, EmailAddress
foreach ($user in $users) {
if (($user.ExpirationDate -lt $warnDays) -and ($2Day -lt $user.ExpirationDate) ) {
$lastdays = ( $user.ExpirationDate -$2Day).days
$EmailBody = $BodyTxt1, $user.name, $BodyTxt2, $lastdays, $BodyTxt3 -join ' '
Send-MailMessage -To $users.EmailAddress -From $Sender -SmtpServer mail.stechtemp.ru -Port 587 -Credential $smtpCredential -Subject $Subject -Body $EmailBody
}
}
Сложно сходу сказать. Ругается на значение в поле to. Сделайте отладку скрипта, посмотрите что фактически возвращает $users.EmailAddress.
PS. Сейчас увидел. Замените
$users.EmailAddress
на$user.EmailAddress