我一直在研究PowerShell脚本,当脚本的密码即将到期时,该脚本会向AD用户发送自动电子邮件。我的脚本中包含一个ForEach语句,但是其中实际上没有运行。我已经对其进行了设置,以便将所有活动记录在.txt文件中,这样我就可以看到何时执行每个步骤。它在Windows 2016 Essentials上运行。
下面的脚本:
# VAR
$SMTPHost = "smtp.office365.com"
$FromEmail = "***"
$expireindays = 3
$Date = Get-Date
# Set DIR
$DirPath = "C:\TEMP"
# Check is DIR is present
$DirPathCheck = Test-Path -Path $DirPath
if (!($DirPathCheck)) {
try {
#Create DIR if not present
New-Item -ItemType Directory $DirPath -Force
}
catch {
$_ | Out-File ($DirPath + "\" + "Log.txt") -Append
}
}
# CredObj
$CredObj = ($DirPath + "\" + "EmailExpiry.cred")
# Check if CredObj is Present
$CredObjCheck = Test-Path -Path $CredObj
If (!($CredObjCheck))
{
"$Date - INFO: creating cred object" | Out-File ($DirPath + "\" + "Log.txt") -Append
#If not present get O365 cred and store
$Credential = Get-Credential -Message "Please enter your Office 365 credentials."
#Export CredObj
$Credential | Export-Clixml -Path $CredObj
}
Write-Host "INFO | Importing Cred Object" -ForegroundColor Yellow
$Cred = (Import-Clixml -Path $CredObj)
"$Date - INFO: Importing AD Module" | Out-File ($DirPath + "\" + "Log.txt") -Append
Import-Module ActiveDirectory
"$Date - INFO: Getting Users" | Out-File ($DirPath + "\" + "Log.txt") -Append
Write-Host "INFO | Getting Users" -ForegroundColor Yellow
$users = Get-ADUser -properties Name, PasswordExpired, PasswordLastSet, EmailAddress -filter { (enabled -eq 'True') } | Where-Object { $_.PasswordExpired -eq 'False'}
# Process Each User for Password Expiry
ForEach ($User in $Users) {
$Name = (Get-ADUser $user | Get-ADUser -Property Name)
Write-Host "Working on $Name..." -ForegroundColor White
Write-Host "Getting email address for $Name..." -ForegroundColor Yellow
$emailaddress = $user.EmailAddress
if (!($emailaddress)) {
Write-Host "$Name has no E-Mail address listed, looking at their proxy address attributes..."
if (!($emailaddress)) {
Write-Host "$Name has no email address to send an e-mail to!" -ForegroundColor Red
"$Date - WARNING: No email found for $Name" | Out-File ($DirPath + "\" + "Log.txt") -Append
}
}
#Get password last set
$passwordSetDate = (Get-AAUser $user -properties * | ForEach-Object { $_.PasswordLastSet})
#Get the count on how many days until the password expires and stores it in the $daystoexpire VAR
$daystoexpire = (New-TimeSpan -Start $today -End $Expireson).Days
if (($daystoexpire -ge "0") -and ($daystoexpire -lt $expireindays)) {
"$Date - INFO: Sending expiry notice email to $Name" | Out-File ($DirPath + "\" + "Log.txt")
Write-Host "Sending Password expiry email to $Name" -ForegroundColor Yellow
$SmtpClient = New-Object system.net.mail.smtpclient
$MailMessage = New-Object system.net.mail.mailmessage
#Email Sender
$MailMessage.From = $FromEmail
#SMTP Server
$SmtpClient.Host = $SMTPHost
#SMTP SSL
$SmtpClient.EnableSsl = $true
#SMTP Credentials
$SmtpClient.Credentials = $Cred
#Email Recipients
$MailMessage.To.add($emailaddress)
#Subject
$MailMessage.Subject = "Your password will expire $daystoexpire days"
#Delivery Success
$MailMessage.DeliveryNotificationOptions = ("onSuccess", "onFailure")
#Set Priority
$MailMessage.Priority = "High"
#Body
$MailMessage.Body = "Password will expire, better change it!"
Write-Host "Sending email to $emailaddress..." -ForegroundColor Green
try {
$SmtpClient.Send($MailMessage)
}
catch {
$_ | Out-File ($DirPath + "\" + "Log.txt") -Append
}
else {
"$Date- INFO: Password for $Name not expiring for another $daystoexpire days" | Out-File ($DirPath + "\" + "Log.txt") -Append
Write-Host "Password for $Name does not expire for $daystoexpire days" -ForegroundColor White
}
}
}
输出:
答案 0 :(得分:0)
我注意到您没有在任何地方设置$Expireson
变量,因此您也无法获得$daystoexpire
的正确值。
事实上,我前段时间做了一个脚本来做同样的事情。我已经对其进行了一些编辑以供您试用。
这使用Send-Mailmessage
而不是System.Net.Mail.SmtpClient
来简化事情。这样,我们还可以使用Splatting使代码更具可读性。
Import-Module ActiveDirectory
$smtpServer = "smtp.office365.com"
$expireInDays = 3 # 3 is a bit close... better do something like 7
$from = "YOUR EMAILADDRESS"
$logPath = "C:\TEMP"
$logFile = Join-Path -Path $logPath -ChildPath 'PasswordExpiryLog.txt'
$logDate = '{0:dd-MM-yyyy}' -f (Get-Date)
$credPath = Join-Path -Path $logPath -ChildPath 'EmailExpiry.cred'
# create the output path if it does not exist
if (!(Test-Path -Path $logPath -PathType Container)) {
New-Item -Path $logPath -ItemType Directory | Out-Null
}
# Credentials
If (!(Test-Path -Path $credPath -PathType Leaf)) {
# write to the log and screen
$msg = "Creating credentials object"
Add-Content -Path $logFile -Value "$logDate - INFO: $msg"
Write-Host $msg -ForegroundColor Yellow
# If not present get O365 cred and store
$cred = Get-Credential -Message "Please enter your Office 365 credentials."
# Export CredObj
$cred | Export-Clixml -Path $credPath
}
else {
# write to the log and screen
$msg = "Importing credentials Object"
Add-Content -Path $logFile -Value "$logDate - INFO: $msg"
Write-Host $msg -ForegroundColor Yellow
$cred = Import-Clixml -Path $credPath
}
# create a template for the emails
$emailTemplate = @"
<html>
<head>
<title>Password Expire Notification</title>
<meta name="generator" content="PowerShell" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<style type="text/css">
body {
font-family: verdana, arial, helvetica, sans-serif;
font-size: 12px;
}
</style>
</head>
<body>
Dear _NAME_,
<p>Your password will expire in _DAYS_ days.<br /><br />
To change your password on a Windows pc in the office press CTRL-ALT-Delete and choose <strong>Change a password...</strong><br />
</p>
Regards
</body>
</html>
"@
# get all users that are enabled and that have a password expiry date
# test it out on dummy user(s) first of course !
$users = Get-ADUser -Filter * -Properties GivenName, Name, SamAccountName, PasswordNeverExpires, PasswordExpired,
PasswordLastSet, EmailAddress, AccountExpirationDate, accountExpires |
Where-Object { $_.Enabled -eq $true -and $_.PasswordNeverExpires -eq $false}
# get the domains default max password age
$defaultMaxPasswordAge = (Get-ADDefaultDomainpasswordPolicy).MaxPasswordAge
$mailCount = 0
foreach ($user in $users) {
if ([string]::IsNullOrWhiteSpace($emailAddress)) {
# write to the log and screen
$msg = "$userName has no email address to send an e-mail to!"
Add-Content -Path $logFile -Value "$logDate - INFO: $msg"
Write-Host $msg -ForegroundColor Yellow
# skip this user because we cannot send mail..
continue
}
# just for convenience, store some properties in variables
$firstName = $user.GivenName
$userName = $user.Name
$accountName = $user.SamAccountName
$emailAddress = $user.EmailAddress
$passwordSetDate = $user.PasswordLastSet
$passwordPolicy = (Get-AduserResultantpasswordPolicy $user)
# check if there is a 'Fine Grained Password' policy for this user
if ($null -ne $passwordPolicy) {
$maxPasswordAge = ($passwordPolicy).MaxPasswordAge
}
else {
# no 'Fine Grained Password' policy, so use the default domain password age
$maxPasswordAge = $defaultMaxPasswordAge
}
# prevent errors when the 'User must change password at next logon' checkmark is set
if (!$passwordSetDate -or !$maxPasswordAge) {
# write to the log and screen
$msg = "Please check if the 'User must change password at next logon' checkmark is off for user '$userName'"
Add-Content -Path $logFile -Value "$logDate - INFO: $msg"
Write-Host $msg -ForegroundColor Yellow
}
# calculate the expiry date for the password
$passwordExpiresAt = $passwordSetDate + $maxPasswordAge
# check if the account does not expire before the password does using the accountExpires property.
# 0 means the expiration date has been removed. 9223372036854775807 means the account never had an expiration date
if ($user.accountExpires -ne 0 -and $user.accountExpires -ne 9223372036854775807 -and $user.AccountExpirationDate -ne $null) {
if ($user.AccountExpirationDate -le $passwordExpiresAt) {
# skip this user if the account expires before the password needs changing
$msg = "The account for user '$userName' expires before the password needs changing."
Add-Content -Path $logFile -Value "$logDate - INFO: $msg"
Write-Host $msg -ForegroundColor Yellow
continue
}
}
# calculate how many days are left
$daysToExpire = [int](New-TimeSpan -Start (Get-Date) -End $passwordExpiresAt).Days
if (($daysToExpire -ge 0) -and ($daysToExpire -lt $expireInDays)) {
# if there are still days left to change the password, send an email
# using Send-MailMessage rather than System.Net.Mail.SmtpClient
$msg = "Sending expiry notice email to '$userName'"
Add-Content -Path $logFile -Value "$logDate - INFO: $msg"
Write-Host $msg -ForegroundColor Yellow
# use splatting for cmdlets that take a lot of parameters
$params = @{
SmtpServer = $smtpServer
From = $from
To = $emailAddress
Subject = "Your password will expire in $daysToExpire days."
Body = $emailTemplate -replace "_NAME_", $firstName -replace "_DAYS_", $daysToExpire
BodyAsHtml = $true
Encoding = [System.Text.Encoding]::UTF8
Credential = $cred
UseSsl = $true
Priority = 'High'
DeliveryNotificationOption = 'OnSuccess', 'OnFailure'
# Port = 587
}
Send-Mailmessage @params
# update the counter for the users that were sent an email
$mailCount++
}
elseif ($daysToExpire -le 0) {
$msg = "Password for user '$userName' is already expired!"
Add-Content -Path $logFile -Value "$logDate - WARNING: $msg"
Write-Host $msg -ForegroundColor Red
}
}
$msg = "Password expiry notifications have been sent to $mailCount users"
Add-Content -Path $logFile -Value "$logDate - INFO: $msg"
Write-Host $msg -ForegroundColor Green
注意:与往常一样,创建几个测试用户首先尝试一下。您可以使用-Filter
cmdlet上的Get-ADUser
参数仅获取测试用户,或使用-SearchBase
参数并将测试帐户放入特殊的OU。