一個用 Go 撰寫的組態與安全性檢測程式
作者:Pecezen.org
平台:Windows
語言:Go
在準備 ISO 27001 驗證時,控制項 8.9 組態管理 (Configuration Management),稽核員常會查看
- 伺服器或個人電腦的作業系統版本。
- 是否安裝了未經授權的軟體?
- 防火牆與防毒軟體是否確實開啟?
- 系統服務是否有不必要的項目在執行?
所以寫一支簡單的組態與安全性檢測工具,最近剛好有點時間,放上來供大家參考。
✅ 工具功能簡介:
- 🖥️ 硬體資訊
- 🧩 作業系統(OS)資訊
- 📦 已安裝軟體清單
- 🛡️ 防毒狀態
- 🔥 防火牆狀態
- ⚙️ 系統服務(Services)啟用狀況
- 📤 支援匯出 CSV,作為稽核或留存證據
- 🌐 多語系介面(繁中 / English / 日本語/德文)
🖥️ 操作介面:

💾 Windows 執行檔下載
你可以透過下面的原始碼編譯要執行的程式,這邊也提供已編譯完成的可執行Windows程式:
檔案下載位置
下載後為壓縮檔,解密密碼:pecezen.org
🔗原始碼(Source Code)
package main
import (
"bytes"
"encoding/csv"
"image/color"
"os/exec"
"strings"
"syscall"
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/app"
"fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/dialog"
"fyne.io/fyne/v2/theme"
"fyne.io/fyne/v2/widget"
)
/*
=========================
Theme & Language (i18n)
=========================
*/
type readableTheme struct{}
func (readableTheme) Color(n fyne.ThemeColorName, v fyne.ThemeVariant) color.Color {
if n == theme.ColorNameDisabled {
return color.NRGBA{0, 0, 0, 255}
}
return theme.DefaultTheme().Color(n, v)
}
func (readableTheme) Font(s fyne.TextStyle) fyne.Resource { return theme.DefaultTheme().Font(s) }
func (readableTheme) Icon(n fyne.ThemeIconName) fyne.Resource { return theme.DefaultTheme().Icon(n) }
func (readableTheme) Size(n fyne.ThemeSizeName) float32 { return theme.DefaultTheme().Size(n) }
type Lang string
const (
LangZHTW Lang = "zh-TW"
LangEN Lang = "en"
LangJA Lang = "ja"
LangDE Lang = "de"
)
var langOptions = []string{"繁體中文", "English", "日本語", "Deutsch"}
var langMap = map[string]Lang{
"繁體中文": LangZHTW,
"English": LangEN,
"日本語": LangJA,
"Deutsch": LangDE,
}
const prefLangKey = "SelectedLanguage"
type i18n struct{ lang Lang }
func (i i18n) tr(key string) string {
table := map[string]map[Lang]string{
"app.title": {
LangZHTW: "組態與安全性檢測工具 V1.0",
LangEN: "Config & Security Audit Tool V1.0",
LangJA: "構成とセキュリティ診断 V1.0",
LangDE: "Konfigurations- und Sicherheits-Audit-Tool V1.0",
},
"tab.hardware": {
LangZHTW: "硬體資訊", LangEN: "Hardware Info", LangJA: "ハードウェア情報", LangDE: "Hardware-Info",
},
"tab.os": {
LangZHTW: "OS 資訊", LangEN: "OS Info", LangJA: "OS 情報", LangDE: "OS-Info",
},
"tab.apps": {
LangZHTW: "軟體清單", LangEN: "Software", LangJA: "ソフト一覧", LangDE: "Softwareliste",
},
"tab.av": {
LangZHTW: "防毒狀態", LangEN: "Antivirus", LangJA: "ウイルス対策", LangDE: "Virenschutz",
},
"tab.firewall": {
LangZHTW: "防火牆", LangEN: "Firewall", LangJA: "防火壁", LangDE: "Firewall",
},
"tab.service": {
LangZHTW: "系統服務", LangEN: "Services", LangJA: "サービス", LangDE: "Systemdienste",
},
"tab.policy": {
LangZHTW: "安全原則", LangEN: "Policies", LangJA: "ポリシー", LangDE: "Sicherheitsrichtlinien",
},
"btn.export": {
LangZHTW: "匯出目前分頁 CSV",
LangEN: "Export Current CSV",
LangJA: "現在のページをCSV匯出",
LangDE: "Aktuellen Tab als CSV exportieren",
},
"btn.about": {
LangZHTW: "關於", LangEN: "About", LangJA: "詳しく", LangDE: "Über",
},
"loading": {
LangZHTW: "資料載入中...", LangEN: "Loading...", LangJA: "読み込み中...", LangDE: "Daten werden geladen...",
},
"col.name": {
LangZHTW: "名稱 (Name)", LangEN: "Name", LangJA: "名前", LangDE: "Name",
},
"col.status": {
LangZHTW: "狀態/版本 (Status/Ver)", LangEN: "Status/Ver", LangJA: "状態/版", LangDE: "Status/Ver",
},
"col.detail": {
LangZHTW: "詳細資訊 (Details)", LangEN: "Details", LangJA: "詳細情報", LangDE: "Details",
},
"about.title": {
LangZHTW: "關於程式", LangEN: "About App", LangJA: "アプリについて", LangDE: "Über die App",
},
"about.body": {
LangZHTW: "作者: Pecezen.org\n版權所有 © 2026\n\n免責聲明:\n作者不對因使用本程式所造成的任何資料遺失、損壞或其他後果負責。",
LangEN: "Author: Pecezen.org\nCopyright © 2026\n\nDisclaimer:\nThe author is not responsible for any data loss, damage, or other consequences caused by the use of this program.",
LangJA: "作者: Pecezen.org\n著作權 © 2026\n\n免責事項:\n作者は、本プログラムの使用によって生じたデータの紛失、破損、またはその他の結果について一切の責任を負いません。",
LangDE: "Autor: Pecezen.org\nUrheberrecht © 2026\n\nHaftungsausschluss:\nDer Autor haftet nicht für Datenverlust, Schäden oder andere Folgen, die durch die Verwendung dieses Programms entstehen.",
},
}
return table[key][i.lang]
}
/*
=========================
Custom UI Components
=========================
*/
type fixedWidthLabel struct {
widget.Label
width float32
}
func newFixedWidthLabel(text string, width float32) *fixedWidthLabel {
l := &fixedWidthLabel{width: width}
l.ExtendBaseWidget(l)
l.SetText(text)
l.TextStyle = fyne.TextStyle{Bold: true}
return l
}
func (f *fixedWidthLabel) MinSize() fyne.Size { return fyne.NewSize(f.width, 32) }
/*
=========================
PowerShell Data Logic
=========================
*/
func runCmd(psCmd string) string {
cmd := exec.Command("powershell", "-NoProfile", "-Command", "[Console]::OutputEncoding=[System.Text.Encoding]::UTF8;"+psCmd)
cmd.SysProcAttr = &syscall.SysProcAttr{
HideWindow: true,
CreationFlags: 0x08000000,
}
var out bytes.Buffer
cmd.Stdout = &out
_ = cmd.Run()
return strings.TrimSpace(out.String())
}
func collectHardwareInfo() string {
ps := `
$cpu = (Get-CimInstance Win32_Processor).Name;
$cs = Get-CimInstance Win32_ComputerSystem;
$mem = $cs.TotalPhysicalMemory;
Write-Host "CPU: $cpu";
Write-Host "Total Memory: $([math]::Round($mem/1GB, 2)) GB";
Write-Host "Manufacturer: $($cs.Manufacturer)";
Write-Host "Model: $($cs.Model)";
Write-Host "---------------------------------------------------------------------------";
Write-Host "Disk Partition Info (硬碟分區資訊):";
Get-CimInstance Win32_LogicalDisk | Where-Object {$_.DriveType -eq 3} | ForEach-Object {
$size = [math]::Round($_.Size/1GB, 2); $free = [math]::Round($_.FreeSpace/1GB, 2); $used = $size - $free; $per = [math]::Round(($used/$size)*100, 2);
Write-Host "Drive $($_.DeviceID) | Total: $($size)GB | Free: $($free)GB | Used: $($per)%"
} | Out-String`
return runCmd(ps)
}
func collectAntivirusInfo() string {
ps := `
Write-Host "[ 安裝的防毒軟體清單 ]";
$avList = Get-CimInstance -Namespace root/SecurityCenter2 -ClassName AntivirusProduct;
if ($avList) { $avList | ForEach-Object { Write-Host "- 軟體名稱: $($_.displayName)" } } else { Write-Host "- 未偵測到第三方防毒軟體" }
Write-Host ""; Write-Host "[ Windows Defender 狀態 ]";
Get-MpComputerStatus | Select-Object AntivirusEnabled, RealTimeProtectionEnabled, AntivirusSignatureVersion, AntivirusSignatureLastUpdated | Format-List | Out-String`
return runCmd(ps)
}
func collectListData(psCmd string) [][]string {
raw := runCmd(psCmd + " | ConvertTo-Csv -NoTypeInformation")
r := csv.NewReader(strings.NewReader(raw))
records, err := r.ReadAll()
if err != nil || len(records) <= 1 {
return [][]string{}
}
return records[1:]
}
/*
=========================
Main Application
=========================
*/
func main() {
a := app.NewWithID("org.pecezen.audit.tool")
a.Settings().SetTheme(&readableTheme{})
savedLang := a.Preferences().StringWithFallback(prefLangKey, "繁體中文")
i := i18n{lang: langMap[savedLang]}
w := a.NewWindow(i.tr("app.title"))
if resourceIconPng != nil {
w.SetIcon(resourceIconPng)
}
w.Resize(fyne.NewSize(1100, 560))
appData := [][]string{}
svcData := [][]string{}
var currentTabIndex int = 0
const nameColWidth float32 = 780
const statusColWidth float32 = 250
createTextTab := func() (*widget.Entry, fyne.CanvasObject, *fixedWidthLabel) {
e := widget.NewMultiLineEntry()
e.Disable()
e.TextStyle = fyne.TextStyle{Monospace: true}
headerLabel := newFixedWidthLabel(i.tr("col.detail"), nameColWidth+statusColWidth)
return e, container.NewBorder(container.NewHBox(headerLabel), nil, nil, nil, container.NewScroll(e)), headerLabel
}
createTableTab := func(data *[][]string) (fyne.CanvasObject, *widget.Table, *fixedWidthLabel, *fixedWidthLabel) {
h1 := newFixedWidthLabel(i.tr("col.name"), nameColWidth)
h2 := newFixedWidthLabel(i.tr("col.status"), statusColWidth)
t := widget.NewTable(
func() (int, int) { return len(*data), 2 },
func() fyne.CanvasObject { l := widget.NewLabel(""); l.Truncation = fyne.TextTruncateEllipsis; return l },
func(id widget.TableCellID, o fyne.CanvasObject) {
if id.Row < len(*data) {
o.(*widget.Label).SetText((*data)[id.Row][id.Col])
}
},
)
t.SetColumnWidth(0, nameColWidth)
t.SetColumnWidth(1, statusColWidth)
return container.NewBorder(container.NewHBox(h1, h2), nil, nil, nil, t), t, h1, h2
}
entryHW, uiHW, lblHW := createTextTab()
entryOS, uiOS, lblOS := createTextTab()
entryAV, uiAV, lblAV := createTextTab()
entryFW, uiFW, lblFW := createTextTab()
entryPol, uiPol, lblPol := createTextTab()
uiApps, tableApps, appH1, appH2 := createTableTab(&appData)
uiSvc, tableSvc, svcH1, svcH2 := createTableTab(&svcData)
tabs := container.NewAppTabs(
container.NewTabItem(i.tr("tab.hardware"), uiHW),
container.NewTabItem(i.tr("tab.os"), uiOS),
container.NewTabItem(i.tr("tab.apps"), uiApps),
container.NewTabItem(i.tr("tab.av"), uiAV),
container.NewTabItem(i.tr("tab.firewall"), uiFW),
container.NewTabItem(i.tr("tab.service"), uiSvc),
container.NewTabItem(i.tr("tab.policy"), uiPol),
)
tabs.OnSelected = func(ti *container.TabItem) {
for idx, item := range tabs.Items {
if item == ti {
currentTabIndex = idx
break
}
}
}
refresh := func() {
p := dialog.NewProgressInfinite(i.tr("app.title"), i.tr("loading"), w)
p.Show()
go func() {
sHW := collectHardwareInfo()
sOS := runCmd("Get-ComputerInfo | Select-Object OsName, OsVersion, OsArchitecture, WindowsVersion, OsInstallDate | Format-List | Out-String")
sAV := collectAntivirusInfo()
sFW := runCmd("Get-NetFirewallProfile | Select-Object Name, Enabled | Out-String")
sPol := runCmd("net accounts")
appData = collectListData(`Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* | Where-Object {$_.DisplayName} | Select-Object DisplayName, DisplayVersion`)
svcData = collectListData("Get-Service | Where-Object {$_.Status -eq 'Running'} | Select-Object DisplayName, Status")
fyne.Do(func() {
entryHW.SetText(sHW)
entryOS.SetText(sOS)
entryAV.SetText(sAV)
entryFW.SetText(sFW)
entryPol.SetText(sPol)
lblHW.SetText(i.tr("col.detail"))
lblOS.SetText(i.tr("col.detail"))
lblAV.SetText(i.tr("col.detail"))
lblFW.SetText(i.tr("col.detail"))
lblPol.SetText(i.tr("col.detail"))
appH1.SetText(i.tr("col.name"))
appH2.SetText(i.tr("col.status"))
svcH1.SetText(i.tr("col.name"))
svcH2.SetText(i.tr("col.status"))
tableApps.Refresh()
tableSvc.Refresh()
p.Hide()
})
}()
}
exportBtn := widget.NewButton(i.tr("btn.export"), func() {
save := dialog.NewFileSave(func(uc fyne.URIWriteCloser, err error) {
if uc == nil {
return
}
defer uc.Close()
var buf bytes.Buffer
buf.Write([]byte{0xEF, 0xBB, 0xBF})
writer := csv.NewWriter(&buf)
switch currentTabIndex {
case 0:
writer.Write([]string{"Hardware Info"})
writer.Write([]string{entryHW.Text})
case 1:
writer.Write([]string{"OS Info"})
writer.Write([]string{entryOS.Text})
case 2:
writer.Write([]string{"Software Name", "Version"})
writer.WriteAll(appData)
case 3:
writer.Write([]string{"Antivirus Status"})
writer.Write([]string{entryAV.Text})
case 4:
writer.Write([]string{"Firewall Status"})
writer.Write([]string{entryFW.Text})
case 5:
writer.Write([]string{"Service Name", "Status"})
writer.WriteAll(svcData)
case 6:
writer.Write([]string{"Security Policy"})
writer.Write([]string{entryPol.Text})
}
writer.Flush()
uc.Write(buf.Bytes())
}, w)
tabNames := []string{"Hardware", "OS", "Software", "Antivirus", "Firewall", "Services", "Policies"}
save.SetFileName("Audit_" + tabNames[currentTabIndex] + ".csv")
save.Show()
})
aboutBtn := widget.NewButton(i.tr("btn.about"), func() {
dialog.ShowInformation(i.tr("about.title"), i.tr("about.body"), w)
})
langSelect := widget.NewSelect(langOptions, func(s string) {
a.Preferences().SetString(prefLangKey, s)
i.lang = langMap[s]
w.SetTitle(i.tr("app.title"))
exportBtn.SetText(i.tr("btn.export"))
aboutBtn.SetText(i.tr("btn.about"))
for idx, key := range []string{"tab.hardware", "tab.os", "tab.apps", "tab.av", "tab.firewall", "tab.service", "tab.policy"} {
tabs.Items[idx].Text = " " + i.tr(key) + " "
}
tabs.Refresh()
refresh()
})
langSelect.SetSelected(savedLang)
controls := container.NewHBox(widget.NewLabel("Lang:"), langSelect, exportBtn, aboutBtn)
w.SetContent(container.NewBorder(container.NewVBox(controls), nil, nil, nil, tabs))
w.ShowAndRun()
}
⚠️ 免責聲明(Disclaimer)
作者不對因使用本程式所造成的任何資料遺失、損壞或其他後果負責。
「為了保障你的隱私與安全,PeceZen 的工具堅持不追蹤、不放廣告、完全離線。如果你覺得這些工具為你節省了寶貴的時間,歡迎請我喝杯咖啡,幫助我維持伺服器的運行與工具的更新。」
[ ☕ 請我喝杯咖啡 ]




