Напоминание об истечении срока действия пароля по электронной почте нескольким пользователям

#powershell

#powershell

Вопрос:

Итак, у меня есть несколько пользователей, чьи компьютеры не входят в домен. Одна из неприятных вещей в этом заключается в том, что Windows не будет уведомлять их о том, что срок действия их пароля домена истек, очевидно. Итак, я решил, что собираюсь создать небольшой скрипт с использованием powershell в Windows, который проверяет AD, чтобы узнать, когда истекает срок действия их пароля, а затем, если срок его действия истекает через 3 дня, отправить пользователю электронное письмо с уведомлением о том, что им следует сменить пароль.

Я настроил его прямо сейчас, чтобы просмотреть различимое имя пользователя, чтобы получить всю необходимую информацию. но я могу сделать это только для одного человека, мне нужно просмотреть два отличительных имени пользователей и отправить каждому из них электронное письмо, когда срок действия их пароля истекает. Я попытался создать другую переменную $ DN, в которую я мог бы ввести другое различимое имя и поместить get-aduser -searchbase $DN, $DN2 , но у меня это не сработало. Вероятно, было глупо попробовать, но не уверен, что синтаксис необходим для этого. Ниже приведен мой код.

 $smtpServer="smtp.office365.com" # Office 365 official smtp server 
$expireindays = 100 # number of days for password to expire  
$from =  # email from  
#$logging = "$true" # Set to Disabled to Disable Logging 
$logFile = "c:ScriptsPasswordChangeNotification.csv" # ie. c:ScriptsPasswordChangeNotification.csv 
#$testing = "Disabled" # Set to Disabled to Email Users 
$testRecipient =   
$date = Get-Date -format ddMMyyyy
$DN = "Distinguished name here"
# Add EMAIL Function 
Function EMAIL{ 

    Param( 
        $emailSmtpServer = $smtpServer,   #change to your SMTP server 
        $emailSmtpServerPort = 587, 
        $emailSmtpUser = "User"
        $emailSmtpPass = "Password",   #Password for Send from email account 
        $emailFrom = "email@domain.com",   #Email account you want to send from 
        $emailTo, 
        $emailAttachment, 
        $emailSubject, 
        $emailBody 
    ) 
    Process{ 

    $emailMessage = New-Object System.Net.Mail.MailMessage( $emailFrom , $emailTo ) 
    $emailMessage.Subject = $emailSubject 
    $emailMessage.IsBodyHtml = $true 
    $emailMessage.Priority = [System.Net.Mail.MailPriority]::High 
    $emailMessage.Body = $emailBody 

    $SMTPClient = New-Object System.Net.Mail.SmtpClient( $emailSmtpServer , $emailSmtpServerPort ) 
    $SMTPClient.EnableSsl = $true 
    $SMTPClient.Credentials = New-Object System.Net.NetworkCredential( $emailSmtpUser , $emailSmtpPass ); 

    $SMTPClient.Send( $emailMessage ) 
    } 
} 

# Get Users From AD who are Enabled, Passwords Expire and are Not Currently Expired 
Import-Module ActiveDirectory 
$users = get-aduser -SearchBase $DN -filter * -properties Name, PasswordNeverExpires, PasswordExpired, PasswordLastSet, EmailAddress |where {$_.Enabled -eq "True"} | where { $_.PasswordNeverExpires -eq $false } | where { $_.passwordexpired -eq $false }
$DefaultmaxPasswordAge = (Get-ADDefaultDomainPasswordPolicy).MaxPasswordAge

# Process Each User for Password Expiry 
foreach ($user in $users) 
{ 
    $Name = $user.Name 
    $emailaddress = $user.emailaddress 
    $passwordSetDate = $user.PasswordLastSet 
    $PasswordPol = (Get-AduserResultantPasswordPolicy $user) 
    # Check for Fine Grained Password 
    if (($PasswordPol) -ne $null) 
    { 
        $maxPasswordAge = ($PasswordPol).MaxPasswordAge 
    } 
    else 
    { 
        # No FGP set to Domain Default 
        $maxPasswordAge = $DefaultmaxPasswordAge 
    } 

    $expireson = $passwordsetdate   $maxPasswordAge 
    $today = (get-date) 
    $daystoexpire = (New-TimeSpan -Start $today -End $Expireson).Days 

    # Set Greeting based on Number of Days to Expiry. 

    # Check Number of Days to Expiry 
    $messageDays = $daystoexpire 

    if (($messageDays) -ge "1") 
    { 
        $messageDays = "in "   "$daystoexpire"   " days." 
    } 
    else 
    { 
        $messageDays = "today." 
    } 

    # Email Subject Set Here 
    $subject="Your password will expire $messageDays" 

    # Email Body Set Here, Note You can use HTML, including Images. 
    $body ="     
    <p>Dear $name,<br></P><br> 
    <p>Your domain password will expire $messageDays<br><br> 
    Please change your password before it expires.<br></P><br><br> 
    <p>Thanks, <br>

    } # End Send Message 

} # End User Processing  
# End
  

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

Ответ №1:

Как вы обнаружили, вы можете хранить значения DN в массиве $DNs и обрабатывать каждый элемент массива. Два выражения внутри круглых скобок отличаются только $DN указанными вами переменными. Использование цикла немного эффективнее, чем переход к, но в вашем случае это будет незначительно. Foreach ForEach-Object

 $users = Foreach ($DN in $DNs) {
  get-aduser -SearchBase $DN -filter {
  Enabled -eq "True" -and 
  PasswordNeverExpires -eq "False" -and 
  passwordexpired -eq "False" 
  } -properties Name, PasswordNeverExpires, PasswordExpired, PasswordLastSet, EmailAddress)
  

Это дает дополнительные преимущества:

  • Удаление Where-Object : Get-ADUser имеет свой собственный фильтр в качестве параметра, который может значительно повысить производительность по сравнению с использованием where в определенных запросах. Это должно быть быстрее для вас здесь, так как количество возвращенных пользователей из Get-ADUser запроса увеличивается.

Комментарии:

1. Спасибо за ваш вклад, извините, я едва прочитал ваш пост. Итак, если я расширюсь и начну добавлять больше пользователей в свой скрипт, было бы лучше использовать цикл?

2. Используйте циклы, когда вы перебираете данные и не знаете, сколько раз вам, возможно, придется повторять. Циклы в вашем случае позволяют вашему коду быть более динамичным. Перебор двух строк не будет иметь никакого значения с точки зрения скорости. Это просто то, что следует учитывать при разработке сценариев, например. может быть компромисс между запуском Get-ADUser на каждой итерации или просто выполнением этого один раз и циклическим просмотром результата. Вы должны заменить where предложения -filter предложениями, где вы можете. Where работает намного медленнее и становится более очевидным, когда вы Get-ADUser возвращаете большое количество объектов.

3. Добавление к where удалению заключается в том, что не все атрибуты AD индексируются. Некоторые будут возвращать данные очень быстро -filter , а некоторые будут медленнее. Вам следует протестировать разные проекты, если для вас важна производительность. Трудно использовать слово «всегда» для каждого сценария.

4. ах, хорошо, звучит неплохо… Я возился с предложенным вами фрагментом кода, и я получаю сообщение об ошибке, в котором говорится Method invocation failed because [Microsoft.ActiveDirectory.Management.ADUser] does not contain a method named 'op_Addition'. , что я предполагаю, что op_addition говорит о добавлении двух вместе? Я читал, что мне нужно добавить $users = @() … но у меня это не сработало. есть идеи? Огромное спасибо!

5. Возможно, это проблема с версией или то, как вы объявили $users в другом месте скрипта. Я тестировал это только в версиях 5.1 и 5.0. Объявление $users , как вы говорите, тоже должно работать.

Ответ №2:

Понял!!

Я изменил $ DN на: $DN = "Distinguished name","Distinguished name" затем изменил свой код get-aduser на: $users= $DN | ForEach-Objects {get-aduser -SearchBase $PSItem -filter * .....

Спасибо,