简介:PD2BS脚本包是一套面向暗黑破坏神2模组Project Diablo 2玩家的自动化脚本集合,基于Kolbot框架构建,主要解决挂机、多开、自动带队、自动跟随与仓库管理等重复性操作问题。脚本放入d2bs文件夹后即可调用,常见任务模块以任务入口文件形式组织,同时提供大量JavaScript脚本、文本配置、物品拾取过滤规则和任务日志文件,支持通过调整关键参数适配不同角色与装备需求,适用范围覆盖普通打宝、频道管理、组队协作与小号仓库运转等场景。压缩包共229个文件,大小约707KB,其中主体为151个JavaScript脚本,另有33个文本配置、22个物品过滤规则和10个任务入口文件,目录结构清晰,便于按模块检索和二次修改。资源内还附带常见问题排错说明,如GS服务器修改、技能编号查询、拾取规则配置以及D2BS崩溃后的处理思路,能帮助玩家减少实际使用中的高频障碍。目前已有241人学习下载,推荐给希望基于Kolbot快速搭建PD2自动化脚本环境、又想保留灵活定制空间的玩家。
1. 项目概述:一组脚本解决什么问题
如果你做开发或者运维,大概率遇到过这种情况:明明在 PowerShell 里跑得好好的命令,换到 cmd 或者计划任务里就各种报错;或者机器刚装完系统,要手动敲几十条初始化命令;再或者同事发来一个.ps1文件,你却没法直接双击运行,还得去调执行策略。
pd2bs-scripts 这个项目名很短,但它的定位很明确——它是一套围绕pd2bs核心工具展开的脚本集合,主要解决两类问题:一类是把 PowerShell 脚本安全、可靠地转换为批处理脚本(Batch),让原本只能在 PowerShell 环境下运行的逻辑,可以在 cmd、计划任务、开机启动等更基础的 Windows 系统环境中直接执行;另一类是把日常运维和开发中大量重复性的操作,封装成标准化的脚本模板,降低手工操作带来的失误率。
我折腾这套脚本的原因很实际。当时接手一台服务器,发现上面有一条跑了两年的定时任务,居然是用一种非常古老的方式实现的——把 PowerShell 脚本通过计划任务调用,但执行策略一直是 Restricted,导致脚本时灵时不灵。排查到最后,问题就出在powershell.exe -Command的调用参数上。后来我用类似 pd2bs 的思路,把所有 PowerShell 逻辑全部封装成带参数的批处理入口,再用统一格式的脚本目录管理起来,这个问题再也没有出现过。
这套脚本方案适合谁?如果你符合下面任意一条,都值得参考:
- 你经常需要在 Windows 服务器或PC上跑自动化脚本,但执行环境五花八门;
- 你手头有一堆散落的
.ps1、.bat、.py脚本,缺少统一的管理方式和调用规范; - 你需要在计划任务、开机自启、登录脚本等场景中稳定触发 PowerShell 逻辑,却总被执行策略和路径问题困扰;
- 你刚开始接触脚本,想找一套可以“抄作业”的模板来规范自己写脚本的习惯。
从维护者的角度来看,这套脚本表面上只是几个.bat和.ps1文件的组合,但核心价值在于它提供了一种“入口统一、逻辑隔离、错误可查”的脚本组织思路。这篇文章我会从项目设计思路讲起,接着拆解脚本内容,然后给出部署操作步骤,最后整理我在实际使用中踩过的坑和排查方法。
2. 核心思路拆解:为什么要把 PowerShell 封装成批处理
2.1 执行策略问题的根源
Windows 系统默认的 PowerShell 执行策略是 Restricted,也就是说双击.ps1文件根本无法运行,这是保护机制,但也是日常自动化最大的阻力之一。很多同学第一反应是随手执行一条Set-ExecutionPolicy RemoteSigned把策略改掉。这个做法单机临时用没问题,但如果到了生产服务器或者公司域环境,改执行策略可能会被安全策略拦截,也可能引入不必要风险。
pd2bs-scripts 采取的是另一种思路:利用批处理作为统一入口,在批处理内部显式调用 PowerShell 引擎,并通过参数绕过执行策略的限制。这样既不需要修改系统默认策略,又能让普通双击、cmd 调用、计划任务三种场景共享同一个入口。
这里补充一点关于绕过执行策略的常识。PowerShell 启动时,执行策略的优先级从高到低大致是:MachinePolicy > UserPolicy > Process > CurrentUser > LocalMachine。其中 Process 级别只对当前进程生效,不会写入注册表,也不会持久化。pd2bs-scripts 的做法就是在调用时通过-ExecutionPolicy Bypass -File来设定 Process 级策略,这是最安全、改动最小的一种方案。
2.2 “入口统一,逻辑隔离”的设计模式
我见过很多脚本项目,最大的问题不是脚本写不出来,而是入口散乱。有的逻辑直接写在.bat里,有的写在.ps1里,还有的直接就是一段裸命令。时间一长,项目维护者自己都忘了哪个脚本对应哪个功能。
pd2bs-scripts 的思路可以用三句话概括:
.bat只做一件事:负责定位脚本目录、拼接参数、调用 PowerShell;.ps1只做一件事:接收参数、执行业务逻辑、返回错误码;- 公共配置单独用
.psm1或.json文件存放,避免在脚本里硬编码路径。
这种设计带来一个很实在的好处:排查问题时分界线非常清楚。如果双击.bat没有反应,先检查.bat里路径对不对;如果.bat正常但业务结果不对,再去检查.ps1的逻辑。不会出现“改了 bat 里的逻辑导致 ps1 也受影响”的情况。
2.3 脚本名里隐藏的版本管理意识
pd2bs-scripts 里的文件名往往带有版本号或日期后缀,比如deploy_20250101.ps1这类命名。很多人觉得文件名带日期麻烦,但从实际运维角度看,这恰恰是最朴素也最有效的版本管理方式——特别是在没有引入 Git 的存量服务器上。
我在实践中发现,脚本命名最好的模式是“功能名_动作_版本号”三段式,比如backup_run_v2.ps1。这样当脚本出问题时,可以直接根据时间线回溯改动,也能同时保留新旧版本便于回滚。比依赖 Git 提交记录更直观,也更适合在服务器上快速定位。
3. 脚本内容解析与实操要点:关键脚本到底怎么用
3.1 标准入口批处理的写法
pd2bs-scripts 中最核心的文件是一个名为run.bat的模板。一个基本可用的版本类似这样:
@echo off setlocal set SCRIPT_DIR=%~dp0 set SCRIPT_NAME=%~n0 powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%SCRIPT_DIR%\scripts\%SCRIPT_NAME%.ps1" %* set EXIT_CODE=%ERRORLEVEL% if not "%EXIT_CODE%"=="0" ( echo [ERROR] Script failed with code %EXIT_CODE% exit /b %EXIT_CODE% ) endlocal这里有几个容易踩坑的细节需要重点说明:
第一,%~dp0获取的是当前批处理所在目录,结尾带反斜杠。如果你的批处理和 ps1 不在同一目录,千万不要拼成%SCRIPT_DIR%scripts\xxx.ps1,否则会出现双反斜杠导致路径解析失败。
第二,%*表示透传所有参数。很多新手会写成%1 %2 %3,这样每加一个参数都要改批处理,完全没必要。直接用%*透传,PowerShell 侧再用param()块接收即可。
第三,set EXIT_CODE=%ERRORLEVEL%这行不能省。ERRORLEVEL在批处理中是一个动态变量,如果直接拿它做条件判断,一旦后面的命令改变了错误码,前面的调用结果就被覆盖了。先把它保存到一个普通变量中再使用,是稳定判断的前提。
3.2 PowerShell 脚本侧的参数设计
对应的 PowerShell 脚本模板可以这样写:
param( [Parameter(Mandatory = $false)] [string]$ConfigPath = "", [Parameter(Mandatory = $false)] [switch]$Force ) $ErrorActionPreference = "Stop" $scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path # 加载公共函数 Import-Module (Join-Path $scriptDir "common.psm1") -Force # 日志初始化 $logDir = Join-Path $scriptDir "logs" if (-not (Test-Path $logDir)) { New-Item -ItemType Directory -Path $logDir -Force | Out-Null } $logFile = Join-Path $logDir ("{0:yyyyMMdd_HHmmss}.log" -f (Get-Date)) Start-Transcript -Path $logFile -Append try { # 业务逻辑写在这里 if ($Force) { Write-Host "[INFO] Force mode enabled" } Write-Host "[INFO] Task completed" exit 0 } catch { Write-Host "[ERROR] $($_.Exception.Message)" exit 1 } finally { Stop-Transcript }这里面的关键设计有四个:
$ErrorActionPreference = "Stop"必须放在脚本最前面,否则非终止错误不会触发 catch,脚本可能“表面成功实际失败”。Start-Transcript是 PowerShell 自带的日志记录工具,它会把控制台输出的所有内容同步写入日志文件。排查问题时比在代码里到处写Write-Log要省事得多。param块放在脚本第一行,前面不能有任何输出或注释(注释可以放在 param 之后)。- 最后
exit 0/exit 1返回的状态码,会被批处理侧的%ERRORLEVEL%捕获,从而决定外层是否提示失败。
3.3 公共模块的写法
第三类关键脚本是common.psm1,它用于存放多个脚本共同调用的函数。我在项目里放得最多的两个函数是日志写入和配置读取:
function Write-Log { param( [string]$Message, [string]$Level = "INFO" ) $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" Write-Host "[$timestamp][$Level] $Message" } function Get-ConfigValue { param( [string]$Key, [string]$FilePath ) $config = Get-Content $FilePath -Raw | ConvertFrom-Json return $config.$Key }需要提醒的是,powershell.exe -File调用脚本时,当前目录是批处理所在的目录,而不是 PowerShell 脚本所在目录。所以脚本内部如果要引用相对路径,必须基于$MyInvocation.MyCommand.Path动态获取脚本自身目录,再拼接路径。这个细节非常容易踩坑,尤其是脚本被计划任务调用时,工作目录往往是C:\Windows\System32,相对路径会全部失效。
4. 虚拟环境与部署实践:把脚本接到日常流程里
4.1 环境准备与目录约定
在部署 pd2bs-scripts 之前,建议按下面的方式组织目录结构,这是我从多次项目经验中总结出来的比较稳的布局:
C:\Scripts\ ├── bat\ # 存放所有批处理入口 ├── ps1\ # 存放所有 PowerShell 业务脚本 ├── modules\ # 存放公共模块 (.psm1) ├── config\ # 存放 JSON/INI 配置文件 ├── logs\ # 日志目录 └── backup\ # 脚本备份目录这个结构与 pd2bs-scripts 的“入口统一”思想是完全一致的。批处理和业务脚本分开目录,是为了防止误修改;模块单独放,是为了让多个脚本共享同一套函数实现;日志集中放,方便日常巡检。
4.2 快速接入计划任务
把一套脚本接到计划任务里,是 pd2bs-scripts 最常见的用法。过程中可以参考下面的步骤:
- 打开任务计划程序,选择“创建任务”;
- 在“常规”选项卡中,填任务名称(建议用“功能_频率_版本”格式),勾选“不管用户是否登录都要运行”;
- 在“触发器”选项卡中,点击“新建”,按需设置执行时间和间隔;
- 在“操作”选项卡中,点击“新建”,程序或脚本填写
C:\Scripts\bat\run.bat,起始于填写C:\Scripts\bat; - 在“条件”选项卡中,取消勾选“只有在计算机使用交流电源时才启动此任务”(如果脚本必须在电池模式下运行);
- 在“设置”选项卡中,勾选“如果任务失败,按计划重新启动”。
这里特别强调两个容易忽略的地方:第一是“起始于”目录,虽然批处理内已经通过%~dp0定位了脚本目录,但在计划任务环境里,显式声明工作目录依然能规避意外情况;第二是触发器的“重复任务间隔”选项,很多人设置定时任务后没勾选“重复”,结果任务只跑了一次就再也不执行了。
4.3 在命令行下测试脚本的常用命令
我调试这类脚本时,最常用的命令是下面三条:
:: 测试批处理入口是否正常 C:\Scripts\bat\run.bat :: 单独测试 PowerShell 脚本本身的逻辑 powershell.exe -NoProfile -ExecutionPolicy Bypass -File C:\Scripts\ps1\run.ps1 -Force :: 直接进入 PowerShell 并测试模块加载 powershell.exe -NoProfile -ExecutionPolicy Bypass -Command "Import-Module C:\Scripts\modules\common.psm1; Get-ConfigValue -Key 'server' -FilePath 'C:\Scripts\config\app.json'"在 Windows 10/11 以及较新的 PowerShell 7 环境下,还可以用pwsh替代powershell.exe,效果基本一致,执行策略参数名保持不变。有一点需要特别注意:powershell.exe(Windows PowerShell 5.1)和pwsh(PowerShell 7+)是两个不同的引擎,脚本如果在其中一个环境下能跑、在另一个环境下报错,大概率是模块兼容性问题,而不是逻辑问题。
5. 常见问题与排查技巧实录
5.1 高频问题速查表
我在实际使用中还经常遇到下面这些报错,整理成速查表方便参考。
| 现象 | 可能原因 | 排查思路 |
|---|---|---|
| 双击 .bat 后窗口一闪而过 | 脚本执行错误,但命令窗口自动关闭 | 在 .bat 开头加pause,或者在末尾加echo %EXIT_CODE% & pause观察错误码 |
| 提示“无法将 xxx 项识别为 cmdlet、函数、脚本文件或可运行程序的名称” | PowerShell 侧找不到命令或脚本路径 | 检查 ps1 内部路径是否基于$MyInvocation.MyCommand.Path,不要用相对路径 |
| 计划任务显示“上次结果 0x1” | 脚本非零退出,但无法看到具体错误 | 把Start-Transcript日志打开,查看日志文件中的堆栈信息 |
| 脚本执行成功但没有任何输出 | Start-Transcript 吞掉了 Write-Host 的输出(极少见) | 改用Write-Output替代Write-Host,或在脚本末尾手动读取日志文件 |
| PowerShell 脚本无法加载,提示“禁止运行脚本” | 执行策略是 Restricted | 不要改系统默认策略,改用-ExecutionPolicy Bypass -File调用 |
| 执行策略已设但是非管理员账号仍报错 | 当前用户级策略被组策略锁定 | 在 cmd 中运行gpresult /h gp.html查看生效的组策略结果,确认 MachinePolicy/UserPolicy 是否覆盖了当前设置 |
5.2 定位问题的“三步法”
有一次我在客户现场调试一个定时同步脚本,白天手动执行完全正常,晚上计划任务总是失败。最后的排查过程让我总结出了下面这套“三步定位法”。
第一步,把计划任务的运行账户切换成当前登录用户,并勾选“仅在用户登录时运行”,看是否能复现问题。这一步能排除权限不足的情况。那次就是因为计划的运行账户没有对应目录的写权限,白天用管理员本地跑当然没有异常,晚上计划任务用另一个账户跑就直接失败。
第二步,在 .bat 里临时加上pause,把输出留在屏幕上,通过任务计划“手动运行”功能观察实际输出。虽然计划任务窗口通常不可见,但通过“生成的事件报告”和日志文件也能获取线索。
第三步,清理排查运行环境。哪怕计划任务设置的账户是管理员,其实际加载的环境变量也可能和你手动打开 cmd 时不一样,尤其是 PATH 变量和当前工作目录。所以在脚本内部绝对不要依赖“当前位置”,所有路径都必须显式声明。
5.3 日志轮转的简单实现
脚本跑久了,log 目录会越来越大。如果不做轮转,一两年后一个脚本就能制造出几十 GB 的日志文件(我确实见过这种情况)。一个简单实用的轮转策略是按天数分目录,每天一个日志文件,同时只保留最近 30 天。
在 PowerShell 里可以用Get-ChildItem加Where-Object来做清理:
$keepDays = 30 $threshold = (Get-Date).AddDays(-$keepDays) Get-ChildItem $logDir -Directory | Where-Object { $_.CreationTime -lt $threshold } | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue这个逻辑我一般放在common.psm1里,每次脚本启动时自动执行一次,成本几乎为零,但能避免日志无节制增长。
5.4 处理 PowerShell 命令无法被识别的问题
热搜词里频繁出现的“claude 无法将‘claude’项识别为 cmdlet、函数、脚本文件或可运行程序的名称”,本质上跟npm、git、pnpm、mvn这类命令无法识别是同一个问题——命令对应的可执行文件不在 PATH 环境变量中,或者根本没有安装。
如果你遇到的是这类问题,排查顺序可以按照下面的清单走:
- 确认对应软件是否真的已安装;
- 确认安装后是否重启了终端窗口(PATH 在会话启动时加载,重启是必要的);
- 运行
where.exe claude或Get-Command claude -ErrorAction SilentlyContinue查看系统能否找到该命令; - 如果找不到,找到安装目录后手动追加到 PATH(或在当前终端里
$env:PATH += ";C:\path\to\bin"); - 如果之前是通过
npm install -g安装的,检查 npm 的全局目录是否在 PATH 中。
这类问题跟 pd2bs-scripts 的关系在于:当你要在批处理或计划任务中调用这类命令时,一定不能假设 PATH 是完整的。最稳妥的方式是在脚本中显式写出命令的完整路径,比如C:\Program Files\nodejs\claude.exe,这样无论环境变量怎么变化都不会受影响。
6. 实用扩展:从脚本库到自动化小平台
pd2bs-scripts 做到后面,已经不只是一个脚本集合了,它完全可以将脚本入口收敛到一个统一的控制台。这里分享一个我在项目中验证过的扩展思路:做一个简单的菜单式调用入口。
用cmd的choice命令就能实现,不需要任何额外工具:
@echo off :menu cls echo ========================================== echo Scripts Management Console echo ========================================== echo 1. Run backup script echo 2. Run health check script echo 3. Run log clean script echo 0. Exit echo ========================================== choice /c 1230 /n /m "Please select: " if errorlevel 4 exit /b 0 if errorlevel 3 call bat\log_clean.bat if errorlevel 2 call bat\health_check.bat if errorlevel 1 call bat\backup.bat pause goto menuchoice命令返回值是逆序的,errorlevel 4对应选择0,errorlevel 3对应选择3,以此类推。这个套路写过一次之后,后面加任何脚本都只需要复制一行。
我在实际使用中的体会是,脚本自动化这件事,最怕的不是代码写得多复杂,而是没有一个“统一入口”的概念。pd2bs-scripts 这类项目看起来只是简单的封装和整理,但它把“执行环境差异”“日志记录”“参数传递”“错误码规范”这几件看似琐碎但实际非常重要的事一次性标准化了。如果你也经常被 Windows 下的脚本执行环境折磨,不妨现在就建一个这样结构的脚本库,把第一个脚本从批处理入口开始写起——你很快就会感受到这种规范化带来的省心。
本文还有配套的精品资源,点击获取