VBScript sendkeys doesn't work on powershell in admin mode - powershell

I have a vbscript that spawns powershell in admin mode via:
Set oShell = CreateObject("Shell.Application")
oShell.ShellExecute "powershell", "-executionpolicy bypass", "", "runas", 1
and then I attempt to send keys via:
Set WshShell = WScript.CreateObject("WScript.Shell")
WScript.sleep 2000
WshShell.sendkeys "hello"
Since the keys didn't work, I tried separating the latter part into a separate file and specifically did a WshShell.AppActivate on the PID to make sure it gets the right window focus before sendkeys, however it still won't send the string.
Conversely, if I don't run powershell in admin, everything works fine:
Set WshShell = WScript.CreateObject("WScript.Shell")
WshShell.run "powershell"
WScript.sleep 200
WshShell.sendkeys "cls"
Can someone please tell me what I'm doing wrong?

While I don't have an official reference for you, I'm pretty sure that by design, for security reasons, you can not send keystrokes to elevated (run-as-admin) processes from a non-elevated process.
If this were possible, non-elevated processes could bypass their limited privileges, which would be an obvious violation of the rules.

Related

Powershell self-elevate loop

I'm one of the IT admins in our company. Lately, cyber-security want to get stricter on how easily users can read and/or write data on USB sticks and external mass storage. In addition all new users getting new Windows notebooks will only have "non admin" permissions. All requests to install software etc must come through the IT desk.
An Active Directory OU has been created and some test notebooks have been assigned to it. My boss would like to me to write and test some Powershell scripts that would allow my colleagues and I (in a screen-sharing session with the user) to temporarily delete the registry keys that control USB storage access (until the next group policy update comes along). The hard part has already been taken care of. The intention is that script will be stored as a Nal-Object on ZenWorks, so the user would not be able to see the source code (kinda similar to an exe file that is just double-clicked on).
The code that is causing hassle...
# self-elevate to admin user - code at the very top of the PS file..
if (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
Start-Process PowerShell -Verb RunAs "-NoProfile -ExecutionPolicy Bypass -Command `"cd '$pwd'; & '$PSCommandPath';`"";
exit;}
# all the main code follows..
Here, if I run the script (in an non-admin account) I am prompted by UAC to enter the name and password of a local (or domain) admin account, a new window/session in PS opens and I can run whatever main commands need running.
The problem however is that is that when prompted for credentials and then type the correct password for a local non-admin account (as some users are inevitably going to do!) a new empty PS window/session just keeps opening indefinitely in a periodic fashion.
I've also tried adding an 'else clause' to the if-statement (to show an alert to the user and/or force quit Powershell, but it never seems to be get executed).
When I test this on a computer is that non part of any domain etc, I just get a "user is not authorised" kind of alert in UAC and no error gets the chance to propagate.
Is there any kind of workaround for this? It would be great too if the UAC prompt just defaulted to the name "ROOT\install". Nobody knows that password to this account except for IT admins.
I've also run Get-ExecutionPolicy -List... MachinePolicy and LocalMachine are "RemoteSigned", everything else is "Undefined".
I don't think execution policy plays a role in this strange loop, but I am open to being wrong. The script I am testing has not been through any signing procedures etc and is just sitting locally on the Desktop of one of the test computers.
Thanks.
Your symptom is mysterious; it implies the following:
The UAC prompt triggered by Start-Process -Verb RunAs mistakenly accepts a NON-admin user's credentials.
On re-entry into the script, the test for whether the session is elevated (!([Security.Principal.WindowsPrincipal] ...) then fails, and Start-Process -Verb RunAs is run again, at which point no UAC prompt is shown, because Start-Process does think the session is elevated and instantly spawns a new window.
The result is an infinite loop of new windows getting opened.
I have no idea what would cause this discrepancy - do tell us if you ever find out.
As workaround, you can try the following approach:
if (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
$passThruArgs = "-NoProfile -ExecutionPolicy Bypass -NoExit -Command `"cd \`"$pwd\`"; & \`"$PSCommandPath\`""
if ([Environment]::CommandLine -match [regex]::Escape($passThruArgs)) {
throw "You entered non-admin credentials. Please try again with admin credentials."
}
Start-Process -Verb RunAs PowerShell $passThruArgs
exit
}
# all the main code follows..
'Now running elevated...'
That is, the on re-entry the process command line is examined for containing the same arguments that were passed on elevated re-invocation. If so, the implication is that even though the UAC prompt accepted the credentials, the new session still isn't elevated, and an error is thrown.
Note that I've added -NoExit to the re-invocation, so that the new window stays open, which allows the results to be examined.

Running PowerShell code inside VBS with many nested quotes, in one line

I'm starting to see double here from staring at this so long. I am trying to use an environment variable inside a script path that I'm going to launch from PowerShell, all initiated from a single line inside an mshta command run from a scheduled task on logon.
In case you were wondering, MSHTA can execute HTML/VBS/JS as if a local GUI app.
mshta vbscript:Execute("CreateObject(""Wscript.Shell"").Run ""powershell -NoLogo -Command """"& '\\$env:USERDNSDOMAIN\FOLDER1\FOLDER with Spaces\Folder3\Script-To-Run.ps1'"""""", 0 : window.close")
Premise: I have to do it this way to prevent momentary popups that flash onscreen when running from a scheduled task in user context. I cannot run this script in the System context.
I know that putting anything inside two single quotes gives me a string literal but if I try double quotes it seems to then use the space in the path. I've tried separating the two and concatenating them in all sorts of ways to no avail.
VBS equivalent of $env:USERDNSDOMAIN is
CreateObject("Wscript.Shell").ExpandEnvironmentStrings( "%USERDNSDOMAIN%" )
If the goal/purpose is to execute a PowerShell script without displaying the powershell.exe console window, you can do this by running it from a VBScript script executed by wscript.exe (not cscript.exe).
Example VBScript script:
Dim WshShell
Set WshShell = CreateObject("WScript.Shell")
WshShell.Run "%SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe -NoProfile -ExecutionPolicy Bypass -File """d:\path name\whatever.ps1"" [parameter [...]]", 0, False
The second parameter of the WshShell object's Run method is 0, so powershell.exe executes from a hidden window.
(Hint: The -File parameter to powershell.exe is generally easier to use than -Command. It must be the last parameter on the powershell.exe command line.)
End result: VBScript script runs the PowerShell script from a hidden window. Also, the VBScript itself has no console window, because you executed it using wscript.exe (the GUI host).

Run PowerShell script from folder Program Files via VBScript

How can I run a PowerShell script from within the %ProgramFiles% folder?
I have tried the variable %ProgramFiles% without any progress, also "Program Files" but can't get ut to work.
My current code
Set shell = WScript.CreateObject("WScript.shell")
shell.Run("powershell C:\Program Files\Temp\test.ps1"), 0 , True
It's working if I use a network share without any spaces
Set shell = WScript.CreateObject("WScript.shell")
shell.Run("powershell \\domain\SYSVOL\script\test.ps1"), 0 , True
I have also tried using """ but can't get PowerShell to work.
Anyone know how to solve this? I need to use VBScript in order to start the PowerShell script in the background at logon via a GPO. Otherwise it will show a PowerShell window.
Try this. Add parameter "-file" and double quotes around the path. You can get and store %ProgramFiles% in a variable using ExpandEnvironmentStrings:
Set shell = WScript.CreateObject("WScript.shell")
sProgramFiles = shell.ExpandEnvironmentStrings("%PROGRAMFILES%")
shell.Run "powershell -file """ & sProgramFiles & "\Temp\test.ps1""", 0 , True

Protractor supports Windows Authentication pop up?

Is there a way that Protractor supports windows authentication pop up for IE and Chrome, this doesn't work for my application, "http://username:password#server.url/", are there any alternate ways through which we can handle windows pop up.
Chrome supports directly embedding credentials in URL and just works fine as "http://username:password#server.url/".
However IE does not support that as security issue so you may have to write a shell script as below:
set WshShell = WScript.CreateObject("WScript.Shell")
WshShell.AppActivate "Windows Security"
WshShell.Sleep 500
WshShell.SendKeys "Username"
WshShell.SendKeys "{TAB}"
WshShell.SendKeys "password"
WshShell.SendKeys "{ENTER}"

Schedule a .vbs file to run in Windows

I have a VBScript script that starts a cmd prompt, telnets into a device and TFTP's the configuration to a server. It works when I am logged in and run it manually. I would like to automate it with Windows Task Scheduler.
Any assistance would be appreciated, here is the VBScript script:
set WshShell = WScript.CreateObject("WScript.Shell")
WshShell.Run "cmd"
WScript.Sleep 100
WshShell.AppActivate "C:\Windows\system32\cmd.exe"
WScript.Sleep 300
WshShell.SendKeys "telnet 10.20.70.254{ENTER}"
WScript.Sleep 300
WshShell.SendKeys "netscreen"
WScript.Sleep 300
WshShell.SendKeys "{ENTER}"
WScript.Sleep 300
WshShell.SendKeys "netscreen"
WshShell.SendKeys "{ENTER}"
WScript.Sleep 300
WScript.Sleep 300
WshShell.SendKeys "save conf to tftp 10.10.40.139 test.cfg{ENTER}"
WScript.Sleep 200
WshShell.SendKeys "exit{ENTER}" 'close telnet session'
set WshShell = WScript.CreateObject("WScript.Shell")
WshShell.Run "cmd"
WScript.Sleep 100
WshShell.AppActivate "C:\Windows\system32\cmd.exe"
WScript.Sleep 300
WshShell.SendKeys "telnet 10.20.70.254{ENTER}"
WScript.Sleep 300
WshShell.SendKeys "netscreen"
WScript.Sleep 300
WshShell.SendKeys "{ENTER}"
WScript.Sleep 300
WshShell.SendKeys "netscreen"
WshShell.SendKeys "{ENTER}"
WScript.Sleep 300
WScript.Sleep 300
WshShell.SendKeys "save conf to tftp 10.10.40.139 palsg140.cfg{ENTER}" 'repeat as needed
WScript.Sleep 200
WshShell.SendKeys "exit{ENTER}" 'close telnet session'
WshShell.SendKeys "{ENTER}" 'get command prompt back
WScript.Sleep 200
WshShell.SendKeys "exit{ENTER}" 'close cmd.exe
WshShell.SendKeys "{ENTER}" 'get command prompt back
WScript.Sleep 200
WshShell.SendKeys "exit{ENTER}" 'close cmd.exe
Add a scheduled task that runs the script with your credentials. Remind yourself that you need to update the credentials on the task every time you change your password. It be a good idea to have the script "phone home" via email or something every time it is run so that you can tell if it is being executed.
It might also be a good idea to set up a separate service id for these sorts of activities. You may not need to change the password on the service id as frequently.
You can add a scheduled task and enter no credentials or password for it. This will cause it to run under LOCAL SYSTEM (which normally is the context the Task Scheduler service uses).
Be aware that this is a backdoor vulnerability scenario: Anyone allowed to edit your script file could misuse it to do undesirable things on the machine that runs the task. Put proper permission on the script file to prevent that. On the other hand - a task running as LOCAL SYSTEM cannot wreck havoc over the network.
I propose you condense your script file a little:
Set WshShell = WScript.CreateObject("WScript.Shell")
Run "cmd.exe"
SendKeys "telnet 10.20.70.254{ENTER}"
SendKeys "netscreen"
SendKeys "{ENTER}"
SendKeys "netscreen"
SendKeys "{ENTER}"
SendKeys "save conf to tftp 10.10.40.139 test.cfg{ENTER}"
SendKeys "exit{ENTER}" 'close telnet session'
Run "cmd.exe"
SendKeys "telnet 10.20.70.254{ENTER}"
SendKeys "netscreen"
SendKeys "{ENTER}"
SendKeys "netscreen"
SendKeys "{ENTER}"
SendKeys "save conf to tftp 10.10.40.139 palsg140.cfg{ENTER}" 'repeat as needed
SendKeys "exit{ENTER}" 'close telnet session'
SendKeys "{ENTER}" 'get command prompt back
SendKeys "exit{ENTER}" 'close cmd.exe
SendKeys "{ENTER}" 'get command prompt back
SendKeys "exit{ENTER}" 'close cmd.exe
Sub SendKeys(s)
WshShell.SendKeys s
WScript.Sleep 300
End Sub
Sub Run(command)
WshShell.Run command
WScript.Sleep 100
WshShell.AppActivate command
WScript.Sleep 300
End Sub
I'm pretty sure SendKeys will not work if the desktop is locked or no user is logged in.
I'm pretty SendKeys will not work if you aren't logged in.
It's unreliable in my experience anyway.
You might be better off using a DOS batch file.
getftpconf.bat:
telnet 10.10.40.139
netscreen
netscreen
save conf to tftp 10.10.40.139 palsg140.cf
exit
Something like that.
If there is output in the command prompt that you need to record, you can put a " >> output.txt" at the end of the command line shortcut.
You could then call another batch file which sends that output.txt via ftp to where ever you need.
You can easily setup this batch file to run as a scheduled task in windows.
just make a batch file that contains this:
cscript.exe myscript.vbs
save it as something like myscript.bat.
Use schedule tasks to schedule the .bat file. After you create the scheduled task, you may have to check it's properties to make sure it's has appropriate user rights.
There are some options you can use with cscript so it doesn't show the logo, etc.
Batch files don't work in Windows with Telnet (works fine in UNIX -- again, way to go Microsoft). As already mentioned here, sendkeys does not work in vba when not logged on.
Sorry I don't have the "this does work" solution for you....I'm stuck on the same problem