PowerShell执行字符串脚本时如何让$PSScriptRoot返回正确有效值
底层运行机制说明
$PSScriptRoot 是 PowerShell 内置的自动变量,仅在和物理脚本文件绑定的作用域下会被自动赋值:
- 直接写在
.ps1文件中的代码、以及文件内通过{...}字面量定义的脚本块,都会继承所属脚本文件的上下文,所以可以正常读取到$PSScriptRoot,这就是测试3、测试5能正常返回结果的核心原因。 - 而
Invoke-Expression执行字符串、[ScriptBlock]::Create()从字符串生成脚本块的场景下,PowerShell 会判定这部分代码为无文件绑定的动态代码,不会自动注入路径相关的自动变量,因此返回空值,对应测试2、4、6的表现。
问题解答
- 不存在用
{...}字面量语法基于字符串生成脚本块的方法,该语法是编译时静态语法,仅支持写固定代码内容。 - 不需要调用
Invoke-Expression也可以实现需求,可使用上下文继承的脚本块创建方案。
核心需求解决方案
方案1:动态注入变量(兼容性最高)
在待执行的脚本字符串开头拼接赋值逻辑,直接继承父脚本的 $PSScriptRoot 值,无需修改原有混淆脚本的逻辑:
# script.ps1 # 从可执行程序拿到的混淆脚本字符串 $obfuscatedScript = 你从stdout读取到的脚本内容 # 拼接变量注入代码,用格式化语法避免特殊字符转义问题 $execString = "`$PSScriptRoot = @' $PSScriptRoot '@ $obfuscatedScript" Invoke-Expression $execString
方案2:上下文绑定脚本块(无需调用Invoke-Expression)
使用 PowerShell 执行上下文提供的 NewScriptBlock 方法创建脚本块,该方法生成的脚本块会继承当前父脚本的完整上下文,包含 $PSScriptRoot 自动变量:
# script.ps1 $obfuscatedScript = 你从stdout读取到的脚本内容 # 生成继承当前上下文的脚本块 $scriptBlock = $executionContext.InvokeCommand.NewScriptBlock($obfuscatedScript) # 点源执行脚本块 . $scriptBlock # 脚本内的$PSScriptRoot会正常返回父脚本所在目录路径
内容的提问来源于stack exchange,提问作者brandon_busby
相关产品推荐
相关产品推荐

