You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

将PowerShell安全事件监控脚本转化为常驻系统进程并优化资源占用

搞定持久化运行你的安全事件监听脚本

作为PowerShell新手,你遇到的这个"脚本关了ISE就停"的问题太常见了,我给你两个靠谱的解决方案,还有脚本优化的小建议,帮你把脚本改成开机自启、后台稳跑的服务。

一、原生方案:不用额外工具,直接注册成Windows服务

Windows自带的工具就能把你的脚本做成系统服务,开机自动启动,后台默默运行,完全不用依赖控制台窗口。

操作步骤:

  1. 先把你的脚本存成固定路径的.ps1文件,比如E:\apps\me\SecurityEventMonitor.ps1,注意所有路径都用绝对路径,别用相对路径或者环境变量,避免服务运行时找不到文件。
  2. 写个简单的批处理文件(比如StartMonitor.bat),用来调用PowerShell运行脚本:
@echo off
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "E:\apps\me\SecurityEventMonitor.ps1"

解释下参数:-NoProfile跳过加载用户配置文件(服务用的是系统账户,没用户配置),-ExecutionPolicy Bypass确保脚本能跑(如果服务器的PowerShell执行策略设得比较严的话)。
3. 用管理员权限打开PowerShell,注册服务:

New-Service -Name "SecurityEventMonitor" -BinaryPathName "C:\path\to\StartMonitor.bat" -DisplayName "安全事件日志监控服务" -StartupType Automatic

要是习惯用sc命令也可以:

sc create SecurityEventMonitor binPath= "C:\path\to\StartMonitor.bat" start= auto displayname= "安全事件日志监控服务"

⚠️ 注意:binPath=start=后面必须加空格,这是sc命令的奇葩语法要求,别漏了!
4. 启动服务:

Start-Service SecurityEventMonitor

之后你可以在「服务」管理器里看到它的状态,确认是不是在运行。

踩坑提醒:

  • 服务默认用Local System账户运行,如果你的脚本里Get-ADUser需要访问AD的权限,得去服务属性里把登录账户改成有AD读取权限的域账户。
  • 脚本里写CSV的路径(E:\apps\me\testScript.csv)要给服务账户加写入权限,不然会报错写不进去。
  • 要是想调试脚本,把批处理里的命令改成这样,把输出日志存下来:
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "E:\apps\me\SecurityEventMonitor.ps1" >> "E:\apps\me\monitor_debug.log" 2>&1

二、NSSM:非原生但更省心的工具,绝对可靠

你提到的NSSM(Non-Sucking Service Manager)真的是个宝藏工具,完全不像它名字里的"Non-Sucking"那么调侃,它是开源的,已经维护很多年了,生产环境用的人特别多,把普通程序包装成服务比原生方案稳定太多——比如脚本崩溃了它能自动重启,还能配置各种恢复策略。

而且它根本不用"安装",解压出来一个nssm.exe就能用,完全符合你"尽量不用额外工具"的需求,顶多就是复制个文件到服务器而已。

使用步骤:

  1. 下载对应你服务器位数的NSSM版本,解压后把nssm.exe放到C:\Windows\System32(这样全局都能调用),或者直接记住它的路径。
  2. 管理员打开命令提示符/PowerShell,运行:
nssm install SecurityEventMonitor
  1. 弹出图形配置窗口,照着填:
    • Path:选powershell.exe的路径,一般是C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
    • Arguments:填-NoProfile -ExecutionPolicy Bypass -File "E:\apps\me\SecurityEventMonitor.ps1"
    • Working Directory:选脚本所在的文件夹,比如E:\apps\me
    • 切到「Log On」标签,要是需要AD权限,就设置成有对应权限的域账户
    • 切到「Recovery」标签,设置失败后的重启策略(比如第一次失败重启,第二次也重启,第三次重启服务,这样容错性拉满)
  2. 点「Install Service」完成安装,然后启动服务:
nssm start SecurityEventMonitor

三、给你的脚本提个关键优化建议

我看你的脚本里有个$lineNo变量,但从头到尾没定义过!这肯定会导致提取用户名失败的,得赶紧改。而且用分割事件消息的方式提取属性太不靠谱了——如果服务器是中文系统还好,要是换成英文系统,事件消息的行号完全不一样,脚本直接就废了。

推荐用解析事件XML的方式提取属性,不管系统语言是什么都能用:

# 替换你原来分割Message的代码,用XML解析事件属性
$eventXml = [xml]$Evlog.ToXml()
if ($eventID -eq 4724) {
    $SubjectUserName1 = $eventXml.Event.EventData.Data | Where-Object { $_.Name -eq "SubjectUserName" } | Select-Object -ExpandProperty "#text"
    $TargetUserName1 = $eventXml.Event.EventData.Data | Where-Object { $_.Name -eq "TargetUserName" } | Select-Object -ExpandProperty "#text"
}
if ($eventID -eq 4723) {
    $SubjectUserName1 = $eventXml.Event.EventData.Data | Where-Object { $_.Name -eq "SubjectUserName" } | Select-Object -ExpandProperty "#text"
    $TargetUserName1 = $eventXml.Event.EventData.Data | Where-Object { $_.Name -eq "TargetUserName" } | Select-Object -ExpandProperty "#text"
}

另外,脚本里的Get-Event | Remove-Event也可以删掉,服务环境里事件订阅的处理是独立的,这个命令可能会误删其他系统事件,没必要留着。

最后总结

  • 要是不想碰任何第三方工具,原生服务方案完全够用,就是要注意权限和路径的配置。
  • 追求稳定省心的话,NSSM绝对是首选,配置灵活,还能自动恢复故障,生产环境放心用。
  • 赶紧把脚本里的$lineNo问题解决,换成XML解析的方式,不然脚本跑起来也抓不到正确的用户名。

内容的提问来源于stack exchange,提问作者sting_array

火山引擎 最新活动