因此我们在自动化中使用PsExec来安装虚拟机,因为我们无法在Windows 2003机器上使用ps远程会话。一切都很好,并没有问题,但PsExec不断抛出错误,即使每个命令都没有正确执行。 例如:
D:\tools\pstools\psexec.exe $guestIP -u $global:default_user -p $global:default_pwd -d -i C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -command "Enable-PSRemoting -Force"
在guest虚拟机上启用PsRemoting,但也会抛出此错误消息:
psexec.exe :
Bei D:\Scripts\VMware\VMware_Module5.ps1:489 Zeichen:29
+ D:\tools\pstools\psexec.exe <<<< $guestIP -u $global:default_user -p $global:default_pwd -d -i C:\Windows\System32\WindowsPowerShell\
v1.0\powershell.exe -command "Enable-PSRemoting -Force"
+ CategoryInfo : NotSpecified: (:String) [], RemoteException
+ FullyQualifiedErrorId : NativeCommandError
PsExec v1.98 - Execute processes remotely
Copyright (C) 2001-2010 Mark Russinovich
Sysinternals - www.sysinternals.com
Connecting to 172.17.23.95...Starting PsExec service on 172.17.23.95...Connecting with PsExec service on 172.17.23.95...Starting C:\Windows\
System32\WindowsPowerShell\v1.0\powershell.exe on 172.17.23.95...
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe started on 172.17.23.95 with process ID 2600.
这些类型的错误消息始终无论我如何使用psexec,如引号,vriables /固定值,其他标志等等。是否有人知道如何解决这个问题?这不是一个真正的问题,但它会让发现错误成为一种痛苦,因为“错误”无处不在。完全禁用psexec的错误消息也会有所帮助......
答案 0 :(得分:13)
这是因为当进程写入STDERR时,PowerShell有时会报告NativeCommandError。 PsExec写入infoline
PsExec v1.98 - Execute processes remotely
Copyright (C) 2001-2010 Mark Russinovich
Sysinternals - www.sysinternals.com
到STDERR,这意味着它可以导致这种情况。
有关详细信息,请参阅以下问题/答案:
答案 1 :(得分:3)
将stderr重定向到null对我来说效果最好。见下面链接
Error when calling 3rd party executable from Powershell when using an IDE
以下是该链接的相关部分:
为避免这种情况,您可以将stderr重定向为null,例如:
du 2&gt; $空 本质上,控制台主机和ISE(以及远程处理)以不同方式处理stderr流。在控制台主机上,PowerShell支持像edit.com这样的应用程序与其他将彩色输出和错误写入屏幕的应用程序一起工作非常重要。如果未在控制台主机上重定向I / O流,则PowerShell会为本机EXE提供直接写入的控制台句柄。这会绕过PowerShell,因此PowerShell无法看到写入的错误,因此无法通过$ error或写入PowerShell的stderr流来报告错误。 ISE和远程处理不需要支持这种情况,所以他们确实看到stderr上的错误,然后写错误并更新$ error。
。\ PsExec.exe \ $ hostname -u $ script:userName -p $ script:password / accepteula -h cmd / c $ powerShellArgs 2&gt; $空
答案 2 :(得分:0)
我为powershell创建了一个psexec包装器,这可能对浏览此问题的人有所帮助:
function Return-CommandResultsUsingPsexec {
param(
[Parameter(Mandatory=$true)] [string] $command_str,
[Parameter(Mandatory=$true)] [string] $remote_computer,
[Parameter(Mandatory=$true)] [string] $psexec_path,
[switch] $include_blank_lines
)
begin {
$remote_computer_regex_escaped = [regex]::Escape($remote_computer)
# $ps_exec_header = "`r`nPsExec v2.2 - Execute processes remotely`r`nCopyright (C) 2001-2016 Mark Russinovich`r`nSysinternals - www.sysinternals.com`r`n"
$ps_exec_regex_headers_array = @(
'^\s*PsExec v\d+(?:\.\d+)? - Execute processes remotely\s*$',
'^\s*Copyright \(C\) \d{4}(?:-\d{4})? Mark Russinovich\s*$',
'^\s*Sysinternals - www\.sysinternals\.com\s*$'
)
$ps_exec_regex_info_array = @(
('^\s*Connecting to ' + $remote_computer_regex_escaped + '\.{3}\s*$'),
('^\s*Starting PSEXESVC service on ' + $remote_computer_regex_escaped + '\.{3}\s*$'),
('^\s*Connecting with PsExec service on ' + $remote_computer_regex_escaped + '\.{3}\s*$'),
('^\s*Starting .+ on ' + $remote_computer_regex_escaped + '\.{3}\s*$')
)
$bypass_regex_array = $ps_exec_regex_headers_array + $ps_exec_regex_info_array
$exit_code_regex_str = ('^.+ exited on ' + $remote_computer_regex_escaped + ' with error code (\d+)\.\s*$')
$ps_exec_args_str = ('"\\' + $remote_computer + '" ' + $command_str)
}
process {
$return_dict = @{
'std_out' = (New-Object 'system.collections.generic.list[string]');
'std_err' = (New-Object 'system.collections.generic.list[string]');
'exit_code' = $null;
'bypassed_std' = (New-Object 'system.collections.generic.list[string]');
}
$process_info = New-Object System.Diagnostics.ProcessStartInfo
$process_info.RedirectStandardError = $true
$process_info.RedirectStandardOutput = $true
$process_info.UseShellExecute = $false
$process_info.FileName = $psexec_path
$process_info.Arguments = $ps_exec_args_str
$process = New-Object System.Diagnostics.Process
$process.StartInfo = $process_info
$process.Start() | Out-Null
$std_dict = [ordered] @{
'std_out' = New-Object 'system.collections.generic.list[string]';
'std_err' = New-Object 'system.collections.generic.list[string]';
}
# $stdout_str = $process.StandardOutput.ReadToEnd()
while ($true) {
$line = $process.StandardOutput.ReadLine()
if ($line -eq $null) {
break
}
$std_dict['std_out'].Add($line)
}
# $stderr_str = $process.StandardError.ReadToEnd()
while ($true) {
$line = $process.StandardError.ReadLine()
if ($line -eq $null) {
break
}
$std_dict['std_err'].Add($line)
}
$process.WaitForExit()
ForEach ($std_type in $std_dict.Keys) {
ForEach ($line in $std_dict[$std_type]) {
if ((-not $include_blank_lines) -and ($line -match '^\s*$')) {
continue
}
$do_continue = $false
ForEach ($regex_str in $bypass_regex_array) {
if ($line -match $regex_str) {
$return_dict['bypassed_std'].Add($line)
$do_continue = $true
break
}
}
if ($do_continue) {
continue
}
$exit_code_regex_match = [regex]::Match($line, $exit_code_regex_str)
if ($exit_code_regex_match.Success) {
$return_dict['exit_code'] = [int] $exit_code_regex_match.Groups[1].Value
} elseif ($std_type -eq 'std_out') {
$return_dict['std_out'].Add($line)
} elseif ($std_type -eq 'std_err') {
$return_dict['std_err'].Add($line)
} else {
throw 'this conditional should never be true; if so, something was coded incorrectly'
}
}
}
return $return_dict
}
}