Итак, у меня есть несколько пользователей, у которых компы не в домене. Одна из раздражающих вещей в этом заключается в том, что 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:\Scripts\PasswordChangeNotification.csv" # ie. c:\Scripts\PasswordChangeNotification.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 protected]", #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
Я просто пытаюсь понять, как я могу изменить свой код, чтобы использовать два отличительных имени вместо одного. Я уверен, что это не лучший способ сделать это, но я еще не слишком хорошо разбираюсь в кодировании. Надеюсь, все это имеет смысл, я ценю помощь!
Понятно!!
Я изменил $DN на:
$DN = "Distinguished name","Distinguished name"
затем изменил мой код get-aduser на:
$users= $DN | ForEach-Objects {get-aduser -SearchBase $PSItem -filter * .....
Спасибо,
Как вы обнаружили, вы можете хранить значения 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
увеличивается.Используйте циклы, когда вы перебираете данные и не знаете, сколько раз вам, возможно, придется выполнять итерацию. Циклы в вашем случае позволяют вашему коду быть более динамичным. Перебор двух строк не будет иметь никакого значения с точки зрения скорости. Это просто то, что следует учитывать при разработке сценариев, например. может быть компромисс между запуском Get-ADUser
на каждой итерации и просто выполнением этого один раз и циклическим просмотром результата. Вы должны заменить пункты where
на пункты -filter
, где это возможно. Where
работает намного медленнее и становится более очевидным, когда ваш Get-ADUser
возвращает большое количество объектов.
К удалению where
добавляется тот факт, что не все атрибуты AD индексируются. Некоторые будут возвращать данные очень быстро, используя -filter
, а некоторые будут медленнее. Вы должны протестировать различные проекты, если для вас важна производительность. Трудно использовать слово «всегда» для каждого сценария.
ааа, хорошо, звучит хорошо... Я возился с предложенным фрагментом кода, и я получаю сообщение об ошибке Method invocation failed because [Microsoft.ActiveDirectory.Management.ADUser] does not contain a method named 'op_Addition'.
Я предполагаю, что op_addition говорит о сложении двух вместе? Я читал, что мне нужно добавить $users = @()
... но это не сработало для меня. есть идеи? Благодаря тонну!
Возможно, это проблема версии или того, как вы объявили $users в другом месте скрипта. Я тестировал это только на версиях 5.1 и 5.0. Объявление $users
, как вы говорите, тоже должно работать.
хм странно. Я только что проверил, и у меня версия 5.1... здесь что-то другое, я просто запускаю get-aduser -SearchBase $DN1 -filter * -properties Name, PasswordNeverExpires, PasswordExpired, PasswordLastSet, EmailAddress
, а мне пишет Get-ADUser : Cannot validate argument on parameter 'SearchBase'. The argument is null. Provide a valid value for the argument, and then try running the command again.
я запускаю $DN1
в параметре SearchBase. В $DN1 содержится только отличительное имя конкретного пользователя. Раньше все работало нормально, не знаю что изменилось. Данг.
На самом деле я столкнулся с этой ошибкой, я не знаю, в чем проблема, но если я просто введу отличительное имя в качестве аргумента для параметра Searchbase, это сработает. Но у меня все еще есть ошибка op_Addition
Возможно, не все ваши пользовательские объекты имеют одинаковые атрибуты, присутствующие на выходе, и выдают эту ошибку. Я тестировал только с подмножеством пользователей. Если это так, то просто игнорируйте синтаксис +
. Сокращение where
по-прежнему полезно.
Я ценю вашу помощь! Я думаю, что понял. Изначально у меня был Users = @()
отдельный, который не заставлял его работать. Я уверен, что вы могли бы сказать мне это, ха-ха (дурр). Это не сработало, пока я не выразил это так: $users =@(get-aduser -searchbase "DN"....
теперь работает как шарм.
Спасибо за ваш вклад, извините, я только что увидел ваш пост. Итак, если я расширяюсь и начинаю добавлять больше пользователей в свой скрипт, не будет ли лучше использовать цикл?