记住XY 问题,这是我的 X 和 Y 问题。
有一些 PowerShell 脚本,我已经对其内容进行了混淆。不过,我仍然可以运行该脚本。
其工作原理是脚本存储在可执行文件内。PowerShell 可以执行可执行文件,通过将脚本名称作为 CLI 参数传递来请求特定脚本。然后,可执行文件的进程将通过 stdout 转发 PowerShell 脚本的内容。PowerShell 将 stdout 存储在字符串变量中,然后调用Invoke-Expression,传入字符串,运行混淆的脚本。
问题是$PSScriptRoot当它出现在混淆脚本中时,被评估为$null。
当 PowerShell 脚本script.ps1将 PowerShell 脚本作为字符串执行时$scriptString,如何$PSScriptRoot像在script.ps1.
测试1
# script.ps1
$PSScriptRoot
# Output: Path to directory containing `script.ps1`.
Run Code Online (Sandbox Code Playgroud)
这表明至少在一种情况下$PSScriptRoot是非的。$null
测试2
# script.ps1
Invoke-Expression '$PSScriptRoot'
# Output: Nothing
Run Code Online (Sandbox Code Playgroud)
表明我当前执行字符串的方式不起作用。
测试3
# script.ps1
. { $PSScriptRoot }
# Output: Path to directory containing `script.ps1`.
Run Code Online (Sandbox Code Playgroud)
使用语法创建脚本块{ ... }确实有效。然而,这需要实际的命令。我拥有的是一个包含命令的字符串。将该字符串放在大括号之间将导致命令被输出而不是运行。
测试4
# script.ps1
. [ScriptBlock]::Create('$PSScriptRoot')
# Output: Nothing
Run Code Online (Sandbox Code Playgroud)
创建脚本块的另一种方法是使用 C#[ScriptBlock]::Create(...)方法。这实际上允许从字符串创建脚本块。不幸的是,它不起作用。
测试5
# script.ps1
Invoke-Command -ScriptBlock { $PSScriptRoot }
# Output: Path to directory containing `script.ps1`.
Run Code Online (Sandbox Code Playgroud)
与测试 3 相同,只是调用Invoke-Command脚本块而不是点源脚本块。
测试6
# script.ps1
$scriptBlock = [ScriptBlock]::Create('$PSScriptRoot')
Invoke-Command -ScriptBlock $scriptBlock
# Output: Nothing.
Run Code Online (Sandbox Code Playgroud)
与测试 3 相同,只是调用Invoke-Command脚本块而不是点源脚本块。
Invoke-Expressioncmdlet,但它不起作用。也许还有另一种方法可以直接执行字符串,但我不知道。{ ... }似乎可以工作,但它似乎不适用于字符串。[ScriptBlock]::Create(...)不起作用,但可以使用字符串。Invoke-Expression?{ ... }?$PSScriptRoot出正确的非$null值?您可以让 PowerShell 将存储在字符串中的脚本视为已从磁盘读取,也就是说,$PSScriptRoot通过$PSCommandPath手动解析它,它将正确解析:
# Prepare script + path
$script = 'Write-Host "Script root: $PSScriptRoot`nCommand path: $PSCommandPath"'
$fileName = "C:\my\path\to\script.ps1"
# Make the parser generate an AST from the input script + path
$AST = [System.Management.Automation.Language.Parser]::ParseInput($script, $fileName, [ref]$null, [ref]$null)
# Get an executable scriptblock from AST
$block = $AST.GetScriptBlock()
# Now invoke it
& $block
Run Code Online (Sandbox Code Playgroud)
此时您会发现$PS*变量已正确解析:
# Prepare script + path
$script = 'Write-Host "Script root: $PSScriptRoot`nCommand path: $PSCommandPath"'
$fileName = "C:\my\path\to\script.ps1"
# Make the parser generate an AST from the input script + path
$AST = [System.Management.Automation.Language.Parser]::ParseInput($script, $fileName, [ref]$null, [ref]$null)
# Get an executable scriptblock from AST
$block = $AST.GetScriptBlock()
# Now invoke it
& $block
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
856 次 |
| 最近记录: |