如何让Run-Elevated的ScriptBlock访问调用脚本的参数?
解决方案:实现带参数传递的
Run-Elevated函数 问题核心
你的基础实现中,Start-Process启动的是全新的PowerShell进程,原脚本的参数/变量无法直接跨进程共享,.GetNewClosure()仅适用于当前进程内的闭包,无法跨进程传递,因此导致ScriptBlock无法访问原脚本参数。以下是两种简洁的实现方案,满足你的要求:
方案1:序列化参数传递(支持命名参数)
该方案将调用脚本的参数序列化为可传递的字符串,在新进程中反序列化后绑定到ScriptBlock执行,完美支持命名参数。
函数实现
function Run-Elevated { param( [Parameter(Mandatory)] [scriptblock]$Callback, [Parameter()] [hashtable]$Parameters = $PSBoundParameters ) # 序列化参数为PowerShell可解析的格式 $serializedParams = [System.Management.Automation.PSSerializer]::Serialize($Parameters) # 构建新进程中执行的命令逻辑 $executionScript = @" `$deserializedParams = [System.Management.Automation.PSSerializer]::Deserialize('$serializedParams') & `$Callback @deserializedParams "@ # 转Base64避免命令行解析错误 $encodedCommand = [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($executionScript)) Start-Process -FilePath powershell.exe -ArgumentList "-EncodedCommand", $encodedCommand -Verb RunAs }
使用示例(myscript.ps1)
param( [Parameter(Mandatory=$True)] [string]$name, [int]$age = 18 ) # 调用Run-Elevated,传递当前脚本的所有参数 Run-Elevated -Callback { param($name, $age) Write-Host "管理员模式执行:姓名=$name,年龄=$age" } -Parameters $PSBoundParameters
方案2:直接传递参数列表(简洁灵活)
该方案将参数直接拼接进执行脚本,通过$args或命名参数的方式在ScriptBlock中接收,写法更简洁。
函数实现
function Run-Elevated { param( [Parameter(Mandatory)] [scriptblock]$Callback, [Parameter(ValueFromRemainingArguments)] $ArgumentList ) # 处理参数,给字符串参数添加引号避免解析问题 $formattedArgs = $ArgumentList | ForEach-Object { if ($_ -is [string]) { "`"$_`"" } else { $_ } } # 构建执行脚本 $executionScript = "& `$Callback $($formattedArgs -join ' ')" $encodedCommand = [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($executionScript)) Start-Process powershell.exe -ArgumentList "-EncodedCommand", $encodedCommand -Verb RunAs }
使用示例
方式1:通过$args接收参数
param([Parameter(Mandatory)][string]$name) Run-Elevated -Callback { Write-Host "管理员模式执行:姓名=$($args[0])" } -ArgumentList $name
方式2:使用命名参数
param([Parameter(Mandatory)][string]$name) Run-Elevated -Callback { param($username) Write-Host "管理员模式执行:用户名=$username" } -ArgumentList "-username", $name
关键说明
- 两种方案均通过
-EncodedCommand传递脚本内容,避免了命令行解析时的引号、特殊字符等问题。 - 无需额外传递上下文或回调函数名,直接实现参数跨进程传递,满足你的核心要求。
内容的提问来源于stack exchange,提问作者sstchur
相关产品推荐
相关产品推荐

