Ghi chú:
Giải pháp sau đây hoạt động với bất kỳ chương trình bên ngoài nào và thu được kết quả đầu ra dưới dạng văn bản .
Để gọi một phiên bản PowerShell khác và nắm bắt đầu ra của nó dưới dạng các đối tượng phong phú (có giới hạn), hãy xem giải pháp biến thể trong phần dưới cùng hoặc xem xét câu trả lời hữu ích của Mathias R. Jessen , sử dụng SDK PowerShell .
Đây là một bằng chứng khái niệm dựa trên việc sử dụng trực tiếp các loại System.Diagnostics.Process
và System.Diagnostics.ProcessStartInfo
.NET để nắm bắt đầu ra quá trình trong bộ nhớ (như đã nêu trong câu hỏi của bạn, Start-Process
không phải là một tùy chọn, vì nó chỉ hỗ trợ chụp đầu ra trong các tệp , như trong câu trả lời này ) :
Ghi chú:
Do chạy như một người dùng khác, điều này chỉ được hỗ trợ trên Windows (kể từ .NET Core 3.1), nhưng trong cả hai phiên bản PowerShell đều có.
Do cần phải chạy như một người dùng khác nhau và cần phải đầu ra chụp, .WindowStyle
không thể được sử dụng để chạy các lệnh ẩn (vì sử dụng .WindowStyle
đòi hỏi .UseShellExecute
phải $true
, đó là không phù hợp với các yêu cầu này); tuy nhiên, vì tất cả đầu ra đang bị bắt , thiết lập .CreateNoNewWindow
để $true
có kết quả thực hiện ẩn.
# Get the target user's name and password.
$cred = Get-Credential
# Create a ProcessStartInfo instance
# with the relevant properties.
$psi = [System.Diagnostics.ProcessStartInfo] @{
# For demo purposes, use a simple `cmd.exe` command that echoes the username.
# See the bottom section for a call to `powershell.exe`.
FileName = 'cmd.exe'
Arguments = '/c echo %USERNAME%'
# Set this to a directory that the target user
# is permitted to access.
WorkingDirectory = 'C:\' #'
# Ask that output be captured in the
# .StandardOutput / .StandardError properties of
# the Process object created later.
UseShellExecute = $false # must be $false
RedirectStandardOutput = $true
RedirectStandardError = $true
# Uncomment this line if you want the process to run effectively hidden.
# CreateNoNewWindow = $true
# Specify the user identity.
# Note: If you specify a UPN in .UserName
# (user@doamin.com), set .Domain to $null
Domain = $env:USERDOMAIN
UserName = $cred.UserName
Password = $cred.Password
}
# Create (launch) the process...
$ps = [System.Diagnostics.Process]::Start($psi)
# Read the captured standard output.
# By reading to the *end*, this implicitly waits for (near) termination
# of the process.
# Do NOT use $ps.WaitForExit() first, as that can result in a deadlock.
$stdout = $ps.StandardOutput.ReadToEnd()
# Uncomment the following lines to report the process' exit code.
# $ps.WaitForExit()
# "Process exit code: $($ps.ExitCode)"
"Running ``cmd /c echo %USERNAME%`` as user $($cred.UserName) yielded:"
$stdout
Những điều trên mang lại một cái gì đó như sau, cho thấy quá trình đã chạy thành công với danh tính người dùng nhất định:
Running `cmd /c echo %USERNAME%` as user jdoe yielded:
jdoe
Vì bạn đang gọi một phiên bản PowerShell khác , bạn có thể muốn tận dụng khả năng của PowerShell CLI để thể hiện đầu ra ở định dạng CLIXML, cho phép khử lưu lượng đầu ra thành các đối tượng phong phú , mặc dù có độ trung thực loại hạn chế , như được giải thích trong câu trả lời liên quan này .
# Get the target user's name and password.
$cred = Get-Credential
# Create a ProcessStartInfo instance
# with the relevant properties.
$psi = [System.Diagnostics.ProcessStartInfo] @{
# Invoke the PowerShell CLI with a simple sample command
# that calls `Get-Date` to output the current date as a [datetime] instance.
FileName = 'powershell.exe'
# `-of xml` asks that the output be returned as CLIXML,
# a serialization format that allows deserialization into
# rich objects.
Arguments = '-of xml -noprofile -c Get-Date'
# Set this to a directory that the target user
# is permitted to access.
WorkingDirectory = 'C:\' #'
# Ask that output be captured in the
# .StandardOutput / .StandardError properties of
# the Process object created later.
UseShellExecute = $false # must be $false
RedirectStandardOutput = $true
RedirectStandardError = $true
# Uncomment this line if you want the process to run effectively hidden.
# CreateNoNewWindow = $true
# Specify the user identity.
# Note: If you specify a UPN in .UserName
# (user@doamin.com), set .Domain to $null
Domain = $env:USERDOMAIN
UserName = $cred.UserName
Password = $cred.Password
}
# Create (launch) the process...
$ps = [System.Diagnostics.Process]::Start($psi)
# Read the captured standard output, in CLIXML format,
# stripping the `#` comment line at the top (`#< CLIXML`)
# which the deserializer doesn't know how to handle.
$stdoutCliXml = $ps.StandardOutput.ReadToEnd() -replace '^#.*\r?\n'
# Uncomment the following lines to report the process' exit code.
# $ps.WaitForExit()
# "Process exit code: $($ps.ExitCode)"
# Use PowerShell's deserialization API to
# "rehydrate" the objects.
$stdoutObjects = [Management.Automation.PSSerializer]::Deserialize($stdoutCliXml)
"Running ``Get-Date`` as user $($cred.UserName) yielded:"
$stdoutObjects
"`nas data type:"
$stdoutObjects.GetType().FullName
Các đầu ra ở trên giống như sau, cho thấy đầu ra của [datetime]
thể hiện ( System.DateTime
) Get-Date
được khử lưu như vậy:
Running `Get-Date` as user jdoe yielded:
Friday, March 27, 2020 6:26:49 PM
as data type:
System.DateTime