Invoke-Expression 是干什么的
Invoke-Expression(别名 iex)把一段字符串当作 PowerShell 代码来执行,效果类似其他语言的 eval。它的存在价值是执行动态拼出来的命令,代价是失去了静态解析与语法检查:命令里的错误只有运行时才暴露,而如果把外部输入拼进字符串再交给 iex,就等于把任意代码执行的入口交给了外部。
基本信息
| 适用平台 | Windows PowerShell 5.1 与 PowerShell 7+ |
|---|---|
| 语法 | Invoke-Expression -Command <字符串>;别名 iex |
| 高危点 | 字符串含外部可控内容时形成命令注入 |
| 更安全的替代 | 调用运算符 & $exe $args;脚本块 & { ... };Get-Command 后再调用 |
典型使用场景
- 执行用户输入的表达式:做简单计算器或查询工具时读取一行表达式求值
- 动态拼装命令:参数来自配置文件且无法预先固定时(应先验证白名单)
- 运行已有字符串:从文件或数据库读出命令文本后执行
- 老脚本迁移:理解遗留脚本里 iex 的实际作用再替换为安全写法
- 安全审计:识别日志中 iex 出现的位置,作为可疑执行的线索
常用示例
常用示例
# 最基础的用法:执行字符串命令
$cmd = 'Get-Date -Format yyyy-MM-dd'
Invoke-Expression $cmd
# 调用运算符:能表达同样意图时优先用它
& 'C:\Windows\System32\notepad.exe' D:\logs\a.txt
# 脚本块写法
& { Get-Process | Sort-Object CPU -Descending | Select-Object -First 5 }
# 未加校验的拼接是典型注入入口(反面示例,勿在生产使用)
# Invoke-Expression "ping $userInput"
# 需要外部输入时先做白名单校验
$allow = 'status','version'
if ($userInput -in $allow) { Invoke-Expression "mycli $userInput" }执行方式对比
| 写法 | 解析方式 | 安全与可维护性 |
|---|---|---|
| & $exe $args | 直接调用可执行文件 | 参数不经二次解析,较安全 |
| & { ... } | 脚本块,静态解析 | 推荐,语法错误可提前发现 |
| Invoke-Expression | 运行时解析字符串 | 最灵活也最危险 |
| Start-Process | 启动独立进程 | 适合带参数的命令行调用 |
只要字符串中有一部分来自用户输入、文件名、网页内容或数据库,就不该送进 iex。安全日志里 iex 是重点监控对象,被滥用时既是攻击者的手段,也会让你自己的脚本被安全团队标记。
iex 报错通常指向被拼接出来的内部命令,行号与真实原因对不上,调试体验很差。能确定命令结构时,改用调用运算符能显著改善报错可读性。
PowerShell 也提供了更专用的动态求值途径,例如执行算术表达式用 Invoke-Command 配合脚本块或直接使用 [scriptblock]::Create 并校验来源;通道越窄,风险越小。