)
簡介這份資源面向需要在Windows環(huán)境下管理多臺設備的IT運維人員與Python學習者提供一套自動遠程批量關機的腳本方案解決逐臺手動關機效率低、易遺漏的問題。壓縮包共3個文件包含1個py腳本與2個txt說明文檔整體僅923B輕量易取腳本可直接參考或改造使用。內容圍繞WMI遠程管理展開涉及通過win32com.client建立遠程連接、調用Win32_ComputerSystem的Shutdown方法執(zhí)行軟關機或強制關機并以IP列表遍歷實現批量下發(fā)命令同時提示管理員權限、目標機遠程管理策略配置以及用戶名密碼的安全存放方式。已有897人學習下載適合希望快速掌握遠程批量關機思路、并在此基礎上擴展重試與超時等健壯性處理的讀者參考借鑒。1. 機房巡檢收尾那點事為什么我最終選了 Python 批量遠程關機凌晨一點半實驗室的燈還亮著三十多臺 Windows 工作站跑完最后一輪渲染任務風扇聲像一群不肯落地的直升機。手動一臺臺點“開始→關機→確定”點到最后手都麻了還漏了兩臺第二天被導師問“昨晚那幾臺怎么還開著”。這就是我最初折騰批量遠程關機的真實動機——不是炫技是實在受不了重復勞動。這份資源要解決的核心問題很具體在 Windows 環(huán)境下用 Python 腳本對局域網內多臺 Windows 主機發(fā)起自動、批量的遠程關機。它適合誰適合手里管著幾臺到幾十臺 Windows 機器、又不想逐臺登錄操作的人——實驗室管理員、測試機維護者、小型機房值守人員。關鍵詞里的“自動”“遠程關機”“批量關機”“windows”“python”五個詞基本就是它的全部能力邊界。下面我按“先跑通一臺再擴到一批最后處理翻車”的順序拆開講。2. 遠程關機的底層通道WMI、RPC 與 shutdown 命令怎么選2.1 三條常見技術路線對比Windows 上讓另一臺機器關機繞不開三個東西shutdown命令、WMIWindows Management Instrumentation、以及基于 RPC 的遠程調用。它們不是并列關系而是層層包裹——shutdown /m底層走的就是 RPCWMI 也能調Win32_OperatingSystem的Shutdown方法。路線調用方式依賴服務適用場景主要限制shutdown 命令shutdown /s /m \\目標IPRPC、Remote Registry快速腳本、臨時操作報錯信息模糊權限要求高WMIwmic /node:IP或 Pythonwmi庫WMI 服務、DCOM需要讀取狀態(tài)再關機配置復雜防火墻端口多PsExec 類工具遠程執(zhí)行進程Admin$ 共享、SMB需要執(zhí)行任意命令需額外工具易被殺軟攔截我一般優(yōu)先用shutdown命令因為它最輕不需要額外裝庫Python 里一個subprocess就能調。但它的坑也最多后面避坑章節(jié)會細說。2.2 為什么用 Python 而不是批處理批處理也能寫for循環(huán)調shutdown但一旦要處理“哪些機器在線”“失敗重試”“記錄日志”“并發(fā)控制”bat 就力不從心了。Python 的優(yōu)勢在于可以用concurrent.futures做并發(fā)用subprocess拿返回碼用logging落日志用ipaddress生成網段。這些在幾十臺機器的場景下不是錦上添花是剛需——串行關機等一臺超時 30 秒三十臺就是十五分鐘。2.3 前置條件目標機器必須打開什么遠程關機不是發(fā)個包就完事目標 Windows 主機必須滿足幾個條件缺一個就報“拒絕訪問”Remote Registry 服務默認手動啟動遠程 RPC 調用需要它。設為自動并啟動。防火墻規(guī)則入站放行“Windows Management Instrumentation (WMI)”和“Remote Service Management”相關規(guī)則或者臨時關閉域內防火墻測試。賬號權限發(fā)起端使用的賬號必須是目標機的管理員組成員且目標機不能是空密碼賬號Windows 默認禁止空密碼遠程登錄。網絡發(fā)現同一網段或路由可達能 ping 通是基本前提。這些條件在域環(huán)境里通常由組策略統(tǒng)一配好但在工作組環(huán)境比如實驗室臨時搭的機器里得一臺臺確認。我習慣先拿一臺當“小白鼠”跑通了再批量。import subprocess def shutdown_one(ip, timeout10): 對單臺 Windows 主機發(fā)起遠程關機 :param ip: 目標主機 IP :param timeout: 子進程超時秒數防止卡死 :return: (ip, 是否成功, 返回信息) cmd fshutdown /s /t 0 /m \\\\{ip} /f try: # capture_output 捕獲 stdout/stderrtext 讓輸出為字符串 result subprocess.run( cmd, shellTrue, capture_outputTrue, textTrue, timeouttimeout ) if result.returncode 0: return ip, True, 關機指令已發(fā)送 else: return ip, False, result.stderr.strip() or result.stdout.strip() except subprocess.TimeoutExpired: return ip, False, 超時目標無響應這段代碼是整套腳本的最小單元。shutdown /s表示關機/t 0表示立即執(zhí)行延遲 0 秒/m \\IP指定遠程目標/f強制關閉正在運行的程序——不加/f時如果有未保存的文檔目標機會彈窗等待遠程場景下沒人點確認就會一直掛著。timeout參數是血淚經驗網絡不通時shutdown命令可能卡很久不設超時整個批量任務會被一臺機器拖死。提示/t 0和/f組合會直接丟棄未保存內容生產環(huán)境慎用測試機隨意。3. 從單臺到批量IP 列表、并發(fā)與日志三件套3.1 IP 來源文件讀取還是網段掃描批量關機的第一步是拿到目標列表。常見做法有兩種一是維護一個hosts.txt每行一個 IP二是給一個網段先 ping 掃描再關機。前者可控后者省事但容易誤傷。我一般用文件方式因為“哪些機器該關”是個業(yè)務判斷不該交給腳本猜。文件格式就一行一個 IP允許#開頭注釋# 渲染組 192.168.1.101 192.168.1.102 # 測試組 192.168.1.201讀取時過濾空行和注釋順便去重def load_targets(path): 從文本文件加載 IP 列表忽略空行和 # 注釋 targets [] with open(path, r, encodingutf-8) as f: for line in f: line line.strip() if not line or line.startswith(#): continue targets.append(line) # 去重但保持順序 return list(dict.fromkeys(targets))dict.fromkeys是去重的常用技巧比set好的地方是保留原始順序日志讀起來符合直覺。3.2 并發(fā)控制線程池不是越多越好三十臺機器串行關機每臺哪怕只花 2 秒也要一分鐘。用線程池并發(fā)能把時間壓到幾秒。但線程數不是越大越好——shutdown命令本身會創(chuàng)建進程線程太多反而搶資源而且目標機可能扛不住同時涌入的連接。from concurrent.futures import ThreadPoolExecutor, as_completed def shutdown_batch(targets, max_workers8): 并發(fā)批量關機max_workers 控制同時發(fā)起的關機數 results [] with ThreadPoolExecutor(max_workersmax_workers) as executor: future_map { executor.submit(shutdown_one, ip): ip for ip in targets } for future in as_completed(future_map): ip future_map[future] try: results.append(future.result()) except Exception as e: results.append((ip, False, f異常: {e})) return resultsmax_workers8是我在幾十臺規(guī)模下比較穩(wěn)的值。機器少可以調到 4上百臺可以到 16但再高收益遞減還容易觸發(fā)目標機的連接限制。as_completed保證誰先返回先處理誰不會因為某臺慢而阻塞日志輸出。3.3 日志與結果核對別關完就完事批量操作最怕“以為都關了其實有幾臺沒關”。所以每次執(zhí)行都要落日志記錄時間、IP、成功與否、失敗原因。日志用標準logging模塊同時輸出到控制臺和文件import logging def setup_logger(log_fileshutdown.log): logger logging.getLogger(batch_shutdown) logger.setLevel(logging.INFO) fmt logging.Formatter(%(asctime)s [%(levelname)s] %(message)s) # 文件處理器追加模式 fh logging.FileHandler(log_file, encodingutf-8) fh.setFormatter(fmt) # 控制臺處理器 ch logging.StreamHandler() ch.setFormatter(fmt) logger.addHandler(fh) logger.addHandler(ch) return logger執(zhí)行完打印一個匯總表成功多少、失敗多少、失敗的是哪些 IP。失敗列表可以直接復制出來排查后重跑——腳本要支持“只對失敗的重試”而不是每次全量重來。注意日志文件別放在會被關機影響的機器上發(fā)起端自己別被關進去。4. 避坑與排查遠程關機最常見的五類翻車4.1 現象提示“拒絕訪問(5)”原因發(fā)起端賬號不是目標機管理員或目標機禁用了空密碼遠程登錄或 Remote Registry 服務沒啟動。解決確認賬號在目標機Administrators組用net use \\IP\IPC$ /user:管理員賬號先建立憑據會話再關機檢查組策略“賬戶使用空密碼的本地賬戶只允許進行控制臺登錄”是否被啟用。4.2 現象命令返回成功但機器沒關原因shutdown返回 0 只代表指令送達不代表目標機執(zhí)行了。目標機可能因為有待保存文檔、有程序阻止關機、或電源策略攔截。解決加/f強制關閉如果仍不關去目標機事件查看器看“系統(tǒng)”日志里User32或Kernel-Power的記錄確認目標機沒有處于“演示模式”或接了不允許關機的策略。4.3 現象部分機器超時腳本卡住原因網絡不通或目標機防火墻攔截shutdown命令在等 RPC 響應。解決subprocess.run必須帶timeout批量前先并發(fā) ping 一輪把不在線的剔掉減少無效等待。4.4 現象關機后無法再次遠程喚醒原因這是關機不是重啟Wake-on-LAN 需要網卡和主板支持且關機后網卡仍供電。解決如果后續(xù)要遠程開機關機前確認目標機 BIOS 和網卡驅動開啟了 WOL否則只能現場開機。這個坑我在實驗室踩過關得爽第二天全員現場按電源鍵。4.5 現象殺軟或安全軟件攔截 shutdown 調用原因部分終端防護會把遠程shutdown當成可疑行為。解決在目標機安全軟件里把發(fā)起端 IP 或shutdown.exe加入白名單或者改用 WMI 方式但 WMI 同樣可能被攔。沒有銀彈只能按環(huán)境調。5. 進階把關機做成可調度、可回滾的例行任務5.1 用計劃任務做定時批量關機腳本跑通后下一步是讓它自動在固定時間執(zhí)行。Windows 任務計劃程序里建一個基本任務觸發(fā)器設為每天 23:30操作設為python.exe D:\scripts\batch_shutdown.py起始目錄填腳本所在目錄。注意“不管用戶是否登錄都要運行”要勾上否則鎖屏后不執(zhí)行。5.2 加一個“預演模式”再真關直接批量關機風險高我后來給腳本加了一個--dry-run參數只 ping 和打印將要關機的列表不真正調用shutdown。確認列表無誤后再去掉參數執(zhí)行。這個習慣救過我好幾次——有一次 IP 文件里混進了一臺正在跑重要任務的機器預演時看到了及時刪掉。import argparse def parse_args(): parser argparse.ArgumentParser(descriptionWindows 批量遠程關機) parser.add_argument(--file, defaulthosts.txt, helpIP 列表文件) parser.add_argument(--workers, typeint, default8, help并發(fā)數) parser.add_argument(--dry-run, actionstore_true, help只預演不關機) return parser.parse_args()argparse讓腳本從“改代碼調參數”變成“命令行傳參”配合計劃任務和手動執(zhí)行都方便。--dry-run是布爾開關不加就是真關加了就只打印。5.3 驗證關機結果ping 輪詢確認指令發(fā)出去不等于關掉了。執(zhí)行完等 30 秒再對目標列表做一輪 ping還在線的就是沒關成功的單獨列出來。這個“發(fā)指令→等待→驗證”的閉環(huán)比只看shutdown返回碼可靠得多。import subprocess def check_offline(ip): ping 一次返回 True 表示已離線關機成功 # -n 1 發(fā)一個包-w 1000 超時 1 秒 result subprocess.run( fping -n 1 -w 1000 {ip}, shellTrue, capture_outputTrue, textTrue ) return result.returncode ! 0ping返回非 0 通常意味著目標不可達結合關機場景可以判定為已關機。但要注意有些機器關機后網卡仍響應 ARPping 可能還通這時以shutdown返回碼和事件日志為準。從那以后我每次批量關機前都強制走一遍--dry-run確認列表、確認時間、確認沒有漏網的重要機器再真刀真槍執(zhí)行。希望幫到你。本文還有配套的精品資源點擊獲取