Я заметил, что вы нигде не устанавливали переменную $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
в командлете Get-ADUser
, чтобы получить только тестового пользователя, или использовать параметр -SearchBase
и поместить свои тестовые аккаунты в специальное подразделение.