Назад | Перейти на главную страницу

psexec зависает только при использовании имени пользователя и пароля и вызове из сценария PowerShell

Я пытаюсь использовать psexec для запуска процесса в интерактивном сеансе, который уже был открыт. И моя машина, и удаленная машина работают под управлением Windows 7. Использование команды из командной строки работает нормально, исполняемый файл запускается и отображается в графическом интерфейсе.

psexec64 -accepteula -nobanner \\hostname -u domain\user -p password -h -i 2 -d C:\workingdir\subfolder\application.exe

Однако когда я пытаюсь выполнить тот же вызов в сценарии PowerShell, он не работает. Видеть полный сценарий для контекста.

# invalid args: $psExecArgs = "-accepteula", "-nobanner", "-u domain`\${username}", "-p ${password}", "-h", "-i ${sessionId}", "-d", "`\`\${hostname}", "`"${executableDirectory}`\${executableName}`""
# hangs: $psExecArgs = "-accepteula", "-nobanner", "-u domain`\${username}", "-p ${password}", "-h", "-d", "`\`\${hostname}", "`"${executableDirectory}`\${executableName}`""
$psExecArgs = "-accepteula", "-nobanner", "-h", "-d", "`\`\${hostname}", "`"${executableDirectory}`\${executableName}`""
& $EchoArgsPath $psExecArgs
$result = & $PsExecPath $psExecArgs #2>$null

Я наблюдаю такое же поведение при использовании pslist и pskill, поэтому я заменил их на tasklist и taskkill. Я убедился, что UAC отключен и что я могу сопоставить его с общим ресурсом Admin $ на удаленном компьютере, используя предоставленные мной учетные данные.

При вводе этого вопроса я обнаружил вопрос предполагая, что stdin может быть проблемой но я не уверен, актуально ли это в моем случае.

Отладка всегда ваш друг - если вы проверите значение $ psExecArgs (в полном скрипте) во время выполнения, вы заметите, что вы не указываете значение для $ password. Это означает, что вы отправляете -p (ничего) в psexec, что снова приводит к зависанию psexec в ожидании ввода пароля.

C:\..\foobar.ps1
cmdlet foobar.ps1 at command pipeline position 1
Supply values for the following parameters:
hostname: myhostname
username: myusername
password: mypassword
sourcedirectory: c:\mysourcedir
targetdirectory: c:\mytargetdir
executablename: myexec.exe
Hit Line breakpoint on 'C:\...\foobar.ps1:34'
[DBG]: PS C:\Users\Zerqent>> $psExecArgs
-accepteula
-nobanner
\\myhostname
-u domain\myusername
-p 
qwinsta

Чтобы избежать этого в PowerShell, сделайте параметры обязательными https://msdn.microsoft.com/en-us/powershell/reference/5.1/microsoft.powershell.core/about/about_functions_advanced_parameters

Обновление: вы также должны разделить часть имени пользователя и пароля, чтобы они были отдельными записями в списке. Обычно каждый раз, когда у вас есть пробел в cmd-команде, вы создаете отдельную запись в списке. Итак, ваш $ psexecArgs станет:

$psExecArgs = "-accepteula", "-nobanner", "-u", "domain`\${username}", "-p", "${password}", "-h", "-d", "`\`\${hostname}", "`"${executableDirectory}`\${executableName}`""

Не совсем уверен, будет ли это перенаправление работать, (# 2> $ null), или это также должно быть каким-то образом включено в список.

Объявление переменной типа $psExecArgs = "-accepteula", "-nobanner" создает массив строк.

Вы выполняете все, что написано в строках (используя &) вместо запуска процесса и предоставления аргументов, поэтому аргументы также должны быть простыми строками (а не массивом строк).

Затем, чтобы еще больше запутать это, если вы должны предоставить аргументы в одной строке ($psExecArgs = "-accepteula -nobanner"), который на самом деле появляется только как один аргумент для PSExec и тоже не будет работать.

Итак, вместо того, чтобы пытаться запустить строки, один из вариантов - использовать PowerShell Start-Process команда, которая ожидает, что аргументы будут переданы ей в массиве (как вы сейчас делаете).

Попробуйте изменить командные строки, например:

& $PsExecPath $psExecArgs

примерно так:

Start-Process $PsExecPath $psExecArgs

Вам придется обрабатывать код возврата и ошибки немного иначе, например:

try {
  $process = (Start-Process -FilePath $psexec -ArgumentList $psExecArgs -NoNewWindow -PassThru)
} 
catch {
  Write-Output "Error launching process!" 
  Write-Output $_.Exception.Message
  $process = $null
}
finally {
  if ($process) {
    $process.WaitForExit()
    Write-Host "Process exit code: " $process.ExitCode
  }
}