【问题标题】:PsExec Throws Error Messages, but works without any problemsPsExec 抛出错误消息,但没有任何问题
【发布时间】:2013-08-25 04:06:06
【问题描述】:

因此,我们在自动化系统中大量使用 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"

在客户机上启用 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,这些类型的错误消息总是会出现,例如使用引号、变量/固定值、其他标志等。有人知道我该如何解决这个问题吗?这不是一个真正的问题,但它让查找错误变得很痛苦,因为“错误”无处不在。完全禁用 psexec 的错误消息也会有所帮助...

【问题讨论】:

  • 我有同样的问题,我在 psexec 命令之前使用$ErrorActionPreference = "SilentlyContinue"。但这不是一个真正的解决方案。
  • 嗯,不是最好的主意,但比我的“解决方案”要好得多。我想,我将编写一个 psexec-silent 函数,在 psexec 命令之前打开和关闭 ErrorActionPreference。至少我可以关闭错误消息,这显然不是一个。

标签: windows powershell automation psexec


【解决方案1】:

这是因为当进程写入 STDERR 时,PowerShell 有时会报告 NativeCommandError。 PsExec 写入信息行

PsExec v1.98 - Execute processes remotely
Copyright (C) 2001-2010 Mark Russinovich
Sysinternals - www.sysinternals.com

到 STDERR,这意味着它可能导致这种情况。

有关更多信息,请参阅以下问题/答案:

【讨论】:

    【解决方案2】:

    redirect stderr to null 最适合我。请看下面的链接

    Error when calling 3rd party executable from Powershell when using an IDE

    这是该链接中的相关部分:

    为避免这种情况,您可以将 stderr 重定向到 null 例如:

    du 2> $null 本质上,控制台主机和 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> $null

    【讨论】:

    • 您能否详细说明链接中提供的信息,以防它过时?
    • 虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接的答案可能会失效。
    • 已修复。从超链接添加了相关部分。
    【解决方案3】:

    我为 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
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2021-05-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多