11

So we are using PsExec a lot in our automations to install virtual machines, as we can't use ps remote sessions with our windows 2003 machines. Everything works great and there are no Problems, but PsExec keeps throwing errors, even every command is being carried out without correctly. For example:

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"

Enables the PsRemoting on the guest, but also throws this error message:

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.

These kinds of error messages apear ALWAYS no matter how i use psexec, like with quotes, with vriables/fixed values, other flags, etc. Does anybody has an idea how i could fix this? It is not a real problem, but it makes finding errors a pain in the ass, because the "errors" are everywhere. Disabling the error messages of psexec at all would also help...

modmoto
  • 2,901
  • 7
  • 29
  • 54
  • 1
    I have the same problem, and i use `$ErrorActionPreference = "SilentlyContinue"` before the psexec command. But it is not a real solution. – plunkets Aug 22 '13 at 12:45
  • Well, not the best idea, but way better than my "solution". I guess, i will write a psexec-silent function, tuning the ErrorActionPreference on and off before the psexec command. At least i can switch off the error message, which clearly isn't one. – modmoto Aug 22 '13 at 12:56
  • Check this; http://stackoverflow.com/a/2095623/469777 – Stafford Williams Dec 31 '13 at 06:12

3 Answers3

17

This is because PowerShell sometimes reports a NativeCommandError when a process writes to STDERR. PsExec writes the infoline

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

to STDERR which means it can cause this.

For more information, see these questions / answers:

Community
  • 1
  • 1
TessellatingHeckler
  • 27,511
  • 4
  • 48
  • 87
5

redirect stderr to null worked best for me. see below link

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

Here's the relevant section from that link:

To avoid this you can redirect stderr to null e.g.:

du 2> $null Essentially the console host and ISE (as well as remoting) treat the stderr stream differently. On the console host it was important for PowerShell to support applications like edit.com to work along with other applications that write colored output and errors to the screen. If the I/O stream is not redirected on console host, PowerShell gives the native EXE a console handle to write to directly. This bypasses PowerShell so PowerShell can't see that there are errors written so it can't report the error via $error or by writing to PowerShell's stderr stream. ISE and remoting don't need to support this scenario so they do see the errors on stderr and subsequently write the error and update $error.

.\PsExec.exe \$hostname -u $script:userName -p $script:password /accepteula -h cmd /c $powerShellArgs 2> $null

Community
  • 1
  • 1
Gopi Palamalai
  • 391
  • 6
  • 6
  • Can you elaborate on the information provided in the link in case it goes stale? – sushain97 Jul 08 '14 at 01:01
  • While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. – Onik Jul 08 '14 at 01:03
  • Fixed it. Added relevant section from hyperlink. – Gopi Palamalai Jul 18 '14 at 04:47
1

I have created a psexec wrapper for powershell, which may be helpful to people browsing this question:

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
    }
}
sam-6174
  • 3,104
  • 1
  • 33
  • 34