Search code examples
powershellcmd

Powershell - String together commands in a runas cmd


I tried to title this one the best I could. Currently, I have the following Powershell script:

Start-Process -Wait runas.exe "/netonly /user:$username `"cmd.exe /k sc.exe \\$target stop $service >> C:\temp\script_logs\servicerestart.txt 2>&1`""

Note: I switch /c to /k so that I can see the cmd window.

That all works just fine. The cmd window comes up (in this case, imagine that the variables are already set), I enter the password, and the command executes and pipes the output to the file.

However, since the use case is to restart a service (sc stop and then sc start), instead of having two separate threads, and entering the password twice, what I am attempting to do is string them together. My code:

Start-Process -Wait runas.exe "/netonly /user:$username `"cmd.exe /C sc.exe \\$target stop $service && sc.exe \\$target start $service >> C:\temp\script_logs\servicerestart.txt 2>&1`""

I know that && is correct from a cmd/bat standpoint, but clearly this setup is not valid. What happens in this case is that the stop command does run, but the start never does. I "thought" that what should happen is that the stop is sent, and once processed, then the start is sent.

What am I missing? Can this even be done in the first place?


Solution

  • Yes, it is possible, and there's nothing wrong with your command per se, except that:

    • using && means that that the RHS statement is only executed if the LHS one reports success, i.e. exit code 0

    • applying your redirections (>>..., 2>&1) only to the RHS of the && operation means that only its output is captured.

      • To capture the output from both statements, enclose the entire && operation in (...)

    Your symptom implies that sc.exe \\$target stop $service signaled failure, which is why sc.exe \\$target start $service and its redirections never got to execute.

    Therefore:

    • By using the (...) technique, you would be able to capture the error message from the LHS statement, allowing you to diagnose the problem.

    • However, since you note that the problem turned out to be that the service was already stopped, you can simply use the & operator instead of &&, which unconditionally sequences two statements and therefore effectively ignores any failure of the LHS statement; you can then make do without the (...) enclosure under the assumption that if sc.exe \\$target stop $service fails for a reason other than the service simply not being started, the subsequent start command would report an error too, which is captured by the redirections.

    • Note that if you didn't need to wait for the launched process to exit (with Start-Process -Wait), you could also run runas.exe directly,[1] which would avoid the need for an additional new console window to ask for the user's password.
      However, you report an inexplicable hang when trying this technique with your command.

    To put it all together:

    Start-Process -Wait runas.exe "/netonly /user:$username `"cmd.exe /C sc.exe \\$target stop $service & sc.exe \\$target start $service >> C:\temp\script_logs\servicerestart.txt 2>&1`""
    

    [1] Note that directly invoking external programs is synchronous (blocking) too, but the waiting applies only to the immediately launched process, whereas Start-Process -Wait waits for the entire child process tree, i.e. also for processes launched from the immediately launched one, such as in the case at hand.