如何将提权执行的Start-Process输出捕获到变量中?
提权执行Get-WinEvent并捕获输出(无需临时文件)
问题说明
需要提权执行Get-WinEvent读取Security日志,通过-Verb RunAs触发UAC认证弹窗,但无法将新窗口的输出捕获到变量中,且不想使用临时文件。尝试用ProcessStartInfo的代码无法弹出认证提示,还返回「未找到事件」错误(因无权限读取Security日志)。
核心限制
Start-Process -Verb RunAs默认使用UseShellExecute=$true,此时无法重定向标准输出/错误,直接捕获输出不可行。ProcessStartInfo中设置UseShellExecute=$false时,Verb="RunAs"不生效,无法触发提权,导致无权限读取Security日志。
可行方案:使用命名管道(Named Pipe)
通过命名管道实现提权进程与原进程的输出传递,无需临时文件,同时保留UAC弹窗。
实现代码
# 定义命名管道路径 $pipePath = "\\.\pipe\WinEventElevatedOutput" # 启动命名管道服务器,等待提权进程的输出 $pipeServer = New-Object System.IO.Pipes.NamedPipeServerStream($pipePath, [System.IO.Pipes.PipeDirection]::InOut, 1, [System.IO.Pipes.PipeTransmissionMode]::Byte) Write-Host "等待提权进程连接管道..." $pipeServer.WaitForConnection() # 启动提权的PowerShell进程,将Get-WinEvent的输出序列化后写入管道 $lookBackTimeFrame = (Get-Date).AddDays(- $p_lookBackDays) $arguments = @" -noprofile -command &{ `$events = Get-WinEvent -FilterHashtable @{ LogName = 'Security'; StartTime = '$lookBackTimeFrame'; Id = 4800, 4801 } `$events | Export-Clixml -Path '\\.\pipe\WinEventElevatedOutput' -Depth 10 } "@ Start-Process -Verb RunAs -FilePath "powershell.exe" -ArgumentList $arguments -Wait # 从管道读取序列化的输出并还原为对象 $streamReader = New-Object System.IO.StreamReader($pipeServer) $serializedOutput = $streamReader.ReadToEnd() $rv_matchingEvents = $serializedOutput | ConvertFrom-Clixml # 清理资源 $streamReader.Close() $pipeServer.Close() # 输出结果 $rv_matchingEvents
代码说明
- 命名管道创建:创建本地命名管道,作为提权进程和原进程的通信通道。
- 提权进程执行:用
Start-Process -Verb RunAs启动提权PowerShell,将Get-WinEvent的结果用Export-Clixml序列化后写入管道(保留对象结构,而非纯文本)。 - 读取并还原对象:原进程从管道读取序列化数据,用
ConvertFrom-Clixml还原为原始事件对象。
原错误代码问题分析
你提供的ProcessStartInfo代码存在两个关键问题:
- 变量名错误:定义了
$argumentList但赋值给$processStartInfo.Arguments的是$arguments,导致参数传递错误。 UseShellExecute=$false与Verb="RunAs"冲突:只有UseShellExecute=$true时,Verb参数才会生效触发UAC提权,设置为false后无法提权,因此无权限读取Security日志,返回「未找到事件」错误。
内容的提问来源于stack exchange,提问作者Bbb
相关产品推荐
相关产品推荐

