Discussion:
ShellExecute with "RunAs" verb ignores the working directory argument
(too old to reply)
JJ
2019-03-20 14:31:00 UTC
Permalink
I'm trying to write a script for Win7 that will run a program with elevated
priviledge. Just like what the "Run as administrator" context menu does. I
know that this is done by using shell with the "RunAs" verb instead of the
default "Open" verb. However with "RunAs" verb, the working directory
argument passed to the ShellExecute is ignored, and I always end up getting
the Windows' SYSTEM32 directory as the working directory instead.

Here's the "elevate.vbs" script. Note: everything here are minimal code for
the sake of reproducing the problem.

cd = createobject("wscript.shell").currentdirectory
wscript.echo "elevate.vbs: " & cd
set sh = createobject("shell.application")
sh.shellexecute wscript.arguments(0), wscript.arguments(1), cd, "runas", 1

Here's the "test.vbs" script that I use for testing.

cd = createobject("wscript.shell").currentdirectory
wscript.echo "test.vbs: " & cd

When I tested it, I use non elevated Command Prompt with "E:\WORK" as the
current directory. All of the script files are in this directory. If I use
below command line:

elevate wscript test.vbs

"elevate.vbs" script shows the message box with the correct working
directory:

elevate.vbs: e:\WORK

But the elevated WSCRIPT complained with this error message box:

Can not find script file "C:\Windows\system32\test.vbs".

Now if I use full path to the "test.vbs" file like this:

elevate wscript e:\work\test.vbs

"elevate.vbs" script shows the same message as expected, but the elevated
"test.vbs" script shows this message:

test.vbs: C:\Windows\system32

Meaning that the "RunAs" verb did ignored or messed up the given working
directory. FYI, if the Command Prompt is already elevated, everything works
fine. So is there a solution other than manually readjusting the working
directory?
Mayayana
2019-03-20 17:45:13 UTC
Permalink
"JJ" <***@vfemail.net> wrote

| Meaning that the "RunAs" verb did ignored or messed up the given working
| directory. FYI, if the Command Prompt is already elevated, everything
works
| fine. So is there a solution other than manually readjusting the working
| directory?

Just guessing as I'm not on a restricted system. My
first guess would be that, of course, why should it
cooperate with a programmatic attempt to elevate?
That would defeat the purpose of restrcitions.

My second guess is... what? I can't find ShellExecute
as being available either in the WSH docs or in Win7
MSDN for the Shell object. I've only seen it as an
API call. Nor do I see it in the typelib on XP.

This is a longshot, but you might test this:

MsgBox WScript.ScriptFullName
Set SH = CreateObject("WScript.Shell")
MsgBox sh.CurrentDirectory
Set sh = Nothing

That will not always return the same path for both. The
first is the path of the script. The second can vary. You
may be getting the path of cscript parent folder.
JJ
2019-03-21 14:48:11 UTC
Permalink
Post by Mayayana
| Meaning that the "RunAs" verb did ignored or messed up the given working
| directory. FYI, if the Command Prompt is already elevated, everything
works
| fine. So is there a solution other than manually readjusting the working
| directory?
Just guessing as I'm not on a restricted system. My
first guess would be that, of course, why should it
cooperate with a programmatic attempt to elevate?
That would defeat the purpose of restrcitions.
Well, the shell framework itself is automatable. Be it from a VBScript, or
any native application that can use COM. The shell's "runas" verb is a known
method to run an application elevated. The UAC is the one which is
responsible for allowing the elevation or not, by showing the UAC prompt.
Post by Mayayana
My second guess is... what? I can't find ShellExecute
as being available either in the WSH docs or in Win7
MSDN for the Shell object. I've only seen it as an
API call. Nor do I see it in the typelib on XP.
The ShellExecute is a method of the IShellDispatch2 interface, but MSDN
separate it from the Shell automation object. The Shell automation object
actually implements multiple interfaces: IShellDispatch, IShellDispatch2,
IShellDispatch3, and IShellDispatch4; for shell versions that support those
interfaces. IShellDispatch is the main interface for the Shell object. It's
just like the FolderItems object which also implement FolderItems2 and
FolderItems3.
Post by Mayayana
MsgBox WScript.ScriptFullName
Set SH = CreateObject("WScript.Shell")
MsgBox sh.CurrentDirectory
Set sh = Nothing
That will not always return the same path for both. The
first is the path of the script. The second can vary. You
may be getting the path of cscript parent folder.
I only use CurrentDirectory which is already proven as correct by
"elevate.vbs", and that same directory is also used for ShellExecute's
working directory argument.

If "elevate.vbs" (i.e. the parent process) is already elevated, the child
process (i.e. "test.vbs") will have the correct working directory
("test.vbs" shows that too, using CurrentDirectory).

However, if "elevate.vbs" (i.e. the parent process) is not elevated, the
child process (i.e. "test.vbs") will *not* have the correct working
directory ("test.vbs" shows that too, using CurrentDirectory).

None of the script is modified, and the same command line is used, to
reproduce both results.

To sum it up, all of below conditions must be met in order to reproduce the
problem.

1. Windows version is Vista or later.

2. Parent process is not elevated.

3. Working directory of parent process is not Windows's SYSTEM32 directory.
e.g. is not "c:\windows\system32"

4. Child process is executed using VBScript using Shell object's
ShellExecute method.

5. When calling ShellExecute, parent process' working directory is used for
the working directory (vDirectory) argument, and "runas" is used for the
verb (vOperation) argument.

Expected result:
The initial working directory of the child process is same as parent
process'.

Actual result:
The initial working directory of the child process is always the Windows's
SYSTEM32 directory.
Mayayana
2019-03-21 15:34:16 UTC
Permalink
"JJ" <***@vfemail.net> wrote

| The ShellExecute is a method of the IShellDispatch2 interface, but MSDN
| separate it from the Shell automation object. The Shell automation object
| actually implements multiple interfaces: IShellDispatch, IShellDispatch2,
| IShellDispatch3, and IShellDispatch4; for shell versions that support
those
| interfaces. IShellDispatch is the main interface for the Shell object.
It's
| just like the FolderItems object which also implement FolderItems2 and
| FolderItems3.

Interesting. Thanks. I never noticed that. This is really obscure.
2,3,4,5 haven't been added to the original shell object listing,
but they're in the help file from the Win7 SDK. But runas is
undocumented. Secrets within secrets.

At first I was excited, but aside from what you're doing
and the ability to stop/start services (which can be done
with WMI) they haven't added anything interesting.

I found this, in case it's useful:

https://ss64.com/vb/shellexecute.html

"When a script is run with elevated permissions several aspects of the user
environment may change: The current directory, the current TEMP folder and
any mapped drives will be disconnected."

|
| > This is a longshot, but you might test this:
| >
| > MsgBox WScript.ScriptFullName
| > Set SH = CreateObject("WScript.Shell")
| > MsgBox sh.CurrentDirectory
| > Set sh = Nothing
| >
| > That will not always return the same path for both. The
| > first is the path of the script. The second can vary. You
| > may be getting the path of cscript parent folder.
|
| I only use CurrentDirectory which is already proven as correct by
| "elevate.vbs", and that same directory is also used for ShellExecute's
| working directory argument.
|
| If "elevate.vbs" (i.e. the parent process) is already elevated, the child
| process (i.e. "test.vbs") will have the correct working directory
| ("test.vbs" shows that too, using CurrentDirectory).
|
| However, if "elevate.vbs" (i.e. the parent process) is not elevated, the
| child process (i.e. "test.vbs") will *not* have the correct working
| directory ("test.vbs" shows that too, using CurrentDirectory).
|
| None of the script is modified, and the same command line is used, to
| reproduce both results.
|
| To sum it up, all of below conditions must be met in order to reproduce
the
| problem.
|
| 1. Windows version is Vista or later.
|
| 2. Parent process is not elevated.
|
| 3. Working directory of parent process is not Windows's SYSTEM32
directory.
| e.g. is not "c:\windows\system32"
|
| 4. Child process is executed using VBScript using Shell object's
| ShellExecute method.
|
| 5. When calling ShellExecute, parent process' working directory is used
for
| the working directory (vDirectory) argument, and "runas" is used for the
| verb (vOperation) argument.
|
| Expected result:
| The initial working directory of the child process is same as parent
| process'.
|
| Actual result:
| The initial working directory of the child process is always the Windows's
| SYSTEM32 directory.
JJ
2019-03-23 04:11:31 UTC
Permalink
Post by Mayayana
At first I was excited, but aside from what you're doing
and the ability to stop/start services (which can be done
with WMI) they haven't added anything interesting.
That no longer apply to Windows Vista and newer versions.
Post by Mayayana
https://ss64.com/vb/shellexecute.html
"When a script is run with elevated permissions several aspects of the user
environment may change: The current directory, the current TEMP folder and
any mapped drives will be disconnected."
I guess "runas" verb in IShellDispatch2.ShellExecute is bugged. The flat
API's ShellExecute/Ex function seems to be the only ones that handle it
reliably.
Mayayana
2019-03-23 13:27:49 UTC
Permalink
"JJ" <***@vfemail.net> wrote

| > At first I was excited, but aside from what you're doing
| > and the ability to stop/start services (which can be done
| > with WMI) they haven't added anything interesting.
|
| That no longer apply to Windows Vista and newer versions.
|

No longer applies? What? WMI is still there. Do you mean
shell ability to stop/start services was removed? I have Win7
help files for WMI and Shell, from the Win7 SDK. I don't
see anything discontinued.
JJ
2019-03-24 06:37:20 UTC
Permalink
|> At first I was excited, but aside from what you're doing
|> and the ability to stop/start services (which can be done
|> with WMI) they haven't added anything interesting.
|
| That no longer apply to Windows Vista and newer versions.
|
No longer applies? What? WMI is still there. Do you mean
shell ability to stop/start services was removed? I have Win7
help files for WMI and Shell, from the Win7 SDK. I don't
see anything discontinued.
Everything is still there, but to start/stop a service requires an elevated
process, or the SYSTEM account. Even if the user is already a member of the
Administrators group, it still require elevation.

Some other things also require elevation. e.g. changing process priority to
Real Time.
Mayayana
2019-03-24 15:17:34 UTC
Permalink
"JJ" <***@vfemail.net> wrote

| > No longer applies? What? WMI is still there. Do you mean
| > shell ability to stop/start services was removed? I have Win7
| > help files for WMI and Shell, from the Win7 SDK. I don't
| > see anything discontinued.
|
| Everything is still there, but to start/stop a service requires an
elevated
| process, or the SYSTEM account. Even if the user is already a member of
the
| Administrators group, it still require elevation.
|

I guess I've never needed to do that, but I don't
see any issue. Can't you just run a script or HTA
elevated? My impression was that the only total
loss in a restricted system was drag-drop, because
there's no way to right-click -> Run as Admin when
you drop a file onto a VBS.

In other words, I've written tools that use WMI
in VBScript to manage services on XP. If I used Win7
very much I imagine it might be useful for me to
write a similar tool for that. Is there any reason I
couldn't just right-click my HTA and choose Run
as Admin, and thereby have it fully functional? Are
you saying I'd need to log on as the real admin to
do that?
JJ
2019-03-25 13:12:39 UTC
Permalink
Post by Mayayana
I guess I've never needed to do that, but I don't
see any issue. Can't you just run a script or HTA
elevated? My impression was that the only total
loss in a restricted system was drag-drop, because
there's no way to right-click -> Run as Admin when
you drop a file onto a VBS.
The point of using VBScript is to automate things. If manually
right-clicking on the file then choose Run as administrator is acceptable,
then I wouldn't need VBScript in the first place. Moreover, the context menu
of *.vbs file doesn't have a "Run as administrator" menu, like *.bat file
does.
Post by Mayayana
In other words, I've written tools that use WMI
in VBScript to manage services on XP. If I used Win7
very much I imagine it might be useful for me to
write a similar tool for that. Is there any reason I
couldn't just right-click my HTA and choose Run
as Admin, and thereby have it fully functional?
Batch files and VBScript that start/stop service(s), and works in WinXP,
won't work in Vista+ unless it's run elevated. Without elevation, the
start/stop service action would be denied by the system.
Post by Mayayana
Are you saying I'd need to log on as the real admin to do that?
No. The "Run as administrator" context menu is not the same as running a
process using a different user. You can find out more about UAC here:

https://en.wikipedia.org/wiki/User_Account_Control
Mayayana
2019-03-25 14:52:31 UTC
Permalink
"JJ" <***@vfemail.net> wrote

| The point of using VBScript is to automate things. If manually
| right-clicking on the file then choose Run as administrator is acceptable,
| then I wouldn't need VBScript in the first place.

Ah. I typically run them by mouse. Or in an HTA.
I can see what you mean if you're doing something
like putting them in the startup folder.

| > Are you saying I'd need to log on as the real admin to do that?
|
| No. The "Run as administrator" context menu is not the same as running a
| process using a different user.

I didn't mean just a different user. I meant the
"Administrator" user. The real admin. I wrote a program
to remove file restrictions easily, for instance. It
works fine with Run as Admin. But it would also work
fine if I logged in as Administrator, because that user
really is an admin. :)

If I ever get stuck running on NTFS I might just
do that -- use the Administrator account.

Thomas Langer
2019-03-24 21:50:38 UTC
Permalink
Post by JJ
I'm trying to write a script for Win7 that will run a program with elevated
priviledge. Just like what the "Run as administrator" context menu does. I
know that this is done by using shell with the "RunAs" verb instead of the
default "Open" verb. However with "RunAs" verb, the working directory
argument passed to the ShellExecute is ignored, and I always end up getting
the Windows' SYSTEM32 directory as the working directory instead.
Here's the "elevate.vbs" script. Note: everything here are minimal code for
the sake of reproducing the problem.
cd = createobject("wscript.shell").currentdirectory
wscript.echo "elevate.vbs: " & cd
set sh = createobject("shell.application")
sh.shellexecute wscript.arguments(0), wscript.arguments(1), cd, "runas", 1
Here's the "test.vbs" script that I use for testing.
cd = createobject("wscript.shell").currentdirectory
wscript.echo "test.vbs: " & cd
When I tested it, I use non elevated Command Prompt with "E:\WORK" as the
current directory. All of the script files are in this directory. If I use
elevate wscript test.vbs
"elevate.vbs" script shows the message box with the correct working
elevate.vbs: e:\WORK
Can not find script file "C:\Windows\system32\test.vbs".
elevate wscript e:\work\test.vbs
"elevate.vbs" script shows the same message as expected, but the elevated
test.vbs: C:\Windows\system32
Meaning that the "RunAs" verb did ignored or messed up the given working
directory. FYI, if the Command Prompt is already elevated, everything works
fine. So is there a solution other than manually readjusting the working
directory?
If e: is a mapped network drive then modify your registry setting of
EnableLinkedConnections to dword:1

see here:
https://support.microsoft.com/en-us/help/3035277/mapped-drives-are-not-available-from-an-elevated-prompt-when-uac-is-co

https://docs.microsoft.com/en-us/windows/security/identity-protection/user-account-control/how-user-account-control-works#uac-process-and-interactions
Loading...