news 2026/10/27 17:51:39

终端保密检查工具:Windows安全基线PowerShell核查与复检

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
终端保密检查工具:Windows安全基线PowerShell核查与复检

简介:终端保密检查工具.zip 是一套面向 Windows 终端安全自查与保密合规场景的轻量工具包,适合单位保密检查、终端风险排查及日常安全巡检人员参考使用。压缩包共 9 个文件,整体约 3.92MB,主要由 4 个 dll 动态库、2 个 ids 标识文件、2 个 xml 配置文件与 1 个 exe 可执行程序组成,兼顾程序运行、规则配置与数据识别等用途,结构紧凑,便于在本地快速部署和调用。已有 1035 人学习下载,说明其在终端保密检查相关需求中具有一定参考价值。对需要开展终端保密自查的单位用户而言,包内配置规则与程序模块相对完整,可减少从零搜集与梳理资料的时间。读者可借此了解此类检查工具的文件构成与配置方式,围绕关键词扫描、终端信息识别、权限校验等环节梳理自查思路,也可作为安全合规检查、教学演示或工具二次整理的基础素材。

1. 终端保密检查工具:一台没有做过自查的 Windows 机器,我不敢直接交付

上周帮人处理一台二手工作站,开机第一件事不是装驱动,而是插上 U 盘看它认不认——结果 USBSTOR 的 Start 值还是 3,说明这台机器从来没有做过外设管控。这类问题在交付、报废、跨部门流转三个环节最容易出事故,而人工逐项翻注册表、翻本地策略、翻事件日志,一台机器能耗掉半小时,还容易漏。终端保密检查工具.zip要解决的就是这件事:把 Windows 终端上那些散落在注册表、本地安全策略、SMB 服务、审计策略里的保密相关配置,用一组 PowerShell 脚本一次性读出来、判级、导成能交差的报告。它适合三类人:负责终端交付和离职回收的运维、要做内部自查的技术负责人、以及需要给机器留一份“体检存档”的开发者。下面按我实际拆包、跑通、改配置的顺序讲。

2. 拆包先看清单:这份 zip 里到底有哪些脚本和检查项

压缩包解开之后不要急着双击运行,先花五分钟把目录结构和检查项看明白,后面出问题才知道该去哪一节找。这类工具包的设计思路通常是“一个主入口 + 一堆单项检查脚本 + 一份基线配置”,好处是加检查项不用动主流程,坏处是文件一多就容易搞不清哪个是入口、哪个是数据。我拆下来的这份基本就是这个套路,不同版本的文件命名可能有出入,但分层逻辑一致。

2.1 目录结构与每个文件的职责

先把文件按职责分堆,比逐个打开看要快得多。典型的布局是这样:

路径职责能不能改
Invoke-SecCheck.ps1主入口,负责参数解析、按顺序调用检查项、汇总导出不建议改,扩展走配置
checks\*.ps1单项检查脚本,一类配置一个文件,输出统一对象可以增删,注意输出字段对齐
config\baseline.json基线期望值,决定“什么算合格”必须改,默认值只是参考
lib\Common.ps1公共函数:写日志、判级、转 HTML只读,改了会影响所有检查项
reports\输出目录,CSV 和 HTML 都落这里每次跑之前清空
使用说明.txt参数列表和已知限制值得读一遍

真正决定检查结果的不是脚本,是config\baseline.json。脚本只负责“读当前值”,基线负责“判断这个值对不对”。我见过有人直接把包扔给同事跑,报告一片绿,结果基线里 USB 管控那一条的期望值被设成了“不检查”,等于什么都没查。所以拿到包的第一件事是打开基线文件,把每一条的Enabled和Expect过一遍,确认它和你们内部的终端保密要求对得上。

checks\目录下的文件建议按名字排序看一眼,命名一般能反映检查范围,比如账户类的、外设类的、共享类的、审计类的。如果某个文件名你完全看不懂它查什么,打开看前二十行注释,通常有说明。这一步别省,后面报告里出现一条你不认识的检查项,你会不知道该不该签字。

2.2 检查项分五类,先弄清判定口径

工具包里的检查项再多,落到判定口径上其实就五类。搞清楚每类的“合格”怎么定义,比记住具体条目更重要:

类别典型检查内容判定口径
账户与口令空口令限制、口令长度与有效期、管理员组成员有明确数值阈值,可硬判
外设与介质USB 存储启停、便携设备、历史挂载痕迹开关可硬判,痕迹需人工确认
共享与远程SMB 共享、当前会话、远程桌面、WinRM白名单制,非白即异常
审计与日志审计子类别开关、安全日志容量与保留阈值 + 覆盖率
系统面补丁级别、防护软件状态、遗留敏感文件多为提示项,不作硬判

这里最容易踩的口径问题是“开关”和“痕迹”混在一起判。USBSTOR 的 Start 值等于 4,只能说明现在禁用了,不能说明这台机器从来没插过 U 盘;反过来,痕迹里有大量设备记录但开关是关的,恰恰说明管控是后加的,历史数据可能已经流出去过。所以报告里这两类一定要分列,别合成一条“USB 管控:合格”。

共享那一类建议用白名单而不是黑名单。默认共享C$、ADMIN$是系统自带的,禁不掉也不该禁,如果基线里写成“存在任何共享即不合格”,每台机器都会红,报告就废了。正确做法是基线里维护一份允许的共享名列表,脚本比对列表外的共享才判异常。

2.3 运行前置条件:PowerShell 版本、权限、编码

跑之前先确认三件事:PowerShell 版本、当前会话是不是管理员、控制台代码页。这三样任何一样不对,报告都可能出现“看起来正常但其实缺项”的情况,比直接报错更麻烦。

# 1. 版本与位数:5.1 和 7.x 在部分 CIM 类上行为不同 $PSVersionTable | Format-List PSVersion, PSEdition, OS # 2. 是否管理员:非管理员读不到安全日志和部分注册表键 $isAdmin = ([Security.Principal.WindowsPrincipal] ` [Security.Principal.WindowsIdentity]::GetCurrent() ).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) "管理员会话: $isAdmin" # 3. 控制台编码:决定 CSV 里的中文会不会变问号 chcp [Console]::OutputEncoding.WebName

这三段输出的含义要看清。PSEdition为Desktop说明是 Windows PowerShell 5.1,为Core说明是 7.x;老脚本一般在 5.1 上验证过,7.x 上可能出现Get-WmiObject不可用的情况,常见做法是把脚本里的Get-WmiObject换成Get-CimInstance,或者在 5.1 里跑。$isAdmin为False时不要继续,安全日志、SAM 相关键、Get-SmbSession都会读不全,而脚本大概率不会报错,只会少几行。chcp显示 936 是 GBK 代码页,导出的 CSV 用 Excel 直接打开通常没问题,但如果目标是给别的系统消费,建议在导出时显式指定 UTF8。

提示:不要在没有确认这三项的情况下跑全量扫描,尤其是给别人机器做交付检查时,一份缺项的报告比没有报告更危险。

3. 首次跑通:从解压校验到生成一份可交付的检查报告

第一次跑的目标不是拿报告,是确认这条链路在你自己的环境里没有断点。我的习惯是先在一台测试机上完整走一遍,包括解压、校验、干跑、正式跑、读报告,确认每一步的输出都符合预期,再拿到正式机器上执行。

3.1 解压与完整性校验

不要直接在压缩包里双击脚本运行。Windows 会把从网络来源的压缩包标记为“来自其他计算机”,解压出来的文件带着 Zone.Identifier 备用数据流,PowerShell 执行时会按远程脚本处理,行为可能和预期不一致。正确做法是先落到本地固定目录,再统一解锁。

# 目标目录尽量短、不带空格,避免部分老脚本拼接路径时出错 $zip = 'D:\pkg\终端保密检查工具.zip' $dst = 'C:\SecCheck' # 1. 记录哈希,方便日后确认包没被换过 Get-FileHash -LiteralPath $zip -Algorithm SHA256 | Format-List # 2. 解压(-Force 覆盖旧目录,首次可省) Expand-Archive -LiteralPath $zip -DestinationPath $dst -Force # 3. 解除“来自网络”标记,避免执行策略误判 Get-ChildItem -LiteralPath $dst -Recurse -File | Unblock-File # 4. 清点文件数量与总大小,和说明里的清单对一下 $files = Get-ChildItem -LiteralPath $dst -Recurse -File "文件数: $($files.Count) 总字节: $(($files | Measure-Object Length -Sum).Sum)"

-LiteralPath而不是-Path,是因为路径里有中文和可能的方括号,-Path会把方括号当通配符解析,导致找不到文件。Unblock-File这一步很关键,很多人忽略它,结果脚本跑起来只执行了一半就静默退出,报告里少了整整一类检查项,还不报错。第四步的清点不是形式主义:如果文件数明显少于说明里的清单,说明解压不完整,后面所有结论都不可信。

3.2 用管理员会话执行主脚本

主脚本的参数名各版本不完全一样,别照抄网上的命令。先把它自己的参数列出来,再决定怎么传:

cd C:\SecCheck # 列出主脚本支持的参数,避免凭印象传错 (Get-Command .\Invoke-SecCheck.ps1).Parameters.Keys # 看帮助里的示例,重点看 -Mode 和 -OutputDir 的取值 Get-Help .\Invoke-SecCheck.ps1 -Full

参数确认之后再跑。下面这条是我常用的组合,含义在代码后逐条说明:

# 只在当前进程放开执行策略,不改机器全局设置 Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass -Force .\Invoke-SecCheck.ps1 ` -Mode Full ` -Baseline .\config\baseline.json ` -OutputDir .\reports ` -IncludeHistory ` -Verbose

-Mode Full表示跑全部检查项;如果脚本支持Quick或Audit之类的枚举值,快速模式通常只跑硬判项、跳过需要遍历文件系统的重活,适合日常巡检,全量留给交付前。-Baseline显式指定基线文件,是为了避免脚本默认去读同目录下的同名文件、结果你改了另一份却不生效。-OutputDir指向相对路径时,脚本内部一般会转成绝对路径,但如果你的当前目录有写入限制,建议直接给绝对路径。-IncludeHistory控制是否扫描历史痕迹(USB 设备记录、最近打开文档、回收站残留),这一类最耗时,单机可能多花两三分钟,但恰恰是保密检查里最有价值的部分。-Verbose把每一步的执行过程打到控制台,第一次跑一定要加,出问题时这串输出就是唯一的现场记录。

跑完先看退出码,再看报告目录里多了什么文件:

"退出码: $LASTEXITCODE" Get-ChildItem .\reports | Select-Object Name, Length, LastWriteTime

退出码为 0 不代表全部合格,只代表脚本正常结束;非 0 一般是参数错误或中途异常,这时候不要去看报告,先翻-Verbose输出里最后几行的异常信息。

3.3 报告三个文件怎么读

多数这类工具会同时导出 CSV、HTML 和一份汇总,三者的用途完全不同,别只挑好看的看:

文件用途读法
result_*.csv逐项明细,一行一个检查项用 Excel 或Import-Csv过滤 High 级
report_*.html汇总展示,给非技术同事看只看统计和红项,不追细节
summary_*.txt一行结论 + 计数贴在工单里当结论

明细 CSV 里我最关注四个字段:检查项 ID、当前值、期望值、判定级别。ID 是稳定标识,同一台机器两次扫描用 ID 对齐才能做差分;当前值和期望值并排看,能立刻判断是“配置错了”还是“基线设错了”;判定级别决定你要不要马上处理。有些包会多一个“修复建议”字段,内容通常比较笼统,真正的修复动作还是得自己写。

注意:CSV 里如果出现System.Object[]这种值,说明某个检查项返回了多值而导出时没展开,这条结论不可用,需要单独跑一次对应的单项脚本确认。

4. 把检查项落到实处:账户、外设、共享、审计四类配置怎么读怎么写

报告看不懂,多半是因为不知道每个数值背后的系统对象是什么。这一节把四类高频检查项拆到具体的命令和注册表路径,每条都给判定口径。命令可以直接粘到管理员 PowerShell 里跑,用来交叉验证报告结论。

4.1 账户与口令:net accounts 和本地组成员

口令策略有两种来源:本地安全策略和域组策略,域环境下后者优先,本地改了也会被覆盖。所以判定之前先确认机器是不是加了域,否则你会对着一条永远改不动的配置反复折腾。

# 口令与锁定策略,输出是本地化文本,字段名随系统语言变化 net accounts # 注册表口径更稳,不依赖输出文本 $lsa = 'HKLM:\SAM\SAM\Domains\Account' # 注意:SAM 键默认连管理员都读不了,需要临时授权,非必要不动 # 本地用户与管理员组,比 net localgroup 更结构化 Get-LocalUser | Select-Object Name, Enabled, PasswordRequired, LastLogon Get-LocalGroupMember -Group 'Administrators' | Select-Object Name, ObjectClass, PrincipalSource

net accounts的输出里,“最小密码长度”“密码最长使用期限”“锁定阈值”是三条硬指标,但它是按系统语言本地化的,脚本解析时容易因为中英文差异失败,所以我一般只用它做人工核对,脚本判定走Get-LocalUser和策略对象的属性。Get-LocalGroupMember的PrincipalSource字段很关键:值为Local是本地账户,ActiveDirectory是域账户,AzureAD是云端账户。管理员组里出现来源不明的域账户或云端账户,比出现一个本地管理员更值得追查,因为前者往往是历史遗留的权限,没人记得是谁加的。

判定口径建议这样定:管理员组成员数量设上限(比如不超过 3 个),且必须是白名单里的账户;PasswordRequired为False且账户处于启用状态的,直接判高风险,这类账户能空口令登录,是典型的后门入口。内置 Administrator 是否启用单独一条,很多单位的基线要求是禁用。

4.2 外设与移动介质:开关要看,历史痕迹更要看

外设管控是保密检查里权重最高的一块,也是最容易被“当前值合格”骗过去的一块。开关在注册表里,痕迹在设备枚举和安装日志里,两者必须分开读。

# 1. USB 存储类驱动启停:3=允许,4=禁用 Get-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Services\USBSTOR' -Name Start | Select-Object Start # 2. 便携设备(MTP 类,手机、相机)由 WPD 类驱动控制 Get-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Services\WpdUpFltr' -Name Start -ErrorAction SilentlyContinue # 3. 历史挂载过的 USB 存储设备:这是“用过没有”的证据 Get-ChildItem 'HKLM:\SYSTEM\CurrentControlSet\Enum\USBSTOR' -ErrorAction SilentlyContinue | ForEach-Object { $dev = Get-ItemProperty $_.PSPath [pscustomobject]@{ 设备 = $dev.FriendlyName 实例ID = $_.PSChildName 服务 = $dev.Service } } # 4. 当前在线的可移动磁盘 Get-CimInstance Win32_DiskDrive | Where-Object { $_.MediaType -like '*Removable*' } | Select-Object Model, InterfaceType, SerialNumber

第 1 条的Start值是判定核心:4表示 USB 存储驱动被禁用,插上 U 盘只会认成一个无法访问的设备;3表示正常启用。改这个值需要重启才生效,而且如果机器上有组策略下发的外设管控,你改完重启会被打回原值,这点在第五节会细说。第 2 条的 WPD 类驱动控制手机和相机的 MTP 连接,很多人只关 USBSTOR,结果手机插上照样能拷照片,就是这个键没动。

第 3 条是这套检查里最有价值的部分。Enum\USBSTOR下每一个子键对应一台曾经接入过的存储设备,FriendlyName里通常带厂商和型号,实例ID里带序列号。数量多、时间新、型号杂,说明这台机器被当作数据中转站用过。判定上不要一刀切,交付前发现几十条历史记录很正常(谁没插过几个 U 盘),但如果记录里出现了不属于本单位的设备型号,或者最近一条记录晚于设备回收登记时间,就要单独核实。第 4 条只反映“此刻插着什么”,容易漏,别当主证据用。

提示:历史痕迹的清理本身就是一项操作,如果一台机器上Enum\USBSTOR干干净净但setupapi.dev.log里有大量设备安装记录,这个矛盾点值得单独记一笔。

4.3 共享与远程入口:Get-SmbShare 之后还要看会话

共享和远程这两块的问题不是“有没有开”,是“开给了谁”。默认共享禁不掉,判定的重点是自定义共享和当前连接会话。

# 1. 所有 SMB 共享,重点看 Name 和 Path Get-SmbShare | Select-Object Name, Path, Description, Special # 2. 当前连接进来的会话:谁正在读你的盘 Get-SmbSession | Select-Object ClientComputerName, ClientUserName, NumOpens # 3. 远程桌面开关:0=允许,1=禁止 Get-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server' ` -Name fDenyTSConnections | Select-Object fDenyTSConnections # 4. WinRM 是否在跑,跑着就意味着有远程命令通道 Get-Service WinRM | Select-Object Status, StartType

第 1 条的Special字段为True的是系统默认共享(C$、IPC$、ADMIN$),这类不计入异常;Special为False的自定义共享才是判定对象,尤其是Path指向用户目录、桌面、项目盘的,一律按高风险处理。第 2 条的Get-SmbSession需要管理员权限,非管理员会话返回空数组,看起来像“没有连接”,这是个经典的假阴性。

第 3 条fDenyTSConnections为0表示允许远程桌面接入,这在运维场景下很常见,但在保密要求高的终端上应该是1。这里要注意它是机器级开关,用户级的远程协助是另一套配置,别混。第 4 条 WinRM 的StartType如果是Automatic而Status是Stopped,说明服务被手动停过但开机还会起来,这种“半关”状态比明确开启更容易被忽略。

4.4 审计策略与日志留存:auditpol 的输出怎么判

审计这块的判定逻辑和前几类不一样:不是“开没开”,而是“开了多少、留了多久”。日志留存时间不够,出了事查不到,等于没开。

# 1. 所有审计子类别的当前设置 auditpol /get /category:* # 2. 只看关键三项:登录、对象访问、策略更改 auditpol /get /category:* | Select-String -Pattern '登录|对象访问|策略更改' # 3. 安全日志的容量与保留方式 wevtutil gl Security # 4. 日志文件实际大小与最早一条记录时间 Get-WinEvent -LogName Security -MaxEvents 1 | Select-Object TimeCreated, Id

auditpol /get的输出是表格文本,/category:*会把所有子类别列全,重点看三类:账户登录(成功和失败都要开,只开成功等于放过暴力破解)、对象访问(文件系统审计需要有 SACL 配合,光开策略没用)、策略更改(防止有人中途改配置)。输出里显示“无审核”或“No Auditing”的,就是没开。

wevtutil gl Security有三个字段要盯:maxSize(日志上限,默认 20MB 在现代终端上偏小,建议 128MB 起)、retention(false表示写满即覆盖,true表示按需覆盖,AutoBackup表示写满自动归档)、AutoBackup。如果retention是false且maxSize很小,一台忙的机器可能几小时就把日志冲掉了,这条应该判中风险,即使审计策略全开。

第 4 条取最早一条记录的时间,和第 3 条的容量对照着看,能估出留存天数。留存天数低于基线要求(比如 90 天)的,直接列入整改项。这里有个坑:Get-WinEvent在日志很大时取-MaxEvents 1是取最新一条,不是最早一条,要拿最早记录得用-Oldest:

Get-WinEvent -LogName Security -Oldest -MaxEvents 1 | Select-Object TimeCreated, Id

这两个参数的差别我踩过一次,用错了方向,把一台日志只剩两小时的机器判断成留存充足,后来复盘时脸都绿了。

5. 避坑记录:五个让报告“全绿”却毫无意义的翻车现场

这一节全是我自己或身边人真实踩过的。共同点是:脚本不报错,报告能生成,结论看起来漂亮,但完全不能用。

5.1 现象:报告所有项都是“合格”,包括本该红的项

原因几乎一定是权限。非管理员会话下,Get-SmbSession返回空、Get-WinEvent -LogName Security抛异常被脚本的try/catch吞掉、HKLM:\SAM相关键读不到默认返回$null,而脚本里大量判定写的是if ($value -eq $expect) { 合格 } else { 不合格 },$null不等于期望值时本该判不合格,但如果脚本写成了if ($value -ne $expect) { 不合格 }且前面有if (-not $value) { return },就会直接跳过,跳过项在统计里不计入“不合格”,于是全绿。

解决:跑之前强制检查管理员会话,不满足就退出。在脚本开头加一段:

$id = [Security.Principal.WindowsIdentity]::GetCurrent() $pr = New-Object Security.Principal.WindowsPrincipal($id) if (-not $pr.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) { throw '需要管理员权限,当前会话不满足,停止执行' }

另外在报告里加一列“是否成功读取”,读失败的项单独标黄,不要静默丢弃。

5.2 现象:脚本只跑了一半就结束,退出码还是 0

从压缩包直接双击,或者解压后没解锁文件,PowerShell 会按远程脚本处理。有些检查项在Set-StrictMode下遇到未定义变量会抛终止错误,主脚本如果用了-ErrorAction SilentlyContinue或每个检查项独立try/catch,单个失败不影响整体,于是你看到的是“跑完了”,实际上是“跑到一半后面全跳了”。

解决:解压后统一Unblock-File,跑之前用Get-Item .\checks\*.ps1 | Get-Item -Stream Zone.Identifier确认没有残留标记;同时在主脚本里统计“实际执行的检查项数”和“基线里定义的检查项数”,两个数不一致就在报告首行打警告。

5.3 现象:CSV 用 Excel 打开中文全是乱码,或者列错位

编码问题和分隔符问题经常一起出现。脚本用Export-Csv默认写的是当前代码页,如果跑的时候是 936 而在别处用 UTF-8 打开,中文就变问号;另一种情况是某个检查项的返回值里本身带逗号(比如设备名SanDisk, Crucial),导出时没加引号,整行右移一列。

解决:导出时显式指定编码和分隔符,并在写之前把值里的逗号、换行替换掉:

$rows | ForEach-Object { $o = $_.PSObject.Copy() foreach ($p in $o.PSObject.Properties) { if ($p.Value -is [string]) { $p.Value = $p.Value -replace "[\r\n]", ' ' -replace ',', ',' } } $o } | Export-Csv .\reports\result_fixed.csv -NoTypeInformation -Encoding UTF8

-Encoding UTF8在 5.1 上写的是带 BOM 的 UTF-8,Excel 能正确识别;PowerShell 7 默认不带 BOM,需要额外处理。这一步做完再打开,列就不会串。

5.4 现象:手动改完注册表,重启后又被改回去了

这是域环境最典型的情况。你在本机把USBSTOR\Start改成 4,gpupdate /force之后变回 3,因为域里有组策略在下发外设管控,本地设置优先级低。反过来也成立:有人为了让报告变绿,临时改了本地策略,检查当时是合格的,下一次策略刷新就回滚,问题原封不动。

解决:先确认配置来源,再决定改哪里。

# 看当前生效的是域策略还是本地策略 gpresult /h .\reports\gpresult.html /f # 快速看外设相关策略是否被下发 gpresult /r /scope:computer | Select-String -Pattern '设备|Device'

如果确认是域策略下发,本地改了没用,正确路径是提变更单改 GPO,或者在 OU 层面把这类终端挪到允许外设的策略组里。检查报告里也应该体现“配置来源”这一列,来源为域的项,整改动作要写“联系策略管理员”,而不是“修改本机注册表”。

5.5 现象:某一类检查项整体缺失,报告里连条目都没有

多半是 CIM/WMI 调用失败。Get-CimInstance Win32_DiskDrive在 WMI 服务异常、仓库损坏、或者机器负载极高时会超时,脚本如果没设超时、直接try/catch忽略,这一类就整体消失。还有一种情况是脚本用了Get-WmiObject,在 PowerShell 7 上这个命令不存在,整段直接报错跳过。

解决:跑之前先探一下 WMI 是否健康,把超时显式设上:

# WMI 仓库自检,输出应为 True Test-Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Wbem' # 带超时的 CIM 查询,避免卡死 $opt = New-CimSessionOption -TimeoutSec 20 Get-CimInstance -ClassName Win32_DiskDrive -OperationTimeoutSec 20 -ErrorAction Stop | Measure-Object

再在主脚本的汇总环节加一条校验:基线里定义的检查项 ID 集合,减去报告里出现的 ID 集合,差集不为空就在报告首行打印缺失清单。这一步加上之后,我再没出现过“报告看着完整实际缺一类”的情况。

6. 二次开发与复检:让这套脚本适配你自己的基线

包里的默认基线只能当起点,真正要能用,得换成你们内部那套终端保密要求。改动尽量集中在配置文件里,别去动checks\下的脚本逻辑,否则下次换版本合并起来会很痛苦。我一般的做法是把基线抽成 JSON 数组,一条一个检查项,字段固定为 ID、名称、类型、路径、期望值、级别、整改建议,脚本只负责按类型分派读取函数。这样加一条新检查项就是加一段 JSON,不用碰代码。

6.1 把基线搬进 JSON

[ { "Id": "SEC-USB-001", "Name": "USB 存储驱动启停", "Type": "Registry", "Path": "HKLM:\\SYSTEM\\CurrentControlSet\\Services\\USBSTOR", "Value": "Start", "Expect": 4, "Level": "High", "Advice": "无外设需求的终端应将 Start 置为 4,改后需重启生效" }, { "Id": "SEC-LOG-002", "Name": "安全日志上限不低于 128MB", "Type": "WevtSize", "LogName": "Security", "MinBytes": 134217728, "Level": "Medium", "Advice": "调整日志上限并开启按需覆盖,避免写满即丢" } ]

JSON 里反斜杠要转义成\\,这是最常见的语法错误来源。Expect用数字而不是字符串,避免'4' -eq 4这类隐式转换带来的判定歧义。Level只留 High/Medium/Low 三档,档位太多会导致整改优先级排不明白。

跑的时候用-Baseline指向新文件,跑完先看总数对不对:

$b = Get-Content .\config\baseline.json -Raw -Encoding UTF8 | ConvertFrom-Json "基线条目数: $($b.Count)" $r = Import-Csv .\reports\result_*.csv "报告条目数: $($r.Count)" Compare-Object $b.Id $r.CheckId | Format-Table

两个数一致、Compare-Object无输出,才说明每一条基线都被执行到了。

6.2 造一台“不合格”的虚拟机来验证

基线改完必须验证,否则你不知道是自己写错了还是机器本来合格。我习惯在一台干净的虚拟机上故意造几个不合格项,看脚本能不能抓出来:

# 故意放开 USB 存储,造一个高危项 Set-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Services\USBSTOR' -Name Start -Value 3 # 故意建一个自定义共享 New-Item -Path 'C:\Temp\share_probe' -ItemType Directory -Force New-SmbShare -Name 'probe_share' -Path 'C:\Temp\share_probe' -ReadAccess 'Everyone' # 故意关掉一项审计 auditpol /set /subcategory:'登录' /failure:disable

跑完检查,报告里 SEC-USB-001 应为 High 不合格、共享类应出现probe_share异常、审计类应报登录失败未审计。三项都对上,说明基线写得没错。验证完记得把这三处改回去,虚拟机拍个快照更省事。

6.3 两次扫描做 diff 才看得出整改有没有落地

单次报告只能说明“此刻状态”,说明不了“改没改”。整改前后各扫一次,用检查项 ID 做键做差分,才是一份能给上级看的材料:

$before = Import-Csv .\reports\result_20240110.csv | Group-Object CheckId -AsHashTable $after = Import-Csv .\reports\result_20240118.csv | Group-Object CheckId -AsHashTable $after.Keys | ForEach-Object { $a = $after[$_][0]; $b = $before[$_] if ($b -and $b[0].Result -ne $a.Result) { [pscustomobject]@{ Id = $_ Name = $a.CheckName Before = $b[0].Result After = $a.Result Level = $a.Level } } } | Sort-Object Level | Export-Csv .\reports\diff.csv -NoTypeInformation -Encoding UTF8

Group-Object -AsHashTable是为了防止同一个 ID 出现多行(多值检查项常见),取[0]只比较首条,如果要严格比对得改成比较整个集合。这一步跑出来的diff.csv才是有价值的产物:整改了几项、恶化了几项、哪些高危项原地不动,一目了然。

说个我自己的教训。最早做这类检查,我图快,只跑一次就把报告交上去,结果对方问“上次发现的那三个高危项改了吗”,我翻半天翻不出来,只能重新跑一遍。从那以后我每次扫描都强制先归档一份基线快照、命名带日期,并且在报告目录里放一个diff脚本,两次结果一比,谁也别想糊弄。这套习惯比工具本身值钱,希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/27 17:50:55

Windows终端保密检查工具安装配置与零命中排查

简介:这款「终端保密检查工具」面向 Windows 平台的终端保密自查与合规检查场景,适合单位保密管理人员、安全运维人员及需要做终端风险排查的读者参考使用,可用于整理检查工具、验证运行环境与了解基础检查流程。压缩包共 9 个文件&#xff0…

作者头像 李华
网站建设 2026/10/27 17:49:55

PC端网页录音实战:麦克风采集、实时波形与分片上传

简介:一套围绕 H5 音频能力的前端实战示例,面向需要实现浏览器端麦克风采集、实时音频流处理与录音上传的开发者,尤其适合 PC 端 Web 项目。内容借助 Web Audio API 与 getUserMedia 取得实时音频流,再用 MediaRecorder 分片录制并…

作者头像 李华
网站建设 2026/10/27 17:49:28

ECharts智慧交通大屏源码实战:从数据模型到性能优化

简介:数据可视化是智能业务系统升级的重要基础,当信息需要承载到指挥中心大屏上时,多图表协同、秒级感知和数据稳定就成了关键。大屏不同于普通报表,它要求前端工程在有限屏幕内高效呈现车流趋势、区域拥堵与状态指标。ECharts作为…

作者头像 李华
网站建设 2026/10/27 17:49:08

深度学习训练-推理不匹配问题与学习率调度优化

1. 问题背景与核心挑战在深度学习模型训练过程中,我们常常会遇到一个棘手的问题:模型在训练集上表现优异,但在实际推理(inference)阶段却出现性能下降。这种现象被称为"训练-推理不匹配"(Trainin…

作者头像 李华
网站建设 2026/10/27 17:48:32

2025年终总结写作指南:量化成果与创新呈现

1. 年终总结的价值与意义每到岁末年初,年终总结总是职场人绕不开的话题。作为一位经历过十余次年终总结的老职场人,我深刻体会到这份看似形式化的文档背后蕴含的巨大价值。年终总结不是简单的流水账,而是个人职业成长的里程碑,是梳…

作者头像 李华
网站建设 2026/10/27 17:47:27

网络安全工程师的日常:从渗透测试到安全架构设计

1. 网络安全行业的真实面貌很多人对网络安全从业者的印象还停留在"修防火墙"的刻板认知中。实际上,现代网络安全工程师的工作范畴早已突破了传统边界,他们更像是数字世界的"全科医生",需要掌握从底层硬件到上层应用的全栈…

作者头像 李华