Detailed close-up of computer components including RAM and cables inside a server or high-performance PC.

【共有】Windowsの構成およびセキュリティチェックツール(CSVエクスポート機能付き)

Goで作成されたWindows向けの構成およびセキュリティチェックツールです。OSバージョン確認、インストール済みソフトウェアの一覧、ウイルス対策・ファイアウォールの状態確認、システムサービスの監査、CSV出力に対応。ISO 27001監査や個人のシステムチェックに最適。

Goで作成された構成およびセキュリティチェックツール

作者:Pecezen.org
プラットフォーム:Windows
言語:Go

ISO 27001 の認証準備において、コントロール項目 8.9「構成管理(Configuration Management)」では、監査員は通常以下の点を確認します。

  • サーバーや個人用コンピューターのOSバージョン
  • 許可されていないソフトウェアがインストールされていないか
  • ファイアウォールやアンチウイルスソフトが正しく有効になっているか
  • 不要なシステムサービスが実行されていないか

所以寫一そこで、簡単な構成およびセキュリティチェックツールを作成しました。最近少し時間があったので、皆さんの参考のために公開します。

ツール機能の紹介

  • 🖥️ ハードウェア情報
  • 🧩 オペレーティングシステム(OS)情報
  • 📦 インストール済みソフトウェアの一覧
  • 🛡️ ウイルス対策ソフトの状態
  • 🔥 ファイアウォールの状態
  • ⚙️ システムサービスの有効状況
  • 📤 CSVエクスポート対応(監査や記録のため)
  • 🌐 多言語インターフェース(繁体字中国語 / 英語 / 日本語 / ドイツ語)

🖥️ インターフェース概要:

💾 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 のツールは「追跡なし・広告なし・完全オフライン」を大切にしています。
もしこれらのツールが、あなたの貴重な時間を節約する助けになったのであれば、コーヒー一杯のご支援で、サーバーの維持やツールの継続的な更新を支えていただければ幸いです。
[ ☕ コーヒーを一杯おごる ]

返信を残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です