2025年7月28日 星期一

【IT Notes】PowerShell Script排程發信通知者用者密碼到期

以前寫過一些簡單的script發信通知,不過後來忘記保存,現在要再找也找不到了,要重寫又不知道花多少時間,幸好現在ChatGPT方便,把完整的需求丟給它,就幾乎可以做到我要的程式結果,而且寫出的內容非常不錯,必須說現在寫程式土法煉鋼的日子愈來愈少了,以後懂程式的人不知道還有沒有高薪上的優勢?雖然方便又快速,但還是把過程紀錄一下,誰知道以後會不會再用到。

一.基本需求

1.篩選 AD帳號 中 EmployeeID 以「A」開頭的帳號
2. 計算帳號密碼剩餘天數,不處理時間細節,只留年月日
3. 剩餘天數為 1~5 天內發送提醒郵件(跳過已過期或未啟用帳號)
4. 使用 Office 365 SMTP 發信(支援應用程式密碼)
5. UTF-8 編碼
6. 可排入工作排程器每天上午9點執行

二.產出應用程式密碼

現在不論是GWS還是M365,都已經改掉了以往用登入帳號當應用程式的登入密碼了,取而代之的是用戶要自己產出一支專用的應用程式密碼,改組密碼屬於單一用途,用在其他地方就會沒效,這是比較新且安全的機制。

選定要發信的M365帳號,然後在安全性資訊>新增登入方法>應用程式密碼,讓系統產出一組專用密碼

三.Powershell內容

將以下內容做一些修改,然後存檔命名為account_notification.ps1,然後放在C:\底下。路徑:C:\account_notification.ps1。

# region ===== 設定參數 =====
# Office 365 發信資訊
$smtpServer = "smtp.office365.com"
$smtpPort = 587
$smtpUser = "it@abc.com"         # 發信者信箱
$smtpPass = "klhykvzxlvhbbtyk"       # M365 應用程式密碼

# 發信者名稱與主旨
$from = "資訊部 <it@abc.com>"
$subject = "您的AD帳號密碼即將到期通知"

# 取得今日日期(只保留年月日)
$today = (Get-Date).Date

# 匯入AD模組
Import-Module ActiveDirectory

# 取得所有 EmployeeID 開頭為 "A" 的啟用帳號
$users = Get-ADUser -Filter {Enabled -eq $true -and EmployeeID -like "A*"} -Properties DisplayName, EmailAddress, PasswordLastSet, PasswordNeverExpires, msDS-UserPasswordExpiryTimeComputed

foreach ($user in $users) {

    # 跳過沒有 Email 的帳號
    if ([string]::IsNullOrEmpty($user.EmailAddress)) { continue }

    # 跳過永不過期的帳號
    if ($user.PasswordNeverExpires) { continue }

    # 密碼到期日(只保留年月日)
    $expiryDate = [datetime]::FromFileTime($user."msDS-UserPasswordExpiryTimeComputed").Date

    # 計算剩餘天數(忽略具體時間,只算日期)
    $daysLeft = ($expiryDate - $today).Days

    # 跳過已過期或不在 1~5 天內的帳號
    if ($daysLeft -lt 1 -or $daysLeft -gt 5) { continue }

    # 通過條件後,開始發信
    $LastDay = $daysLeft
    $CName = $user.GivenName
    $to = $user.EmailAddress

    # 郵件內容(UTF8 編碼)
    $body = @"
親愛的 $CName
您的AD帳號剩下 $LastDay 天將到期,為了維護資訊安全,請盡快更新您的AD密碼。

密碼規則為:
1.共8碼以上
2.數字、英文大小寫、特殊符號的複雜度
3.不可用與帳號相同的內容,例如英文姓名

修改方式:
1.在您的電腦上輸入Ctrl+Alt+Del,然後選擇「變更密碼」
2.到遠端主機上(RDS)上,輸入Ctrl+Alt+End,再選擇「變更密碼」

若有問題請洽資訊部,謝謝!

"@

    # 建立郵件物件
    $mailParams = @{
        From       = $from
        To         = $to
        Subject    = $subject
        Body       = $body
        SmtpServer = $smtpServer
        Port       = $smtpPort
        UseSsl     = $true
        Credential = New-Object System.Management.Automation.PSCredential($smtpUser, (ConvertTo-SecureString $smtpPass -AsPlainText -Force))
        Encoding   = ([System.Text.Encoding]::UTF8)
    }

    try {
        Send-MailMessage @mailParams
        Write-Host "發送成功: $to"
    } catch {
        Write-Warning "發送失敗: $to - $_"
    }
}


第一次寫完並放到排程測試跑幾天後,發現一個小問題,如果某帳戶的密碼到期間是在我設定排程發信時間點之後,那麼他隔天會收到兩封信,其中一封是前一天錯過排程時間、後來又補寄的,這樣會讓用戶感到困惑,為了避免造成麻煩並簡化程式邏輯,所有時間的計算都建議調整只要年月日,時和分的細節就忽略它。

四.排程器設定

排程器的設定跟以前用的Windows 2012也有點不一樣了,為了安全性,目前改用的Windows 2022支援powershell執行ps1也變得很嚴謹,這個過程也需要留意和紀錄一下。
建立一個基本的工作排程

命名工作「名稱」,設定「不論使用者登入與否都執行」,最後「以最高權限執行」

觸發程序設定成每天的9:00一次性執行

確認好執行時間

重要步驟之一,執行powershell指令現在必須要用PowerShell7的pwsh.exe,要記得事先安裝好。下面的「新增引數」要填「-ExecutionPolicy Bypass -File "C:\account_notification.ps1"

因為用最高權限執行此排程,所以設定完畢後,要正確輸入管理員帳密

最後可以開始測試排程是否正常執行

這應該會是一個滿實用的腳本,一般使用者總是希望系統會主動通知密碼到期的問題,留下這篇當作今後若還有需求時使用。

沒有留言:

張貼留言

【當兵回憶】八里連

 在我心目中新兵日記是天花板等級的軍教片,並不是說沒有比它更好的作品,只是因為它的在拍攝的背景和時間,也正是我在服兵役的同時,老婆很多次好奇問我,為什麼我總是放在YouTube的新兵日記直播,我都說我只放在有個聲音在,我沒有真正在看,但這行為仔細想想也好多年了吧!台詞聽到我都會背...