#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 * .....
Спасибо,