Start-Process
从PowerShell调用PowerShell 将是我的最后选择 -尤其是因为所有I / O都是字符串而不是(反序列化的)对象。
两种选择:
1.如果用户是本地管理员,并且配置了PSRemoting
如果可以选择针对本地计算机的远程会话(不幸的是仅限于本地管理员),我肯定会选择Invoke-Command
:
$strings = Invoke-Command -FilePath C:\...\script1.ps1 -ComputerName localhost -Credential $credential
$strings
将包含结果。
2.如果用户不是目标系统上的管理员
您可以Invoke-Command
通过以下方式来扩展进程外运行空间,从而编写自己的“仅本地”:
PowerShellProcessInstance
在其他登录名下创建一个
- 在上述过程中创建一个运行空间
- 在上述进程外运行空间中执行代码
我在下面放了一个这样的功能,请参阅内联注释以获取演练:
function Invoke-RunAs
{
[CmdletBinding()]
param(
[Alias('PSPath')]
[ValidateScript({Test-Path $_ -PathType Leaf})]
[Parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
[string]
${FilePath},
[Parameter(Mandatory = $true)]
[pscredential]
[System.Management.Automation.CredentialAttribute()]
${Credential},
[Alias('Args')]
[Parameter(ValueFromRemainingArguments = $true)]
[System.Object[]]
${ArgumentList},
[Parameter(Position = 1)]
[System.Collections.IDictionary]
$NamedArguments
)
begin
{
# First we set up a separate managed powershell process
Write-Verbose "Creating PowerShellProcessInstance and runspace"
$ProcessInstance = [System.Management.Automation.Runspaces.PowerShellProcessInstance]::new($PSVersionTable.PSVersion, $Credential, $null, $false)
# And then we create a new runspace in said process
$Runspace = [runspacefactory]::CreateOutOfProcessRunspace($null, $ProcessInstance)
$Runspace.Open()
Write-Verbose "Runspace state is $($Runspace.RunspaceStateInfo)"
}
process
{
foreach($path in $FilePath){
Write-Verbose "In process block, Path:'$path'"
try{
# Add script file to the code we'll be running
$powershell = [powershell]::Create([initialsessionstate]::CreateDefault2()).AddCommand((Resolve-Path $path).ProviderPath, $true)
# Add named param args, if any
if($PSBoundParameters.ContainsKey('NamedArguments')){
Write-Verbose "Adding named arguments to script"
$powershell = $powershell.AddParameters($NamedArguments)
}
# Add argument list values if present
if($PSBoundParameters.ContainsKey('ArgumentList')){
Write-Verbose "Adding unnamed arguments to script"
foreach($arg in $ArgumentList){
$powershell = $powershell.AddArgument($arg)
}
}
# Attach to out-of-process runspace
$powershell.Runspace = $Runspace
# Invoke, let output bubble up to caller
$powershell.Invoke()
if($powershell.HadErrors){
foreach($e in $powershell.Streams.Error){
Write-Error $e
}
}
}
finally{
# clean up
if($powershell -is [IDisposable]){
$powershell.Dispose()
}
}
}
}
end
{
foreach($target in $ProcessInstance,$Runspace){
# clean up
if($target -is [IDisposable]){
$target.Dispose()
}
}
}
}
然后像这样使用:
$output = Invoke-RunAs -FilePath C:\path\to\script1.ps1 -Credential $targetUser -NamedArguments @{ClientDevice = "ClientName"}