Install
openclaw skills install @virtualhotbar/pecmd-pro-maxPECMD2012 WinPE 脚本编程 — 轻量级 Windows GUI、系统工具、启动/初始化 脚本、自动化。适用于 .wcs/.wci/.wce 文件、磁盘分区、批处理转 PECMD、 系统信息收集、PE/预安装环境工具、PECMD 代码调试。 参考文件:references/commands-full.md、references/pecmd-gui.md、references/pe-startup.md、 references/how-tos/storage.md、references/how-tos/system.md、references/how-tos/gui.md、references/how-tos/net.md、 references/troubleshooting.md。
openclaw skills install @virtualhotbar/pecmd-pro-max你是 PECMD 专家程序员。PECMD 是从 XCMD V2.2 演进而来的 WinPE 命令解释器与脚本语言——可将其视为 Windows PE 系统管理和轻量级 GUI 工具的领域特定语言。
PECMD 有两种执行模式:
PECMD.EXE ENVI $PPPoE=OK — 单条命令,注释默认关闭PECMD.EXE LOAD C:\PECMD.INI — 多命令文件,注释默认开启PECMD 脚本是一组平铺的顶层语句。从上到下顺序执行。_SUB 块在解析时声明,仅在 CALL 时运行。所有 GUI 由定义窗口函数的 _SUB 块创建(通过 CALL @窗口名 调用)。
关键运行时事实:
PECMD.EXE MAIN 路径\PECMD.INI — 标准 WinPE 入口,执行 INI 并启动消息循环EXEC =!"%MyNAME%" <命令> — 用于隔离的子操作EXIT FILE 终止整个脚本;EXIT _SUB 从当前函数返回EXIT CONTINUE 继续下一次迭代;EXIT - 跳到当前 {} 块尾部;EXIT LOOP / EXIT FORX / EXIT BREAK 跳出循环;EXIT ToWin 中止函数返回窗口消息循环.wcs 扩展名(也支持 .wce、.wci、.wcx、.ini、.inf、.txt、.log 等)。中文脚本首行加 #code=65001 声明 UTF-8 编码。若首行以 #! 开头,编码指令放在第二行。标准 I/O(stdin/stdout/stderr):
READ -,n,&var — 从 stdin 读取一行WRIT -,$+0,text — 写入 stdoutWRIT --,$+0,text — 写入 stderrLOGS * CONOUT$ — 输出到控制台(调试终端输出)PECMD 有四种访问前缀对应三种存储层级(加上就近查找机制)。搞错这一点是绝大多数错误的根源。
| 层级 | 语法 | 设置方式 | 作用域 |
|---|---|---|---|
| 环境变量 | %var% | ENVI var=val 或 ENVI $var=val | 进程级,与子进程共享 |
| PE 全局变量 | %&::var% | ENVI &::var=val 或 SET &::var=val | 跨函数、跨线程、文件级,永不消失 |
| PE 局部变量 | %&&var% | SET &&var=val 或 ENVI &&var=val | 当前 _SUB/{} 块,退出自动销毁 |
| PE 变量引用 | %&var% | ENVI &var=val 或 SET var=val | 就近解析:从内向外查找,找到谁就是谁;找不到则创建为 &&var |
&a 解析顺序(反向匹配,从内向外):
&&a → 找到就用它&::a(全局)→ 找到就用它&&a 在当前范围新建关键规则:
ENVI^ ForceLocal=1 放在文件顶部——强制 ENVI 和 SET 默认创建局部 PE 变量。务必始终使用(默认 ForceLocal=0,变量按就近查找链解析)。ENVI^ EnviMode=1 — 空变量引用返回空字符串。务必始终使用(默认 EnviMode=0,兼容 4.0 模式:空变量不解释为字面文本,自动多轮次非顺序解释)。SET 始终等价于 ENVI &(SET 总是创建 PE 变量而非环境变量)。ForceLocal=1 同时影响 SET 和 ENVI 的作用域(默认局部)。%Desktop% 是环境变量版本;%&Desktop% 是PE 变量版本。&var)——环境变量跨线程共享会竞态。跨线程通信用 &:: 类变量。SET~ &&dest=Source.Key — ~ 运算符执行间接解引用:将右侧展开为变量名,再读取该变量的值。伪数组必备。^ 前缀(^SET、^ENVI、^CALC、^IFEX 等)— 预先解释本命令(help.txt: "命令前若干个^表示预先解释本命令几次")。循环中动态变量名必备。^^ 预解释两次。ENVI-ret %~1=%var% — 将值设置到名称存储在 %~1 中的变量(引用返回)。SET-def var=value — 仅在变量未定义时设置(安全默认值)。| 命令 | 功能 |
|---|---|
ENVI^ EnviMode=1 | 标准模式:空变量解释为空字符串,顺序解释1遍 |
ENVI^ ForceLocal=1 | 强制所有变量为 PE 变量,最简多线程/并行窗口 |
ENVI^ EXPORTLOCAL=1|0|&1|&0 | PE 变量继承:1=继承,0=隔离(默认),&1=仅本级及以下继承,&0=仅本级及以下隔离 |
ENVI^ Alias name=cmd | 命令别名:替代命令前半部(可包装 DLL 调用为伪命令) |
ENVI^ WndProc[1|2|3][C][,ptr] | Win32 回调绑定(C=C 调用约定) |
ENVI^ memvar=[?返回名,][:字节数:]偏移,值 | 修改/查询 PECMD 内存变量 |
ENVI^ LoadPlugin=basename | 加载插件 |
ENVI^ DisX64=1[,Old] | 禁用/恢复 WOW64 文件系统重定向 |
ENVI^ zero=0|1 | 私密模式:内存用完清零 |
ENVI^ Arg=*[字符集]字符串 | 词语分断 |
ENVI^ Clipboard=text|?=var | 读写剪贴板 |
ENVI^ EnviBroad=0|1|- | 环境变量广播开关 |
ENVI^ __arg=0|1 | 兼容模式:启用 &&__arg 参数表 |
ENVI^ LoadEnvi [路径|-] [变量名] | 从注册表刷新环境变量 |
ENVI^ HelpColor=[*高度] [前景色][#背景色] | HELP 显示颜色 |
ENVI @@DeskTopFresh=[clearicon][;][1|2|4|8|16][;[-+]path] | 桌面刷新 |
ENVI @@TaskIcoMenu=0|1|2 | 托盘菜单切换(0=关闭, 1=开启, 2=切换) |
完整 ENVI^ 控制命令、二进制缓冲区操作(SET-cmp、SET-tom、SET-copy、SET?int 等)和函数参数引用,参见 commands-full.md。
ENVI-env 和 SET-env 后缀临时绕过 ForceLocal=1 限制,直接操作环境变量。常用于线程内读取父窗口上下文的环境变量(如 __WinID):
ENVI-env hwnd0=%&__WinID% // 从环境变量读取 __WinID(绕过 ForceLocal)
SET-env MyName=%MyName% // 临时设为环境变量
#code=65001
ENVI^ EnviMode=1
ENVI^ ForceLocal=1
SET$ &NL=0d 0a
SET$ &TAB=09
SET$ &NL=0d 0a // 十六进制转宽字符串(Unicode)
SET$# &buf=*4096 0 // 十六进制转原始字节(二进制缓冲区)
ENVI$ &data=*1M 30 0d 0a // 可变长度十六进制分配
_SUB 函数名 [*] // * = this-call(在调用者栈中运行)
SET ¶m1=%~1 // %~1 剥离外层引号
ENVI-ret %~3=%&result% // 通过引用参数返回值
// 函数参数:%0=函数名, %1~%n=各参数, %#=参数个数, %*=全部参数, %~=去掉引号
_END
CALL 函数名 [参数] // 调用函数
CALL *函数名 [参数] // this-call(调用者栈)
CALL @窗口名 [参数] // 创建/显示窗口(模态,阻塞)
CALL @*窗口名 [参数] // 并行窗口(可同时操作,但关闭前阻塞后续命令)
CALL @-窗口名 [参数] // 后台窗口
CALL @~窗口名 [参数] // 后台,完全非阻塞
CALL @~~窗口名 [参数] // 后台快速调用(非阻塞)
CALL @^窗口名 [参数] // 并行,父窗口不阻塞子窗口
CALL @+窗口名 [参数] // 弃养子窗口
CALL @-- // 销毁 Win 环境(无参数)
CALL @--popmenu 窗口名 [x.y[:对齐]] // 在指定位置弹出菜单(对齐:对齐方式)
CALL --mem &变量名 [*] [参数] // 执行内存中的动态函数代码
_SUB 窗口名,L200T100W400H300,窗口标题,[关闭命令],[图标],[样式],[遮罩] [-标志1 -标志2 ...]
_END
窗口形状:L<左>T<上>W<宽>H<高>。省略 L/T 则居中。
窗口样式:- = 无标题栏,# = 无边框,数字 1-99 = 透明度,:透明色。
常用标志:-trap(关闭按钮不退出)、-nocap(无标题栏)、-nosysmenu、-top、-size、-maxb、-disminb、-discloseb、-nfocus、-ntab、-forcenomin、-scalef、-scale[:DPI]、-nxp、-csize、-na、-layer(支持渐透明)、-disaltmv(禁用 ALT 拖动)
IMPORT 路径\库文件.wcs // 将可复用函数加载到当前脚本
_ENDFILE-IMPORT // 此行以下内容在 IMPORT 时被丢弃
{ // 带独立 PE 变量栈的代码块
SET temp=仅此处有效
}
{* // this-call 代码块(在调用者栈中运行)
LOCK .ole // COM 初始化等需要在当前作用域执行的操作
}
文件级和函数级的 { 必须从第 1 列开始。嵌套 _SUB 用双冒号访问:类名::子函数名。点号用于数据成员访问(如 类名.属性)。
*c 后缀区分)FIND $%var%=hello, 命令 // 相等(不区分大小写)
FIND $%var%*c=hello, 命令 // 相等(区分大小写,*c 后缀)
FIND $%var%<>hello, 命令 // 不等
FIND $%var%=, 命令 // "为空" 测试(惯用法)
FIND *=var, 命令 // 惯用法:"为空"
FIND *<>var, 命令 // 惯用法:"非空"
FIND |%a%>%b%, 命令 // | 前缀 = 浮点数比较
FIND #%a%>%b%, 命令 // # 前缀 = 整数比较(INT64)
FIND [ $A & $B ], 命令 // 复合 AND
FIND [ $A | $B ], 命令 // 复合 OR(| 分隔)
FIND --pid &var, // 返回 5 值:空闲时间 总时间 CPU个数 1秒时钟数 一时钟100ns数
FIND --pid*@ &var, // 进程列表(用于 TABL)
FIND --class:Shell_TrayWnd --wid*@ &var // 按类名过滤窗口列表
FIND --forpid:PID --wid*@ &var // 按进程 ID 过滤窗口
FIND --sub --wid*@ &var // 递归子窗口
FIND --menu &var,窗口ID // 查询窗口的 MENU 句柄
FIND --menu#Index &var,MenuID // 按索引查询子 MENU
IFEX C:\boot.ini, 命令 // 文件/目录存在
IFEX C:\boot.ini,! 命令 // 不存在
IFEX x:\, 命令 // 盘符存在且有文件系统
IFEX $%val%>=5, 命令 // $=浮点数比较(#=整数比较,|=字符串比较)
IFEX [ 条件1 & 条件2 ], 命令 // AND 复合条件
IFEX [ 条件1 | 条件2 ], 命令 // OR 复合条件(| 分隔)
IFEX MEMU=?,&var // 查询可用内存
IFEX C:\=?,&可用空间 // 查询磁盘可用空间
SET &&I=0
LOOP #%&I%<=10, { MESS %&I% | CALC &I=%&I% + 1 }
FORX * %&list%,&&item, { MESS %&item% } // * = 空格分隔
FORX *NL &多行变量,&&line, { ... } // *NL = 换行分隔
FORX *NL:| &数据,&&item, { ... } // *NL:分隔符 = 自定义分隔符
FORX *L 0 2 10,&&val, { ... } // *L = 数值循环(起始 步长 结束)
FORX /S C:\Windows\*.exe,&&file,0 { ... } // 文件系统枚举
FORX @\Windows,&&winDir,1 { ... } // @=仅搜索目录,\=所有盘符
// ⚠ FORX 循环变量引用规则:
// 定义用 &&item,引用值用 %&item%(单&),**不是** %&&item%
// 示例:FORX *NL &list,&&line, { SET &val=%&line% } // ✅ 正确
// FORX *NL &list,&&line, { SET &val=%&&line% } // ❌ 错误
TEAM SET &a=1| SET &b=2| CALC &c=%&a% + %&b% // 多命令链
// 线程
THREAD* CALL WorkerFunc // * = 持久栈(共享变量,保持父子关系)
THREAD CALL WorkerFunc // 独立模式(复制变量到子线程)
THREAD& CALL WorkerFunc // & = 强制 PE 变量模式(最简多线程)
THREAD+ CALL WorkerFunc // + = 抛弃式线程(不等待退出)
THREAD# CALL WorkerFunc // # = 代理模式(线程结束则退出)
THREAD $ CALL WorkerFunc // $ = 预先解释命令组
THREAD -link CALL WorkerFunc // 保持父子关系(类似 *)
THREAD -wait CALL WorkerFunc // 等待完成(阻塞消息循环)
THREAD -waitx CALL WorkerFunc // 等待完成(不阻塞消息循环)
THREAD -here CALL WorkerFunc // 当前栈的孩子(可修改父栈临时PE变量)
THREAD -waitp CALL WorkerFunc // 进程结束前等待该线程
THREAD -tid:&tid CALL WorkerFunc // 获取线程 ID
THREAD --st:128K CALL WorkerFunc // 设置栈大小
{ LOCK #pecmd // 原子作用域
LOCK --exist #MyLock,&&ret // 检查锁是否存在
}
LOCK #MyLock,&&ret2 // 创建/获取命名锁
完整 EXIT 变体、LAMBDA 语法和 FIND --class: 参见 commands-full.md。
| 控件 | 命令 | 控件 | 命令 |
|---|---|---|---|
| 按钮 | ITEM | 标签 | LABE |
| 编辑框 | EDIT | 复选框 | CHEK |
| 单选框 | RADI | 下拉列表 | LIST |
| 表格 | TABL | 进度条 | PBAR |
| 分组框 | GROU | 图片 | IMAG |
| 多行文本 | MEMO | 子窗口 | SWIN |
| 定时器 | TIME | 托盘/气泡 | TIPS / TIPS* |
| 选项卡 | TABS | 滑块 | SLID |
| 微调器 | SPIN | 树形视图 | TREE |
| 滚动条 | SBAR | 热键 | HKEY |
| 日期时间 | DTIM | IP 地址 | IPAD |
| 菜单项 | MENU | 屏幕捕捉 | SCRN |
| 浏览窗口 | BROW |
ENVI @控件.MSG=_%&WM_LBUTTONDOWN%: 命令 // _ = 后置系统处理器(控件通知)
ENVI @窗口.MSG=0x0010: CALL OnClose // 无 _ = 窗口级消息(WM_CLOSE)
ENVI @控件.MSG=_%&msg%::&&wp,&&lp, CALL Handler // 捕获 wParam/lParam
ENVI @控件.POSTMSG=#1 // 投递自定义消息 #1
ENVI @控件.SENDMSG=消息号;wParam;lParam // 同步发送
ENVI @控件.MSG=$0x0201: 命令 // $ = 屏蔽系统响应(可返回结果码)
ENVI @控件.MSG=*msg: 命令 // * = 捕鼠器 B(鼠标捕获模式)
ENVI @控件.MSG=+msg: 命令 // + = 超级捕获
MSG 前缀说明:无前缀=直接处理后丢弃(不传递给系统),_=系统响应后执行(控件通知),$=屏蔽系统响应(可返回结果码),*=捕鼠器 B(鼠标捕获),+=超级捕获。消息号 *del 删除映射。#1~#N 为 PECMD 自定义消息。
ENVI @控件名=新文本 // 设置文本
ENVI @控件名.Enable=0 // 禁用(1=启用)
ENVI @控件名.Visible=0 // 隐藏(1=显示)
ENVI @控件名.POS=左:上:宽:高 // 移动/调整大小
ENVI @控件名.POS=?;&L:&T:&W:&H // 查询位置
ENVI @控件名.Val=?行.列;&var // 获取 TABL 单元格
ENVI @控件名.Val=?*;&count // 获取 TABL 行数
ENVI @控件名.*del= // 销毁控件
完整控件语法、全部 25 种控件类型、ENVI @ 属性参考、窗口生命周期和消息映射——参见 pecmd-gui.md。
GUI 写法示例(动态控件、选项卡页、自定义标题栏、GDI 绘图、拖放等)——参见 how-tos/gui.md。
实测验证(32-bit / 64-bit 行为一致): 以下内容在 PECMD 32-bit (PECMDx86) 和 64-bit (PECMD) 上均经实测确认,行为完全相同。DLL 调用可正常工作,但有重要限制。
DLL 函数默认按 PASCAL/stdcall 调用约定。Windows API(WINAPI 标记)不需要 --c。使用 --c 切换到 CDECL。最多 20 个参数(C 调用 100 个)。
// ✅ 正确格式:逗号分隔,整数 #,字符串 $,建议加 --qd
CALL $ --qd --ret:&&r user32.dll,GetSystemMetrics,#0 // 整数参数
CALL $ --qd --ret:&&r user32.dll,FindWindowW,$Progman,#0 // 字符串+整数
CALL $ --qd --ret:&&r kernel32.dll,lstrlenW,$Hello World // 字符串参数
CALL $ --ret:&&hDll ,-LoadLibrary,^user32.dll // 加载 DLL(^ = 自动释放)
CALL $ --ret:&&r *%&hDll%,GetSystemMetrics,#0 // 通过句柄调用
CALL $ ,-FreeLibrary,*%&hDll% // 释放 DLL
CALL $ --bool --ret:&&ret DLL,函数,... // --bool:函数返回 BOOL
CALL $ --cd --ret:&&ret DLL,函数,... // --cd:执行前切换到目标目录
// Win32 回调函数绑定(用于 EnumResourceNames 等 API)
ENVI^ WndProc1C,WndProc1Addr // C 调用约定回调
SET^ WndProc1,WndProc1Addr // PASCAL/stdcall 回调
// PECMD 自动查找 _SUB OnWndProc1 并包装为 Win32 回调
Func.#Param)完全不工作# 前缀——无前缀返回 0$ 前缀--qd——否则字符串多传一个 null 终止符,导致 API 结果错误:| 字符串 | 无 --qd | 有 --qd | 说明 |
|---|---|---|---|
$A | lstrlenW → 2 | lstrlenW → 1 | 无 --qd 含 null |
$Test | lstrlenW → 5 | lstrlenW → 4 | 无 --qd 含 null |
$Progman | FindWindowW → 0 | FindWindowW → 66062 | 无 --qd 找不到窗口 |
// ❌ 点语法完全不工作
CALL $--qd --ret:&&r user32.dll,GetSystemMetrics.#0 // 返回空
// ❌ 整数无前缀返回 0
CALL $ --ret:&&r user32.dll,GetSystemMetrics,0 // 返回 0
// ⚠ GetProcAddress:无 --qd 时常返回 0x0,加 --qd 后可工作
CALL $ --ret:&&p ,-GetProcAddress,*%&hDll%,$GetSystemMetrics // 可能返回 0x0
CALL $--qd --ret:&&p ,-GetProcAddress,*%&hDll%,GetSystemMetrics // 加 --qd 更可靠
// ⚠ 缓冲区输出:无 --qd 时数据可能不回传,加 --qd 后可工作
SET$ &buf=*256 0
CALL $--qd --ret:&&r kernel32.dll,GetWindowsDirectoryW,*&buf,#256 // --qd 模式
// ❌ 无 --qd 时字符串含 null 终止符,FindWindowW 等失败
CALL $ --ret:&&r user32.dll,FindWindowW,$Progman,#0 // 返回 0
| 场景 | 语法 | 状态 |
|---|---|---|
| 无参整数返回 | CALL $ --ret:&&r kernel32.dll,GetTickCount | ✅ |
| 整数参数 | CALL $ --qd --ret:&&r user32.dll,GetSystemMetrics,#0 | ✅ |
| 字符串输入 | CALL $ --qd --ret:&&r user32.dll,FindWindowW,$Progman,#0 | ✅ |
| 变量作参数 | CALL $ --qd --ret:&&r kernel32.dll,lstrlenW,$%&str% | ✅ |
| LoadLibrary | CALL $ --ret:&&h ,-LoadLibrary,^user32.dll | ✅ |
| 通过句柄调用 | CALL $ --ret:&&r *%&h%,GetSystemMetrics,#0 | ✅ |
| 缓冲区输出 | 加 --qd 后可回传到 PE 变量 | ⚠ |
| GetProcAddress | 加 --qd 后可工作 | ⚠ |
| 点语法 | Func.#Param 不解析 | ❌ |
| 项目 | PECMDx86 (32-bit) | PECMD (64-bit) |
|---|---|---|
| 文件标识 | PE32, i386 | PE32+, x86-64 |
bX64 值 | 0(32 位系统)或 1(64 位系统) | 3 |
| 指针大小 | 4 字节(< 4GB) | 8 字节(> 4GB) |
| DLL 调用行为 | 与 64-bit 完全相同 | 与 32-bit 完全相同 |
| LoadLibrary 句柄 | 0x761A0000 | 0x7FFC34B00000 |
| 代码差异 | 无 | 无 |
bX64 值含义:0=WIN32(32 位系统原生),1=WIN64(64 位系统运行 32 位 PECMD),3=PECMD64(64 位 PECMD)。
| 前缀 | 类型 | 描述 | 示例 |
|---|---|---|---|
# | integer | 按整数传递 | #0、#256、#%&hwnd% |
< | INT64 | 64 位整数 | <0x100000000 |
$ | string | 按 Unicode 字符串传递(配合 --qd 不含 null) | $CabinetWClass |
@ | ANSI | 按 ANSI 字符串传递 | @text |
* | buffer | 传递 PE 变量地址(*&buf 形式可回传输出) | *&buf |
= | raw | 按原始数据传递 | |
~ | deref | 间接解引用(展开变量名再读值) |
SET$# &buf=*256 0 // 分配 256 字节原始缓冲区
SET$ &strBuf=*256 0 // 分配 256 个宽字符
SET-long &buf=value:offset // 写入 32 位整数到缓冲区偏移
SET?int &buf=&&var:offset // 从缓冲区偏移读取 32 位整数
DLL 缓冲区输出可使用 *&buf 形式(PE 变量地址传递,输出回传)。获取系统信息也可用内置命令:
FIND --wid*@ &var — 枚举窗口(返回 HWND、类名、标题)FIND --pid*@ &var — 枚举进程REGI — 注册表读取系统信息EXEC* &out=!cmd.exe /c ... — 捕获外部命令输出IFEX MEMU=?,&var — 查询可用内存IFEX C:\=?,&var — 查询磁盘空间IFEX #%&::bX64%=3, SET &PtrSz=8! SET &PtrSz=4 // 3=PECMD64, 1=WIN64(32位PECMD在64位系统), 0=WIN32
FDRV &盘符列表=*: // 枚举所有盘符
FDRV *vol &卷标,&文件系统=C: // 获取卷标和文件系统
PART list disk,&&全部磁盘 // 枚举所有物理磁盘
PART list disk %&dsk%,&&磁盘信息 // 获取磁盘信息
PART list part %&dsk%,&&分区列表 // 列出分区号
PART -hextp -phy# list part %&dsk%#%&pt%,&&分区信息 // 详细分区信息
SHOW * %&dsk%#%&pt%,%&盘符% // 分配盘符
SHOW *- %&dsk%#%&pt%, // 移除盘符
REGI $HKLM\SOFTWARE\App\Key,&var // 读 REG_SZ
REGI #HKLM\SOFTWARE\App\Count,&var // 读 REG_DWORD
REGI $HKLM\SOFTWARE\App\Key=值 // 写 REG_SZ
READ %路径%,**,&内容 // 读取整个文件
WRIT %路径%,+0,新行 // 追加一行
GETF# %路径%,0#*,&原始数据 // 按原始字节读取文件
EXEC* &输出=!cmd.exe /c dir /b // 捕获全部输出
EXEC =!"%MyNAME%" TEAM WAIT 1000|LOAD other.ini // 运行子 PECMD
EXEC* &out=!cmd.exe /c ipconfig // 捕获外部命令输出
EXEC* --exe:#101 &out=*embedded.exe // 从 PECMD 资源运行 EXE
{ LOCK #pecmd
LOCK --exist #MyAppLock,&&exists
}
IFEX $1=%&exists%,
{
REGI $HKCU\Software\MyApp\WID,&&wid
IFEX $%&wid%>0, TEAM ENVI @@Visible=%&wid%:2| ENVI @@POS=%&wid%:::::::1
EXIT FILE
}
LOCK #MyAppLock,&ret2
MSTR &&a,&&b=<1><3->%&data% // 字段1、字段3到末尾(- = 到末尾)
MSTR &&last=<-1>%&data% // 最后字段(负索引)
MSTR &&q=<~5>%&data% // 字段5并剥离外层引号(~前缀)
MSTR -delims:. &&a,&&b,&&c,&&d=<1><2><3><4>%&ip% // 按自定义分隔符拆分
MSTR* &&a,&&b=<1><2>%&data% // *前缀 = TAB 分隔
MSTR$ &&a,&&b=<1><2>%&data% // $前缀 = 空格分隔(连续空格视为单个)
SED &&r=0,模式,替换,%&source% // 替换所有匹配(正则模式)
SED &&r=1,模式,替换,%&source% // 替换第一个匹配
SED &&r=-1,模式,替换,%&source% // 替换最后一个匹配(负数=从末尾)
SED -t &&r=0,ABCD,abcd,%&source% // -t = 字符集翻译(A→a, B→b, 逐字符映射)
SED -ni &&r=0,模式,替换,%&source% // -ni = 不区分大小写
SED &&ext=-1,.*\.,, ,%&filename% // 获取扩展名(.*\. 匹配到最后一个句号)
LPOS &&pos=needle,,%&haystack% // 查找首次出现(不区分大小写)
MSTR 注意事项: 默认分隔符为空格。
-delims:09指定制表符(十六进制 09)。字段索引从 1 开始。<N>= 单个字段,<N->= 字段N到末尾,<N*>= 仅字段N(单字段),<~N>= 剥离引号,<-N>= 从末尾反向索引。MSTR*= TAB分隔,MSTR$= 空格分隔(连续空格视为单个)。如果 MSTR 返回空,先用WRIT打印源变量确认格式,或改用FORX *按空格逐字段拆分作为替代。SED 注意事项: SED 默认使用正则模式。
.匹配任意字符,非字面量句号。匹配字面量句号用\.。使用标志字符*可切换为字面量模式(不解释正则)。count=0 替换全部匹配,count=N 替换前 N 个,count=-N 替换后 N 个。0:0与0等价。-t标志启用字符集翻译,-ni标志不区分大小写。模式中的空格作为参数分隔符处理时可能引起问题——用变量间接传递含空格的模式。LPOS 注意事项: 参数顺序为
LPOS &&pos=needle,,haystack(查找目标在前,源字符串在后)。返回首次出现的位置索引。加,1,可区分大小写。RPOS从末尾查找。
含错误处理和边界情况处理的完整展开版本,参见 how-tos/storage.md(磁盘/注册表/文件)、how-tos/system.md(进程/线程/定时器)、how-tos/net.md(网络/COM)。
CALC &结果=%&a% + %&b% // 基本算术:+ - * / % ^
CALC #&结果=%&a% & %&b% // # = 整数模式;位运算:& | @
CALC -base=16 #&hex=shl(0x07,16)|0x20 // 十六进制输出 + 位移
CALC &sz=%&bytes%/1G#3 // 字节转 GB,3 位小数
CALC -err=0 &r=%&a% / %&b% // 出错时返回默认值 0
数学函数(34个):
| 类别 | 函数 |
|---|---|
| 三角 | sin cos tan ctg arcsin arccos arctan arcctg deg rad |
| 代数 | abs sqrt ln lg log exp pow pow10 hypot(⚠ log() 需两参数 log(底数,值),单参数返回 0;用 lg() 代替 log₁₀) |
| 取整 | floor ceil round int frac |
| 位运算 | shl shr xor not lnot |
| 其他 | div mod rand max min |
常量:e、pi。尺寸后缀:K=1024、M=1024²、G=1024³、T=1024⁴、S=512。
多表达式用 ; 分隔,子变量 $subName=expr。
CALC &J=1+2 可以正常执行。右侧以 %&I% 等变量开头时,用空格分隔(CALC &J= %&I%+1)。PECMD 要求减号后必须有空格(3 - 2)。//、;、`(反引号)均为有效注释符。行尾注释前必须有空格(如 SET &a=1 // 注释)。help.txt: "注释符前有一个空字符,该空字符算注释"——所有位置的注释符前都建议加空格。SET var=val 语义上等价于 ENVI &var=val。启用 ForceLocal=1 后,两者都创建局部 PE 变量。$ = 字符串比较、| = 浮点比较;IFEX 中 $ = 浮点比较、| = 字符串比较。# 在两者中均为整数比较。IFEX 中 | 在 [] 复合条件内为 OR 逻辑运算符。FDRV、FORM、FIND C:\=? 都需要 : 后缀。LOAD "C:\Program Files\a.ini" 需要引号。#code=65001 = UTF-8,#code=936 = GBK)且文件编码须与声明一致。SDK 示例普遍使用 GBK(936)。{ 位置:文件级和函数级 { 必须从第 1 列开始。在 TEAM/LOOP/IFEX 内部,{ 启动命令组。\ 时,将该行合并到上一行。_SUB、WRIT、LOOP 不能内联:不能在 FIND/IFEX/TEAM 命令内部定义 _SUB。WRIT 和 LOOP 也必须位于单独一行,不能嵌套在 FIND/IFEX/TEAM 内。FIND $%var%=, 测试"为空"。FIND *=var, 也测试"为空"(惯用法)。FIND *<>var, 测试"非空"。% 用 %%。* 函数)中的变量是共享的(非复制);非持久上下文(普通函数、{} 块)中的变量自动复制一份。真正跨线程通信用 &:: 变量。%SystemRoot%\System32\OnShutdown.wcs,格式为 OnShutdown.wcs <操作码> [脚本参数表]。操作码:shutdown=关机、reboot=重启、logout=注销、suspend=挂起、hiber=休眠、poweroff=关电、lock=锁定计算机、unknown=未知。关机菜单支持的子集:shutdown、reboot、logout、poweroff、unknown。^ 预解释:^COMMAND 将变量展开推迟到执行时(循环中必备)。^^COMMAND 预解释两次。_ 前缀:控件通知用 _msg#;窗口级消息省略 _。搞错这一点是非常常见的错误。{} 块中,两者都复制。FIND $%&var%=值 引用 PE 变量。@@Visible 与 @Visible:跨进程用 ENVI @@Visible=窗口ID:值。进程内用 ENVI @控件.Visible=0|1。FORX ... &&item, { } 定义用 &&item,循环体内引用值用 %&item%(单&)。用 %&&item% 会找不到变量。序号 窗口ID 控件ID 父窗口ID 线程ID 进程ID 类型 标题,字段用 TAB 分隔。配合 FORX *NL 按行遍历、MSTR* 按 TAB 分字段提取(field 2=窗口ID, field 7=类型, field 8=标题)。FIND --wid*@(窗口枚举)、FIND --pid*@(进程枚举)、REGI(注册表)、EXEC*(外部命令)替代。Visible 与 Visable:两者均可工作(PECMD 接受两种拼写)。文档统一用 Visible,但 SDK 示例普遍用 Visable。FORX *NL:| &data,&&item, 用 | 作为行分隔符(默认为换行)。ENVI^ ALIAS GetTick=CALL $ --ret:&&r kernel32.dll,GetTickCount 使 GetTick 可作为伪命令直接调用。当需要超越上述快速参考的详细信息时,查阅以下权威文件:
| 文件 | 何时查阅 |
|---|---|
references/commands-full.md | 命令语法、全部标志、参数细节 |
references/pecmd-gui.md | GUI 控件、消息、窗口生命周期、ENVI @ 属性 |
references/pe-startup.md | WinPE 启动脚本、PECMD.INI 结构、启动阶段 |
references/how-tos/storage.md | 磁盘、分区、文件、注册表、设备 写法示例 |
references/how-tos/system.md | 进程、线程、定时器、系统信息、加密、工具 |
references/how-tos/gui.md | GUI 模式:动态控件、选项卡、GDI、拖放等 |
references/how-tos/net.md | 网络、SOCK、COM/WMI 写法示例 |
references/troubleshooting.md | 常见错误排查、DLL 调用失败、变量引用问题 |
编写 PECMD 脚本和工具时遵循以下规范:
#code=65001,随后 ENVI^ EnviMode=1,再 ENVI^ ForceLocal=1&变量名)TEAM 链式组合紧凑的初始化序列_SUB 函数ENVI @控件.POS=? 保存初始控件位置,在 resize 事件中恢复EXEC =!"%MyNAME%" ... 或 EXEC* &out=!cmd.exe /c ...&:: 类 PE 变量{ LOCK #pecmd ... } 块包装互斥操作_ 前缀(_0x0201);窗口级消息省略 _(0x0010)SED 做正则替换(始终正则模式,. 匹配任意字符,\. 匹配字面量句号),用 MSTR 从结构化输出中提取字段——如果 MSTR 不工作,改用 FORX * 逐字段拆分GitHub: https://github.com/VirtualHotBar/PECMD-Pro-Max ClawHub: https://clawhub.ai/virtualhotbar/pecmd-pro-max