計劃把原本的手工部署與設定操作逐步轉成 PowerShell Script。這樣做有幾個好處:

  1. 作業標準化,避免人為失誤
    寫成腳本,不管誰來操作結果都一致,不會無人交接手藝失傳,也排除腦殘眼拙手滑出錯的風險,
  2. 大量部署或需重複執行時可節省可觀時間
    例如要部署上百台機器的場合。
  3. 可設定排程自動化部署
    例如半夜才能執行的部署作業,只需少量人員留守負責驗證結果即可。

今天我要練習的題目是「使用 PowerShell 設定 Windows 排程跑 PowerShell Script」,以下是試寫的範例:

Param ([string]$ForceOverwrite = 'N')
$taskName = "Log 定期打包壓縮"
$taskPath = "維運作業"
$ErrorActionPreference = "STOP"
$chkExist = Get-ScheduledTask | Where-Object { $_.TaskName -eq $taskName -and $_.TaskPath -eq "\$taskPath\" }
if ($chkExist) {
    if ($ForceOverwrite -eq 'Y' -or $(Read-Host "[$taskName] 已存在,是否刪除? (Y/N)").ToUpper() -eq 'Y') {
        Unregister-ScheduledTask $taskName -Confirm:$false 
    }
    else {
        Write-Host "放棄新增作業" -ForegroundColor Red
        Exit 
    }
}
$action = New-ScheduledTaskAction -Execute "Powershell.exe" -Argument '-NoProfile -ExecutionPolicy ByPass -NonInteractive -WindowStyle Hidden -Command "D:\Workroom\PSLab\ArchiveLogs.ps1 D:\Logs\W3SVC1" '
$trigger = New-ScheduledTaskTrigger -Weekly -WeeksInterval 4 -DaysOfWeek Sunday -At 1am
Register-ScheduledTask $taskName -TaskPath $taskPath -Action $action -Trigger $trigger -User "SYSTEM"

整理幾個重點:

  1. PowerShell 有一系列內建的排程管理 Cmdlet,例如:Register-ScheduledTaskStart-ScheduledTask,官方文件寫得十分詳細還有大量範例,是最權威的參考來源。
  2. 設定排程的基本流程為:用 New-ScheduledTaskAction 指定動作、用 New-ScheduledTaskTrigger 設定執行週期,再用 Register-ScheduledTask 輸入名稱、路徑跟執行身分,參數幾乎都能對映到操作介面的欄位,加上文件完整,不難上手。
  3. 最前方我加了一小段檢查,若發現排程已存在會提示刪除重新設定。
  4. Windows 排程提供類似資料夾的概念,可將排程分群方便檢查管理,在註冊排程工作時指定 TaskPath 即可。
  5. 範例將排程設成用 Local System 身分執行不需提供密碼,若要使用一般帳號並互動輸入密碼,可參考淺談 PowerShell 中的密碼字串加密處理 介紹過的技巧。
  6. 在排程執行 PowerShell,主程式為 powershell.exe,參數可寫成 -NoProfile -ExecutionPolicy ByPass -NonInteractive -WindowStyle Hidden -Command "ps1路徑 ps1參數1 ps1參數2",其中 -NoProfile 代表不載入任何 Profile 避免干擾,-NonInteractive 可在遇到等待使用者輸入時直接報錯避免卡住,WindowStyle Hidden 會隱藏視窗,ExecutionPolicy ByPass 確保 .ps1 被允許執行。Command 為 .ps1 路徑跟 .ps1 需要的參數,若 .ps1 沒有輸入參數,則可寫成-File .ps1路徑。以上設定 .ps1 會默默執行默默結束,若要手動測試檢視其輸出或錯誤訊息,則可拿掉 -WindowStyle Hidden,加上 -NoExit。參考

執行結果像這樣:

不過我發現一個問題 - PowerShell 提供的排程管理指令不知何故無法設成每月固定一天執行,New-ScheduledTaskTrigger 有 Once、Daily、Weekly 選項,但沒有 Monthly。研究了一下,好像只能改用 schtasks.exe,例如:參考

#New-ScheduledTaskTrigger 不支援 Monthly,改用 schtasks
# 用 PowerShell 陣列轉字串做出以空白間隔的參數字串,含空白的參數值要加雙引號
$taskParams = @(
    "/Create",
    "/TN", "`"$taskPath\$taskName`"",
    "/SC", "monthly",
    "/D", "1", #每個月幾號
    "/ST", "01:00", #開始時間
    "/TR", "`"powershell.exe -NoProfile -ExecutionPolicy ByPass -NonInteractive -WindowStyle Hidden -Command 'C:\Workroom\PSLab\ArchiveLogs.ps1 D:\Logs\W3SVC1'`"", 
    "/RU", "System"
)
schtasks.exe $taskParams

練習完畢。

Exmaple of how to set a scheduled PowerShell script with PowerShell.


Comments

# by Chui-Wen Chiu

應該是 -NonInteractive

# by Jeffrey

to Chui-Wen Chiu,感謝,已更正。

Post a comment