4

SS64 says it means

Don’t wait for the application to terminate. Only use for non-interactive applications.

But I don't understand this. I'm trying to run some non-interactive system calls but, if I don't pass -d, my powershell job never returns and, if I do, pass -d, I don't get anything back when it does return. Can anyone tell me what exactly -d does?

Or for bonus points, you could tell me how to make this return something useful:

C:\PSExec.exe \\$hostname /accepteula -u user -p pass -d cmd /C "type $file" 2> $null
sirdank
  • 202
  • 1
  • 3
  • 12
  • cmd /C "type $file" 2> $null This does nothing, remove the cmd part and type it in your own command prompt, that's not an actual command. This is why it's returning nothing. – Cole Jul 22 '16 at 19:14
  • @Cole Sorry, I'm not sure what part of it is invalid. It works fine for me if I type it in my powershell window (not using -d). However, when I don't use -d, and push it to `Start-Job` my started job never returns. – sirdank Jul 22 '16 at 19:19
  • `C:\PSExec.exe \\$hostname /accepteula -u user -p pass -d cmd` means you are running `cmd` on remote system. try `C:\PSExec.exe \\$hostname -u user -p pass powershell` – NetwOrchestration Jul 22 '16 at 19:26
  • @AmirHossein Thanks for the suggestion and you're right. `type C:\Shared\file.txt` works through the command prompt though. Powershell resolves `$file` before sending the command to PSExec. This line works great as long as I do it without `-d` and not inside of a `Start-Job` task. – sirdank Jul 22 '16 at 19:29

2 Answers2

3

The -d switch, as alluded to in the description quoted in your question, makes PsExec not wait for the new process to exit. You can't get any exit code or output because the remote PsExec service just starts the process, tells the new process ID to the original PsExec program, and stops caring about what the new process does. Without -d, all the process's output will be sent back to the PsExec program that started the whole thing, and PsExec will have to wait for the new process to exit so it can know when to exit itself.

PsExec doesn't play nicely with redirection or PowerShell. I did manage to get partial output by launching the starting PowerShell instance with the -inputformat none parameter, but PsExec weirdly chops off some of the command's output and I couldn't get around it.

You could try PowerShell remoting instead:

Invoke-Command {type $file} -ComputerName $hostname -Credential (New-Object PSCredential -ArgumentList 'username', (ConvertTo-SecureString 'password' -AsPlainText -Force))
Ben N
  • 40,045
  • 17
  • 140
  • 181
  • That's what I was afraid of. I can also get three lines of output depending on the parameters used but that's not very much help. I was trying to avoid powershell remoting since it requires special setup in order to function but I may have to resort to it in the future. I think for now I'll try mapping the remote drives and loading the file from the filesystem. Thanks! – sirdank Jul 25 '16 at 12:19
2

About non-interactive -d, it just runs the command, without returning output and then terminates remote prompt. Actually, it does, by only returning the error code of remote process. In your case, it shows the output of $file on a non-existent, hidden cmd window on remote machine and terminates. That's why you don't see anything. Try to create a file on remote machine using -d switch and then you see it works.

Update:

If $file is a variable in remote machine, the problem is you're using a variable that expands in your local powershell environment (as you mentioned) so use a cmd variable instead (considering you're sending the command to cmd) that doesn't expand in powershell. PSExec.exe \\$hostname -u user -p pass -d cmd /c "type %file%" 2> $null

However, that's not the REAL solution! because what if you want to send a command to powershell remotely? You need something preventing the expansion, like %%varibale%% in cmd. I've found using " will expand, but ' prevents expanding in powershell:

PS> "This is $file" against PS> 'This is $file'

But that doesn't help in your case, another way though, is to create an script in local machine, and send to destination with PSEXEC:

PSExec.exe \\$hostname -u user -p pass -c powershell script.ps1 2> $null

Or... use Invoke-Command as mentioned here:

PS C:\> invoke-command -filepath c:\scripts\test.ps1 -computerName $hostname
NetwOrchestration
  • 3,205
  • 2
  • 21
  • 33
  • Hi Amir, I think you may be a little confused. This command works great in the script file run synchronously and in the console window but breaks only when I try to run it as a powershell background job. I tried /K and it did not help me out. – sirdank Jul 22 '16 at 20:01
  • Updated my answer, if I'm still confused about it, please tell me :) – NetwOrchestration Jul 22 '16 at 22:08
  • Amir, thank you for being so patient with my silly problem. `$file` is not a remote variable but a local one that I want to expand. All I want to run on the target machine is `type C:\Shared\file.config` but it doesn't work. Unfortunately, I think I'll have to accept Ben's answer because it says "PsExec doesn't play nicely" which is now my experience as well. Thanks again! – sirdank Jul 25 '16 at 12:14
  • 1
    You're welcome! I told I'm not an expert in Powershell yet. I upvoted his answer before you approve it too. Good Luck! – NetwOrchestration Jul 25 '16 at 13:58