🔒

Windows 伺服器運維工具箱

👤 fyniujin 📦 v3.1.0 ⭐ 4.7 ⬇️ 562 下載
🔒 IT運維與安全 免費

📖 技能介紹


name: winskill slug: winskill displayName: "Windows 伺服器運維工具箱" description: "Windows 伺服器運維工具箱 - 磁碟分析、臨時檔案清理、IIS 站點管理、批次檔案操作、服務狀態監控、Windows Update 診斷、即時效能監控、安全審計、登錄檔啟動項審計、磁碟健康檢測、網路埠監控、事件日誌診斷、已安裝程式管理、使用者會話監控、計劃任務審計、檔案共享審計、DNS網絡卡診斷、SSL證書過期檢測、防火牆規則審計、服務崩潰恢復狀態、系統檔案修復、儲存池管理、備份狀態檢查、Docker容器管理、K8s叢集監控、自動化修復嚮導、效能基線與趨勢分析、等保合規檢查清單、遠端多伺服器管理、日誌輪轉、模組索引。只讀分析+安全確認,絕不誤刪檔案,完全免費離線執行。" description_zh: "Windows 伺服器運維工具箱 - 磁碟分析、清理、IIS 管理、批次操作、服務監控、更新診斷、效能監控、安全審計、登錄檔審計、磁碟健康、網路監控、事件日誌、程式管理、會話監控、計劃任務、共享審計、DNS診斷、SSL證書、防火牆審計、服務崩潰記錄、系統修復、儲存池、備份檢查、Docker容器管理、K8s監控、自動化修復嚮導、效能基線與趨勢分析、等保合規檢查清單、遠端多伺服器管理、日誌輪轉、模組索引。只讀+確認模式,零依賴離線執行。" version: 3.1.0 category: system-administration platforms: - windows tags: - windows - sysadmin - disk-cleanup - iis - monitoring - file-management - devops - performance - security - audit - registry - disk-health - network - event-log - software - session - scheduled-tasks - smb-share - dns - ssl-certificate - firewall - service-recovery requires_api_key: false


Winskill — Windows 伺服器運維工具箱

快速開始

直接對 AI 說就行,不用記命令。

你想做什麼 直接對 AI 說
看磁碟空間 "幫我掃一下 D 盤大檔案"
清理臨時檔案 "看看我電腦的臨時檔案"
檢查 IIS "我的 IIS 站點還活著嗎?"
檢測重複檔案 "幫我找下重複檔案"
檢查服務狀態 "看下資料庫和 IIS 服務有沒有掛"
Windows Update 狀態 "Windows Update 正常嗎?有積壓補丁嗎?"
伺服器卡頓定位 "伺服器變卡了,幫我看看是什麼原因"
檢查有沒有被入侵 "幫我查一下有沒有異常登入"
檢查可疑啟動項 "有沒有可疑的自啟動程式"
磁碟健康狀態 "硬碟還健康嗎?有沒有壞道"
網路連線監控 "誰在連我的伺服器"
系統日誌哪裡錯了 "系統日誌有沒有最近的錯誤"
伺服器裝了什麼程式 "看看系統安裝了哪些軟體"
誰在伺服器上 "當前有誰登入了伺服器"
檢查計劃任務 "有沒有可疑的計劃任務"
檔案共享審計 "有哪些共享資料夾,許可權安全嗎"
DNS / 網絡卡診斷 "DNS 解析正常嗎"
搞不定了 "我遇到報錯了,幫我看看"

⚠️ AI 必須遵守:凡涉及刪除、停止服務、修改系統的操作,必須先展示操作清單,等使用者明確說"確認執行"後才可執行。


安全宣告

保護項 方式
系統目錄保護 絕不操作 C:\WindowsC:\Program Files
刪除必須確認 先展示受影響檔案,等使用者說"確認清理"後才執行
回收站優先 刪除用 Shell.Application 回收站 API
只讀診斷 所有分析命令不修改任何檔案/服務/登錄檔
排除保護 pagefile.syshiberfil.sys 等系統檔案不可操作
登錄檔保護 登錄檔分析只讀,任何修改需雙重確認
日誌讀取保護 事件日誌只讀檢視,不修改任何日誌記錄

功能模組

📋 日誌記錄與輪轉

function Write-WinskillLog {
    param([string]$Message)
    $logDir = "$env:USERPROFILE\.workbuddy\output\winskill"
    $logFile = Join-Path $logDir "winskill.log"
    New-Item -ItemType Directory -Force -Path $logDir | Out-Null
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    "$timestamp $Message" | Out-File $logFile -Append -Encoding utf8
    if (Test-Path $logFile) {
        $size = (Get-Item $logFile).Length
        if ($size -gt 10MB) {
            $timestamp = Get-Date -Format "yyyyMMddHHmmss"
            Move-Item $logFile "winskill.log.$timestamp" -Force
        }
    }
    Get-ChildItem $logDir -Filter "winskill.log.*" | Where-Object {
        $_.LastWriteTime -lt (Get-Date).AddDays(-7)
    } | Remove-Item -Force
}

📋 模組索引(一鍵列出所有可用操作)

Write-Host "`n📋 Winskill 3.1.0 - 模組索引(共 30 個模組)"
Write-Host ("=" * 60)
Write-Host ("{0,-25} {1,-35}" -f "模組", "用途")
Write-Host ("-" * 60)
$modules = @(
    "模組 1: 磁碟空間分析 - 掃大檔案/目錄佔用",
    "模組 2: 大檔案重複檢測 - 找重複檔案",
    "模組 3: 臨時檔案安全清理 - 清理臨時檔案",
    "模組 4: IIS 站點管理 - IIS 站點/應用池狀態",
    "模組 5: 服務狀態監控 - Windows 服務狀態",
    "模組 6: 批次檔案操作 - 批次重新命名/移動/複製",
    "模組 7: 目錄磁碟使用報告 - 目錄大小報告",
    "模組 8: Windows Update 服務狀態 - 更新服務/快取",
    "模組 9: 即時效能監控 - CPU/記憶體/磁碟/網路",
    "模組 10: 安全審計與日誌分析 - 暴力破解/特權操作",
    "模組 11: 登錄檔與啟動項安全審計 - 啟動項/WMI",
    "模組 12: 磁碟健康狀態檢測 - SMART/壞道/溫度",
    "模組 13: 網路連線與埠監控 - 連線/埠/防火牆",
    "模組 14: Windows 事件日誌診斷 - 系統/應用日誌",
    "模組 15: 已安裝程式與補丁管理 - 程式/補丁清單",
    "模組 16: 使用者會話與登入狀態監控 - 會話/登入",
    "模組 17: 計劃任務審計 - 計劃任務清單",
    "模組 18: 檔案共享與 SMB 審計 - 共享/許可權",
    "模組 19: DNS 解析與網絡卡診斷 - DNS/網絡卡",
    "模組 20: SSL 證書過期檢測 - 證書掃描",
    "模組 21: 防火牆規則審計 - 規則/高危檢測",
    "模組 22: 關鍵服務崩潰與自動恢復 - 服務崩潰記錄",
    "模組 23: 系統檔案完整性檢查與修復 - SFC/DISM",
    "模組 24: 儲存池與虛擬磁碟管理 - Storage Spaces",
    "模組 25: Windows Server Backup 狀態檢查 - 備份狀態",
    "模組 26: Docker / K8s 容器管理 - 容器/叢集",
    "模組 27: 自動化修復嚮導 - 一鍵修復常見問題",
    "模組 28: 效能基線 & 趨勢分析 - 趨勢/告警/預測",
    "模組 29: 安全合規檢查清單 - 等保2.0/CIS",
    "模組 30: 遠端多伺服器管理 - 多機批次管理"
)
$modules | ForEach-Object { Write-Host $_ }
Write-Host ("=" * 60)
Write-Host "直接對 AI 說模組名稱或用途即可呼叫"

📌 模組導航(點選直達,共 30 個模組)

🖥️ 基礎運維(1-7): 模組 1:磁碟空間分析 · 模組 2:大檔案重複檢測 · 模組 3:臨時檔案安全清理 · 模組 4:IIS 站點管理 · 模組 5:服務狀態監控 · 模組 6:批次檔案操作 · 模組 7:目錄磁碟使用報告

🔧 進階運維(8-18): 模組 8:Windows Update 服務狀態與快取管理 · 模組 9:即時效能監控與程序資源分析 · 模組 10:安全審計與日誌分析 · 模組 11:登錄檔與啟動項安全審計 · 模組 12:磁碟健康狀態檢測 · 模組 13:網路連線與埠監控 · 模組 14:Windows 事件日誌診斷 · 模組 15:已安裝程式與補丁管理 · 模組 16:使用者會話與登入狀態監控 · 模組 17:計劃任務審計 · 模組 18:檔案共享與 SMB 審計

🔒 安全專項(19-25): 模組 19:DNS 解析與網絡卡診斷 · 模組 20:SSL 證書過期檢測 · 模組 21:Windows 防火牆規則審計 · 模組 22:關鍵服務崩潰與自動恢復狀態 · 模組 23:系統檔案完整性檢查與修復(SFC / DISM) · 模組 24:儲存池與虛擬磁碟管理(Storage Spaces) · 模組 25:Windows Server Backup 狀態檢查

🚀 高階功能(26-30): 模組 26:Docker / K8s 容器管理 · 模組 27:自動化修復嚮導 · 模組 28:效能基線 & 趨勢分析 · 模組 29:安全合規檢查清單 · 模組 30:遠端多伺服器管理


模組 1:磁碟空間分析

📋 展開檢視:模組 1:磁碟空間分析 **用途**:掃描指定路徑,找出佔用空間的大檔案和目錄。 **常你說**:`"掃一下 C 盤大檔案"` / `"D 盤哪個最佔空間"`
$scanPath = "C:\"   # ← 改成你要掃的磁碟機代號或目錄

Get-ChildItem -Path $scanPath -Recurse -File -ErrorAction SilentlyContinue |
    Where-Object { $_.Length -gt 100MB } |
    Sort-Object Length -Descending |
    Select-Object -First 50 @{N='路徑';E={$_.FullName}},
        @{N='大小(GB)';E={[math]::Round($_.Length/1GB,2)}},
        @{N='最後修改';E={$_.LastWriteTime}}
**風險等級**:🟢 無(只讀) | 報錯 | 含義 | 解決 | |-----|------|-----| | `Access to the path 'xxx' is denied` | 許可權不足 | 管理員身份執行 PowerShell | | `Could not find a part of the path` | 目錄不存在 | 確認路徑 |

↑ 返回頂部


模組 2:大檔案重複檢測

📋 展開檢視:模組 2:大檔案重複檢測 **用途**:通過 MD5 雜湊找出重複檔案。 **常你說**:`"找找 D 盤有沒有重複檔案"`
$scanPath = "D:\"   # ← 掃描目標目錄
$minSize = 1MB      # ← 只檢測大於 1MB 的檔案

Get-ChildItem -Path $scanPath -Recurse -File -ErrorAction SilentlyContinue |
    Where-Object { $_.Length -gt $minSize } |
    ForEach-Object {
        $hash = (Get-FileHash $_.FullName -Algorithm MD5 -ErrorAction SilentlyContinue).Hash
        if ($hash) {
            [PSCustomObject]@{
                路徑 = $_.FullName
                雜湊 = $hash
                大小MB = [math]::Round($_.Length/1MB,2)
            }
        }
    } |
    Group-Object 雜湊 |
    Where-Object { $_.Count -gt 1 } |
    ForEach-Object { $_.Group }
**風險等級**:🟢 無(只讀) | 報錯 | 含義 | 解決 | |-----|------|-----| | `Exception getting file hash` | 檔案正在使用 | 跳過 | | `The specified path is not valid` | 路徑格式不對 | 檢查路徑 |

↑ 返回頂部


模組 3:臨時檔案安全清理

📋 展開檢視:模組 3:臨時檔案安全清理 **用途**:掃描安全可刪的臨時檔案,先預覽後確認再清理。 **常你說**:`"幫我清理臨時檔案"` / `"C 盤快滿了幫清 temp"` **安全清理路徑**: | 路徑 | 說明 | 安全天數 | |------|------|---------| | `%TEMP%\*` | 使用者臨時檔案 | >7 天 | | `C:\Windows\Temp\*` | 系統臨時檔案 | >7 天 | | `C:\Windows\SoftwareDistribution\Download\*` | Windows Update 下載快取 | 任意 | | `C:\Windows\Prefetch\*` | 程式預取 | >30 天 | | `IIS Temporary Compressed Files\*` | IIS 壓縮快取 | >1 天 |
$tempPath = $env:TEMP
$daysOld = 7
$cutoff = (Get-Date).AddDays(-$daysOld)

$tempFiles = Get-ChildItem -Path $tempPath -Recurse -ErrorAction SilentlyContinue |
    Where-Object { $_.LastWriteTime -lt $cutoff }

Write-Host "═══════════════════════════════════════════"
Write-Host "  📋 掃描結果: $tempPath"
Write-Host "  過期臨時檔案數: $($tempFiles.Count) 個"
Write-Host "═══════════════════════════════════════════"

$tempFiles | Sort-Object Length -Descending |
    Select-Object -First 20 |
    Select-Object @{N='檔案路徑';E={$_.FullName}},
        @{N='大小(KB)';E={[math]::Round($_.Length/1KB,1)}},
        @{N='最後修改';E={$_.LastWriteTime}} |
    Format-Table -AutoSize

$totalKB = ($tempFiles | Measure-Object -Property Length -Sum).Sum
Write-Host "  預計可釋放空間: $([math]::Round($totalKB/1MB,2)) MB"
Write-Host "  ⚠️ 確認刪除請說 '確認清理'"
# ⚠️ 僅當用戶明確說「確認清理」後才執行!
Write-Host "  正在移到回收站..."
$shell = New-Object -ComObject Shell.Application
$rb = $shell.NameSpace(0x0a)
$totalFiles = 0
foreach ($f in $tempFiles) {
    try {
        $rb.MoveHere($f.FullName)
        $totalFiles++
    } catch { }
}
Write-Host "  ✅ 已完成!已將 $totalFiles 個檔案移到回收站"
Write-Host "  如需徹底刪除,請手動清空回收站"
**風險等級**:🟡 中(需確認後刪除) | 報錯 | 含義 | 解決 | |-----|------|-----| | `Cannot find path ... does not exist` | temp 目錄下某些路徑不存在 | 自動跳過 | | `Access is denied` | 系統臨時檔案正在使用中 | 跳過,正常現象 | | `MoveHere` 失敗 | 回收站操作異常 | 手動清或用其他方式 |

↑ 返回頂部


模組 4:IIS 站點管理

📋 展開檢視:模組 4:IIS 站點管理 **用途**:檢視站點狀態、應用池資訊、快速重啟。 **常你說**:`"我的 IIS 站點正常嗎?"` / `"重啟一下應用池"` **前置條件**(需管理員許可權):
if (-not (Get-Module -ListAvailable -Name WebAdministration)) {
    Write-Host "⚠️ IIS 管理工具未安裝,請以管理員執行:"
    Install-WindowsFeature Web-Mgmt-Tools
}
Import-Module WebAdministration
Import-Module WebAdministration

Write-Host "════════ IIS 站點列表 ════════"
Get-Website | Select-Object @{N='站點名';E={$_.Name}},
    @{N='狀態';E={$_.State}},
    @{N='物理路徑';E={$_.PhysicalPath}},
    @{N='應用池';E={$_.ApplicationPool}},
    @{N='繫結';E={$_.Bindings -join ';'}} |
    Format-Table -AutoSize

Write-Host "`n════════ 應用池狀態 ════════"
Get-WebAppPoolState | Select-Object @{N='名';E={$_.Name}}, @{N='狀態';E={$_.Value}} |
    Format-Table -AutoSize
# ⚠️ 僅當用戶明確確認後才執行!
# Restart-WebSite -Name "你的站點名"
**風險等級**:🟢 檢視只讀 / 🟡 重啟需確認 | 報錯 | 含義 | 解決 | |-----|------|-----| | `Get-Website is not recognized` | IIS 模組未載入 | `Install-WindowsFeature Web-Mgmt-Tools` | | `Cannot connect to IIS` | W3SVC 服務未啟動 | 管理服務 | | `Could not find WebAdministration` | 未裝 IIS 管理工具 | 新增 Web 管理工具 |

↑ 返回頂部


模組 5:服務狀態監控

📋 展開檢視:模組 5:服務狀態監控 **用途**:一眼看出哪些關鍵服務掛了。 **常你說**:`"檢查伺服器關鍵服務"` / `"看下資料庫有沒有掛"`
$criticalServices = @(
    "W3SVC",        # IIS
    "MSSQLSERVER",  # SQL Server
    "MySQL80",      # MySQL
    "Redis",        # Redis
    "Elasticsearch",# ES
    "Docker",       # Docker
    "Spooler",      # 列印
    "TermService",  # 遠端桌面
    "Nginx",        # Nginx
    "Apache",       # Apache
    "Tomcat"        # Tomcat
)

Write-Host "════════ 關鍵服務狀態 ════════"
$hasStopped = $false
foreach ($svc in $criticalServices) {
    $s = Get-Service -Name $svc -ErrorAction SilentlyContinue
    if ($s) {
        $icon = if ($s.Status -eq 'Running') { '✅' } else { '❌'; $hasStopped = $true }
        Write-Host "  $icon $($s.DisplayName) [$($s.Status)]"
    }
}
Write-Host "═══════════════════════════════"
if ($hasStopped) { Write-Host "  ⚠️ 有服務未執行" }
else { Write-Host "  ✅ 所有檢測服務正常" }
**風險等級**:🟢 無(只讀) | 報錯 | 含義 | 解決 | |-----|------|-----| | `Cannot find any service ...` | 該服務未安裝 | 自動跳過 |

↑ 返回頂部


模組 6:批次檔案操作

📋 展開檢視:模組 6:批次檔案操作 **用途**:先預覽規則,再確認執行批次重新命名/移動。 **常你說**:`"把所有 .log 改成 backup_1.log 格式"`
$sourceDir = "D:\logs"    # ← 源目錄
$searchFilter = "*.log"   # ← 檔案篩選
$renamePrefix = "backup"  # ← 新檔名字首

$files = Get-ChildItem -Path $sourceDir -Filter $searchFilter -File
Write-Host "════════ 批次重新命名預覽 ════════"
Write-Host "  掃描到 $($files.Count) 個 $searchFilter 檔案"

$i = 1
foreach ($f in $files) {
    Write-Host "  🔄 $($f.Name) → ${renamePrefix}_${i}${f.Extension}"
    $i++
}

Write-Host "`n  共 $($files.Count) 個檔案將被重新命名"
Write-Host "  ⚠️ 確認執行請說 '確認重新命名'"
# ⚠️ 僅當用戶明確說「確認重新命名」後才執行!
# $i = 1
# foreach ($f in $files) {
#     $newName = "${renamePrefix}_${i}${f.Extension}"
#     Rename-Item -Path $f.FullName -NewName $newName
#     Write-Host "  ✅ $($f.Name) → $newName"
#     $i++
# }
**風險等級**:🟡 中(需確認) | 報錯 | 含義 | 解決 | |-----|------|-----| | `Cannot rename because item already exists` | 新檔名已存在 | 加時間戳避免重名 | | `Access to the path is denied` | 檔案鎖定 | 關相關程式再試 |

↑ 返回頂部


模組 7:目錄磁碟使用報告

📋 展開檢視:模組 7:目錄磁碟使用報告 **用途**:用進度條樣式一眼看出各目錄佔用。 **常你說**:`"看看各個目錄的空間佔用"`
function Get-DirectorySize([string]$Path) {
    (Get-ChildItem -Path $Path -Recurse -File -ErrorAction SilentlyContinue |
     Measure-Object -Property Length -Sum).Sum
}

$dirs = @("C:\inetpub", "C:\Windows\Temp", "C:\ProgramData",
          "$env:TEMP", "C:\Users",
          "C:\Windows\SoftwareDistribution", "D:\")

foreach ($d in $dirs) {
    if (Test-Path $d) {
        $sizeGB = [math]::Round((Get-DirectorySize $d) / 1GB, 2)
        if ($sizeGB -gt 10)     { $icon = '🔴' }
        elseif ($sizeGB -gt 5) { $icon = '🟡' }
        else                  { $icon = '🟢' }
        Write-Host "  $icon $d : ${sizeGB} GB"
    }
}
**風險等級**:🟢 無(只讀)

↑ 返回頂部


🆕 模組 8:Windows Update 服務狀態與快取管理

📋 展開檢視:🆕 模組 8:Windows Update 服務狀態與快取管理 **用途**:診斷 Windows Update 是否卡住、檢視已安裝補丁、清理更新快取。 **常你說**:`"Windows Update 正常嗎?"` / `"更新快取能不能刪"` ### 8.1 檢視更新服務狀態與已安裝補丁(只讀)
# 更新服務狀態
Get-Service -Name wuauserv |
    Select-Object @{N='服務';E={$_.Name}},
        @{N='狀態';E={$_.Status}},
        @{N='啟動型別';E={$_.StartType}},
        @{N='賬號';E={$_.StartName}}

Write-Host ""

# 已安裝補丁(最近 10 個)
Get-HotFix | Sort-Object InstalledOn -Descending |
    Select-Object -First 10 @{N='補丁ID';E={$_.HotFixID}},
        @{N='安裝日期';E={$_.InstalledOn}}
### 8.2 檢查 SoftwareDistribution 更新快取大小
$sd = "C:\Windows\SoftwareDistribution"
if (Test-Path $sd) {
    $total = (Get-ChildItem -Path $sd -Recurse -ErrorAction SilentlyContinue |
              Measure-Object -Property Length -Sum).Sum
    Write-Host "  SoftwareDistribution 大小: $([math]::Round($total/1MB,1)) MB"

    $dlDir = Join-Path $sd "Download"
    if (Test-Path $dlDir) {
        $dlSize = (Get-ChildItem -Path $dlDir -Recurse -ErrorAction SilentlyContinue |
                   Measure-Object -Property Length -Sum).Sum
        Write-Host "  └─ 下載快取(Download): $([math]::Round($dlSize/1MB,1)) MB"
    }
    Write-Host "  💡 若超過 500MB 可考慮清理(需先停止 wuauserv 服務)"
} else {
    Write-Host "  ⚠️ SoftwareDistribution 目錄不存在"
}
# ⚠️ 僅當用戶明確說「確認清理更新快取」後才執行!
# Stop-Service -Name wuauserv -Force
# Remove-Item -Path "$sd\Download\*" -Recurse -Force -ErrorAction SilentlyContinue
# Start-Service -Name wuauserv
# Write-Host "  ✅ 已清理更新下載快取,Windows Update 將重新下載所需補丁"
**風險等級**:🟢 檢視只讀 / 🟡 清理快取需確認 | 報錯 | 含義 | 解決 | |-----|------|-----| | `The service ... cannot be stopped` | 服務正在使用 | 稍後重試或重啟後清理 | | `Access is denied` | 部分快取檔案被鎖定 | 先停服務再清理 | **常見坑 & 解決**: | 場景 | 說明 | |-----|------| | Windows Update 一直不下載 | 服務掛起,重停重啟動可解決 | | 錯誤碼 0x80070005 | 許可權問題,清理快取可修復 | | 補丁安裝失敗 | 清理 Download 快取後重新檢查更新 |

↑ 返回頂部


🆕 模組 9:即時效能監控與程序資源分析

📋 展開檢視:🆕 模組 9:即時效能監控與程序資源分析 **用途**:定位 CPU/記憶體/磁碟 I/O 瓶頸,按程序排序找到罪魁禍首。 **常你說**:`"伺服器變卡了,幫我看看"` / `"哪個程序吃記憶體最多"` ### 9.1 即時效能計數器(只讀)
Get-Counter '\Processor(_Total)\% Processor Time',
              '\Memory\Available MBytes',
              '\Memory\% Used',
              '\PhysicalDisk(_Total)\% Disk Time',
              '\PhysicalDisk(_Total)\Current Disk Queue Length' |
    Select-Object -ExpandProperty CounterSamples |
    Select-Object @{N='指標';E={$_.Path.Split('\')[-2..-1] -join '\'}},
        @{N='當前值';E={[math]::Round($_.CookedValue, 1)}} |
    Format-Table -AutoSize
### 9.2 記憶體佔用 Top 10 程序
Get-Process | Sort-Object WorkingSet64 -Descending |
    Select-Object -First 10 @{N='程序名';E={$_.Name}},
        @{N='記憶體(MB)';E={[math]::Round($_.WorkingSet64/1MB,1)}},
        @{N='CPU(s)';E={[math]::Round($_.CPU,1)}} |
    Format-Table -AutoSize
### 9.3 磁碟 I/O 詳細統計(按程序)
Get-Counter '\Process(*)\Read Bytes/sec',
              '\Process(*)\Write Bytes/sec' |
    Select-Object -ExpandProperty CounterSamples |
    Where-Object { $_.CookedValue -gt 0 } |
    Sort-Object CookedValue -Descending |
    Select-Object -First 15 @{N='程序';E={
        $_.Path -replace '\\Process\((.*)\)\\Read Bytes/sec$','$1' |
        ForEach-Object { if ($_ -eq 'idle') { 'System Idle' } else { $_ }
    }}, @{N='Bytes/s';E={[math]::Round($_.CookedValue, 0)}} |
    Format-Table -AutoSize
# ⚠️ 僅當用戶明確說「確認建立」後才執行!
# $collector = New-DataCollectorSet -Name "ServerPerf_$(Get-Date -Format 'yyyyMMdd')" -Path "C:\PerfLogs"
# $collector.DataCollectors.Create(0, "Counter", 0,
#     '\Processor(_Total)\% Processor Time',
#     '\Memory\Available MBytes',
#     '\PhysicalDisk(_Total)\% Disk Time'
# )
# $collector.Commit("C:\PerfLogs\ServerPerf", 0, 0x01) | Out-Null
# Write-Host "  ✅ 已建立效能採集器,資料將儲存到 C:\PerfLogs"
**風險等級**:🟢 即時檢視 / 🟡 建立採集器需確認 | 報錯 | 含義 | 解決 | |-----|------|-----| | `The specified counter is not found` | 計數器未註冊 | 執行 `lodctr /R` 重建計數器 | | `Access denied` | 需要管理員許可權 | 提升後執行 | **常見坑 & 解決**: | 場景 | 說明 | |-----|------| | CPU 持續 >90% | 按程序排序定位異常程序 | | 可用記憶體 <500MB | 判斷是否記憶體洩漏, IIS 應用池是否需回收 | | 磁碟佇列長度 >2 | I/O 瓶頸,檢查是否日誌寫入過多 | | 計數器全為零 | `lodctr /R` 重建效能計數器 |

↑ 返回頂部


🆕 模組 10:安全審計與日誌分析

📋 展開檢視:🆕 模組 10:安全審計與日誌分析 **用途**:檢測暴力破解、特權操作、異常登入。 **常你說**:`"幫我查下有沒有被入侵"` / `"有沒有異常登入記錄"` ### 10.1 檢測暴力破解嘗試(最近 24 小時)
$since = (Get-Date).AddHours(-24)

$failedLogins = Get-WinEvent -FilterHashtable @{
    LogName='Security'; ID=4625; StartTime=$since
} -ErrorAction SilentlyContinue

if ($failedLogins) {
    Write-Host "⚠️ 最近 24h 失敗登入 $($failedLogins.Count) 次`n"
    $failedLogins |
        Select-Object TimeCreated,
            @{N='賬號';E={$_.Properties[5].Value}},
            @{N='來源IP';E={$_.Properties[19].Value}} |
        Group-Object SourceIP |
        Sort-Object Count -Descending |
        Select-Object -First 10 @{N='攻擊源IP';E={$_.Name}},
            @{N='嘗試次數';E={$_.Count}} |
        Format-Table -AutoSize
    Write-Host "  💡 嘗試次數 >10 的 IP 建議加入防火牆黑名單"
} else {
    Write-Host "  ✅ 最近 24 小時無失敗登入記錄"
}
### 10.2 檢視特權提升操作(管理員操作審計)
$since = (Get-Date).AddHours(-24)

Write-Host "════════ 特權操作(4672)════════"
Get-WinEvent -FilterHashtable @{
    LogName='Security'; ID=4672; StartTime=$since
} -ErrorAction SilentlyContinue |
    Select-Object TimeCreated,
        @{N='使用者';E={$_.Properties[1].Value}},
        @{N='特權';E={$_.Properties[2..($_.Properties.Count-1)].Value -join ', '}} |
    Format-Table -AutoSize
### 10.3 本地管理員組成員檢查
Write-Host "════════ 本地管理員組成員 ════════"
Get-LocalGroupMember -Group "Administrators" |
    Select-Object @{N='使用者名稱';E={$_.Name}},
        @{N='來源';E={$_.PrincipalSource}} |
    Format-Table -AutoSize
# ⚠️ 僅當用戶明確說「確認匯出」後才執行!
# $logPath = "C:\Logs\Security_$(Get-Date -Format 'yyyyMMdd').evtx"
# if (-not (Test-Path "C:\Logs")) { New-Item -ItemType Directory -Path "C:\Logs" -Force }
# wevtutil epl Security $logPath
# Write-Host "  ✅ 安全日誌已匯出到: $logPath"
**風險等級**:🟢 只讀審計 / 🟡 匯出需確認 | 報錯 | 含義 | 解決 | |-----|------|-----| | `No events were found ...` | 沒有符合條件的日誌 | 正常,說明期間無異常 | | `The requested operation cannot be performed on a file ...` | 日誌檔案被佔用 | 複製到另一路徑匯出 | | `Get-LocalGroupMember` 報錯 | 需要管理員許可權 | 提升執行 | **常見坑 & 解決**: | 場景 | 說明 | |-----|------| | 某 IP 失敗登入 >100 次 | 暴力破解,建議防火牆封禁 | | 4672 事件頻繁 | 有人在頻繁執行管理員操作,需排查 | | 管理員組成員異常多了不認識賬號 | 立即排查是否被入侵後留後門,刪非法賬號 |

↑ 返回頂部


🆕 模組 11:登錄檔與啟動項安全審計

📋 展開檢視:🆕 模組 11:登錄檔與啟動項安全審計 **用途**:檢測惡意持久化機制(登錄檔自啟動、計劃任務、WMI 訂閱)。 **常你說**:`"有沒有可疑的自啟動程式"` / `"檢查一下持久化威脅"` > ⚠️ **本模組所有操作均為只讀分析,絕不修改登錄檔或刪除任何鍵值。** ### 11.1 經典自啟動登錄檔位置掃描
$runKeys = @(
    "HKLM:\Software\Microsoft\Windows\CurrentVersion\Run",
    "HKLM:\Software\Microsoft\Windows\CurrentVersion\RunOnce",
    "HKCU:\Software\Microsoft\Windows\CurrentVersion\Run",
    "HKCU:\Software\Microsoft\Windows\CurrentVersion\RunOnce",
    "HKLM:\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Run"
)

Write-Host "════════ 自啟動登錄檔項 ════════"
foreach ($key in $runKeys) {
    if (Test-Path $key) {
        Write-Host "`n  📁 $($key.Split('\')[-1..-1] -join '\')"
        Get-ItemProperty $key -ErrorAction SilentlyContinue |
            Get-Member -MemberType NoteProperty |
            Where-Object { $_.Name -notlike 'PS*' } |
            ForEach-Object {
                $val = (Get-ItemProperty $key -Name $_.Name -ErrorAction SilentlyContinue).$($_.Name)
                Write-Host "    🔹 $($_.Name) = $val"
            }
    }
}
Write-Host "`n═══════════════════════════════"
Write-Host "  💡 不認識的程式請搜尋確認,不要直接刪除"
### 11.2 計劃任務審計
Write-Host "════════ 計劃任務列表 ════════"
Get-ScheduledTask | Where-Object { $_.State -ne 'Disabled' } |
    Select-Object @{N='任務名';E={$_.TaskName}},
        @{N='狀態';E={$_.State}},
        @{N='作者';E={$_.Author}},
        @{N='執行方式';E={$_.Principal.UserId}} |
    Format-Table -AutoSize

Write-Host "`n════════ 最近修改的任務 ════════"
Get-ScheduledTask | Sort-Object LastWriteTime -Descending |
    Select-Object -First 10 @{N='任務名';E={$_.TaskName}},
        @{N='修改時間';E={$_.LastWriteTime}} |
    Format-Table -AutoSize
### 11.3 WMI 持久化檢測
Write-Host "════════ WMI 事件訂閱 ════════"
try {
    $wmiSubs = Get-CimInstance -Namespace root\subscription -ClassName __EventFilter -ErrorAction SilentlyContinue
    if ($wmiSubs) {
        $wmiSubs | Select-Object @{N='名稱';E={$_.Name}},
            @{N='查詢';E={$_.Query}} |
            Format-Table -AutoSize
    } else {
        Write-Host "  ✅ 未發現 WMI 事件訂閱"
    }
} catch {
    Write-Host "  ⚠️ WMI 查詢失敗,可能需要管理員許可權"
}
### 11.4 系統服務異常檢測
Write-Host "════════ 非微軟服務列表 ════════"
Get-Service | Where-Object {
    $_.DisplayName -notlike '*Microsoft*' -and
    $_.DisplayName -notlike '*Windows*' -and
    $_.DisplayName -notlike '*Intel*' -and
    $_.DisplayName -notlike '*NVIDIA*' -and
    $_.DisplayName -notlike '*AMD*' -and
    $_.DisplayName -notlike '*Realtek*' -and
    $_.DisplayName -notlike '*HP*' -and
    $_.DisplayName -notlike '*Dell*'
} | Select-Object @{N='服務名';E={$_.Name}},
    @{N='顯示名';E={$_.DisplayName}},
    @{N='狀態';E={$_.Status}},
    @{N='啟動型別';E={$_.StartType}} |
    Format-Table -AutoSize
**風險等級**:🟢 無(只讀審計) | 報錯 | 含義 | 解決 | |-----|------|-----| | `Access to the path is denied` | 許可權不足 | 管理員身份執行 | | `Requested registry access is not allowed` | 登錄檔許可權限制 | 提升許可權執行 | | `Get-CimInstance` 報錯 | WMI 服務未啟動 | 檢查 Winmgmt 服務 | **常見坑 & 解決**: | 場景 | 說明 | |-----|------| | Run 鍵值超多(>20個) | 正常軟體也會註冊,重點排查不認識的 | | WMI 訂閱存在未知項 | 可能是惡意軟體持久化,需進一步分析 | | 服務名隨機字串 | 典型惡意軟體特徵,需立即排查 |

↑ 返回頂部


🆕 模組 12:磁碟健康狀態檢測

📋 展開檢視:🆕 模組 12:磁碟健康狀態檢測 **用途**:檢測磁碟 SMART 狀態、壞道預警、磁碟壽命預測。 **常你說**:`"硬碟還健康嗎?"` / `"有沒有壞道"` / `"磁碟壽命還剩多久"` > ⚠️ **本模組所有操作均為只讀檢測,不會執行磁碟修復或擦除操作。** ### 12.1 SMART 狀態概覽
Write-Host "════════ 磁碟 SMART 狀態 ════════"
Get-PhysicalDisk | Select-Object @{N='磁碟';E={$_.FriendlyName}},
    @{N='狀態';E={$_.HealthStatus}},
    @{N='使用時長';E={[math]::Round($_.UsageHours,0)}},
    @{N='溫度(°C)';E={$_.Temperature}},
    @{N='剩餘壽命%';E={$_.RemainingLifetimePercent}} |
    Format-Table -AutoSize
### 12.2 磁碟壞道與錯誤計數
Write-Host "════════ 磁碟錯誤統計 ════════"
Get-PhysicalDisk | ForEach-Object {
    $disk = $_
    $errors = Get-StorageReliabilityCounter -PhysicalDisk $disk -ErrorAction SilentlyContinue
    if ($errors) {
        [PSCustomObject]@{
            磁碟 = $disk.FriendlyName
            讀取錯誤 = $errors.ReadErrorsTotal
            寫入錯誤 = $errors.WriteErrorsTotal
            重對映扇區 = $errors.ReallocatedSectors
            待對映扇區 = $errors.PendingSectors
            不可修復錯誤 = $errors.UncorrectableErrors
        }
    }
} | Format-Table -AutoSize

Write-Host "`n  💡 重對映扇區 >0 或待對映扇區 >0 表示磁碟開始老化"
Write-Host "  💡 不可修復錯誤 >0 建議立即備份資料並更換磁碟"
### 12.3 磁碟溫度監控
Write-Host "════════ 磁碟溫度監控 ════════"
Get-PhysicalDisk | ForEach-Object {
    $temp = $_.Temperature
    if ($temp -gt 50)     { $icon = '🔴' }
    elseif ($temp -gt 40) { $icon = '🟡' }
    else                  { $icon = '🟢' }
    [PSCustomObject]@{
        磁碟 = $_.FriendlyName
        溫度 = "${temp}°C"
        狀態 = $icon
    }
} | Format-Table -AutoSize

Write-Host "`n  💡 溫度 >50°C 需檢查散熱,>60°C 立即停機檢查"
### 12.4 磁碟 I/O 延遲分析
Write-Host "════════ 磁碟 I/O 延遲 ════════"
Get-Counter '\PhysicalDisk(*)\Avg. Disk sec/Read',
              '\PhysicalDisk(*)\Avg. Disk sec/Write' |
    Select-Object -ExpandProperty CounterSamples |
    Where-Object { $_.CookedValue -gt 0 } |
    Select-Object @{N='磁碟';E={
        $_.Path -replace '\\PhysicalDisk\((.*)\)\\.*$','$1'
    }}, @{N='平均延遲(ms)';E={[math]::Round($_.CookedValue * 1000, 2)}} |
    Format-Table -AutoSize

Write-Host "`n  💡 讀延遲 >20ms 或寫延遲 >20ms 表示磁碟效能下降"
**風險等級**:🟢 無(只讀檢測) | 報錯 | 含義 | 解決 | |-----|------|-----| | `No MSFT_PhysicalDisk ...` | 系統不支援儲存診斷 | 需 Windows Server 2016+ | | `Temperature` 屬性不存在 | 磁碟不支援溫度感測器 | 用第三方工具檢測 | | `Get-StorageReliabilityCounter` 報錯 | 需要管理員許可權 | 提升執行 | **常見坑 & 解決**: | 場景 | 說明 | |-----|------| | SMART 狀態顯示 "Warning" | 磁碟開始老化,立即備份資料 | | 重對映扇區持續增長 | 磁碟壽命將盡,儘快更換 | | I/O 延遲突然飆升 | 可能磁碟故障前兆,檢查 SMART |

↑ 返回頂部


🆕 模組 13:網路連線與埠監控

📋 展開檢視:🆕 模組 13:網路連線與埠監控 **用途**:檢測異常網路連線、監聽埠、可疑外連行為。 **常你說**:`"誰在連我的伺服器"` / `"有沒有異常外連"` / `"檢查監聽埠"` > ⚠️ **本模組所有操作均為只讀檢測,不會修改防火牆規則或終止連線。** ### 13.1 活動網路連線概覽
Write-Host "════════ 活動網路連線 ════════"
Get-NetTCPConnection -State Established -ErrorAction SilentlyContinue |
    Select-Object @{N='本地地址';E={$_.LocalAddress}},
        @{N='本地埠';E={$_.LocalPort}},
        @{N='遠端地址';E={$_.RemoteAddress}},
        @{N='遠端埠';E={$_.RemotePort}},
        @{N='狀態';E={$_.State}},
        @{N='程序';E={(Get-Process -Id $_.OwningProcess -ErrorAction SilentlyContinue).Name}} |
    Sort-Object RemoteAddress |
    Format-Table -AutoSize
### 13.2 監聽埠審計
Write-Host "════════ 監聽埠列表 ════════"
Get-NetTCPConnection -State Listen -ErrorAction SilentlyContinue |
    Select-Object @{N='本地地址';E={$_.LocalAddress}},
        @{N='監聽埠';E={$_.LocalPort}},
        @{N='程序';E={
            $proc = Get-Process -Id $_.OwningProcess -ErrorAction SilentlyContinue
            if ($proc) { "$($proc.Name) (PID: $($proc.Id))" } else { "未知" }
        }} |
    Sort-Object LocalPort |
    Format-Table -AutoSize
### 13.3 可疑外連檢測(高頻連線分析)
Write-Host "════════ 高頻外連目標 ════════"
Get-NetTCPConnection -State Established -ErrorAction SilentlyContinue |
    Group-Object RemoteAddress |
    Where-Object { $_.Count -gt 5 } |
    Sort-Object Count -Descending |
    Select-Object -First 15 @{N='遠端IP';E={$_.Name}},
        @{N='連線數';E={$_.Count}},
        @{N='程序';E={
            $proc = Get-Process -Id ($_.Group[0].OwningProcess) -ErrorAction SilentlyContinue
            if ($proc) { $proc.Name } else { "未知" }
        }} |
    Format-Table -AutoSize

Write-Host "`n  💡 連線數 >20 的 IP 需重點排查是否為惡意外連"
### 13.4 防火牆規則審計
Write-Host "════════ 防火牆入站規則 ════════"
Get-NetFirewallRule -Direction Inbound -Enabled True -ErrorAction SilentlyContinue |
    Where-Object { $_.Action -eq 'Allow' } |
    Select-Object @{N='規則名';E={$_.DisplayName}},
        @{N='操作';E={$_.Action}},
        @{N='本地埠';E={$_.LocalPort}},
        @{N='遠端地址';E={$_.RemoteAddress}} |
    Format-Table -AutoSize
**風險等級**:🟢 無(只讀檢測) | 報錯 | 含義 | 解決 | |-----|------|-----| | `Get-NetTCPConnection` 報錯 | 需要管理員許可權 | 提升執行 | | `Get-NetFirewallRule` 報錯 | 防火牆服務未啟動 | 檢查 mpssvc 服務 | | `OwningProcess` 為 0 | 系統程序,正常 | 無需處理 | **常見坑 & 解決**: | 場景 | 說明 | |-----|------| | 未知程序監聽 80/443 埠 | 可能是 Web 服務或惡意軟體,需排查 | | 大量外連到同一 IP | 可能是 C2 通訊,立即斷網排查 | | 防火牆規則異常寬鬆 | 建議收緊為最小許可權原則 |

↑ 返回頂部


🆕 模組 14:Windows 事件日誌診斷

📋 展開檢視:🆕 模組 14:Windows 事件日誌診斷 **用途**:快速定位系統錯誤、警告,按時間/級別篩選關鍵日誌。 **常你說**:`"系統日誌有沒有最近錯誤"` / `"最近系統出了什麼問題"` / `"看看日誌"` > ⚠️ **本模組僅讀取日誌,不會修改或清除日誌檔案。** ### 14.1 系統最近錯誤日誌(最近 2 小時)
$since = (Get-Date).AddHours(-2)

Write-Host "════════ 最近 2 小時系統日誌(錯誤/警告)════════"
Get-WinEvent -FilterHashtable @{
    LogName='System';Level=2,3;StartTime=$since
} -ErrorAction SilentlyContinue |
    Select-Object @{N='時間';E={$_.TimeCreated}},
        @{N='來源';E={$_.Message.Split("`r`n")[0] -replace '^.*?: '}},
        @{N='級別';E={if ($_.Level -eq 2) { '❌錯誤' } else { '⚠️警告' }}} |
    Select-Object -First 30 |
    Format-Table -AutoSize -Wrap
### 14.2 應用程式錯誤日誌
$since = (Get-Date).AddHours(-24)

Write-Host "════════ 最近 24 小時應用程式錯誤 ════════"
Get-WinEvent -FilterHashtable @{
    LogName='Application'; Level=2; StartTime=$since
} -ErrorAction SilentlyContinue |
    Select-Object @{N='時間';E={$_.TimeCreated}},
        @{N='來源';E={$_.ProviderName}},
        @{N='錯誤摘要';E={
            ($_.Message -replace "`r`n",' ' | Select-Object -First 120)
        }} |
    Select-Object -First 20 |
    Format-Table -AutoSize -Wrap
### 14.3 關鍵系統事件掃描(藍色畫面/重啟/故障)
Write-Host "════════ 關鍵系統事件(最近 7 天)════════"
Get-WinEvent -FilterHashtable @{
    LogName='System';
    ID=1074, 6005, 6006, 6008, 6009, 41, 1001, 1002;
    StartTime=(Get-Date).AddDays(-7)
} -ErrorAction SilentlyContinue |
    Select-Object @{N='時間';E={$_.TimeCreated}},
        @{N='事件ID';E={$_.Id}},
        @{N='說明';E={
            switch ($_.Id) {
                1074 {'系統關機/重啟 (User initiated)'}
                6005 {'系統啟動'}
                6006 {'系統正常關機'}
                6008 {'非正常關機 (意外斷電/崩潰)'}
                6009 {'系統啟動 (新會話)'}
                41  {'Kernel-Power 重啟 (無干淨關機)'}
                1001{'BugCheck (藍色畫面)'}
                1002{'應用程式掛起/無響應'}
                default {$_.Message.Split("`r`n")[0]}
            }
        }} |
    Format-Table -AutoSize -Wrap
### 14.4 Setup 日誌審計(最近 7 天)
Write-Host "════════ Setup 最近 7 天事件 ════════"
Get-WinEvent -FilterHashtable @{
    LogName='Setup';
    StartTime=(Get-Date).AddDays(-7)
} -ErrorAction SilentlyContinue |
    Select-Object @{N='時間';E={$_.TimeCreated}},
        @{N='來源';E={$_.ProviderName}},
        @{N='摘要';E={
            ($_.Message -replace "`r`n",' ' | Select-Object -First 120)
        }} |
    Select-Object -First 15 |
    Format-Table -AutoSize -Wrap
**風險等級**:🟢 無(只讀閱讀) | 報錯 | 含義 | 解決 | |-----|------|-----| | `No events were found ...` | 沒有符合條件的日誌 | 正常,說明期間無異常 | | `RPC server is unavailable` | 事件日誌服務未執行 | 檢查 EventLog 服務 | | `Access denied` | 許可權不足 | 管理員身份執行 | **常見坑 & 解決**: | 場景 | 說明 | |-----|------| | 每天大量 Error 日誌 | 說明存在持續性故障,需逐條排查來源 | | 非正常關機 (6008) | 可能存在硬體/電源問題 | | 藍色畫面 (1001) | 記錄藍色畫面程式碼,排查驅動/硬體 |

↑ 返回頂部


🆕 模組 15:已安裝程式與補丁管理

📋 展開檢視:🆕 模組 15:已安裝程式與補丁管理 **用途**:檢視所有已安裝的軟體、補丁,檢測缺失或不一致情況。 **常你說**:`"看看系統安裝了哪些軟體"` / `"伺服器裝了什麼程式"` / `"補丁檢查"` > ⚠️ **本模組僅讀,不會解除安裝/安裝/修改任何軟體。** ### 15.1 已安裝程式清單
Write-Host "════════ 已安裝程式清單 ════════"
Get-ItemProperty "HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*" -ErrorAction SilentlyContinue |
    Where-Object { $_.DisplayName -and $_.UninstallString -notlike '*{*' } |
    Select-Object @{N='程式名';E={$_.DisplayName}},
        @{N='版本';E={$_.DisplayVersion}},
        @{N='安裝日期';E={$_.InstallDate}},
        @{N='大小';E={if($_.EstimatedSize){[math]::Round($_.EstimatedSize/1MB,1)}else{'?'}}} |
    Sort-Object DisplayName |
    Format-Table -AutoSize
### 15.2 已安裝 Windows 補丁
Write-Host "════════ 已安裝 Windows 補丁 ════════"
Get-HotFix | Sort-Object InstalledOn -Descending |
    Select-Object @{N='補丁ID';E={$_.HotFixID}},
        @{N='安裝日期';E={$_.InstalledOn}},
        @{N='描述';E={$_.Description}} |
    Format-Table -AutoSize
### 15.3 安裝時間線分析
Write-Host "════════ 最近安裝的軟體 ════════"
Get-ItemProperty "HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*" -ErrorAction SilentlyContinue |
    Where-Object { $_.InstallDate } |
    Sort-Object InstallDate -Descending |
    Select-Object -First 20 @{N='程式名';E={$_.DisplayName}},
        @{N='版本';E={$_.DisplayVersion}},
        @{N='安裝日期';E={$_.InstallDate}} |
    Format-Table -AutoSize
### 15.4 補丁對比(檢測缺失)
$hotfixes = Get-HotFix -ErrorAction SilentlyContinue | Select-Object -ExpandProperty HotFixID
$currentBuild = [System.Environment]::OSVersion.Version
$expectedPatches = @()

# 檢測 Windows 10/11 常見缺失補丁
if ($currentBuild.Major -ge 10) {
    $kbToCheck = @(
        "KB5034441",  # Secure Boot DBX
        "KB5036897",  # 最新 .NET
        "KB5037771"   # 最新累積
    )
    foreach ($kb in $kbToCheck) {
        if ($hotfixes -notcontains $kb) {
            $expectedPatches += "$kb - 缺失"
        }
    }
}

Write-Host "════════ 補丁一致性檢查 ════════"
Write-Host "  當前版本: $($currentBuild.Major).$($currentBuild.Minor).$($currentBuild.Build)"
Write-Host ""
if ($expectedPatches.Count -gt 0) {
    Write-Host "  ⚠️ 缺失補丁:"
    foreach ($p in $expectedPatches) { Write-Host "    ❌ $p" }
} else {
    Write-Host "  ✅ 常用補丁均已安裝"
}
**風險等級**:🟢 無(只讀閱讀) | 報錯 | 含義 | 解決 | |-----|------|-----| | `Requested registry access is not allowed` | 部分登錄檔許可權限制 | 管理員身份執行 | | `Get-HotFix` 報錯 | 需要管理員許可權 | 管理員身份執行 | **常見坑 & 解決**: | 場景 | 說明 | |-----|------| | 某臺伺服器明顯比其他機器少很多補丁 | 可能 WSUS/自動更新未執行 | | 安裝時間線上出現未知日期的軟體 | 可能未經授權安裝,需排查 | | KB 補丁安裝失敗 | Windows Update 服務或快取異常 |

↑ 返回頂部


🆕 模組 16:使用者會話與登入狀態監控

📋 展開檢視:🆕 模組 16:使用者會話與登入狀態監控 **用途**:監控當前登入的使用者、遠端會話、殭屍會話、賬戶狀態。 **常你說**:`"誰在伺服器上"` / `"有沒有異常登入"` / `"檢視遠端會話"` > ⚠️ **本模組僅讀,不會結束會話、鎖定賬戶或修改密碼策略。** ### 16.1 當前登入使用者概覽
Write-Host "════════ 當前登入使用者 ════════"
Get-CimInstance Win32_LogonSession | Where-Object { $_.LogonType -ne 0 } |
    Select-Object @{N='使用者名稱';E={
        $user = Get-CimInstance Win32_ComputerSystem | Select-Object UserName
        $user.UserName ?? "未知"
    }},
    @{N='會話ID';E={$_.LogonId}},
    @{N='登入型別';E={
        switch ($_.LogonType) {
            2 {'互動 (本地登入)'}
            3 {'網路登入'}
            4 {'批處理'}
            5 {'服務'}
            7 {'解鎖'}
            8 {'網路明文'}
            9 {'新憑據'}
            10 {'遠端互動 (RDP)'}
            11 {'快取互動'}
            default {"其他 ($($_.LogonType))"}
        }
    }},
    @{N='登入時間';E={$_.StartTime}} |
    Format-Table -AutoSize
### 16.2 遠端桌面會話監控
Write-Host "════════ 遠端桌面會話 (RDP) ════════"
Get-CimInstance Win32_LogonSession | Where-Object { $_.LogonType -eq 10 } |
    Select-Object @{N='使用者名稱';E={
        $user = Get-CimInstance Win32_ComputerSystem | Select-Object UserName
        $user.UserName ?? "未知"
    }},
    @{N='會話ID';E={$_.LogonId}},
    @{N='登入時間';E={$_.StartTime}},
    @{N='空閒時間(分鐘)';E={
        if ($_.StartTime) {
            [math]::Round(((Get-Date) - $_.StartTime).TotalMinutes, 0)
        } else { 0 }
    }} |
    Format-Table -AutoSize
Write-Host "`n💡 空閒 >60 分鐘的會話可能為殭屍會話"
### 16.3 異常登入檢測(多 IP / 異地登入)
Write-Host "════════ 最近 7 天的登入來源 ════════"
Get-WinEvent -FilterHashtable @{
    LogName='Security';
    ID=4624;
    StartTime=(Get-Date).AddDays(-7)
} -ErrorAction SilentlyContinue |
    Where-Object { $_.Properties[18].Value -ne '-' } |
    Select-Object @{N='登入時間';E={$_.TimeCreated}},
        @{N='使用者名稱';E={$_.Properties[5].Value}},
        @{N='來源IP';E={$_.Properties[18].Value}},
        @{N='登入型別';E={
            switch ($_.Properties[8].Value) {
                2 {'互動(本地)'}
                3 {'網路'}
                10 {'遠端(RDP)'}
                default {"其他"}
            }
        }} |
    Group-Object SourceIP |
    Sort-Object Count -Descending |
    Select-Object -First 10 @{N='來源IP';E={$_.Name}},
        @{N='登入次數';E={$_.Count}},
        @{N='最近登入';E={$_.Group[0].TimeCreated}} |
    Format-Table -AutoSize

Write-Host "`n💡 任何未知來源IP 的登入都值得警惕"
### 16.4 系統賬戶狀態檢查
Write-Host "════════ 本地使用者賬戶狀態 ════════"
Get-LocalUser | Where-Object { $_.Enabled -eq $true } |
    Select-Object @{N='賬戶名';E={$_.Name}},
        @{N='狀態';E={if ($_.Enabled) {'啟用'}else{'停用'}}},
        @{N='最後登入';E={$_.LastLogon}},
        @{N='密碼過期';E={
            if ($_.PasswordExpires) { $_.PasswordExpires } else { '永不過期 ⚠️' }
        }},
        @{N='需要密碼';E={if ($_.PasswordRequired) {'是'}else{'否 ⚠️'}}} |
    Format-Table -AutoSize

Write-Host "`n⚠️ 標記的賬戶存在安全風險:無密碼或密碼永不過期"
**風險等級**:🟢 無(只讀監控) | 報錯 | 含義 | 解決 | |-----|------|-----| | `Get-LocalUser` 報錯 | 需要管理員許可權 | 管理員身份執行 | | `Get-CimInstance` 報錯 | WMI 未啟動 | 檢查 Winmgmt | | `No events found` | 沒有相關日誌 | 正常 | **常見坑 & 解決**: | 場景 | 說明 | |-----|------| | 多個 RDP 會話來自同一 IP | 可能正常(NAT),也可能為多人共用賬戶 | | Guest 賬戶啟用 | 不必要的安全風險,建議停用 | | 殭屍 RDP 會話 | 佔用資源,閒置超時後應自動斷開 | | 密碼永不過期 | 合規風險,建議設定密碼策略 |

↑ 返回頂部


🆕 模組 17:計劃任務審計

📋 展開檢視:🆕 模組 17:計劃任務審計 **用途**:審計所有計劃任務,檢測可疑的持久化行為(惡意軟體常用的自啟動方式)。 **常你說**:`"有沒有可疑計劃任務"` / `"檢查計劃任務"` / `"有沒有凌晨執行的任務"` > ⚠️ **本模組僅讀,不會建立/刪除/修改任何計劃任務。** ### 17.1 所有計劃任務清單
Write-Host "════════ 所有計劃任務 ════════"
$tasks = Get-ScheduledTask | Where-Object { $_.State -ne 'Disabled' }
$total = ($tasks | Measure-Object).Count
Write-Host "  總數: $total 個啟用的任務`n"

$tasks | Select-Object @{N='任務名';E={$_.TaskName}},
    @{N='路徑';E={$_.TaskPath}},
    @{N='狀態';E={$_.State}},
    @{N='觸發器';E={
        $info = Get-ScheduledTaskInfo -TaskName $_.TaskName -TaskPath $_.TaskPath -ErrorAction SilentlyContinue
        if ($info.LastRunTime) { "上次: $($info.LastRunTime)" } else { "從未執行" }
    }} |
    Sort-Object TaskPath, TaskName |
    Format-Table -AutoSize
### 17.2 異常計劃任務檢測(凌晨執行 / 隱藏視窗 / 臨時目錄)
Write-Host "════════ 異常計劃任務檢測 ════════"
$suspicious = @()
$tasks = Get-ScheduledTask | Where-Object { $_.State -ne 'Disabled' }

foreach ($task in $tasks) {
    $score = 0
    $reasons = @()
    $taskInfo = Get-ScheduledTaskInfo -TaskName $task.TaskName -TaskPath $task.TaskPath -ErrorAction SilentlyContinue
    $lastRun = if ($taskInfo.LastRunTime) { $taskInfo.LastRunTime } else { $null }

    # 檢測1: 凌晨執行 (0:00-5:00)
    # 通過檢查 Actions 中的命令列引數
    $actions = $task.Actions
    foreach ($action in $actions) {
        $argStr = "$($action.Arguments)" + "$($action.Execute)"
        if ($argStr -match '(-WindowStyle\s+Hidden|/hidden|-w\s+hidden|-hide|/background|/min|-NoLogo\s+-NonInteractive\s+-WindowStyle\s+Hidden)') {
            $score += 2
            $reasons += "隱藏視窗執行"
        }
        if ($argStr -match '(\\Temp\\|\\TMP\\|\\AppData\\Local\\Temp\\)') {
            $score += 3
            $reasons += "從臨時目錄執行"
        }
        if ($argStr -match '((?:powershell|cmd|wscript|cscript|rundll32|mshta|regsvr32).*?(?:-enc|-e\s|IEX|Invoke-Expression|DownloadString|FromBase64String|eval))') {
            $score += 4
            $reasons += "可疑命令特徵(編碼/下載)"
        }
    }

    # 檢測2: 無描述資訊的任務
    if (-not $task.Description -or $task.Description -eq '') {
        $score += 1
        $reasons += "無描述資訊"
    }

    if ($score -ge 3) {
        $suspicious += [PSCustomObject]@{
            任務名 = $task.TaskName
            路徑 = $task.TaskPath
            風險分 = $score
            原因 = ($reasons -join ', ')
            上次執行 = $lastRun
        }
    }
}

if ($suspicious.Count -gt 0) {
    $suspicious | Sort-Object 風險分 -Descending |
        Format-Table -AutoSize -Wrap
    Write-Host "`n🔴 以上任務存在可疑特徵,建議逐條排查"
} else {
    Write-Host "✅ 未發現明顯可疑的計劃任務"
}
### 17.3 按觸發條件分類(開機自啟 / 定時 / 使用者登入觸發)
Write-Host "════════ 計劃任務按觸發型別分類 ════════`n"

# 開機自啟
Write-Host "═══ 開機/系統啟動時觸發 ═══"
Get-ScheduledTask | Where-Object {
    $_.Triggers | Where-Object { $_.CimClass.CimClassName -match 'BootTrigger|StartupTrigger' }
} | Select-Object -First 15 @{N='任務名';E={$_.TaskName}},
    @{N='路徑';E={$_.TaskPath}},
    @{N='觸發器';E={
        ($_.Triggers | ForEach-Object { $_.CimClass.CimClassName }) -join ', '
    }} |
    Format-Table -AutoSize

Write-Host "`n═══ 使用者登入時觸發 ═══"
Get-ScheduledTask | Where-Object {
    $_.Triggers | Where-Object { $_.CimClass.CimClassName -match 'LogonTrigger' }
} | Select-Object -First 15 @{N='任務名';E={$_.TaskName}},
    @{N='路徑';E={$_.TaskPath}},
    @{N='觸發器';E={
        ($_.Triggers | ForEach-Object { $_.CimClass.CimClassName }) -join ', '
    }} |
    Format-Table -AutoSize

Write-Host "`n═══ 定時/週期性觸發 (數量最多) ═══"
$timeTasks = Get-ScheduledTask | Where-Object {
    $_.Triggers | Where-Object { $_.CimClass.CimClassName -match 'TimeTrigger|DailyTrigger|WeeklyTrigger|MonthlyTrigger' }
}
Write-Host "  總數: $(($timeTasks | Measure-Object).Count) 個"
### 17.4 非 Microsoft 建立的任務
Write-Host "════════ 非 Microsoft 建立的計劃任務 ════════"
$nonMsTasks = Get-ScheduledTask | Where-Object {
    $_.TaskPath -notmatch '\\\\Microsoft\\\\' -and $_.State -ne 'Disabled'
}

if ($nonMsTasks) {
    $nonMsTasks | Select-Object @{N='任務名';E={$_.TaskName}},
        @{N='路徑';E={$_.TaskPath}},
        @{N='狀態';E={$_.State}},
        @{N='描述';E={
            if ($_.Description) { $_.Description.Substring(0, [Math]::Min(60, $_.Description.Length)) }
            else { '(無描述)' }
        }} |
        Format-Table -AutoSize
    Write-Host "`n💡 第三方任務值得審查,尤其是無描述且來源不明的"
} else {
    Write-Host "✅ 無非 Microsoft 計劃任務"
}

本技能來自小蔥技能站7w4.net。

**風險等級**:🟢 無(只讀審計) | 報錯 | 含義 | 解決 | |-----|------|-----| | `Access denied` | 許可權不足 | 管理員身份執行 | | `The system cannot find the file specified` | 任務引用的程式已刪除 | 正常(殘留任務),值得清理 | | `Task Scheduler service is not running` | 計劃任務服務未啟動 | `Start-Service Schedule` | **常見坑 & 解決**: | 場景 | 說明 | |-----|------| | 大量凌晨執行的隱藏視窗任務 | 軟體更新常見,但需逐條確認來源 | | 從 Temp 目錄執行的任務 | 高危特徵,多數惡意軟體行為 | | 無描述的隨機名任務 | 可能是病毒/蠕蟲建立,建議隔離排查 | | 編碼命令 (Base64) 執行 | 極高風險,常見於挖礦指令碼和外連木馬 |

↑ 返回頂部


🆕 模組 18:檔案共享與 SMB 審計

📋 展開檢視:🆕 模組 18:檔案共享與 SMB 審計 **用途**:列出所有共享資料夾、當前 SMB 連線、許可權風險檢測。 **常你說**:`"有哪些共享資料夾"` / `"共享許可權安全嗎"` / `"誰在訪問共享"` / `"SMB 審計"` > ⚠️ **本模組僅讀,不會關閉共享、斷開連線或修改許可權。** ### 18.1 已共享資料夾清單
Write-Host "════════ 已共享資料夾 ════════"
Get-SmbShare | Where-Object { $_.Name -notin @('IPC$','ADMIN$') -or $_.Special -eq $false } |
    Select-Object @{N='共享名';E={$_.Name}},
        @{N='路徑';E={$_.Path}},
        @{N='描述';E={if($_.Description){$_.Description}else{'(無)'}}},
        @{N='最大使用者數';E={$_.ConcurrentUserLimit}},
        @{N='快取模式';E={$_.CachingMode}},
        @{N='共享狀態';E={$_.ShareState}} |
    Format-Table -AutoSize

Write-Host "`n💡 ADMIN$ 和 IPC$ 為系統預設管理共享,屬正常"
### 18.2 共享許可權審計
Write-Host "════════ 共享許可權審計 ════════"
$shares = Get-SmbShare | Where-Object { $_.Name -notin @('IPC$','ADMIN$') -or $_.Special -eq $false }

foreach ($share in $shares) {
    Write-Host "`n═══ 共享: $($share.Name) → $($share.Path) ═══"

    # 共享級別許可權
    try {
        $sharePerm = Get-SmbShareAccess -Name $share.Name -ErrorAction SilentlyContinue
        foreach ($perm in $sharePerm) {
            $flag = if ($perm.AccessRight -eq 'Full' -and $perm.AccountName -eq 'Everyone') {
                "🔴 高風險: Everyone 擁有完全控制"
            } elseif ($perm.AccountName -eq 'Everyone') {
                "⚠️ Everyone 可訪問"
            } else {
                ""
            }
            Write-Host "  共享許可權: $($perm.AccountName) -> $($perm.AccessRight)  $flag"
        }
    } catch {
        Write-Host "  共享許可權: 無法獲取"
    }

    # NTFS 級別許可權(對物理路徑)
    if (Test-Path $share.Path) {
        $ntfsPerm = Get-Acl $share.Path -ErrorAction SilentlyContinue
        if ($ntfsPerm) {
            $ntfsPerm.Access | Where-Object { $_.IdentityReference -match 'Everyone|BUILTIN|Guest|ANONYMOUS' } |
                ForEach-Object {
                    Write-Host "  NTFS許可權: $($_.IdentityReference) -> $($_.FileSystemRights) ⚠️ 寬鬆許可權"
                }
        }
    }
}
### 18.3 當前 SMB 連線會話
Write-Host "════════ 當前 SMB 連線會話 ════════"
$sessions = Get-SmbSession -ErrorAction SilentlyContinue |
    Select-Object @{N='客戶端';E={$_.ClientComputerName}},
        @{N='使用者名稱';E={$_.UserName}},
        @{N='空閒時間(分鐘)';E={[math]::Round($_.IdleTime.TotalMinutes, 0)}},
        @{N='會話時長(分鐘)';E={[math]::Round((New-TimeSpan -Start $_.SessionStartTime).TotalMinutes, 0)}} |
    Sort-Object @{E='空閒時間(分鐘)';Descending=$true}

if ($sessions) {
    $sessions | Format-Table -AutoSize
    Write-Host "`n💡 空閒 >60 分鐘的會話可能為殭屍連線"
} else {
    Write-Host "  當前無活躍 SMB 會話"
}
### 18.4 開放共享中的風險項彙總
Write-Host "════════ 共享風險彙總 ════════"
$risks = @()
$shares = Get-SmbShare | Where-Object { $_.Name -notin @('IPC$','ADMIN$') -or $_.Special -eq $false }

foreach ($share in $shares) {
    $sharePerm = Get-SmbShareAccess -Name $share.Name -ErrorAction SilentlyContinue
    foreach ($perm in $sharePerm) {
        if ($perm.AccountName -eq 'Everyone') {
            $risks += "🔴 [$($share.Name)] Everyone -> $($perm.AccessRight) 控制權"
        }
        if ($perm.AccountName -eq 'ANONYMOUS LOGON' -or $perm.AccountName -eq 'Guest') {
            $risks += "🔴 [$($share.Name)] $($perm.AccountName) -> $($perm.AccessRight)"
        }
    }

    # 檢查共享指向路徑不存在
    if (-not (Test-Path $share.Path)) {
        $risks += "⚠️ [$($share.Name)] 共享路徑不存在: $($share.Path)"
    }
}

if ($risks.Count -gt 0) {
    $risks | ForEach-Object { Write-Host $_ }
    Write-Host "`n建議: 收緊共享許可權為最小訪問原則,停用 Guest/匿名訪問"
} else {
    Write-Host "✅ 未發現高風險的共享配置"
}

# 同時檢查 SMBv1 是否啟用
$smb1 = Get-WindowsOptionalFeature -Online -FeatureName SMB1Protocol -ErrorAction SilentlyContinue
if ($smb1 -and $smb1.State -eq 'Enabled') {
    Write-Host "`n🔴 SMBv1 已啟用!存在 WannaCry 等勒索軟體漏洞風險,建議停用"
}
**風險等級**:🟢 無(只讀審計) | 報錯 | 含義 | 解決 | |-----|------|-----| | `Get-SmbShare` 報錯 | SMB 未啟用或無許可權 | 管理員身份在伺服器上執行 | | `Get-SmbSession` 為空 | 當前無 SMB 連線 | 正常 | | `Access denied on Get-Acl` | 部分目錄 NTFS 許可權限制 | 某些系統目錄屬正常 | **常見坑 & 解決**: | 場景 | 說明 | |-----|------| | Everyone 擁有完全控制 | 任何網路使用者可讀/寫,極大風險 | | SMBv1 仍啟用 | 永恆之藍等漏洞存在,應立即停用 | | 指向不存在的路徑 | 殘留共享,建議刪除 | | 大量殭屍 SMB 會話 | 客戶端未正常斷開,佔用連線數 |

↑ 返回頂部


🆕 模組 19:DNS 解析與網絡卡診斷

📋 展開檢視:🆕 模組 19:DNS 解析與網絡卡診斷 **用途**:DNS 快取檢視與清空、解析鏈路測試、網絡卡 IP 配置、路由表檢查。 **常你說**:`"DNS 解析正常嗎"` / `"網絡卡配置"` / `"網路診斷"` / `"路由表"` > ⚠️ **本模組操作:DNS 快取檢視/清空(可恢復)+ 網絡卡 IP 檢視(只讀)。DNS 清空後會重新從伺服器獲取,非破壞性。** ### 19.1 DNS 快取與解析測試
Write-Host "════════ DNS 快取 ════════"
$dnsCache = Get-DnsClientCache -ErrorAction SilentlyContinue
if ($dnsCache) {
    Write-Host "  快取條目: $(($dnsCache | Measure-Object).Count)"
    $dnsCache | Select-Object -First 20 @{N='域名';E={$_.Entry}},
        @{N='型別';E={$_.RecordType}},
        @{N='IP地址';E={$_.Data}},
        @{N='TTL(秒)';E={$_.TimeToLive}} |
        Format-Table -AutoSize
} else {
    Write-Host "  當前無 DNS 快取"
}

Write-Host "`n════════ DNS 快取中異常的記錄 (TTL異常長) ════════"
if ($dnsCache) {
    $abnormal = $dnsCache | Where-Object { $_.TimeToLive -gt 86400 }
    if ($abnormal) {
        $abnormal | Select-Object Entry, Data, TimeToLive | Format-Table -AutoSize
    } else {
        Write-Host "  ✅ 無異常記錄"
    }
}

Write-Host "`n💡 如需清空 DNS 快取,說:「確認清空 DNS 快取」"
Write-Host "  清空命令: Clear-DnsClientCache  (清空後會自動從DNS伺服器重新獲取)"
### 19.2 DNS 伺服器配置與解析鏈路測試
Write-Host "════════ DNS 伺服器配置 ════════"
Get-DnsClientServerAddress -AddressFamily IPv4 |
    Where-Object { $_.ServerAddresses.Count -gt 0 } |
    Select-Object @{N='網絡卡';E={$_.InterfaceAlias}},
        @{N='索引';E={$_.InterfaceIndex}},
        @{N='DNS 伺服器';E={($_.ServerAddresses -join ', ')}} |
    Format-Table -AutoSize

Write-Host "`n════════ 解析鏈路測試 (逐級 DNS) ════════"
$testDomains = @('www.baidu.com', 'www.google.com', 'portal.azure.com')
foreach ($domain in $testDomains) {
    try {
        $result = Resolve-DnsName -Name $domain -Type A -ErrorAction Stop
        $ip = ($result | Where-Object { $_.Type -eq 'A' } | Select-Object -First 1).IPAddress
        if ($ip) { Write-Host "  ✅ $domain → $ip" }
        else { Write-Host "  ❌ $domain → 解析失敗" }
    } catch {
        Write-Host "  ❌ $domain → $($_.Exception.Message.Split('.')[0])"
    }
}
### 19.3 網絡卡 IP 配置概覽
Write-Host "════════ 網絡卡 IP 配置 ════════"
Get-NetIPAddress -AddressFamily IPv4 |
    Where-Object { $_.InterfaceAlias -notmatch 'Loopback' -and $_.IPAddress -ne '127.0.0.1' } |
    Select-Object @{N='網絡卡';E={$_.InterfaceAlias}},
        @{N='IP 地址';E={$_.IPAddress}},
        @{N='子網掩碼';E={$_.PrefixLength}},
        @{N='閘道器';E={
            $ifIndex = $_.InterfaceIndex
            $gw = Get-NetRoute -InterfaceIndex $ifIndex -DestinationPrefix '0.0.0.0/0' -ErrorAction SilentlyContinue
            if ($gw) { $gw.NextHop } else { '-' }
        }},
        @{N='狀態';E={$_.AddressState}} |
    Format-Table -AutoSize

Write-Host "`n════════ 網絡卡 MAC 地址與速率 ════════"
Get-NetAdapter | Where-Object { $_.Status -eq 'Up' } |
    Select-Object @{N='網絡卡名';E={$_.Name}},
        @{N='MAC';E={$_.MacAddress}},
        @{N='速率';E={if($_.LinkSpeed){ "$([math]::Round($_.LinkSpeed/1e9,1)) Gbps" }else{'未知'}}},
        @{N='狀態';E={$_.Status}} |
    Format-Table -AutoSize
### 19.4 路由表檢查
Write-Host "════════ IPv4 路由表 ════════"
Get-NetRoute -AddressFamily IPv4 |
    Where-Object { $_.DestinationPrefix -ne '255.255.255.255/32' } |
    Sort-Object @{E={if ($_.DestinationPrefix -eq '0.0.0.0/0') {0} else {1}}},
        @{E='RouteMetric'} |
    Select-Object @{N='目標網路';E={$_.DestinationPrefix}},
        @{N='下一跳';E={$_.NextHop}},
        @{N='介面';E={$_.InterfaceAlias}},
        @{N='躍點數';E={$_.RouteMetric}},
        @{N='協議';E={$_.Protocol}} |
    Format-Table -AutoSize

Write-Host "`n💡 躍點數越小優先順序越高"
Write-Host "💡 0.0.0.0/0 為預設路由(所有出網流量由此控制)"
**風險等級**:🟡 中(含 DNS 快取清空操作,需使用者確認) | 操作 | 風險 | 說明 | |------|------|------| | DNS 快取檢視 | 🟢 無 | 純只讀 | | DNS 解析測試 | 🟢 無 | 純只讀,零風險 | | 網絡卡配置檢視 | 🟢 無 | 純只讀 | | 路由表檢視 | 🟢 無 | 純只讀 | | **DNS 快取清空** | 🟡 中 | 清空後需使用者說「確認清空 DNS 快取」,清空後自動從 DNS 伺服器重建,非破壞性 | | 報錯 | 含義 | 解決 | |-----|------|-----| | `Resolve-DnsName` 超時 | DNS 伺服器不可達 | 檢查 DNS 伺服器配置和網路連通性 | | `Get-NetIPAddress` 為空 | 網絡卡未分配 IPv4 | 檢查 DHCP 或靜態 IP 配置 | | `Get-NetRoute` 無預設路由 | 無網際網路出口 | 檢查閘道器配置 | **常見坑 & 解決**: | 場景 | 說明 | |-----|------| | DNS 快取中大量 TTL 異常長的記錄 | 可能 DNS 伺服器配置問題或域名劫持 | | 多網絡卡存在多個預設路由 | 路由衝突導致網路不穩定 | | DNS 伺服器指向不可達 IP | 域名解析全部失敗 | | 網絡卡速率不匹配(1Gbps vs 100Mbps) | 網線/交換機埠故障 |

↑ 返回頂部


🆕 模組 20:SSL 證書過期檢測

📋 展開檢視:🆕 模組 20:SSL 證書過期檢測 **用途**:檢測本機 IIS / 所有 HTTPS 站點的 SSL 證書到期時間,提前預警,避免網站突然報"證書無效"。 **常你說**:`"SSL 證書快到期了嗎"` / `"證書檢查"` / `"HTTPS 站點證書還有多久"` / `"哪些證書要過期了"` > ⚠️ **本模組僅讀,不會申請、續簽或刪除任何證書。** ### 20.1 本機證書倉庫掃描(個人 + 機器)
Write-Host "════════ 本機證書過期檢查 ════════"
$warningDays = 30
$now = Get-Date

$stores = @(
    [System.Security.Cryptography.X509Certificates.StoreLocation]::LocalMachine,
    [System.Security.Cryptography.X509Certificates.StoreLocation]::CurrentUser
)
$storeNames = @('My', 'WebHosting', 'Root', 'CA')

$certs = foreach ($loc in $stores) {
    foreach ($name in $storeNames) {
        try {
            $store = [System.Security.Cryptography.X509Certificates.X509Store]::new($name, $loc)
            $store.Open('ReadOnly')
            foreach ($cert in $store.Certificates) {
                $daysLeft = ($cert.NotAfter - $now).Days
                [PSCustomObject]@{
                    主體       = ($cert.Subject -replace 'CN=', '' -split ',')[0].Trim()
                    儲存位置   = "$loc\$name"
                    到期時間   = $cert.NotAfter.ToString('yyyy-MM-dd')
                    剩餘天數   = $daysLeft
                    狀態       = if ($daysLeft -lt 0) { '❌ 已過期' }
                                 elseif ($daysLeft -lt $warningDays) { '⚠️ 即將過期' }
                                 else { '✅ 正常' }
                    頒發者     = ($cert.Issuer -replace 'CN=', '' -split ',')[0].Trim()
                }
            }
            $store.Close()
        } catch {}
    }
}

$result = $certs | Where-Object { $_.剩餘天數 -lt 90 } |
    Sort-Object 剩餘天數

if ($result) {
    $result | Format-Table -AutoSize
} else {
    Write-Host "✅ 未發現 90 天內到期的證書"
}
### 20.2 IIS 繫結的 HTTPS 證書檢查
Write-Host "════════ IIS HTTPS 繫結證書 ════════"
Import-Module WebAdministration -ErrorAction SilentlyContinue

$httpsBindings = Get-WebBinding | Where-Object { $_.protocol -eq 'https' }
if (-not $httpsBindings) {
    Write-Host "  未發現 HTTPS 繫結"
} else {
    foreach ($binding in $httpsBindings) {
        $hash = $binding.certificateHash
        if ($hash) {
            $cert = Get-ChildItem Cert:\LocalMachine\My | Where-Object { $_.Thumbprint -eq $hash }
            if ($cert) {
                $daysLeft = ($cert.NotAfter - (Get-Date)).Days
                $status = if ($daysLeft -lt 0) { '❌ 已過期' }
                           elseif ($daysLeft -lt 30) { '⚠️ 即將過期' }
                           else { '✅ 正常' }
                Write-Host "  站點: $($binding.bindingInformation)"
                Write-Host "  證書: $($cert.Subject)"
                Write-Host "  到期: $($cert.NotAfter.ToString('yyyy-MM-dd'))  剩餘: $daysLeft 天  $status"
                Write-Host ""
            }
        }
    }
}
### 20.3 遠端域名證書探測(本地無證書的站點)
# 將下方域名替換為你需要檢測的站點
$domains = @('www.baidu.com', 'www.taobao.com')  # 示例,替換為你的域名

Write-Host "════════ 遠端域名 SSL 證書檢測 ════════"
foreach ($domain in $domains) {
    try {
        $tcpClient = New-Object System.Net.Sockets.TcpClient($domain, 443)
        $sslStream  = New-Object System.Net.Security.SslStream($tcpClient.GetStream(), $false, { $true })
        $sslStream.AuthenticateAsClient($domain)
        $cert = $sslStream.RemoteCertificate
        $expiry = [DateTime]::Parse($cert.GetExpirationDateString())
        $daysLeft = ($expiry - (Get-Date)).Days
        $status = if ($daysLeft -lt 0) { '❌ 已過期' }
                   elseif ($daysLeft -lt 30) { '⚠️ 即將過期' }
                   else { '✅ 正常' }
        Write-Host "  $domain → 到期: $($expiry.ToString('yyyy-MM-dd'))  剩餘: $daysLeft 天  $status"
        $sslStream.Close()
        $tcpClient.Close()
    } catch {
        Write-Host "  $domain → ❌ 連線失敗: $($_.Exception.Message.Split('.')[0])"
    }
}
### 20.4 即將過期證書彙總報告
Write-Host "════════ 30 天內到期證書彙總 ════════"
$now = Get-Date
$soon = @()

foreach ($loc in @('LocalMachine','CurrentUser')) {
    foreach ($name in @('My','WebHosting')) {
        try {
            $store = [System.Security.Cryptography.X509Certificates.X509Store]::new($name, $loc)
            $store.Open('ReadOnly')
            $soon += $store.Certificates | Where-Object {
                ($_.NotAfter - $now).Days -le 30 -and ($_.NotAfter - $now).Days -ge 0
            } | Select-Object @{N='證書名';E={($_.Subject -replace 'CN=','' -split ',')[0].Trim()}},
                @{N='剩餘天數';E={($_.NotAfter - $now).Days}},
                @{N='到期日期';E={$_.NotAfter.ToString('yyyy-MM-dd')}},
                @{N='儲存';E={"$loc\$name"}}
            $store.Close()
        } catch {}
    }
}

if ($soon.Count -gt 0) {
    $soon | Sort-Object 剩餘天數 | Format-Table -AutoSize
    Write-Host "`n🔴 以上證書需要儘快續簽!"
} else {
    Write-Host "✅ 30 天內無證書過期"
}
**風險等級**:🟢 無(只讀,不修改任何證書) | 報錯 | 含義 | 解決 | |-----|------|-----| | `Access denied` | 需管理員許可權 | 管理員身份執行 | | `WebAdministration not found` | IIS 未安裝 | 跳過模組 20.2 | | `Connection refused` | 遠端域名 443 不可達 | 檢查域名和防火牆 | | `AuthenticationException` | SSL 握手失敗 | 域名可能證書異常 | **常見坑 & 解決**: | 場景 | 說明 | |-----|------| | 證書顯示"已過期"但網站仍在訪問 | 瀏覽器有快取,實際使用者已經開始看到警告 | | IIS 繫結的證書和倉庫裡的不一致 | IIS 用指紋引用,需手動在 IIS 管理器重新繫結 | | Let's Encrypt 證書 90 天到期週期 | 需設定自動續簽(如 win-acme) |

↑ 返回頂部


🆕 模組 21:Windows 防火牆規則審計

📋 展開檢視:🆕 模組 21:Windows 防火牆規則審計 **用途**:列出所有防火牆規則,識別過度開放(Any/Any)、可疑來源的規則,找出安全漏洞。 **常你說**:`"防火牆規則有沒有問題"` / `"防火牆審計"` / `"哪些埠對外開放"` / `"有沒有高危防火牆規則"` > ⚠️ **本模組僅讀,不會新增、刪除或修改任何防火牆規則。** ### 21.1 所有入站規則概覽
Write-Host "════════ 入站防火牆規則(啟用中)════════"
$inbound = Get-NetFirewallRule -Direction Inbound -Enabled True -ErrorAction SilentlyContinue

Write-Host "  啟用的入站規則總數: $(($inbound | Measure-Object).Count)"
Write-Host ""

$inbound | ForEach-Object {
    $rule = $_
    $filter = $rule | Get-NetFirewallPortFilter -ErrorAction SilentlyContinue
    $addrFilter = $rule | Get-NetFirewallAddressFilter -ErrorAction SilentlyContinue
    [PSCustomObject]@{
        規則名     = $rule.DisplayName.Substring(0, [Math]::Min(40, $rule.DisplayName.Length))
        協議       = if ($filter.Protocol) { $filter.Protocol } else { '任意' }
        本地埠   = if ($filter.LocalPort) { $filter.LocalPort -join ',' } else { '任意' }
        來源地址   = if ($addrFilter.RemoteAddress) { ($addrFilter.RemoteAddress -join ',').Substring(0, [Math]::Min(30, ($addrFilter.RemoteAddress -join ',').Length)) } else { '任意' }
        動作       = $rule.Action
    }
} | Select-Object -First 30 | Format-Table -AutoSize
### 21.2 高危規則檢測(Any → Any / 暴露全埠)
Write-Host "════════ 高危防火牆規則掃描 ════════"
$risks = @()

Get-NetFirewallRule -Direction Inbound -Action Allow -Enabled True -ErrorAction SilentlyContinue | ForEach-Object {
    $rule = $_
    $portFilter = $rule | Get-NetFirewallPortFilter -ErrorAction SilentlyContinue
    $addrFilter  = $rule | Get-NetFirewallAddressFilter -ErrorAction SilentlyContinue

    $anyPort = ($portFilter.LocalPort -eq 'Any' -or -not $portFilter.LocalPort)
    $anyAddr = ($addrFilter.RemoteAddress -eq 'Any' -or $addrFilter.RemoteAddress -contains 'Any' -or -not $addrFilter.RemoteAddress)

    if ($anyPort -and $anyAddr) {
        $risks += [PSCustomObject]@{
            風險等級 = '🔴 高危'
            規則名   = $rule.DisplayName
            說明     = '允許任意來源訪問任意埠'
            建議     = '收緊來源地址或埠範圍'
        }
    } elseif ($anyAddr) {
        # 檢查是否暴露高危埠(135/445/3389/5985)
        $dangerousPorts = @('135','445','3389','5985','5986','23','21','1433','3306','6379')
        $portStr = ($portFilter.LocalPort -join ',')
        foreach ($p in $dangerousPorts) {
            if ($portStr -match "\b$p\b" -or $anyPort) {
                $risks += [PSCustomObject]@{
                    風險等級 = '⚠️ 中危'
                    規則名   = $rule.DisplayName
                    說明     = "埠 $p 對任意來源開放"
                    建議     = '限制來源 IP 白名單'
                }
                break
            }
        }
    }
}

if ($risks.Count -gt 0) {
    $risks | Format-Table -AutoSize -Wrap
    Write-Host "`n建議: 使用「來源 IP 白名單」替代「任意來源」"
} else {
    Write-Host "✅ 未發現明顯高危防火牆規則"
}
### 21.3 按埠檢視誰在放行
# 修改此處為你想查詢的埠
$targetPorts = @('3389', '445', '80', '443', '1433', '3306')

Write-Host "════════ 關鍵埠放行規則 ════════"
foreach ($port in $targetPorts) {
    $rules = Get-NetFirewallRule -Direction Inbound -Action Allow -Enabled True -ErrorAction SilentlyContinue | Where-Object {
        $pf = $_ | Get-NetFirewallPortFilter -ErrorAction SilentlyContinue
        ($pf.LocalPort -eq 'Any' -or $pf.LocalPort -contains $port)
    }

    if ($rules) {
        Write-Host "`n  埠 $port — 有 $(($rules | Measure-Object).Count) 條放行規則:"
        $rules | Select-Object -First 5 @{N='規則名';E={$_.DisplayName}} |
            ForEach-Object { Write-Host "    - $($_.規則名)" }
    } else {
        Write-Host "`n  埠 $port — 無放行規則(預設拒絕)"
    }
}
### 21.4 防火牆配置檔案狀態
Write-Host "════════ 防火牆配置檔案狀態 ════════"
Get-NetFirewallProfile | Select-Object @{N='配置檔案';E={$_.Name}},
    @{N='是否啟用';E={if($_.Enabled){'✅ 啟用'}else{'❌ 已停用 ⚠️'}}},
    @{N='入站預設';E={$_.DefaultInboundAction}},
    @{N='出站預設';E={$_.DefaultOutboundAction}},
    @{N='通知';E={$_.NotifyOnListen}} |
    Format-Table -AutoSize

Write-Host "`n💡 防火牆應對所有配置檔案均啟用,入站預設「Block」"
Write-Host "💡 如果任一配置檔案顯示「已停用」,立即排查原因"
**風險等級**:🟢 無(只讀審計,不修改任何規則) | 報錯 | 含義 | 解決 | |-----|------|-----| | `Get-NetFirewallRule` 報錯 | 需管理員許可權 | 管理員身份執行 | | `WinRM` 相關報錯 | 防火牆服務異常 | 檢查 `mpssvc` 服務狀態 | | `Access denied on Get-NetFirewallPortFilter` | 域策略限制 | 以域管理員身份執行 | **常見坑 & 解決**: | 場景 | 說明 | |-----|------| | 防火牆被關閉(Enabled=False) | 極高風險,任何連線均可進入 | | 3389 對 Any 開放 | RDP 暴力破解首要目標 | | 445 對 Any 開放 | WannaCry/勒索病毒入侵路徑 | | 大量"Any → Any"規則 | 常見於軟體安裝時自動新增,需逐條清理 |

↑ 返回頂部


🆕 模組 22:關鍵服務崩潰與自動恢復狀態

📋 展開檢視:🆕 模組 22:關鍵服務崩潰與自動恢復狀態 **用途**:檢視服務異常停止記錄、自動恢復策略、"應該執行卻未執行"的服務。 **常你說**:`"哪些服務崩過"` / `"服務崩潰記錄"` / `"服務自動恢復設定"` / `"有服務沒跑起來嗎"` > ⚠️ **本模組僅讀,不會啟動、停止或修改任何服務。** ### 22.1 已停止但設為自動啟動的服務("應跑未跑")
Write-Host "════════ 應執行卻已停止的服務 ════════"
$deadServices = Get-Service | Where-Object {
    $_.StartType -in @('Automatic', 'AutomaticDelayedStart') -and
    $_.Status -eq 'Stopped'
}

if ($deadServices) {
    $deadServices | Select-Object @{N='服務名';E={$_.Name}},
        @{N='顯示名';E={$_.DisplayName}},
        @{N='啟動型別';E={$_.StartType}},
        @{N='狀態';E={$_.Status}} |
        Sort-Object 顯示名 |
        Format-Table -AutoSize
    Write-Host "`n⚠️ 以上服務設定了自動啟動但當前已停止,需要排查原因"
} else {
    Write-Host "✅ 所有自動啟動的服務均在執行"
}
### 22.2 服務崩潰事件記錄(事件日誌 7034/7036)
Write-Host "════════ 服務崩潰記錄(最近 7 天)════════"
$events = Get-WinEvent -FilterHashtable @{
    LogName   = 'System'
    Id        = @(7034, 7035, 7036, 7031, 7040)
    StartTime = (Get-Date).AddDays(-7)
} -ErrorAction SilentlyContinue

if ($events) {
    $events | Select-Object @{N='時間';E={$_.TimeCreated}},
        @{N='事件ID';E={$_.Id}},
        @{N='說明';E={
            switch ($_.Id) {
                7034 { "❌ 服務意外停止: " + ($_.Message -replace "`r`n",' ').Substring(0,[Math]::Min(80,$_.Message.Length)) }
                7031 { "❌ 服務停止後觸發恢復動作: " + ($_.Message -replace "`r`n",' ').Substring(0,[Math]::Min(60,$_.Message.Length)) }
                7035 { "→ 服務控制: " + ($_.Message -replace "`r`n",' ').Substring(0,[Math]::Min(60,$_.Message.Length)) }
                7036 { "● 服務狀態變更: " + ($_.Message -replace "`r`n",' ').Substring(0,[Math]::Min(60,$_.Message.Length)) }
                7040 { "⚙️ 啟動型別變更: " + ($_.Message -replace "`r`n",' ').Substring(0,[Math]::Min(60,$_.Message.Length)) }
                default { $_.Message.Substring(0,[Math]::Min(80,$_.Message.Length)) }
            }
        }} |
        Where-Object { $_.事件ID -in @(7034, 7031) } |
        Sort-Object 時間 -Descending |
        Select-Object -First 20 |
        Format-Table -AutoSize -Wrap
} else {
    Write-Host "✅ 最近 7 天無服務崩潰記錄"
}
### 22.3 服務自動恢復策略檢視
Write-Host "════════ 關鍵服務恢復策略 ════════"
$keyServices = @(
    'W3SVC',       # IIS
    'MSSQLSERVER', # SQL Server
    'WSearch',     # Windows Search
    'Spooler',     # 印表機
    'EventLog',    # 事件日誌
    'WinRM',       # 遠端管理
    'Schedule',    # 計劃任務
    'LanmanServer' # 檔案共享
)

foreach ($svcName in $keyServices) {
    $svc = Get-Service -Name $svcName -ErrorAction SilentlyContinue
    if ($svc) {
        # 使用 sc.exe 讀取恢復策略
        $scOutput = sc.exe qfailure $svcName 2>&1
        $resetPeriod = ($scOutput | Select-String 'RESET_PERIOD') -replace '.*: ', ''
        $actions = ($scOutput | Select-String 'FAILURE_ACTIONS') -replace '.*: ', ''

        Write-Host "  $($svc.DisplayName) [$svcName]"
        Write-Host "    狀態: $($svc.Status)"
        Write-Host "    恢復動作: $(if($actions){$actions}else{'(未配置)'} )"
        Write-Host ""
    }
}
Write-Host "💡 未配置恢復動作的關鍵服務,崩潰後不會自動重啟,需手動干預"
### 22.4 服務依賴關係檢查(關鍵服務是否有依賴未啟動)
Write-Host "════════ 關鍵服務依賴鏈檢查 ════════"
$keyServices = @('W3SVC', 'MSSQLSERVER', 'WinRM', 'Schedule', 'Netlogon')

foreach ($svcName in $keyServices) {
    $svc = Get-Service -Name $svcName -ErrorAction SilentlyContinue
    if ($svc) {
        $deps = $svc.ServicesDependedOn
        $brokenDeps = $deps | Where-Object { $_.Status -ne 'Running' }

        if ($brokenDeps) {
            Write-Host "⚠️ $($svc.DisplayName) 依賴以下未執行的服務:"
            $brokenDeps | ForEach-Object {
                Write-Host "    ❌ $($_.Name) ($($_.Status))"
            }
        } else {
            Write-Host "✅ $($svc.DisplayName) — 所有依賴服務正常"
        }
    }
}
**風險等級**:🟢 無(只讀,不啟動/停止/修改任何服務) | 報錯 | 含義 | 解決 | |-----|------|-----| | `Get-WinEvent` 無許可權 | 需管理員許可權 | 管理員身份執行 | | `sc.exe qfailure` 返回空 | 部分服務無恢復策略 | 正常,說明未配置 | | `Get-Service` 找不到服務 | 該服務未安裝 | 跳過該服務 | **常見坑 & 解決**: | 場景 | 說明 | |-----|------| | IIS 停止但事件日誌無崩潰記錄 | 可能是被人為停止 | | 服務崩潰但無恢復動作 | 需通過"服務屬性 → 恢復"配置自動重啟 | | 依賴服務未執行導致主服務無法啟動 | 先啟動依賴服務 | | 事件 7034 大量重複 | 服務反覆崩潰重啟,存在底層問題 | ---

↑ 返回頂部


🆕 模組 23:系統檔案完整性檢查與修復(SFC / DISM)

📋 展開檢視:🆕 模組 23:系統檔案完整性檢查與修復(SFC / DISM) **用途**:掃描並修復受損的 Windows 系統檔案,診斷元件儲存損壞,解決因系統檔案破壞導致的服務異常。 **常你說**:`"系統檔案好像壞了"` / `"服務啟動報錯找不到檔案"` / `"DISM 修復"` / `"SFC 掃描"` > ⚠️ **本模組需要管理員許可權,僅掃描和修復系統檔案,不修改使用者資料。**
# 掃描所有系統檔案完整性(不修復)
sfc /scanfile=C:\Windows\System32\kernel32.dll

# 掃描並嘗試修復(需管理員)
# sfc /scannow
# 掃描元件儲存是否損壞(不修復)
DISM /Online /Cleanup-Image /ScanHealth

# 檢查元件儲存健康狀態
DISM /Online /Cleanup-Image /CheckHealth

# 檢視可修復的元件列表
DISM /Online /Cleanup-Image /AnalyzeComponentStore

# 清理元件儲存中的舊版本元件
# DISM /Online /Cleanup-Image /StartComponentCleanup

# 修復元件儲存(需聯網)
# DISM /Online /Cleanup-Image /RestoreHealth
# 標準修復流程:先 DISM 修復元件儲存,再 SFC 修復系統檔案
# DISM /Online /Cleanup-Image /RestoreHealth
# sfc /scannow
# 完成後重啟系統
**風險等級**:🟢 掃描只讀 / 🟡 修復需確認 | 報錯 | 含義 | 解決 | |-----|------|-----| | `Windows Resource Protection did not find any integrity violations` | 系統檔案正常 | 無需修復 | | `There is a system repair pending which requires reboot` | 有掛起的修復 | 重啟後再掃描 | | `The source files could not be downloaded` | 需聯網 | 使用安裝介質作為源 | **常見坑 & 解決**: | 場景 | 說明 | |-----|------| | SFC 報告無法修復某些檔案 | 通常是元件儲存損壞,先執行 DISM | | DISM 報錯 0x800f081f | 找不到原始檔,需指定安裝介質 | | 修復後問題依舊 | 可能是檔案許可權問題,檢查 ACL |

↑ 返回頂部


🆕 模組 24:儲存池與虛擬磁碟管理(Storage Spaces)

📋 展開檢視:🆕 模組 24:儲存池與虛擬磁碟管理(Storage Spaces) **用途**:檢視儲存池健康狀態、虛擬磁碟狀態、物理磁碟健康、儲存層使用情況,提前預警儲存故障。 **常你說**:`"儲存池正常嗎"` / `"虛擬磁碟狀態"` / `"物理磁碟健康"` / `"儲存池容量預警"` > ⚠️ **本模組僅讀,不建立/刪除/修改任何儲存池或虛擬磁碟配置。**
Write-Host "════════ 儲存池健康狀態 ════════"
Get-StoragePool | Where-Object { $_.IsPrimordial -eq $false } |
    Select-Object @{N='名稱';E={$_.FriendlyName}},
        @{N='狀態';E={$_.HealthStatus}},
        @{N='操作狀態';E={$_.OperationalStatus}},
        @{N='物理磁碟數';E={$_.PhysicalDisks.Count}},
        @{N='已用空間';E={[math]::Round($_.AllocatedSize/1GB,1)}},
        @{N='總容量';E={[math]::Round($_.Size/1GB,1)}},
        @{N='使用率';E={[math]::Round(($_.AllocatedSize/$_.Size)*100,1)}} |
    Format-Table -AutoSize
Write-Host "════════ 虛擬磁碟狀態 ════════"
Get-VirtualDisk | Select-Object @{N='名稱';E={$_.FriendlyName}},
    @{N='狀態';E={$_.HealthStatus}},
    @{N='操作狀態';E={$_.OperationalStatus}},
    @{N='RAID型別';E={$_.ResiliencySettingName}},
    @{N='已用空間';E={[math]::Round($_.AllocatedSize/1GB,1)}},
    @{N='總容量';E={[math]::Round($_.Size/1GB,1)}},
    @{N='使用率';E={[math]::Round(($_.AllocatedSize/$_.Size)*100,1)}} |
    Format-Table -AutoSize
Write-Host "════════ 儲存池中物理磁碟健康 ════════"
Get-StoragePool | Where-Object { $_.IsPrimordial -eq $false } |
    Get-PhysicalDisk | Select-Object @{N='磁碟';E={$_.FriendlyName}},
        @{N='狀態';E={$_.HealthStatus}},
        @{N='操作狀態';E={$_.OperationalStatus}},
        @{N='使用時長(小時)';E={[math]::Round($_.UsageHours,0)}},
        @{N='溫度';E={if($_.Temperature){"$($_.Temperature)°C"}else{"-"}}},
        @{N='讀取錯誤';E={(Get-StorageReliabilityCounter -PhysicalDisk $_ -ErrorAction SilentlyContinue).ReadErrorsTotal}} |
    Format-Table -AutoSize
Write-Host "════════ 儲存層使用情況 ════════"
Get-StorageTier | Select-Object @{N='名稱';E={$_.FriendlyName}},
    @{N='總容量';E={[math]::Round($_.Size/1GB,1)}},
    @{N='已用';E={[math]::Round(($_.Size - $_.AllocatedSize)/1GB,1)}},
    @{N='媒體型別';E={$_.MediaType}} |
    Format-Table -AutoSize
**風險等級**:🟢 無(只讀) | 報錯 | 含義 | 解決 | |-----|------|-----| | `No MSFT_StoragePool objects` | 系統未配置儲存池 | 僅適用於 Storage Spaces 環境 | | `Get-VirtualDisk` 報錯 | 需要管理員許可權 | 提升執行 | | `HealthStatus` 顯示 `Warning` | 儲存池存在降級 | 立即檢查物理磁碟 | **常見坑 & 解決**: | 場景 | 說明 | |-----|------| | 儲存池狀態顯示 `Degraded` | 有物理磁碟離線或故障 | | 虛擬磁碟顯示 `Incomplete` | 部分成員磁碟離線,需儘快恢復 | | 容量使用率 >90% | 需要擴容,否則寫入將失敗 | | 物理磁碟 `UsageHours` 異常高 | 磁碟可能過熱或長期高負載 |

↑ 返回頂部


🆕 模組 25:Windows Server Backup 狀態檢查

📋 展開檢視:🆕 模組 25:Windows Server Backup 狀態檢查 **用途**:檢查 Windows Server Backup 配置、最近備份狀態、備份目標健康,確保備份作業正常執行。 **常你說**:`"備份正常嗎"` / `"上次備份時間"` / `"備份失敗了"` / `"恢復點檢查"` > ⚠️ **本模組僅讀,不會啟動、停止或配置任何備份任務。**
Write-Host "════════ Windows Server Backup 狀態 ════════"

# 檢查備份策略
try {
    $policy = Get-WBPolicy -ErrorAction Stop
    Write-Host "  ✅ 備份策略已配置"
    Write-Host "  備份目標: $($policy.BackupTargets | ForEach-Object { $_.Path })"
    Write-Host "  包含卷: $($policy.VolumesToBackup | ForEach-Object { $_.Path })"
} catch {
    Write-Host "  ⚠️ 未配置備份策略"
}

# 檢視最近備份
Write-Host "`n════════ 最近備份歷史 ════════"
$backups = Get-WBSummary -ErrorAction SilentlyContinue
if ($backups) {
    $backups | Select-Object @{N='最後備份時間';E={$_.LastBackupTime}},
        @{N='備份大小';E={[math]::Round($_.TotalBackupSize/1GB,2)}},
        @{N='狀態';E={if($_.LastBackupTime){"✅ 成功"}else{"❌ 無記錄"}}} |
        Format-Table -AutoSize
} else {
    Write-Host "  ⚠️ 沒有備份歷史記錄"
}
Write-Host "════════ 備份目標磁碟檢查 ════════"
$policy = Get-WBPolicy -ErrorAction SilentlyContinue
if ($policy -and $policy.BackupTargets.Count -gt 0) {
    foreach ($target in $policy.BackupTargets) {
        $targetPath = $target.Path
        $vol = Get-Volume -FilePath $targetPath -ErrorAction SilentlyContinue
        if ($vol) {
            $freeGB = [math]::Round($vol.SizeRemaining/1GB,1)
            $totalGB = [math]::Round($vol.Size/1GB,1)
            $pctFree = [math]::Round(($vol.SizeRemaining/$vol.Size)*100,1)
            Write-Host "  目標: $targetPath"
            Write-Host "  容量: ${totalGB} GB  剩餘: ${freeGB} GB (${pctFree}%)"
            if ($pctFree -lt 10) {
                Write-Host "  ⚠️ 備份目標即將寫滿!"
            }
        }
    }
} else {
    Write-Host "  ⚠️ 未配置備份目標"
}
Write-Host "════════ 可用還原點 ════════"
Get-WBBackupSet -ErrorAction SilentlyContinue | Sort-Object BackupTime -Descending |
    Select-Object -First 10 @{N='備份時間';E={$_.BackupTime}},
        @{N='備份大小(GB)';E={[math]::Round($_.TotalBackupSize/1GB,2)}},
        @{N='卷數';E={$_.Volumes.Count}},
        @{N='應用一致性';E={if($_.ApplicationConsistent){"✅"}else{"-"}}} |
    Format-Table -AutoSize
Write-Host "════════ 當前備份作業狀態 ════════"
$job = Get-WBJob -ErrorAction SilentlyContinue
if ($job) {
    Write-Host "  狀態: $($job.JobState)"
    Write-Host "  當前操作: $($job.CurrentOperation)"
    Write-Host "  進度: $($job.Progress)%"
} else {
    Write-Host "  ✅ 當前無備份作業執行"
}
**風險等級**:🟢 無(只讀) | 報錯 | 含義 | 解決 | |-----|------|-----| | `Get-WBPolicy` 報錯 | Windows Server Backup 功能未安裝 | `Install-WindowsFeature Windows-Server-Backup` | | `Get-WBSummary` 返回空 | 無備份歷史 | 先配置並執行一次備份 | | `The operation is not supported` | 非 Server 版本 | 僅適用於 Windows Server | **常見坑 & 解決**: | 場景 | 說明 | |-----|------| | 備份目標剩餘 <10% | 備份將失敗,需清理或擴容 | | 備份作業狀態顯示 `Running` 但長時間無進度 | 可能卡住,檢查日誌 | | 應用一致性為 `false` | VSS 卷影複製失敗,檢查 VSS 服務 | | 無可用還原點 | 備份從未成功,需排查 |

↑ 返回頂部


🆕 模組 26:Docker / K8s 容器管理

用途:管理 Windows Server 容器化部署環境,監控 Docker 容器與 K8s 叢集健康狀態。

常你說"Docker 容器正常嗎" / "哪個容器吃資源" / "K8s 叢集狀態" / "容器日誌"

⚠️ 本模組僅在檢測到 Docker 或 kubectl 安裝時啟用,未安裝時給出友好提示。

前置檢測(自動執行)

$dockerPath = Get-Command docker -ErrorAction SilentlyContinue
$kubectlPath = Get-Command kubectl -ErrorAction SilentlyContinue

if (-not $dockerPath -and -not $kubectlPath) {
    Write-Host "⚠️ 未檢測到 Docker 或 kubectl,跳過模組 26"
    Write-Host "  → 安裝 Docker: https://docs.docker.com/engine/install/windows-server/"
    Write-Host "  → 安裝 kubectl: https://kubernetes.io/docs/tasks/tools/install-kubectl-windows/"
}

26.1 Docker 狀態總覽

用途:一鍵檢視容器、映象、網路、卷的使用情況。

常你說"Docker 狀態總覽" / "容器列表" / "映象多大"

📋 展開檢視命令 — Docker 狀態總覽
$dockerPath = Get-Command docker -ErrorAction SilentlyContinue
if (-not $dockerPath) {
    Write-Host "⚠️ Docker 未安裝"
    return
}

Write-Host "════════ Docker 狀態總覽 ════════"

# 容器狀態
$containers = docker ps -a --format "table {{.Names}}   {{.Status}} {{.Image}}  {{.Ports}}" 2>$null
if ($containers) {
    Write-Host "`n📦 容器列表:"
    $containers | ForEach-Object { Write-Host "  $_" }
}

# 映象列表
$images = docker images --format "table {{.Repository}}:{{.Tag}}    {{.Size}}   {{.CreatedSince}}" 2>$null
if ($images) {
    Write-Host "`n🖼️ 映象列表:"
    $images | ForEach-Object { Write-Host "  $_" }
}

# 網路列表
$networks = docker network ls --format "table {{.Name}} {{.Driver}} {{.Scope}}" 2>$null
if ($networks) {
    Write-Host "`n🌐 網路列表:"
    $networks | ForEach-Object { Write-Host "  $_" }
}

# 卷列表
$volumes = docker volume ls --format "table {{.Name}}   {{.Driver}}" 2>$null
if ($volumes) {
    Write-Host "`n💾 卷列表:"
    $volumes | ForEach-Object { Write-Host "  $_" }
}

# 磁碟佔用
$diskUsage = docker system df 2>$null
if ($diskUsage) {
    Write-Host "`n📊 Docker 磁碟佔用:"
    $diskUsage | ForEach-Object { Write-Host "  $_" }
}

風險等級:🟢 無(只讀)


26.2 容器資源監控

用途:即時檢視每個容器的 CPU / 記憶體 / 網路 / 磁碟 I/O 佔用。

常你說"哪個容器吃資源" / "容器 CPU 佔用" / "容器記憶體"

📋 展開檢視命令 — 容器資源監控
$dockerPath = Get-Command docker -ErrorAction SilentlyContinue
if (-not $dockerPath) {
    Write-Host "⚠️ Docker 未安裝"
    return
}

Write-Host "════════ 容器資源監控 ════════"
Write-Host "(單次採集,不持續佔用資源)`n"

# 獲取 CPU 核心數,決定採集併發數
$cpuCores = (Get-CimInstance Win32_Processor).NumberOfLogicalProcessors
$sampleCount = if ($cpuCores -le 4) { 1 } else { 3 }

# 容器資源統計(不流式輸出,避免佔用資源)
$stats = docker stats --no-stream --format "table {{.Name}} {{.CPUPerc}}    {{.MemUsage}}   {{.MemPerc}}    {{.NetIO}}  {{.BlockIO}}" 2>$null
if ($stats) {
    $stats | ForEach-Object { Write-Host "  $_" }
} else {
    Write-Host "  ⚠️ 無執行中的容器"
}

Write-Host "`n💡 單次採集完成,共 $sampleCount 次取樣"

風險等級:🟢 無(只讀,單次採集不佔用資源)


26.3 Docker 健康檢查

用途:檢查 Docker 服務狀態、磁碟佔用、守護程序日誌異常。

常你說"Docker 服務正常嗎" / "Docker 磁碟佔用" / "Docker 日誌異常"

📋 展開檢視命令 — Docker 健康檢查
$dockerPath = Get-Command docker -ErrorAction SilentlyContinue
if (-not $dockerPath) {
    Write-Host "⚠️ Docker 未安裝"
    return
}

Write-Host "════════ Docker 健康檢查 ════════"

# 1. Docker 服務狀態
$dockerSvc = Get-Service com.docker.service -ErrorAction SilentlyContinue
if ($dockerSvc) {
    $svcStatus = if ($dockerSvc.Status -eq 'Running') { '✅ 執行中' } else { '❌ 已停止' }
    Write-Host "  Docker 服務: $svcStatus"
} else {
    Write-Host "  Docker 服務: ⚠️ 未找到服務"
}

# 2. Docker 版本資訊
$dockerVersion = docker version --format "{{.Server.Version}}" 2>$null
if ($dockerVersion) {
    Write-Host "  Docker 版本: $dockerVersion"
}

# 3. Docker 磁碟佔用
$diskUsage = docker system df 2>$null
if ($diskUsage) {
    Write-Host "`n📊 磁碟佔用:"
    $diskUsage | ForEach-Object { Write-Host "  $_" }
}

# 4. 容器健康狀態(如果容器配置了 HEALTHCHECK)
$containers = docker ps --format "{{.Names}}" 2>$null
if ($containers) {
    Write-Host "`n🏥 容器健康狀態:"
    foreach ($c in $containers) {
        $health = docker inspect --format "{{.State.Health.Status}}" $c 2>$null
        if ($health) {
            $icon = if ($health -eq 'healthy') { '✅' } elseif ($health -eq 'unhealthy') { '❌' } else { '⏳' }
            Write-Host "  $icon $c : $health"
        } else {
            Write-Host "  ⏳ $c : 未配置健康檢查"
        }
    }
}

# 5. 最近 24 小時 Docker 相關係統錯誤日誌
$since = (Get-Date).AddHours(-24)
$dockerEvents = Get-WinEvent -FilterHashtable @{
    LogName='System'; ProviderName='Docker'; Level=2; StartTime=$since
} -ErrorAction SilentlyContinue
if ($dockerEvents) {
    Write-Host "`n⚠️ 最近 24h Docker 錯誤事件: $($dockerEvents.Count) 條"
    $dockerEvents | Select-Object -First 5 TimeCreated, Message |
        Format-Table -AutoSize -Wrap
} else {
    Write-Host "`n✅ 最近 24h 無 Docker 錯誤日誌"
}

風險等級:🟢 無(只讀)


26.4 K8s 叢集狀態

用途:檢視 Kubernetes 節點、Pod 健康、資源配額使用率。

常你說"K8s 叢集狀態" / "Pod 健康" / "節點狀態"

📋 展開檢視命令 — K8s 叢集狀態
$kubectlPath = Get-Command kubectl -ErrorAction SilentlyContinue
if (-not $kubectlPath) {
    Write-Host "⚠️ kubectl 未安裝"
    return
}

Write-Host "════════ K8s 叢集狀態 ════════"

# 1. 節點狀態
Write-Host "`n🖥️ 節點狀態:"
$nodes = kubectl get nodes -o wide 2>$null
if ($nodes) {
    $nodes | ForEach-Object { Write-Host "  $_" }
} else {
    Write-Host "  ⚠️ 無法獲取節點資訊,檢查叢集連線"
}

# 2. Pod 狀態(所有名稱空間)
Write-Host "`n📦 Pod 狀態:"
$pods = kubectl get pods --all-namespaces -o wide 2>$null
if ($pods) {
    $pods | ForEach-Object { Write-Host "  $_" }
}

# 3. 資源配額
Write-Host "`n📊 資源配額:"
$resourceQuota = kubectl get resourcequota --all-namespaces 2>$null
if ($resourceQuota) {
    $resourceQuota | ForEach-Object { Write-Host "  $_" }
} else {
    Write-Host "  未配置資源配額"
}

# 4. 異常 Pod 檢測
$allPods = kubectl get pods --all-namespaces --no-headers 2>$null
if ($allPods) {
    $abnormalPods = @()
    foreach ($podLine in $allPods) {
        $parts = $podLine -split '\s+'
        if ($parts.Count -ge 4) {
            $ns = $parts[0]
            $name = $parts[1]
            $ready = $parts[2]
            $status = $parts[3]
            if ($status -ne 'Running' -and $status -ne 'Succeeded') {
                $abnormalPods += [PSCustomObject]@{
                    名稱空間 = $ns
                    Pod名 = $name
                    狀態 = $status
                    就緒 = $ready
                }
            }
        }
    }
    if ($abnormalPods.Count -gt 0) {
        Write-Host "`n⚠️ 異常 Pod:"
        $abnormalPods | Format-Table -AutoSize
    } else {
        Write-Host "`n✅ 所有 Pod 狀態正常"
    }
}

# 5. 節點資源使用(需 metrics-server)
Write-Host "`n📈 節點資源使用:"
$topNodes = kubectl top nodes 2>$null
if ($topNodes) {
    $topNodes | ForEach-Object { Write-Host "  $_" }
} else {
    Write-Host "  ⚠️ metrics-server 未安裝,無法獲取資源使用率"
}

Write-Host "`n💡 K8s 叢集狀態採集完成"

風險等級:🟢 無(只讀)


26.5 容器日誌採集

用途:檢視指定容器的最近日誌,檢測異常模式。

常你說"看容器日誌" / "容器報錯了" / "容器最近日誌"

⚠️ 採集限制:預設採集最近 100 行,記憶體不足 2 GB 時自動縮減到 50 行,避免佔用過多記憶體。

📋 展開檢視命令 — 容器日誌採集
$dockerPath = Get-Command docker -ErrorAction SilentlyContinue
if (-not $dockerPath) {
    Write-Host "⚠️ Docker 未安裝"
    return
}

# 獲取可用記憶體,決定採集行數
$totalRAM = [math]::Round((Get-CimInstance Win32_ComputerSystem).TotalPhysicalMemory/1GB, 1)
$tailCount = if ($totalRAM -lt 2) { 50 } else { 100 }

Write-Host "════════ 容器日誌採集 ════════"
Write-Host "可用記憶體: ${totalRAM} GB,採集行數: $tailCount`n"

# 列出所有容器供選擇
$containerList = docker ps -a --format "{{.Names}} | {{.Status}}" 2>$null
if ($containerList) {
    Write-Host "可用容器:"
    $containerList | ForEach-Object { Write-Host "  $_" }
    Write-Host ""
}

# 替換為你要檢視的容器名
$targetContainer = "your_container_name"  # ← 改成你要看的容器名

if ($targetContainer -eq "your_container_name") {
    Write-Host "⚠️ 請修改 `$targetContainer 變數為要檢視的容器名"
    return
}

Write-Host "📋 容器: $targetContainer (最近 $tailCount 行)"
Write-Host "──────────────────────────────────────"

$logs = docker logs --tail $tailCount $targetContainer 2>&1
if ($logs) {
    $logs | ForEach-Object { Write-Host "  $_" }

    # 異常模式檢測
    $errorKeywords = @('error', 'exception', 'fatal', 'panic', 'failed', 'refused')
    $errorLines = @()
    $lineNum = 0
    foreach ($line in $logs) {
        $lineNum++
        foreach ($kw in $errorKeywords) {
            if ($line -match $kw) {
                $errorLines += "  行 $lineNum : $line"
                break
            }
        }
    }

    if ($errorLines.Count -gt 0) {
        Write-Host "`n⚠️ 檢測到 $($errorLines.Count) 行異常關鍵詞:"
        $errorLines | Select-Object -First 20 | ForEach-Object { Write-Host $_ }
        if ($errorLines.Count -gt 20) {
            Write-Host "  ... 還有 $($errorLines.Count - 20) 行未顯示"
        }
    } else {
        Write-Host "`n✅ 未檢測到異常關鍵詞"
    }
}

風險等級:🟢 無(只讀)

報錯 含義 解決
docker: command not found Docker 未安裝 安裝 Docker Engine
kubectl: command not found kubectl 未安裝 安裝 kubectl
connection refused Docker/K8s 服務未啟動 啟動對應服務
permission denied 許可權不足 管理員身份執行

常見坑 & 解決

場景 說明
日誌採集時記憶體不足 自動縮減到 50 行,進一步減少可修改 $tailCount
容器未配置 HEALTHCHECK 健康狀態顯示"未配置",正常
metrics-server 未安裝 K8s 資源使用率無法獲取,屬常見情況
Docker 在 Windows Server 上需要特定版本 確認 Server 版本與 Docker 相容

🆕 模組 27:自動化修復嚮導

用途:從"診斷"到"修復",提供一鍵式常見問題修復,嚴格遵循「預覽→確認→執行→驗證」四步流程。

常你說"幫我修 DNS" / "網路不正常" / "Windows Update 卡住" / "服務起不來" / "磁碟滿了" / "時間不準"

⚠️ 本模組所有修復操作均需管理員許可權,執行前自動建立還原點,使用者明確確認後才執行。

修復流程(所有子模組通用)

┌─────────────┐    ┌─────────────┐    ┌─────────────┐    ┌─────────────┐
│  Step 1     │ →  │  Step 2     │ →  │  Step 3     │ →  │  Step 4     │
│  問題定位    │    │  修復預覽    │    │  使用者確認    │    │  執行+驗證   │
│ 呼叫現有模組 │    │ 展示命令+影響 │    │ 建立還原點   │    │ 重新診斷確認  │
└─────────────┘    └─────────────┘    └─────────────┘    └─────────────┘

27.1 DNS 解析異常修復

修復命令ipconfig /flushdns + netsh winsock reset

常你說"DNS 修一下" / "網頁打不開 DNS 問題"

📋 展開檢視命令 — DNS 修復四步流程
# ====== Step 1: 問題定位(呼叫模組19) ======
Write-Host "════════ DNS 修復嚮導 ════════"
Write-Host "`n[Step 1] 問題定位..."
$dnsTest = Resolve-DnsName -Name www.baidu.com -ErrorAction SilentlyContinue
if ($dnsTest) {
    Write-Host "  ✅ DNS 解析正常,無需修復"
    return
}
Write-Host "  ❌ DNS 解析失敗,需要修復"

# ====== Step 2: 修復預覽 ======
Write-Host "`n[Step 2] 修復預覽"
Write-Host "  將要執行以下命令:"
Write-Host "  1. ipconfig /flushdns          — 清空 DNS 快取"
Write-Host "  2. netsh winsock reset         — 重置 Winsock 目錄"
Write-Host "  3. ipconfig /registerdns       — 重新註冊 DNS 名稱"
Write-Host "`n  影響範圍:"
Write-Host "  · 短暫斷開網路連線(約 5-10 秒)"
Write-Host "  · 需要重啟後生效"
Write-Host "  · 不會丟失任何資料"

# ====== Step 3: 使用者確認 ======
Write-Host "`n[Step 3] 使用者確認"
$confirm = Read-Host "  輸入 '確認修復' 開始執行"
if ($confirm -ne '確認修復') {
    Write-Host "  ❌ 已取消"
    return
}

# 建立還原點
Write-Host "  正在建立系統還原點..."
try {
    Checkpoint-Computer -Description "winskill-DNS修復前" -RestorePointType MODIFY_SETTINGS -ErrorAction SilentlyContinue
    Write-Host "  ✅ 還原點已建立"
} catch {
    Write-Host "  ⚠️ 無法建立還原點(系統保護可能未啟用)"
}

# ====== Step 4: 執行修復 ======
Write-Host "`n[Step 4] 執行修復..."
Write-Host "  1/3 清空 DNS 快取..."
ipconfig /flushdns
Write-Host "  2/3 重置 Winsock..."
netsh winsock reset
Write-Host "  3/3 註冊 DNS..."
ipconfig /registerdns

# 驗證
Write-Host "`n[驗證] 重新測試 DNS..."
Start-Sleep -Seconds 3
$verifyDns = Resolve-DnsName -Name www.baidu.com -ErrorAction SilentlyContinue
if ($verifyDns) {
    Write-Host "  ✅ DNS 修復成功!"
} else {
    Write-Host "  ⚠️ DNS 仍無法解析,建議檢查 DNS 伺服器配置"
    Write-Host "  → 模組 19 檢視 DNS 伺服器配置"
}

風險等級:🟡 中(需確認,會短暫斷網)


27.2 網路連線異常修復

修復命令netsh int ip reset + 網絡卡停用/啟用

常你說"網路重置" / "網連不上"

📋 展開檢視命令 — 網路修復四步流程
Write-Host "════════ 網路修復嚮導 ════════"

# Step 1: 定位
Write-Host "`n[Step 1] 問題定位..."
$pingTest = Test-NetConnection -ComputerName www.baidu.com -Port 443 -ErrorAction SilentlyContinue
if ($pingTest.TcpTestSucceeded) {
    Write-Host "  ✅ 網路連線正常"
    return
}
Write-Host "  ❌ 網路連線失敗"

# Step 2: 預覽
Write-Host "`n[Step 2] 修復預覽"
Write-Host "  將要執行:"
Write-Host "  1. netsh int ip reset           — 重置 TCP/IP 協議棧"
Write-Host "  2. 停用再啟用網絡卡               — 重新初始化網路介面卡"
Write-Host "`n  影響:短暫斷網(約 10-30 秒),需管理員許可權"

# Step 3: 確認
$confirm = Read-Host "`n  輸入 '確認修復' 開始執行"
if ($confirm -ne '確認修復') { return }

# Step 4: 執行
Write-Host "`n[Step 4] 執行修復..."
netsh int ip reset
Write-Host "  ✅ TCP/IP 已重置"

# 獲取主網絡卡
$adapter = Get-NetAdapter | Where-Object { $_.Status -eq 'Up' } | Select-Object -First 1
if ($adapter) {
    Write-Host "  重啟網絡卡: $($adapter.Name)..."
    Disable-NetAdapter -Name $adapter.Name -Confirm:$false
    Start-Sleep -Seconds 3
    Enable-NetAdapter -Name $adapter.Name -Confirm:$false
    Write-Host "  ✅ 網絡卡已重啟"
}

# 驗證
Start-Sleep -Seconds 5
$verifyNet = Test-NetConnection -ComputerName www.baidu.com -Port 443 -ErrorAction SilentlyContinue
if ($verifyNet.TcpTestSucceeded) {
    Write-Host "`n  ✅ 網路修復成功!"
} else {
    Write-Host "`n  ⚠️ 仍未連通,檢查物理連線和路由器"
}

風險等級:🟡 中(需確認,會短暫斷網)


27.3 Windows Update 修復

修復命令:停服務 → 清理 SoftwareDistribution → 重啟服務

常你說"Windows Update 修一下" / "更新卡住了"

📋 展開檢視命令 — Windows Update 修復四步流程
Write-Host "════════ Windows Update 修復嚮導 ════════"

# Step 1: 定位
Write-Host "`n[Step 1] 問題定位..."
$wuService = Get-Service wuauserv -ErrorAction SilentlyContinue
if ($wuService.Status -eq 'Running') {
    Write-Host "  ✅ Windows Update 服務執行中"
} else {
    Write-Host "  ❌ Windows Update 服務已停止"
}

# Step 2: 預覽
Write-Host "`n[Step 2] 修復預覽"
Write-Host "  將要執行:"
Write-Host "  1. Stop-Service wuauserv       — 停止更新服務"
Write-Host "  2. 清理 SoftwareDistribution   — 刪除損壞的下載快取"
Write-Host "  3. Start-Service wuauserv     — 重啟更新服務"
Write-Host "`n  影響:正在進行的更新將中斷,已安裝補丁不受影響"

# Step 3: 確認
$confirm = Read-Host "`n  輸入 '確認修復' 開始執行"
if ($confirm -ne '確認修復') { return }

# Step 4: 執行
Write-Host "`n[Step 4] 執行修復..."
Write-Host "  1/3 停止更新服務..."
Stop-Service wuauserv -Force
Write-Host "  2/3 清理快取..."
$sdPath = "C:\Windows\SoftwareDistribution\Download"
if (Test-Path $sdPath) {
    Remove-Item -Path "$sdPath\*" -Recurse -Force -ErrorAction SilentlyContinue
}
Write-Host "  3/3 重啟服務..."
Start-Service wuauserv

# 驗證
Start-Sleep -Seconds 3
$verifyWu = Get-Service wuauserv
if ($verifyWu.Status -eq 'Running') {
    Write-Host "`n  ✅ Windows Update 服務已恢復正常"
} else {
    Write-Host "`n  ⚠️ 服務未啟動,檢視事件日誌排查"
}

風險等級:🟡 中(需確認,正在進行的更新會中斷)


27.4 服務啟動失敗修復

修復命令:檢查依賴 → 檢查埠 → 嘗試啟動

常你說"SQL Server 起不來" / "IIS 啟動失敗"

📋 展開檢視命令 — 服務修復四步流程
# 替換為你要修復的服務名
$targetService = "W3SVC"  # ← 改成你要修復的服務名

Write-Host "════════ 服務修復嚮導 ════════"
Write-Host "目標服務: $targetService"

# Step 1: 定位
Write-Host "`n[Step 1] 問題定位..."
$svc = Get-Service -Name $targetService -ErrorAction SilentlyContinue
if (-not $svc) {
    Write-Host "  ❌ 服務不存在: $targetService"
    return
}
Write-Host "  狀態: $($svc.Status)"
Write-Host "  啟動型別: $($svc.StartType)"

# 檢查依賴
$deps = $svc.ServicesDependedOn
$brokenDeps = $deps | Where-Object { $_.Status -ne 'Running' }
if ($brokenDeps) {
    Write-Host "  ⚠️ 依賴服務未執行:"
    $brokenDeps | ForEach-Object { Write-Host "    ❌ $($_.Name)" }
}

# Step 2: 預覽
Write-Host "`n[Step 2] 修復預覽"
Write-Host "  將要執行:"
Write-Host "  1. 啟動依賴服務(如有)"
Write-Host "  2. 檢查端口占用"
Write-Host "  3. 嘗試啟動目標服務"

# Step 3: 確認
$confirm = Read-Host "`n  輸入 '確認修復' 開始執行"
if ($confirm -ne '確認修復') { return }

# Step 4: 執行
Write-Host "`n[Step 4] 執行修復..."

# 啟動依賴
if ($brokenDeps) {
    foreach ($dep in $brokenDeps) {
        Write-Host "  啟動依賴: $($dep.Name)..."
        try {
            Start-Service -Name $dep.Name -ErrorAction Stop
            Write-Host "    ✅ 已啟動"
        } catch {
            Write-Host "    ❌ 啟動失敗: $($_.Exception.Message)"
        }
    }
}

# 檢查埠(如果是 IIS/SQL/MySQL 等已知服務)
$portMap = @{
    'W3SVC' = 80
    'MSSQLSERVER' = 1433
    'MySQL80' = 3306
}
if ($portMap.ContainsKey($targetService)) {
    $port = $portMap[$targetService]
    $portUsed = Get-NetTCPConnection -LocalPort $port -State Listen -ErrorAction SilentlyContinue
    if ($portUsed) {
        $proc = Get-Process -Id $portUsed.OwningProcess -ErrorAction SilentlyContinue
        Write-Host "  ⚠️ 埠 $port 被佔用: $($proc.Name)"
    }
}

# 嘗試啟動
Write-Host "  嘗試啟動 $targetService..."
try {
    Start-Service -Name $targetService -ErrorAction Stop
    Write-Host "  ✅ 服務啟動成功!"
} catch {
    Write-Host "  ❌ 啟動失敗: $($_.Exception.Message)"
    Write-Host "  → 檢視事件日誌: 模組 14"
}

# 驗證
$verifySvc = Get-Service -Name $targetService
Write-Host "`n[驗證] 服務狀態: $($verifySvc.Status)"

風險等級:🟡 中(需確認,會啟動服務)


27.5 磁碟空間不足修復

修復命令:大檔案識別 + 舊檔案建議 + temp 清理

常你說"磁碟滿了" / "C 盤清理"

📋 展開檢視命令 — 磁碟清理四步流程
Write-Host "════════ 磁碟清理修復嚮導 ════════"

# Step 1: 定位
Write-Host "`n[Step 1] 問題定位..."
$vol = Get-Volume -DriveLetter C
$freeGB = [math]::Round($vol.SizeRemaining/1GB, 1)
$totalGB = [math]::Round($vol.Size/1GB, 1)
$usedPct = [math]::Round((1 - $vol.SizeRemaining/$vol.Size) * 100, 1)
Write-Host "  C 盤: ${freeGB} GB 可用 / ${totalGB} GB 總計 (已用 ${usedPct}%)"

if ($freeGB -gt 10) {
    Write-Host "  ✅ 磁碟空間充足"
    return
}
Write-Host "  ⚠️ 磁碟空間不足"

# Step 2: 預覽
Write-Host "`n[Step 2] 修復預覽"
Write-Host "  將要執行:"
Write-Host "  1. 掃描大檔案(>100MB)"
Write-Host "  2. 掃描舊檔案(>30 天)"
Write-Host "  3. 清理臨時檔案(>7 天)"
Write-Host "  4. 清空回收站"
Write-Host "`n  影響:清理臨時檔案不可恢復,大檔案僅建議不自動刪除"

# Step 3: 確認
$confirm = Read-Host "`n  輸入 '確認修復' 開始執行"
if ($confirm -ne '確認修復') { return }

# Step 4: 執行
Write-Host "`n[Step 4] 執行清理..."

# 清理臨時檔案
$tempPath = $env:TEMP
$cutoff = (Get-Date).AddDays(-7)
$tempFiles = Get-ChildItem -Path $tempPath -Recurse -ErrorAction SilentlyContinue |
    Where-Object { $_.LastWriteTime -lt $cutoff }
$tempKB = ($tempFiles | Measure-Object -Property Length -Sum).Sum
$tempCount = $tempFiles.Count
Write-Host "  清理臨時檔案: $tempCount 個檔案,釋放 $([math]::Round($tempKB/1MB,1)) MB"
foreach ($f in $tempFiles) {
    try { Remove-Item $f.FullName -Force -ErrorAction SilentlyContinue } catch {}
}

# 清空回收站
$shell = New-Object -ComObject Shell.Application
$rb = $shell.NameSpace(0x0a)
$rbItems = @($rb.Items())
if ($rbItems.Count -gt 0) {
    Write-Host "  清空回收站: $($rbItems.Count) 個專案"
    $rbItems | ForEach-Object { Remove-Item $_.Path -Recurse -Force -ErrorAction SilentlyContinue }
}

# 驗證
$volAfter = Get-Volume -DriveLetter C
$freeAfter = [math]::Round($volAfter.SizeRemaining/1GB, 1)
Write-Host "`n[驗證] 清理後 C 盤可用: ${freeAfter} GB(釋放 $([math]::Round($freeAfter - $freeGB, 1)) GB)"

風險等級:🟡 中(需確認,清理臨時檔案不可恢復)


27.6 時間不同步修復

修復命令w32tm /resync

常你說"時間不準" / "時間同步"

📋 展開檢視命令 — 時間同步四步流程
Write-Host "════════ 時間同步修復嚮導 ════════"

# Step 1: 定位
Write-Host "`n[Step 1] 問題定位..."
$localTime = Get-Date
$ntpTime = $null

# 嘗試從 NTP 伺服器獲取時間
try {
    $tcp = New-Object System.Net.Sockets.TcpClient("time.windows.com", 123)
    $stream = $tcp.GetStream()
    $data = New-Object byte[] 48
    $stream.Read($data, 0, 48) | Out-Null
    $stream.Close()
    $tcp.Close()
    # 簡化:直接用 w32tm 查詢
    $ntpTime = (w32tm /stripchart /computer:time.windows.com /samples:1 /dataonly 2>$null | Select-Object -Last 1)
} catch {}

$w32tmStatus = w32tm /query /status 2>$null
if ($w32tmStatus) {
    Write-Host "  Windows Time 服務狀態:"
    $w32tmStatus | Select-Object -First 5 | ForEach-Object { Write-Host "  $_" }
}

# Step 2: 預覽
Write-Host "`n[Step 2] 修復預覽"
Write-Host "  將要執行:"
Write-Host "  1. w32tm /resync           — 強制同步時間"
Write-Host "  2. w32tm /query /status   — 驗證同步結果"
Write-Host "`n  影響:無風險,時間同步不會丟失資料"

# Step 3: 確認
$confirm = Read-Host "`n  輸入 '確認修復' 開始執行"
if ($confirm -ne '確認修復') { return }

# Step 4: 執行
Write-Host "`n[Step 4] 執行時間同步..."
w32tm /resync 2>$null
Start-Sleep -Seconds 2

# 驗證
Write-Host "`n[驗證] 同步結果:"
$verifyTime = w32tm /query /status 2>$null
if ($verifyTime) {
    $verifyTime | Select-Object -First 5 | ForEach-Object { Write-Host "  $_" }
    Write-Host "`n  ✅ 時間同步完成"
} else {
    Write-Host "  ⚠️ 同步狀態未知,稍後重試"
}

風險等級:🟢 低(無風險,僅同步時間)


風險等級彙總

子模組 風險 說明
27.1 DNS 修復 🟡 中 短暫斷網 5-10 秒
27.2 網路修復 🟡 中 短暫斷網 10-30 秒
27.3 WinUpdate 修復 🟡 中 正在進行的更新會中斷
27.4 服務修復 🟡 中 會啟動服務
27.5 磁碟清理 🟡 中 臨時檔案不可恢復
27.6 時間同步 🟢 低 無風險
報錯 含義 解決
Access denied 需要管理員許可權 以管理員身份執行
Service cannot be started 服務啟動失敗 檢查依賴和埠
Network reset failed 網絡卡重置失敗 手動停用/啟用網絡卡
w32tm error 時間服務未執行 啟動 W32Time 服務

常見坑 & 解決

場景 說明
修復後問題依舊 檢視對應診斷模組的詳細日誌
無法建立還原點 系統保護未啟用,不影響修復操作
服務啟動後立即停止 檢查事件日誌,可能是程式崩潰
磁碟清理後空間未增加 可能是系統還原點佔用,清理舊還原點

前置要求與依賴

需求 說明 檢測方法
PowerShell 5.1+ Windows 自帶 $PSVersionTable.PSVersion
管理員許可權 IIS/清理/安全審計需要 自動檢測(見下方)
WebAdministration IIS 管理可選 Install-WindowsFeature Web-Mgmt-Tools
執行策略 可能需調整 Set-ExecutionPolicy RemoteSigned
儲存診斷模組 磁碟健康檢測需要 Get-PhysicalDisk 可用
Winmgmt (WMI) 系統事件/會話監控需要 Get-CimInstance 可用

管理員許可權自動檢測

$isAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
if (-not $isAdmin) {
    Write-Host "⚠️ 非管理員執行,部分功能受限"
    Write-Host "  → 右鍵 PowerShell → 以管理員身份執行"
}


⚡ 效能最佳化(硬體自適應)

設計原則:絕不拖累使用者電腦。 所有掃描/採集任務均根據使用者電腦硬體配置自動調整執行緒數和資源佔用。

自動硬體檢測

檢測項 用途 自適應策略
CPU 核心數 決定並行任務數 ≤4 核:單執行緒;8 核:2 執行緒;16+ 核:4 執行緒
實體記憶體 決定是否啟用記憶體快取 ≤4 GB:停用快取;8 GB:小快取;16+ GB:正常快取
磁碟型別 決定是否啟用 I/O 優先順序 HDD:低優先順序 I/O;SSD:正常優先順序
系統負載 決定是否延遲啟動 CPU >80% 時延遲 5 秒後執行

各模組自適應規則

模組 自適應行為
模組 1(磁碟掃描) 根據 CPU 核心數自動分配掃描執行緒數,HDD 自動降低 I/O 優先順序
模組 2(重複檔案) 大檔案自動分批處理,避免記憶體溢位
模組 3(臨時檔案) 掃描時自動跳過正在使用的檔案
模組 9(效能監控) 採集間隔根據 CPU 負載動態調整(1-5 秒)
模組 12(磁碟健康) 檢測時自動限制併發 I/O,避免影響業務
模組 13(網路監控) 連線數採集分批進行,避免一次性佔用過多資源

效能保護命令示例

# 自動檢測硬體並設定執行緒數
$cpuCores = (Get-CimInstance Win32_Processor).NumberOfLogicalProcessors
$totalRAM = [math]::Round((Get-CimInstance Win32_ComputerSystem).TotalPhysicalMemory/1GB, 1)
$diskType = (Get-PhysicalDisk | Select-Object -First 1).MediaType

$threadCount = switch ($cpuCores) {
    { $_ -le 4 } { 1 }
    { $_ -le 8 } { 2 }
    default { 4 }
}

$ioPriority = if ($diskType -eq 'HDD') { 'Low' } else { 'Normal' }

Write-Host "硬體檢測: $cpuCores 核 CPU, ${totalRAM} GB RAM, 磁碟: $diskType"
Write-Host "自動設定: $threadCount 執行緒, I/O 優先順序: $ioPriority"

❓ 常見問題

Q1: 第一次使用怎麼做?

直接說 "幫我掃一下 C 盤""檢查服務狀態"

Q2: 英文報錯看不懂怎麼辦?

貼上報錯內容,AI 會翻譯並給出解法。每個模組也有"報錯與解決"表格。

Q3: 會不會刪壞系統?

三層保護:系統目錄不可操作、刪除前先確認、回收站 API 可恢復。

Q4: 要聯網或付費嗎?

全程離線、零依賴、零費用。

Q5: Windows Update 清理會不會影響已安裝的補丁?

不會。只清理未完成的下載快取,已安裝補丁不受影響。重新檢查更新時會重新下載。

Q6: 效能監控的資料能保留多久?

即時計數器只顯示當前值。如需長期趨勢,可讓 AI 建立資料收集器(需確認),資料會儲存到 C:\PerfLogs

Q7: 安全審計會被攻擊者發現嗎?

只讀審計和匯出操作不會產生額外日誌。但效能計數器採集會佔用少量系統資源。

Q8: 登錄檔審計會不會誤刪系統關鍵項?

不會。模組 11 所有操作均為只讀分析,絕不修改任何登錄檔鍵值。

Q9: 磁碟健康檢測會損傷磁碟嗎?

不會。SMART 資訊和錯誤計數均為只讀讀取,不會執行磁碟擦除或修復操作。

Q10: 網路連線監控會不會洩露隱私?

不會。所有檢測均在本地進行,不會將任何連線資訊傳送到外部。

Q11: 事件日誌會清除或修改嗎?

不會。模組 14 僅讀取日誌內容,不會清除、修改或停止日誌服務。

Q12: 軟體清單會篡改解除安裝程式嗎?

不會。模組 15 僅讀取登錄檔解除安裝鍵值,不會修改任何安裝資訊或解除安裝程式。

Q13: 會話監控會踢出使用者嗎?

不會。模組 16 僅讀取會話資訊,不會結束、鎖定或斷開任何使用者會話。

Q14: 怎麼升級 winskill?

skillhub upgrade winskill

Q15: 計劃任務審計會刪除任務嗎?

不會。模組 17 所有操作均為只讀審計,絕不會建立/刪除/修改任何計劃任務。

Q16: 檔案共享審計會斷開連線嗎?

不會。模組 18 僅讀取共享配置和 SMB 會話資訊,不會關閉共享或斷開任何使用者連線。

Q17: DNS 快取清空會斷網嗎?

不會。Clear-DnsClientCache 清空後會自動從 DNS 伺服器重新獲取解析記錄。只在使用者明確說「確認清空 DNS 快取」後才執行。

Q18: SSL 證書檢測會申請或修改證書嗎?

不會。模組 20 僅讀取證書倉庫和 IIS 繫結資訊,不會申請、續簽或刪除任何證書。

Q19: 防火牆規則審計會改動規則嗎?

不會。模組 21 僅讀取規則配置,不會新增、刪除或修改任何防火牆規則。

Q20: 服務崩潰檢查會重啟服務嗎?

不會。模組 22 僅讀取服務狀態和事件日誌,不會啟動、停止或修改任何服務配置。

Q23: SFC 和 DISM 有什麼區別?

SFC 修復單個系統檔案,DISM 修復元件儲存(SFC 的源)。建議先 DISM 修復元件儲存,再 SFC 修復系統檔案。

Q24: 儲存池的 RAID 型別如何選擇?

Mirror(映象)提供冗餘,Parity(奇偶校驗)提供更高儲存效率。生產環境推薦 Mirror。

Q25: 備份失敗了怎麼查原因?

檢查 Windows 事件檢視器 → Applications and Services Logs → Microsoft → Windows → Backup → Operational。

Q26: Docker 功能需要額外安裝嗎?

模組 26 使用 Windows 系統自帶的 dockerkubectl 命令列工具。Windows Server 2016+ 支援 Docker,但需要手動安裝。未安裝 Docker/kubectl 時模組 26 給出安裝指引,不會報錯。

Q27: 效能基線採集會不會拖慢伺服器?

不會。模組 28 根據 CPU 核心數動態調整採集頻率(≤4 核每 15 分鐘一次,>4 核每 5 分鐘一次),單次採集耗時 <1 秒,記憶體佔用 <10MB。

Q28: 合規檢查會修改系統配置嗎?

不會。模組 29 所有檢查項均為只讀檢測,僅輸出合規/不合規判定和修復建議,不會修改任何系統配置。

Q29: 遠端管理需要開啟 WinRM 服務嗎?

是的。模組 30 基於 PowerShell Remoting(WinRM),目標伺服器需要開啟 WinRM 服務(Enable-PSRemoting)。模組 30.1 包含一鍵開啟 WinRM 的命令。

Q30: 遠端管理支援非域環境嗎?

支援。模組 30 支援域環境和非域環境,非域環境需配置 TrustedHosts 並使用 IP 地址連線。


🆕 模組 28:效能基線 & 趨勢分析

⚠️ 本模組所有操作均為只讀分析,不會修改任何系統配置。

📋 展開檢視:模組 28:效能基線 & 趨勢分析 ### 28.1 效能基線建立(7 天採集) **硬體自適應策略**:根據 CPU 核心數動態調整採集頻率,避免拖累低配伺服器。
# 硬體自適應:確定採集間隔
$cpuCores = (Get-CimInstance Win32_Processor).NumberOfLogicalProcessors
$intervalMinutes = if ($cpuCores -le 4) { 15 } else { 5 }
$tagFile = "$env:USERPROFILE\.workbuddy\output\winskill\baseline_tag.txt"
$csvFile = "$env:USERPROFILE\.workbuddy\output\winskill\perf_baseline.csv"

# 建立輸出目錄
New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\.workbuddy\output\winskill" | Out-Null

# 檢查是否已註冊定時任務
$taskName = "Winskill_PerfBaseline"
$existingTask = Get-ScheduledTask -TaskName $taskName -ErrorAction SilentlyContinue

if (-not $existingTask) {
    # 註冊定時任務(需管理員許可權)
    $action = New-ScheduledTaskAction -Execute "powershell.exe" -Argument @"
-Command "& {`$csv='$csvFile'; `$cpu=(Get-CimInstance Win32_Processor).LoadPercentage; `$mem=(Get-CimInstance Win32_OperatingSystem); `$memPct=[math]::Round(($mem.TotalVisibleMemorySize - `$mem.FreePhysicalMemory)/`$mem.TotalVisibleMemorySize*100,1); `$disk=(Get-CimInstance Win32_LogicalDisk -Filter 'DriveType=3' | Where-Object DeviceID -eq 'C:'); `$diskPct=[math]::Round((`$disk.Size-`$disk.FreeSpace)/`$disk.Size*100,1); `$net=(Get-CimInstance Win32_PerfFormattedData_Tcpip_NetworkInterface | Where-Object Name -notlike '*Loopback*' | Measure-Object BytesTotalPersec -Sum).Sum; `$ts=Get-Date -Format 'yyyy-MM-dd HH:mm:ss'; if(-not(Test-Path `$csv)){'Timestamp,CPU_Pct,Mem_Pct,Disk_Pct,Net_BytesPerSec' | Out-File `$csv -Encoding utf8}; '`$ts,`$cpu,`$memPct,`$diskPct,`$net' | Out-File `$csv -Append -Encoding utf8}"
'@
    $trigger = New-ScheduledTaskTrigger -Once -At (Get-Date) -RepetitionInterval (New-TimeSpan -Minutes $intervalMinutes) -RepetitionDuration (New-TimeSpan -Days 7)
    Register-ScheduledTask -TaskName $taskName -Action $action -Trigger $trigger -Description "Winskill 效能基線採集(7 天)" -Force
    Write-Host "✅ 已註冊定時任務 '$taskName',每 $intervalMinutes 分鐘採集一次,持續 7 天"
} else {
    Write-Host "⚠️ 定時任務 '$taskName' 已存在,無需重複註冊"
}

# 顯示當前基線狀態
if (Test-Path $csvFile) {
    $data = Import-Csv $csvFile
    Write-Host "`n📊 當前基線資料:$($data.Count) 條記錄"
    Write-Host "CPU 基線:$(($data | Measure-Object CPU_Pct -Average).Average)%(均值)"
    Write-Host "記憶體 基線:$(($data | Measure-Object Mem_Pct -Average).Average)%(均值)"
    Write-Host "磁碟 基線:$(($data | Measure-Object Disk_Pct -Average).Average)%(均值)"
} else {
    Write-Host "📋 尚未開始採集,註冊定時任務後自動開始"
}
### 28.2 異常偏離告警(當前值 vs 基線)
$csvFile = "$env:USERPROFILE\.workbuddy\output\winskill\perf_baseline.csv"
$thresholdMultiplier = 2.0  # 偏離基線 200% 觸發告警

if (-not (Test-Path $csvFile)) {
    Write-Host "❌ 尚未建立基線,請先執行 28.1 建立基線"
    exit 1
}

$data = Import-Csv $csvFile
if ($data.Count -lt 10) {
    Write-Host "⚠️ 基線資料不足($($data.Count) 條),建議至少採集 10 條後再分析"
}

# 計算基線均值
$cpuAvg = ($data | Measure-Object CPU_Pct -Average).Average
$memAvg = ($data | Measure-Object Mem_Pct -Average).Average
$diskAvg = ($data | Measure-Object Disk_Pct -Average).Average

# 獲取當前值
$cpuNow = (Get-CimInstance Win32_Processor).LoadPercentage
$mem = (Get-CimInstance Win32_OperatingSystem)
$memNow = [math]::Round(($mem.TotalVisibleMemorySize - $mem.FreePhysicalMemory) / $mem.TotalVisibleMemorySize * 100, 1)
$disk = (Get-CimInstance Win32_LogicalDisk -Filter "DriveType=3" | Where-Object DeviceID -eq 'C:')
$diskNow = [math]::Round(($disk.Size - $disk.FreeSpace) / $disk.Size * 100, 1)

Write-Host "`n📊 偏離分析報告"
Write-Host ("=" * 50)
Write-Host ("指標     當前值    基線均值    偏離倍數    狀態")
Write-Host ("-" * 50)

$alerts = @()

$cpuDev = if ($cpuAvg -gt 0) { $cpuNow / $cpuAvg } else { 0 }
$status = if ($cpuDev -ge $thresholdMultiplier) { "🚨 告警" } elseif ($cpuDev -ge 1.5) { "⚠️ 警告" } else { "✅ 正常" }
Write-Host ("CPU      {0,6}%    {1,6}%    {2,6:F1}x      {3}" -f $cpuNow, $cpuAvg, $cpuDev, $status)
if ($cpuDev -ge $thresholdMultiplier) { $alerts += "CPU 使用率偏離基線 ${cpuDev:F1} 倍(當前 $cpuNow%,基線 $cpuAvg%)" }

$memDev = if ($memAvg -gt 0) { $memNow / $memAvg } else { 0 }
$status = if ($memDev -ge $thresholdMultiplier) { "🚨 告警" } elseif ($memDev -ge 1.5) { "⚠️ 警告" } else { "✅ 正常" }
Write-Host ("記憶體     {0,6}%    {1,6}%    {2,6:F1}x      {3}" -f $memNow, $memAvg, $memDev, $status)
if ($memDev -ge $thresholdMultiplier) { $alerts += "記憶體使用率偏離基線 ${memDev:F1} 倍(當前 $memNow%,基線 $memAvg%)" }

$diskDev = if ($diskAvg -gt 0) { $diskNow / $diskAvg } else { 0 }
$status = if ($diskDev -ge 1.3) { "🚨 告警" } elseif ($diskDev -ge 1.1) { "⚠️ 警告" } else { "✅ 正常" }
Write-Host ("磁碟     {0,6}%    {1,6}%    {2,6:F1}x      {3}" -f $diskNow, $diskAvg, $diskDev, $status)
if ($diskDev -ge 1.3) { $alerts += "磁碟使用率偏離基線 ${diskDev:F1} 倍(當前 $diskNow%,基線 $diskAvg%)" }

Write-Host ("=" * 50)

if ($alerts.Count -eq 0) {
    Write-Host "`n✅ 所有指標正常,無異常偏離"
} else {
    Write-Host "`n🚨 發現 $($alerts.Count) 項異常偏離:"
    $alerts | ForEach-Object { Write-Host "  ⚠️ $_" }
}
### 28.3 趨勢預測(磁碟耗盡時間)
$csvFile = "$env:USERPROFILE\.workbuddy\output\winskill\perf_baseline.csv"

if (-not (Test-Path $csvFile)) {
    Write-Host "❌ 尚未建立基線,請先執行 28.1 建立基線"
    exit 1
}

$data = Import-Csv $csvFile
if ($data.Count -lt 5) {
    Write-Host "⚠️ 資料不足($($data.Count) 條),無法預測"
    exit 1
}

# 簡單線性迴歸預測磁碟耗盡時間
$diskValues = $data | ForEach-Object { [double]$_.Disk_Pct }
$n = $diskValues.Count

# 計算斜率(每天增長百分比)
$sumX = ($n - 1) * $n / 2
$sumY = ($diskValues | Measure-Object -Sum).Sum
$sumXY = 0
$sumX2 = 0
for ($i = 0; $i -lt $n; $i++) {
    $sumXY += $i * $diskValues[$i]
    $sumX2 += $i * $i
}
$slope = ($n * $sumXY - $sumX * $sumY) / ($n * $sumX2 - $sumX * $sumX)

$currentDisk = $diskValues[-1]

Write-Host "`n📈 趨勢預測報告"
Write-Host ("=" * 50)
Write-Host ("當前磁碟使用率:{0}%" -f $currentDisk)

if ($slope -le 0) {
    Write-Host ("趨勢:磁碟使用率穩定或下降(斜率 {0:F4}%/採集週期)" -f $slope)
    Write-Host "✅ 磁碟空間充足,無需擔心"
} else {
    # 估算耗盡時間(基於採集間隔)
    $cpuCores = (Get-CimInstance Win32_Processor).NumberOfLogicalProcessors
    $intervalMinutes = if ($cpuCores -le 4) { 15 } else { 5 }
    $periodsPerDay = 24 * 60 / $intervalMinutes
    $daysToFull = (100 - $currentDisk) / ($slope * $periodsPerDay)

    Write-Host ("增長速率:{0:F4}%/採集週期(約 {1:F2}%/天)" -f $slope, ($slope * $periodsPerDay))

    if ($daysToFull -gt 365) {
        Write-Host ("預計耗盡時間:> 1 年(約 {0:F0} 天)" -f $daysToFull)
        Write-Host "✅ 磁碟空間充足"
    } elseif ($daysToFull -gt 30) {
        Write-Host ("預計耗盡時間:約 {0:F0} 天({1:F1} 個月)" -f $daysToFull, ($daysToFull / 30))
        Write-Host "⚠️ 建議關注磁碟使用趨勢"
    } elseif ($daysToFull -gt 7) {
        Write-Host ("預計耗盡時間:約 {0:F0} 天" -f $daysToFull)
        Write-Host "🚨 建議儘快清理磁碟空間"
    } else {
        Write-Host ("預計耗盡時間:約 {0:F0} 天" -f $daysToFull)
        Write-Host "🔴 磁碟即將耗盡!請立即清理"
    }
}

# 記憶體趨勢預測
$memValues = $data | ForEach-Object { [double]$_.Mem_Pct }
$sumY = ($memValues | Measure-Object -Sum).Sum
$sumXY = 0
for ($i = 0; $i -lt $n; $i++) {
    $sumXY += $i * $memValues[$i]
}
$slope = ($n * $sumXY - $sumX * $sumY) / ($n * $sumX2 - $sumX * $sumX)
$currentMem = $memValues[-1]

Write-Host ("`n當前記憶體使用率:{0}%" -f $currentMem)
if ($slope -le 0) {
    Write-Host "趨勢:記憶體使用率穩定或下降 ✅"
} else {
    $periodsPerDay = 24 * 60 / $intervalMinutes
    $daysToFull = (95 - $currentMem) / ($slope * $periodsPerDay)  # 95% 作為預警線
    if ($daysToFull -gt 30) {
        Write-Host ("增長速率:{0:F4}%/採集週期 ✅ 記憶體充足" -f $slope)
    } elseif ($daysToFull -gt 0) {
        Write-Host ("增長速率:{0:F4}%/採集週期 ⚠️ 約 {1:F0} 天后達到 95%" -f $slope, $daysToFull)
    } else {
        Write-Host "🔴 記憶體使用率持續上升,建議排查記憶體洩漏"
    }
}
Write-Host ("=" * 50)
### 28.4 效能瓶頸關聯分析
Write-Host "`n🔍 效能瓶頸關聯分析"
Write-Host ("=" * 60)

# 採集四維指標
$cpu = (Get-CimInstance Win32_Processor).LoadPercentage
$mem = (Get-CimInstance Win32_OperatingSystem)
$memPct = [math]::Round(($mem.TotalVisibleMemorySize - $mem.FreePhysicalMemory) / $mem.TotalVisibleMemorySize * 100, 1)
$disk = Get-CimInstance Win32_PerfFormattedData_PerfDisk_PhysicalDisk | Where-Object Name -eq "_Total"
$diskPct = [math]::Round($disk.PercentDiskTime, 1)
$net = Get-CimInstance Win32_PerfFormattedData_Tcpip_NetworkInterface | Where-Object Name -notlike '*Loopback*'
$netPct = [math]::Round(($net | Measure-Object BytesTotalPersec -Sum).Sum / 1MB, 1)  # MB/s

Write-Host ("CPU 使用率:    {0,6}%" -f $cpu)
Write-Host ("記憶體使用率:    {0,6}%" -f $memPct)
Write-Host ("磁碟活動時間:  {0,6}%" -f $diskPct)
Write-Host ("網路流量:      {0,6} MB/s" -f $netPct)
Write-Host ("-" * 60)

# 瓶頸判定邏輯
$bottleneck = $null
$severity = "正常"

if ($cpu -ge 90 -and $memPct -ge 85) {
    $bottleneck = "CPU + 記憶體雙重瓶頸"
    $severity = "🔴 嚴重"
} elseif ($diskPct -ge 90 -and $memPct -ge 85) {
    $bottleneck = "磁碟 I/O + 記憶體雙重瓶頸(可能存在記憶體交換)"
    $severity = "🔴 嚴重"
} elseif ($cpu -ge 90) {
    $bottleneck = "CPU 瓶頸"
    $severity = "🚨 高"
} elseif ($memPct -ge 90) {
    $bottleneck = "記憶體瓶頸"
    $severity = "🚨 高"
} elseif ($diskPct -ge 90) {
    $bottleneck = "磁碟 I/O 瓶頸"
    $severity = "🚨 高"
} elseif ($cpu -ge 70 -and $memPct -ge 70) {
    $bottleneck = "CPU + 記憶體輕度壓力"
    $severity = "⚠️ 中"
} elseif ($diskPct -ge 70 -and $memPct -ge 70) {
    $bottleneck = "磁碟 + 記憶體輕度壓力"
    $severity = "⚠️ 中"
} elseif ($cpu -ge 70) {
    $bottleneck = "CPU 輕度壓力"
    $severity = "⚠️ 中"
} elseif ($memPct -ge 70) {
    $bottleneck = "記憶體輕度壓力"
    $severity = "⚠️ 中"
} elseif ($diskPct -ge 70) {
    $bottleneck = "磁碟 I/O 輕度壓力"
    $severity = "⚠️ 中"
}

if ($bottleneck) {
    Write-Host ("瓶頸判定:{0}({1})" -f $bottleneck, $severity)
} else {
    Write-Host "✅ 系統執行正常,無明顯瓶頸"
}

# 關聯分析建議
Write-Host ("-" * 60)
Write-Host "關聯分析:"

if ($memPct -ge 85 -and $diskPct -ge 80) {
    Write-Host "  ⚠️ 記憶體高 + 磁碟 I/O 高 → 可能發生記憶體交換(頁面檔案頻繁讀寫)"
    Write-Host "  建議:檢查記憶體佔用 Top 程序(模組 9.2),考慮增加實體記憶體"
}

if ($cpu -ge 80 -and $diskPct -ge 80) {
    Write-Host "  ⚠️ CPU 高 + 磁碟 I/O 高 → 可能在進行大量檔案操作或資料庫查詢"
    Write-Host "  建議:檢查磁碟 I/O 程序(模組 9.3),定位高 I/O 來源"
}

if ($netPct -gt 100 -and $cpu -ge 70) {
    Write-Host "  ⚠️ 網路流量大 + CPU 高 → 可能受到 DDoS 攻擊或大量資料傳輸"
    Write-Host "  建議:檢查網路連線(模組 13.1),排查可疑外連(模組 13.3)"
}

if ($cpu -lt 50 -and $memPct -lt 50 -and $diskPct -lt 50) {
    Write-Host "  ✅ 四維指標均正常,系統健康"
}

Write-Host ("=" * 60)
### 報錯與解決 | 報錯 | 原因 | 解決 | |------|------|------| | `Register-ScheduledTask 拒絕訪問` | 需要管理員許可權 | 以管理員身份執行 PowerShell | | `無法載入檔案,因為在此係統上禁止執行指令碼` | 執行策略限制 | `Set-ExecutionPolicy RemoteSigned -Scope CurrentUser` | | `基線資料不足` | 採集時間太短 | 等待至少 10 個採集週期後再分析 | | `Get-CimInstance 找不到類` | WMI 服務異常 | 執行 `winmgmt /resetrepository` |

↑ 返回頂部


🆕 模組 29:安全合規檢查清單

⚠️ 本模組所有操作均為只讀檢測,不會修改任何系統配置。

📋 展開檢視:模組 29:安全合規檢查清單 ### 29.1 等保 2.0 檢查項
Write-Host "`n📋 等保 2.0 合規檢查報告"
Write-Host ("=" * 60)
Write-Host ("檢查時間:{0:yyyy-MM-dd HH:mm:ss}" -f (Get-Date))
Write-Host ("計算機名:$env:COMPUTERNAME")
Write-Host ("=" * 60)

$results = @()

# 1. 密碼策略
Write-Host "`n【1. 密碼策略】"
$pwdPolicy = net accounts | Out-String
$minPwdLen = if ($pwdPolicy -match 'Minimum password length\s+(\d+)') { $matches[1] } else { "0" }
$maxPwdAge = if ($pwdPolicy -match 'Maximum password age \(days\)\s+(\d+|Unlimited)') { $matches[1] } else { "Unknown" }
$minPwdAge = if ($pwdPolicy -match 'Minimum password age \(days\)\s+(\d+)') { $matches[1] } else { "0" }
$pwdHistory = if ($pwdPolicy -match 'Password history length\s+(\d+)') { $matches[1] } else { "0" }

$pass = [int]$minPwdLen -ge 8
$results += [PSCustomObject]@{ Category = "密碼策略"; Item = "密碼最小長度≥8"; Status = if ($pass) { "✅ 合規" } else { "❌ 不合規" }; Detail = "當前值:$minPwdLen" }
Write-Host ("  密碼最小長度≥8:{0}(當前:{1})" -f $(if ($pass) { "✅" } else { "❌" }), $minPwdLen)

$pass = $maxPwdAge -ne "Unlimited" -and [int]$maxPwdAge -le 90
$results += [PSCustomObject]@{ Category = "密碼策略"; Item = "密碼最長使用期限≤90天"; Status = if ($pass) { "✅ 合規" } else { "❌ 不合規" }; Detail = "當前值:$maxPwdAge" }
Write-Host ("  密碼最長使用期限≤90天:{0}(當前:{1})" -f $(if ($pass) { "✅" } else { "❌" }), $maxPwdAge)

$pass = [int]$pwdHistory -ge 5
$results += [PSCustomObject]@{ Category = "密碼策略"; Item = "密碼歷史記錄≥5"; Status = if ($pass) { "✅ 合規" } else { "❌ 不合規" }; Detail = "當前值:$pwdHistory" }
Write-Host ("  密碼歷史記錄≥5:{0}(當前:{1})" -f $(if ($pass) { "✅" } else { "❌" }), $pwdHistory)

# 2. 賬戶鎖定策略
Write-Host "`n【2. 賬戶鎖定策略】"
$lockoutThreshold = if ($pwdPolicy -match 'Lockout threshold\s+(\d+|Never)') { $matches[1] } else { "Unknown" }
$lockoutDuration = if ($pwdPolicy -match 'Lockout duration \(minutes\)\s+(\d+|Never)') { $matches[1] } else { "Unknown" }
$lockoutWindow = if ($pwdPolicy -match 'Lockout observation window \(minutes\)\s+(\d+|Never)') { $matches[1] } else { "Unknown" }

$pass = $lockoutThreshold -ne "Never" -and [int]$lockoutThreshold -le 5
$results += [PSCustomObject]@{ Category = "賬戶鎖定"; Item = "鎖定閾值≤5次"; Status = if ($pass) { "✅ 合規" } else { "❌ 不合規" }; Detail = "當前值:$lockoutThreshold" }
Write-Host ("  鎖定閾值≤5次:{0}(當前:{1})" -f $(if ($pass) { "✅" } else { "❌" }), $lockoutThreshold)

$pass = $lockoutDuration -ne "Never" -and [int]$lockoutDuration -ge 15
$results += [PSCustomObject]@{ Category = "賬戶鎖定"; Item = "鎖定時間≥15分鐘"; Status = if ($pass) { "✅ 合規" } else { "❌ 不合規" }; Detail = "當前值:$lockoutDuration" }
Write-Host ("  鎖定時間≥15分鐘:{0}(當前:{1})" -f $(if ($pass) { "✅" } else { "❌" }), $lockoutDuration)

# 3. 審計日誌策略
Write-Host "`n【3. 審計日誌策略】"
$auditPolicy = auditpol /get /category:* 2>$null | Out-String
$logonEvents = if ($auditPolicy -match 'Logon\s+Success and Failure') { "Success and Failure" } elseif ($auditPolicy -match 'Logon\s+(\w+)') { $matches[1] } else { "Not Configured" }
$objectAccess = if ($auditPolicy -match 'Object Access\s+Success and Failure') { "Success and Failure" } elseif ($auditPolicy -match 'Object Access\s+(\w+)') { $matches[1] } else { "Not Configured" }
$privilegeUse = if ($auditPolicy -match 'Privilege Use\s+Success and Failure') { "Success and Failure" } elseif ($auditPolicy -match 'Privilege Use\s+(\w+)') { $matches[1] } else { "Not Configured" }

$pass = $logonEvents -eq "Success and Failure"
$results += [PSCustomObject]@{ Category = "審計日誌"; Item = "登入事件審計(成功+失敗)"; Status = if ($pass) { "✅ 合規" } else { "❌ 不合規" }; Detail = "當前值:$logonEvents" }
Write-Host ("  登入事件審計:{0}(當前:{1})" -f $(if ($pass) { "✅" } else { "❌" }), $logonEvents)

$pass = $objectAccess -eq "Success and Failure"
$results += [PSCustomObject]@{ Category = "審計日誌"; Item = "物件訪問審計(成功+失敗)"; Status = if ($pass) { "✅ 合規" } else { "❌ 不合規" }; Detail = "當前值:$objectAccess" }
Write-Host ("  物件訪問審計:{0}(當前:{1})" -f $(if ($pass) { "✅" } else { "❌" }), $objectAccess)

# 4. 防火牆狀態
Write-Host "`n【4. 防火牆狀態】"
$firewallProfiles = Get-NetFirewallProfile
$allEnabled = ($firewallProfiles | Where-Object Enabled -eq $false).Count -eq 0
$results += [PSCustomObject]@{ Category = "防火牆"; Item = "所有配置檔案已啟用防火牆"; Status = if ($allEnabled) { "✅ 合規" } else { "❌ 不合規" }; Detail = "已啟用:$(($firewallProfiles | Where-Object Enabled).Count)/3" }
Write-Host ("  防火牆全部啟用:{0}(已啟用 {1}/3)" -f $(if ($allEnabled) { "✅" } else { "❌" }), (($firewallProfiles | Where-Object Enabled).Count))

# 5. 補丁更新狀態
Write-Host "`n【5. 補丁更新狀態】"
$hotfixes = Get-HotFix | Sort-Object InstalledOn -Descending
$pass = $false
if ($hotfixes.Count -gt 0) {
    $lastUpdate = $hotfixes[0].InstalledOn
    $daysSinceUpdate = ((Get-Date) - $lastUpdate).Days
    $pass = $daysSinceUpdate -le 30
} else {
    $lastUpdate = "無記錄"
    $daysSinceUpdate = 9999
    $pass = $false
}
$results += [PSCustomObject]@{ Category = "補丁更新"; Item = "最近 30 天內有補丁更新"; Status = if ($pass) { "✅ 合規" } else { "❌ 不合規" }; Detail = "最後更新:$lastUpdate($($daysSinceUpdate.Days) 天前)" }
Write-Host ("  最近 30 天有補丁:{0}(最後:{1:yyyy-MM-dd},{2} 天前)" -f $(if ($pass) { "✅" } else { "❌" }), $lastUpdate, $daysSinceUpdate.Days)

# 6. 遠端桌面安全
Write-Host "`n【6. 遠端桌面安全】"
$rdpEnabled = (Get-ItemProperty -Path 'HKLM:\System\CurrentControlSet\Control\Terminal Server' -Name fDenyTSConnections -ErrorAction SilentlyContinue).fDenyTSConnections
$rdpStatus = if ($rdpEnabled -eq 0) { "已啟用" } else { "已停用" }
$nlaEnabled = (Get-ItemProperty -Path 'HKLM:\System\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp' -Name UserAuthentication -Error Action SilentlyContinue).UserAuthentication
$nlaStatus = if ($nlaEnabled -eq 1) { "已啟用" } else { "未啟用" }

$pass = $rdpEnabled -ne 0 -or $nlaEnabled -eq 1  # 如果 RDP 啟用,必須啟用 NLA
$results += [PSCustomObject]@{ Category = "遠端桌面"; Item = "RDP 網路級身份驗證(NLA)"; Status = if ($pass) { "✅ 合規" } else { "❌ 不合規" }; Detail = "RDP:$rdpStatus,NLA:$nlaStatus" }
Write-Host ("  NLA 已啟用:{0}(RDP:{1},NLA:{2})" -f $(if ($pass) { "✅" } else { "❌" }), $rdpStatus, $nlaStatus)

# 彙總
$compliant = ($results | Where-Object Status -like "✅*").Count
$nonCompliant = ($results | Where-Object Status -like "❌*").Count
$total = $results.Count
$rate = [math]::Round($compliant / $total * 100, 1)

Write-Host ("`n" + "=" * 60)
Write-Host ("📊 合規彙總:{0}/{1} 項合規(合規率 {2}%)" -f $compliant, $total, $rate)
Write-Host ("✅ 合規:$compliant 項")
Write-Host ("❌ 不合規:$nonCompliant 項")
Write-Host ("=" * 60)

if ($nonCompliant -gt 0) {
    Write-Host "`n❌ 不合規項詳情:"
    $results | Where-Object Status -like "❌*" | ForEach-Object {
        Write-Host ("  [{0}] {1}:{2}" -f $_.Category, $_.Item, $_.Detail)
    }
}
### 29.2 CIS Benchmark 檢查(精選關鍵控制項)
Write-Host "`n🔒 CIS Benchmark 檢查(Windows Server 精選)"
Write-Host ("=" * 60)

$cisResults = @()

# CIS 1.1.1 - 密碼最小長度(CIS 要求 14)
Write-Host "`n【密碼策略】"
$minLen = (net accounts | Select-String 'Minimum password length').ToString() -replace '.*?\s+(\d+).*','$1'
$pass = [int]$minLen -ge 14
$cisResults += [PSCustomObject]@{ Control = "1.1.1"; Item = "密碼最小長度≥14"; Status = if ($pass) { "✅" } else { "❌" }; Detail = "當前:$minLen" }
Write-Host ("  1.1.1 密碼最小長度≥14:{0}(當前:{1})" -f $(if ($pass) { "✅" } else { "❌" }), $minLen)

# CIS 1.1.2 - 密碼複雜度
$complexity = (Get-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\Lsa' -Name PasswordComplexity -ErrorAction SilentlyContinue).PasswordComplexity
$pass = $complexity -eq 1
$cisResults += [PSCustomObject]@{ Control = "1.1.2"; Item = "密碼複雜度已啟用"; Status = if ($pass) { "✅" } else { "❌" }; Detail = "當前:$(if ($complexity -eq 1) { '已啟用' } else { '未啟用' })" }
Write-Host ("  1.1.2 密碼複雜度:{0}" -f $(if ($pass) { "✅" } else { "❌" }))

# CIS 2.2.1 - 禁止 Guest 賬戶
Write-Host "`n【賬戶策略】"
$guestAccount = Get-LocalUser -Name "Guest" -ErrorAction SilentlyContinue
$pass = $guestAccount -and $guestAccount.Enabled -eq $false
$cisResults += [PSCustomObject]@{ Control = "2.2.1"; Item = "Guest 賬戶已停用"; Status = if ($pass) { "✅" } else { "❌" }; Detail = "當前:$(if ($guestAccount.Enabled -eq $false) { '已停用' } else { '已啟用' })" }
Write-Host ("  2.2.1 Guest 已停用:{0}" -f $(if ($pass) { "✅" } else { "❌" }))

# CIS 2.3.1.1 - 限制空密碼登入
$limitBlank = (Get-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\Lsa' -Name LimitBlankPasswordUse -ErrorAction SilentlyContinue).LimitBlankPasswordUse
$pass = $limitBlank -eq 1
$cisResults += [PSCustomObject]@{ Control = "2.3.1.1"; Item = "限制空密碼登入"; Status = if ($pass) { "✅" } else { "❌" }; Detail = "當前:$(if ($limitBlank -eq 1) { '已限制' } else { '未限制' })" }
Write-Host ("  2.3.1.1 空密碼限制:{0}" -f $(if ($pass) { "✅" } else { "❌" }))

# CIS 5.1 - Windows Update 服務
Write-Host "`n【系統服務】"
$wuService = Get-Service -Name wuauserv -ErrorAction SilentlyContinue
$pass = $wuService -and $wuService.Status -eq "Running"
$cisResults += [PSCustomObject]@{ Control = "5.1"; Item = "Windows Update 服務執行中"; Status = if ($pass) { "✅" } else { "❌" }; Detail = "當前:$($wuService.Status)" }
Write-Host ("  5.1 Windows Update:{0}({1})" -f $(if ($pass) { "✅" } else { "❌" }), $wuService.Status)

# CIS 9.1 - Windows Firewall
Write-Host "`n【防火牆】"
$fwProfiles = Get-NetFirewallProfile
$allEnabled = ($fwProfiles | Where-Object Enabled -eq $false).Count -eq 0
$cisResults += [PSCustomObject]@{ Control = "9.1"; Item = "所有防火牆配置檔案已啟用"; Status = if ($allEnabled) { "✅" } else { "❌" }; Detail = "已啟用:$(($fwProfiles | Where-Object Enabled).Count)/3" }
Write-Host ("  9.1 防火牆全部啟用:{0}" -f $(if ($allEnabled) { "✅" } else { "❌" }))

# CIS 17.1 - 審計策略
Write-Host "`n【審計策略】"
$auditPolicy = auditpol /get /category:* 2>$null | Out-String
$securityLogon = if ($auditPolicy -match 'Logon\s+Success and Failure') { $true } else { $false }
$cisResults += [PSCustomObject]@{ Control = "17.1"; Item = "登入事件審計(成功+失敗)"; Status = if ($securityLogon) { "✅" } else { "❌" }; Detail = "當前:$(if ($securityLogon) { '已配置' } else { '未配置' })" }
Write-Host ("  17.1 登入審計:{0}" -f $(if ($securityLogon) { "✅" } else { "❌" }))

# 彙總
$compliant = ($cisResults | Where-Object Status -eq "✅").Count
$nonCompliant = ($cisResults | Where-Object Status -eq "❌").Count
$total = $cisResults.Count
$rate = [math]::Round($compliant / $total * 100, 1)

Write-Host ("`n" + "=" * 60)
Write-Host ("📊 CIS 彙總:{0}/{1} 項合規(合規率 {2}%)" -f $compliant, $total, $rate)
Write-Host ("=" * 60)
### 29.3 合規報告生成(Markdown 文本)
# 生成 Markdown 格式合規報告(純文本,可複製儲存為 .md 檔案)
$reportTime = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$reportName = "合規檢查報告_$env:COMPUTERNAME`_$(Get-Date -Format 'yyyyMMdd_HHmmss')"

$report = @"
# Windows Server 合規檢查報告

| 專案 | 內容 |
|------|------|
| 計算機名 | $env:COMPUTERNAME |
| 檢查時間 | $reportTime |
| 作業系統 | $((Get-CimInstance Win32_OperatingSystem).Caption) |
| 版本 | $((Get-CimInstance Win32_OperatingSystem).Version) |

## 等保 2.0 檢查結果

| 類別 | 檢查項 | 狀態 | 詳情 |
|------|--------|------|------|
| 密碼策略 | 密碼最小長度≥8 | 待檢查 | - |
| 密碼策略 | 密碼最長使用期限≤90天 | 待檢查 | - |
| 密碼策略 | 密碼歷史記錄≥5 | 待檢查 | - |
| 賬戶鎖定 | 鎖定閾值≤5次 | 待檢查 | - |
| 賬戶鎖定 | 鎖定時間≥15分鐘 | 待檢查 | - |
| 審計日誌 | 登入事件審計(成功+失敗) | 待檢查 | - |
| 審計日誌 | 物件訪問審計(成功+失敗) | 待檢查 | - |
| 防火牆 | 所有配置檔案已啟用 | 待檢查 | - |
| 補丁更新 | 最近 30 天內有補丁更新 | 待檢查 | - |
| 遠端桌面 | RDP 網路級身份驗證(NLA) | 待檢查 | - |

## CIS Benchmark 檢查結果

| 控制項 | 檢查內容 | 狀態 | 詳情 |
|--------|----------|------|------|
| 1.1.1 | 密碼最小長度≥14 | 待檢查 | - |
| 1.1.2 | 密碼複雜度已啟用 | 待檢查 | - |
| 2.2.1 | Guest 賬戶已停用 | 待檢查 | - |
| 2.3.1.1 | 限制空密碼登入 | 待檢查 | - |
| 5.1 | Windows Update 服務執行中 | 待檢查 | - |
| 9.1 | 所有防火牆配置檔案已啟用 | 待檢查 | - |
| 17.1 | 登入事件審計(成功+失敗) | 待檢查 | - |

## 說明

- 本報告由 winskill 自動生成,僅作參考
- 實際合規判定需結合企業安全策略和行業標準
- 建議定期執行檢查並儲存報告備查
"@

# 輸出到控制台
Write-Host $report

# 儲存到使用者輸出目錄
$outputDir = "$env:USERPROFILE\.workbuddy\output\winskill"
New-Item -ItemType Directory -Force -Path $outputDir | Out-Null
$outputFile = Join-Path $outputDir "$reportName.md"
$report | Out-File -FilePath $outputFile -Encoding utf8

Write-Host ("`n✅ 報告已儲存到:{0}" -f $outputFile)
Write-Host "提示:可將 .md 檔案內容複製到 Word 或線上 Markdown 轉 PDF 工具生成 PDF"
### 29.4 不合規項修復建議
Write-Host "`n🔧 不合規項修復建議"
Write-Host ("=" * 60)
Write-Host "以下命令僅作參考,請確認後再執行:`n"

Write-Host "【密碼策略修復】"
Write-Host "net accounts /minpwlen:8              # 設定密碼最小長度 8 位"
Write-Host "net accounts /maxpwage:90             # 設定密碼最長使用期限 90 天"
Write-Host "net accounts /minpwage:1              # 設定密碼最短使用期限 1 天"
Write-Host "net accounts /uniquepy:5              # 密碼歷史記錄 5 個"

Write-Host "`n【賬戶鎖定修復】"
Write-Host "net accounts /lockoutthreshold:5       # 鎖定閾值 5 次"
Write-Host "net accounts /lockoutduration:15       # 鎖定時間 15 分鐘"
Write-Host "net accounts /lockoutwindow:15         # 鎖定觀察視窗 15 分鐘"

Write-Host "`n【審計策略修復】"
Write-Host "auditpol /set /subcategory:'Logon' /success:enable /failure:enable"
Write-Host "auditpol /set /subcategory:'Object Access' /success:enable /failure:enable"
Write-Host "auditpol /set /subcategory:'Privilege Use' /success:enable /failure:enable"

Write-Host "`n【防火牆修復】"
Write-Host "Set-NetFirewallProfile -Profile Domain,Public,Private -Enabled True"

Write-Host "`n【Guest 賬戶修復】"
Write-Host "Disable-LocalUser -Name 'Guest'        # 停用 Guest 賬戶"

Write-Host "`n【RDP NLA 修復】"
Write-Host "Set-ItemProperty -Path 'HKLM:\System\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp' -Name UserAuthentication -Value 1"

Write-Host ("`n" + "=" * 60)
Write-Host "⚠️ 以上命令僅供參考,請確認後再執行"
### 報錯與解決 | 報錯 | 原因 | 解決 | |------|------|------| | `auditpol 不是內部或外部命令` | 需要管理員許可權 | 以管理員身份執行 PowerShell | | `Get-NetFirewallProfile 拒絕訪問` | 需要管理員許可權 | 以管理員身份執行 PowerShell | | `無法儲存報告到輸出目錄` | 目錄不存在或許可權不足 | 手動建立 `%USERPROFILE%\.workbuddy\output\winskill` | | `net accounts 輸出格式不符` | 系統語言非中文 | 根據實際輸出調整正則匹配 |

↑ 返回頂部


🆕 模組 30:遠端多伺服器管理

⚠️ 本模組需要 WinRM 服務支援,所有操作需管理員許可權。

📋 展開檢視:模組 30:遠端多伺服器管理 ### 30.1 伺服器註冊(Windows Credential Manager)
# 伺服器註冊配置檔案
$serverFile = "$env:USERPROFILE\.workbuddy\output\winskill\servers.json"
New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\.workbuddy\output\winskill" | Out-Null

# 載入已有伺服器列表
$servers = @()
if (Test-Path $serverFile) {
    $servers = Get-Content $serverFile -Raw | ConvertFrom-Json
}

Write-Host "`n🖥️ 遠端伺服器管理"
Write-Host ("=" * 50)
Write-Host "1. 新增伺服器"
Write-Host "2. 檢視已註冊伺服器"
Write-Host "3. 刪除伺服器"
Write-Host "4. 測試連線"
Write-Host ("=" * 50)

# 示例:新增伺服器(實際使用時通過 AI 互動輸入)
$action = Read-Host "請選擇操作 (1-4)"

switch ($action) {
    "1" {
        $ip = Read-Host "伺服器 IP 或主機名"
        $user = Read-Host "使用者名稱(如 Administrator)"
        $auth = Read-Host "認證方式 (1=密碼 2=證書)"

        if ($auth -eq "1") {
            $cred = Get-Credential -Message "輸入 $ip 的憑據"
            # 儲存到 Windows Credential Manager(通過 cmdkey)
            $target = "TERMSRV/$ip"
            cmdkey /generic:$target /user:$($cred.UserName) /pass:$($cred.GetNetworkCredential().Password) 2>$null
            Write-Host "✅ 憑據已儲存到 Windows Credential Manager"
        }

        $newServer = @{
            ip = $ip
            user = $user
            addedAt = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
            tags = @()
        }
        $servers += $newServer
        $servers | ConvertTo-Json -Depth 3 | Out-File $serverFile -Encoding utf8
        Write-Host "✅ 伺服器 $ip 已註冊"
    }
    "2" {
        if ($servers.Count -eq 0) {
            Write-Host "⚠️ 暫無已註冊伺服器"
        } else {
            Write-Host "`n已註冊伺服器:"
            $servers | ForEach-Object { Write-Host "  - $($_.ip)($($_.user))添加於 $($_.addedAt)" }
        }
    }
    "3" {
        $ip = Read-Host "要刪除的伺服器 IP"
        $servers = $servers | Where-Object ip -ne $ip
        $servers | ConvertTo-Json -Depth 3 | Out-File $serverFile -Encoding utf8
        Write-Host "✅ 伺服器 $ip 已刪除"
    }
    "4" {
        $ip = Read-Host "要測試的伺服器 IP"
        $result = Test-WSMan -ComputerName $ip -ErrorAction SilentlyContinue
        if ($result) {
            Write-Host "✅ $ip WinRM 服務正常"
        } else {
            Write-Host "❌ $ip 無法連線,請檢查:"
            Write-Host "  1. 目標伺服器是否開啟 WinRM(Enable-PSRemoting)"
            Write-Host "  2. 防火牆是否放行 5985/5986 埠"
            Write-Host "  3. 網路是否可達"
        }
    }
}
### 30.2 批次命令執行(並行)
$serverFile = "$env:USERPROFILE\.workbuddy\output\winskill\servers.json"

if (-not (Test-Path $serverFile)) {
    Write-Host "❌ 暫無已註冊伺服器,請先執行 30.1 註冊"
    exit 1
}

$servers = Get-Content $serverFile -Raw | ConvertFrom-Json

if ($servers.Count -eq 0) {
    Write-Host "⚠️ 暫無已註冊伺服器"
    exit 1
}

# 硬體自適應:並行數 = min(CPU 核心數, 伺服器數量)
$cpuCores = (Get-CimInstance Win32_Processor).NumberOfLogicalProcessors
$maxParallel = [Math]::Min($cpuCores, $servers.Count)
Write-Host ("`n⚡ 並行執行:{0} 個任務同時執行(CPU {1} 核)" -f $maxParallel, $cpuCores)

# 要執行的命令
$command = Read-Host "要在所有伺服器執行的命令"

Write-Host ("`n在 {0} 臺伺服器上執行:{1}" -f $servers.Count, $command)
Write-Host ("-" * 60)

# PowerShell 5.1 相容:使用 Invoke-Command 並行執行(原生支援多計算機)
$computerNames = $servers.ip
$cred = Get-Credential -Message "輸入所有伺服器的通用憑據"

Write-Host ("`n在 {0} 臺伺服器上執行:{1}" -f $servers.Count, $command)
Write-Host ("-" * 60)

try {
    # Invoke-Command 原生支援多計算機並行執行
    $results = Invoke-Command -ComputerName $computerNames -Credential $cred -ScriptBlock {
        param($cmd)
        $output = Invoke-Expression $cmd 2>&1
        [PSCustomObject]@{
            Server = $env:COMPUTERNAME
            Status = "✅ 成功"
            Output = $output | Out-String
        }
    } -ArgumentList $command -ErrorAction Stop

    # 彙總結果
    Write-Host ("`n" + "=" * 60)
    Write-Host "📊 執行結果彙總:"
    $results | ForEach-Object {
        Write-Host ("`n[{0}] {1}" -f $_.Server, $_.Status)
        if ($_.Output) { Write-Host $_.Output }
    }
    Write-Host ("=" * 60)
} catch {
    Write-Host ("❌ 執行失敗:{0}" -f $_.Exception.Message)
    Write-Host "提示:確認所有伺服器都已開啟 WinRM(執行 Enable-PSRemoting -Force)"
}
### 30.3 統一監控面板
$serverFile = "$env:USERPROFILE\.workbuddy\output\winskill\servers.json"

if (-not (Test-Path $serverFile)) {
    Write-Host "❌ 暫無已註冊伺服器"
    exit 1
}

$servers = Get-Content $serverFile -Raw | ConvertFrom-Json

Write-Host "`n📊 多伺服器統一監控面板"
Write-Host ("=" * 80)
Write-Host ("{0,-20} {1,8} {2,8} {3,8} {4,10} {5,10}" -f "伺服器", "CPU%", "記憶體%", "磁碟%", "狀態", "執行時間")
Write-Host ("-" * 80)

foreach ($server in $servers) {
    try {
        $session = New-PSSession -ComputerName $server.ip -ErrorAction Stop
        $info = Invoke-Command -Session $session -ScriptBlock {
            $cpu = (Get-CimInstance Win32_Processor).LoadPercentage
            $mem = (Get-CimInstance Win32_OperatingSystem)
            $memPct = [math]::Round(($mem.TotalVisibleMemorySize - $mem.FreePhysicalMemory) / $mem.TotalVisibleMemorySize * 100, 1)
            $disk = (Get-CimInstance Win32_LogicalDisk -Filter "DriveType=3" | Where-Object DeviceID -eq 'C:')
            $diskPct = [math]::Round(($disk.Size - $disk.FreeSpace) / $disk.Size * 100, 1)
            $uptime = (Get-Date) - $mem.LastBootUpTime
            [PSCustomObject]@{
                CPU = $cpu
                Mem = $memPct
                Disk = $diskPct
                Uptime = "{0}天{1}小時" -f $uptime.Days, $uptime.Hours
            }
        }
        Remove-PSSession $session

        $statusEmoji = if ($info.CPU -ge 90 -or $info.Mem -ge 90 -or $info.Disk -ge 90) { "🔴" } elseif ($info.CPU -ge 70 -or $info.Mem -ge 70 -or $info.Disk -ge 70) { "🟡" } else { "🟢" }

        Write-Host ("{0,-20} {1,8} {2,8} {3,8} {4,10} {5,10}" -f $server.ip, "$($info.CPU)%", "$($info.Mem)%", "$($info.Disk)%", $statusEmoji, $info.Uptime)
    } catch {
        Write-Host ("{0,-20} {1,8} {2,8} {3,8} {4,10} {5,10}" -f $server.ip, "-", "-", "-", "❌ 離線", "-")
    }
}

Write-Host ("-" * 80)
Write-Host "圖例:🟢 正常  🟡 警告  🔴 嚴重  ❌ 離線"
Write-Host ("=" * 80)
### 30.4 配置差異對比
$serverFile = "$env:USERPROFILE\.workbuddy\output\winskill\servers.json"

if (-not (Test-Path $serverFile)) {
    Write-Host "❌ 暫無已註冊伺服器"
    exit 1
}

$servers = Get-Content $serverFile -Raw | ConvertFrom-Json

if ($servers.Count -lt 2) {
    Write-Host "⚠️ 至少需要 2 臺伺服器才能對比"
    exit 1
}

Write-Host "`n🔍 配置差異對比"
Write-Host ("=" * 60)

# 選擇對比專案
Write-Host "對比專案:"
Write-Host "1. IIS 站點配置"
Write-Host "2. 服務狀態"
Write-Host "3. 防火牆規則"
Write-Host "4. 已安裝補丁"
$choice = Read-Host "請選擇 (1-4)"

$scriptBlock = switch ($choice) {
    "1" { { Get-Website | Select-Object Name, State, PhysicalPath, Bindings | ConvertTo-Json } }
    "2" { { Get-Service | Where-Object Status -ne 'Running' | Select-Object Name, Status, StartType | ConvertTo-Json } }
    "3" { { Get-NetFirewallRule | Where-Object Enabled -eq 'True' | Select-Object DisplayName, Direction, Action | ConvertTo-Json } }
    "4" { { Get-HotFix | Sort-Object InstalledOn -Descending | Select-Object -First 10 HotFixID, InstalledOn | ConvertTo-Json } }
}

# 採集所有伺服器資料
$allData = @{}
foreach ($server in $servers) {
    try {
        $session = New-PSSession -ComputerName $server.ip -ErrorAction Stop
        $data = Invoke-Command -Session $session -ScriptBlock $scriptBlock
        $allData[$server.ip] = $data | ConvertFrom-Json
        Remove-PSSession $session
    } catch {
        Write-Host "⚠️ $($server.ip) 連線失敗:$($_.Exception.Message)"
    }
}

# 對比輸出
if ($allData.Count -ge 2) {
    $firstServer = $allData.Keys | Select-Object -First 1
    $firstData = $allData[$firstServer]

    Write-Host ("`n基準伺服器:$firstServer" -f $firstServer)
    Write-Host ("-" * 60)

    foreach ($server in $allData.Keys) {
        if ($server -eq $firstServer) { continue }
        $serverData = $allData[$server]

        # 簡單差異對比(基於 JSON 字串比較)
        $firstJson = $firstData | ConvertTo-Json -Compress
        $serverJson = $serverData | ConvertTo-Json -Compress

        if ($firstJson -eq $serverJson) {
            Write-Host ("✅ {0}:與基準一致" -f $server)
        } else {
            Write-Host ("⚠️ {0}:存在差異" -f $server)
            # 輸出具體差異(簡化版)
            Write-Host ("  基準項數:{0},對比項數:{1}" -f @($firstData).Count, @($serverData).Count)
        }
    }
}

Write-Host ("=" * 60)
### 報錯與解決 | 報錯 | 原因 | 解決 | |------|------|------| | `WinRM 客戶端無法處理請求` | 目標 WinRM 未開啟 | 在目標伺服器執行 `Enable-PSRemoting -Force` | | `訪問被拒絕` | 憑據錯誤或許可權不足 | 檢查使用者名稱密碼,確認使用者有遠端管理許可權 | | `無法連線到遠端伺服器` | 網路不通或防火牆攔截 | 檢查網路連通性和 5985/5986 埠 | | `New-PSSession 超時` | 伺服器響應慢或網路延遲高 | 增加 `-OperationTimeout` 引數 | | `TrustedHosts 未配置` | 非域環境需配置 TrustedHosts | `Set-Item WSMan:\localhost\Client\TrustedHosts -Value "192.168.1.0/24" -Concatenate` |

↑ 返回頂部


30 秒速查表

你說 AI 執行
"掃 C 盤大檔案" 模組 1
"找重複檔案" 模組 2
"清理臨時檔案" 模組 3(需確認)
"IIS 正常嗎" 模組 4
"檢查服務" 模組 5
"批次改名" 模組 6(需確認)
"磁碟報告" 模組 7
"更新正常嗎" 模組 8
"伺服器卡" 模組 9
"有沒有被入侵" 模組 10
"可疑啟動項" 模組 11
"硬碟健康嗎" 模組 12
"誰在連我" 模組 13
"系統日誌錯誤" 模組 14
"裝了什麼軟體" 模組 15
"誰在伺服器上" 模組 16
"可疑計劃任務" 模組 17
"共享資料夾" 模組 18
"DNS/網絡卡診斷" 模組 19
"SSL證書快到期了嗎" 模組 20
"防火牆規則有沒有漏洞" 模組 21
"哪些服務崩過" 模組 22
"系統檔案修復" 模組 23
"儲存池狀態" 模組 24
"備份正常嗎" 模組 25
"Docker 狀態" 模組 26
"幫我修 DNS" 模組 27
"效能趨勢" 模組 28
"合規檢查" 模組 29
"遠端伺服器" 模組 30

❌ 不支援(明確不能用的場景)

不支援 原因
編輯已壓縮的檔案 壓縮包內檔案無法直接修改
恢復已刪除的回收站檔案 超出工具範圍
修改登錄檔鍵值 風險過高,不在工具範圍
BIOS/硬體層操作 超出作業系統層面
磁碟修復/擦除 超出工具範圍,需專業工具
終止網路連線 超出工具範圍
清除/停止事件日誌 超出工具範圍,僅只讀
解除安裝/安裝軟體 超出工具範圍,只讀審計
結束/斷開使用者會話 超出工具範圍,只讀監控
建立/刪除計劃任務 超出工具範圍,只讀審計
修改共享許可權 超出工具範圍,只讀審計
修改網絡卡 IP/DNS 配置 超出工具範圍,只讀診斷
申請/續簽/刪除 SSL 證書 超出工具範圍,只讀檢測
新增/刪除/修改防火牆規則 超出工具範圍,只讀審計
啟動/停止/修改服務配置 超出工具範圍,只讀診斷

前置要求

  • PowerShell 版本:5.1+(Windows 自帶,無需安裝)
  • 無需 API Key
  • 無需聯網(除首次安裝 IIS 管理工具外)
  • 無需安裝任何第三方軟體
  • ⚠️ 管理員許可權檢測:部分功能(IIS 管理、更新快取清理、安全審計、磁碟健康檢測、網路監控、事件日誌診斷、會話監控、計劃任務審計、共享審計、DNS 網絡卡診斷、SSL 證書檢測、防火牆審計、服務崩潰檢查、效能基線採集、合規檢查、遠端多伺服器管理)需要管理員許可權,AI 會在執行前自動檢測並提示

更新日誌

| v3.1.0 | 2026-08-16 | 新增日誌輪轉功能(Write-WinskillLog,10MB/7天自動輪轉清理);新增模組索引命令(一鍵列出30個模組用途);改進:移除廢棄的 wmic 宣告(已全面遷移 CIM cmdlet) | | v3.0.0 | 2026-08-06 | 新增效能基線與趨勢分析模組(基線建立、異常偏離告警、趨勢預測、瓶頸關聯分析)、安全合規檢查清單模組(等保2.0、CIS Benchmark、合規報告、修復建議)、遠端多伺服器管理模組(伺服器註冊、批次命令執行、統一監控面板、配置差異對比),總計30個模組,從單機工具升級為多機管理平臺;修改展示方式:頂部模組導航錨點+每模組返回頂部連結 | | v2.0.0 | 2026-07-24 | 新增自動化修復嚮導模組(DNS修復、網路修復、WinUpdate修復、服務修復、磁碟清理、時間同步),總計27個模組,從診斷工具升級為修復工具 | | v1.9.0 | 2026-07-16 | 修復邏輯bug,新增 Docker / K8s 容器管理模組(Docker狀態總覽、容器資源監控、Docker健康檢查、K8s叢集狀態、容器日誌採集),總計26個模組,覆蓋Windows Server容器化場景 | | v1.8.0 | 2026-07-16 | 新增 Docker / K8s 容器管理模組(Docker狀態總覽、容器資源監控、Docker健康檢查、K8s叢集狀態、容器日誌採集),總計26個模組,覆蓋Windows Server容器化場景 | | v1.7.0 | 2026-07-10 | 新增系統檔案完整性檢查(SFC/DISM)、儲存池管理、備份狀態檢查3個模組,總計25個模組;每個模組加摺疊塊;效能硬體自適應最佳化;新增更新提醒和禁止檔案型別宣告 | | v1.6.0 | 2026-07-09 | 新增SSL證書過期檢測、防火牆規則審計、服務崩潰恢復狀態3個模組,總計22個模組 | | v1.5.0 | 2026-07-08 | 新增計劃任務審計、檔案共享審計、DNS網絡卡診斷3個模組,總計19個模組 | | v1.4.0 | 2026-07-07 | 新增事件日誌診斷、已安裝程式管理、使用者會話監控3個模組,總計16個模組 | | v1.3.0 | 2026-07-06 | 新增登錄檔啟動項審計、磁碟健康檢測、網路埠監控3個模組,總計13個模組 | | v1.2.0 | 2026-07-05 | 新增Windows Update效能監控、安全審計3個模組,所有命令摺疊隱藏 | | v1.1.0 | 2026-07-04 | 新增快速開始/報錯指引/FAQ | | v1.0.0 | 2026-07-03 | 初始版本,7個模組 |

釋出資訊


🔔 更新提醒

如何獲取 winskill 最新版本:

skillhub upgrade winskill

當前版本:v3.0.0,如有新版本可用,請執行上述命令升級。


🚫 禁止的檔案型別(全 Skill 生效 + SkillHub 打包排除)

以下 5 大類檔案型別在所有涉及檔案操作的模組中均會被攔截,同時也會被 SkillHub 打包排除規則過濾。

1. Windows 可執行 / 批處理指令碼

.bat .cmd .ps1 .vbs .exe .dll .lnk .msi

2. Office 二進位制文件

.docx .xlsx .pptx .doc .xls .ppt .xlsm .docm .pptm

3. 二進位制映象 / 安裝包

.iso .dmg .zip .rar .7z .tar .gz .apk .jar

4. 系統快取 / 隱藏檔案

.DS_Store .git 目錄 .env .log .tmp

5. 其他風險指令碼

.sh .com .scr .hta .reg

🤖 AI 評測

這款工具功能非常強大,30個模組基本覆蓋了伺服器運維的各種場景,安全保護機制做得很到位。但文件太長太複雜,找功能不夠方便,對普通使用者不太友好。

📊 多維度評分

適應性4.8
規範性4.5
有效性4.7
可靠性4.4
可信度5

📁 包含檔案 (1 個)

📄 SKILL.md 179.6 KB