I have an .hta
application that accepts two command line arguments. Executing the application on the remote machine via command line works just like the following
(command line - cmd)Example:
C:\Users\<user>\Desktop>MSI-BUILDER.hta "MSI_APP" "D:\APP\15.9.98"
But when using my desktop trying to execute the same command on the remote machine via PSEXEC I see the application running in task manager but nothing happens.
The first steps were assigning the command line arguments to variables in PowerShell:
$arg1 = "MSI_APP"
$arg2 = "D:\APP\15.9.98"
and executing this command in PowerShell fails (no errors, just hangs):
.\psexec -s -i \\Srv2012 cmd /c "start /i "MSI-BUILDER" "C:\Users\<user>\Desktop\MSI-BUILDER.hta" $arg1 $arg2"
The application launches just in task manager and I'm assuming in the background but I don't see any changes, so it might just be hanging...
Im not 100% sure if my syntax in this matter is correct for launching an HTA via powershell with command-line arguments.
Also is there a way or switch that I can actually see the application launch and do its thing after remotely executing the code, for testing purposes?
The invocation of your *.hta
file can be simplified, by passing its path and arguments directly to mshta.exe
(this also prevents a console window from appearing briefly if you launch via cmd/ c
):
# From PowerShell (-accepteula omitted for brevity)
# IMPORTANT: You must use the *.hta file's FULL PATH.
.\psexec \\SERVER -i -s mshta.exe "D:\path\toapp\app.hta" $arg1 $arg2
By default, psexec
runs synchronously, i.e. it doesn't return until the remote process exits, which is necessary if you want to know the process' exit code.[1]
In your case, the process doesn't exit until the HTA application window closes, so I assume that yours automatically closes when invoked with command-line arguments - if it doesn't, psexec
wouldn't return until the interactive user closes the window when invoked with -i
, or not at all without -i
.
In cases where you need asynchronous execution, use the -d
option; this makes psexec
return after successfully launching the target process, without waiting for it to exit. Since you then by definition cannot know the true exit code of the launched process, all that psexec
will tell you is whether the process could be created.
Caveat: Running interactively (-i
) with -s
, i.e. as the NT AUTHORITY\SYSTEM
account, is a security risk - see next section.
However, with proper quoting your original attempt could be made to work too - see the bottom section.
As for:
Also is there a way or switch that I can actually see the application launch?
It is psexec
's -i
option that makes the specified command run visibly, interactively on the remote target machine, in the session of whatever user happens to be logged on there interactively at the time.[2]
In terms of user identity, psexec
generally allows you to launch commands as:
either: the
SYSTEM
account (NT AUTHORITY\SYSTEM
) with option-s
, which is not recommended with-i
, however:NT AUTHORITY\SYSTEM
is a highly privileged account that represents the local computer, so its use in an application that the user can control interactively is a a security risk.
or: a given, fixed user, with option
-u
(and-p
; see example below)
Note that what you cannot do with -i
is to automatically run with the identity of whatever user happens to be logged on to the interactive session on the target computer, as that would be highly problematic from a security perspective. However, explicitly using -u
with the same credentials as the currently interactive user (if known) works.
See the documentation for more information.
With -i
, it's better to use an account that has only the minimum set of privileges required for the application to function; instead of -s
, you would then use the -u
(username) and -p
(password) parameters; e.g.:
# From PowerShell
.\psexec \\SERVER -i -u user1 -p passwd1 mshta.exe "D:\path\toapp\app.hta" $arg1 $arg2
As for what you tried (in your question):
Your original command probably would have worked, if you had fixed your quoting problems:
.\psexec \\Srv2012 -s -i cmd /c start /i `"MSI-BUILDER`" "C:\Users\<user>\Desktop\MSI-BUILDER.hta" $arg1 $arg2
To avoid problems with nested quoting, the outer quoting around the command passed to cmd /c
has been omitted.
Note how the "
chars. that enclose MSI-BUILDER
must - unfortunately - be escaped as `"
so as to ensure that PowerShell passes them through to psexec
and, ultimately, cmd /c
:
PowerShell uses a double-quoting on demand policy behind the scenes, so that even arguments that you originally specified with quotes end up not double-quoted, if the argument value doesn't contain spaces[3] - therefore, your
"MSI-BUILDER"
argument ends up getting passed as justMSI-BUILDER
- without double-quoting - topsexec
.Unfortunately, the
cmd
-internalstart
command has an awkward syntax: it always requires the argument that is the window title to be enclosed in"..."
on the command line, even if the title is a single word (such asMSI-BUILDER
in your case).Therefore, in this particular edge case, the
"
around the window-title argument forstart
must be escaped as`"
to ensure that they are retained.
As shown above, however, there's a simpler way to invoke your *.hta
(not requiring an intermediate cmd.exe
process).
As an aside: the start
command is superfluous, and setting a title for the transient window that launches the *.hta
GUI is pointless, as the window will just flash for an instant.
[1] Note that HTA applications don't support setting exit codes explicitly, unless you employ an elaborate workaround. Without it, the exit code would always be 0
- unless the mshta.exe
process crashes.
[2] That psexec
is capable of doing so may be surprising; it is made possibly by the following clever technique: psexec
connects to the target machine's $ADMIN
share (typically, C:\Windows
), temporarily extracts a service executable in its own executable image (PSEXESVC.exe
) to that location, and starts that executable as local service (PSEXESVC
) on the target machine. It is this service that launches the command passed to psexec
on invocation, optionally (-i
) in the current user's session (visible window station). The calling psexec
instance on the origin machine communicates with the service via a named pipe (psexecsvc
), which is what enables the calling machine to receive the remote process' console output if -i
was not specified; on completion of the command (or, with the -d
(don't wait) option, on successfully launching the command), the service is stopped and the service executable is deleted - see this article for more information.
[3] There are other, complex criteria relating to "
chars. embedded in the value.
Okay so finally after hours of trying different things this is the command that worked for me
Edited Command:
.\PSEXEC -accepteula -s -i 2 \\SERVER cmd /c "D:\path\toapp\app.hta" $arg1 $arg2 -u username -p password
来源:https://stackoverflow.com/questions/57978335/executing-an-hta-application-via-psexec-with-command-line-arguments