How to write passed variables using sendkeys - batch-file

Brief explanation: trying to use sendkeys to type two variables/keys from the output of a batch file.
I keep getting syntax or out of subscript errors.
Two variables are passed from a batch script, via:
cscript //nologo sendKeys.vbs !config! !arguments!
rem Yes, both variables are defined, and delayed expansion in enabled.
My attempts to put them in sendkeys doesn't seem to work. I'm not familiar with VBS...
VBScript:
Set WshShell = WScript.CreateObject("WScript.Shell")
WshShell.Run "notepad.exe", 9 ' Start notepad in order to test my failure.
WScript.Sleep 500 ' Give notepad time to load
WshShell.SendKeys & WshShell.Arguments(0) ' write passed !config! variable
WshShell.SendKeys "{TAB}" ' tab key
WshShell.SendKeys & WshShell.Arguments(1) ' write passed !arguments! variable
WshShell.SendKeys "{ENTER}" ' enter key

The .Arguments belong to the WScript object, not the Shell. & is the concatenation operator, it makes no sense between a method name and the first/only argument. So use
Set WshShell = WScript.CreateObject("WScript.Shell")
WshShell.Run "notepad.exe", 9 ' Start notepad in order to test my failure.
WScript.Sleep 500 ' Give notepad time to load
WshShell.SendKeys WScript.Arguments(0) ' write passed !config! variable
WshShell.SendKeys "{TAB}" ' tab key
WshShell.SendKeys WScript.Arguments(1) ' write passed !arguments! variable
WshShell.SendKeys "{ENTER}" ' enter key
or - better - think about a way to solve your real world problem without SendKeys.

Related

VBScript - Bring Microsoft Edge window to foreground

My script launches a MS Edge window and then tries to log into Netflix with my credentials. The problem is, at times, the browser window comes up behind the CMD console and the script doesn't work.
How do I launch the browser in the foreground or bring it to the foreground after it's launched?
<!-- :
rem #Echo Off
Set "usr_name=#####"
Set "usr_pass=#####"
%SystemRoot%\System32\cscript.exe //NoLogo "%~f0?.wsf" "%browser%" "%usr_name%" "%usr_pass%"
Exit /B
-->
<Job>
<Script Language="VBScript">
Dim ObjShell, MyChrome
Set ObjShell = WScript.CreateObject("WScript.Shell")
MyChrome = Chr(34) & WScript.Arguments(0) & Chr(34)
ObjShell.Run MyChrome & "--app=""https://www.netflix.com/login""", 1
WScript.Sleep 5000
ObjShell.SendKeys "{TAB}"
ObjShell.SendKeys "{TAB}"
ObjShell.SendKeys(WScript.Arguments(1))
ObjShell.SendKeys "{TAB}"
ObjShell.SendKeys(WScript.Arguments(2))
ObjShell.SendKeys "{ENTER}"
WScript.Sleep 6000
ObjShell.SendKeys "{ESCAPE}"
ObjShell.SendKeys "{TAB}"
WScript.Sleep 1000
ObjShell.SendKeys "{TAB}"
WScript.Sleep 1000
ObjShell.SendKeys "{ENTER}"
WScript.Sleep 6000
ObjShell.SendKeys "%{F4}"
</Script>
</Job>
Scripts that depend on SendKeys are notoriously unreliable. A more reliable approach is to control the browser with Seleniumbasic and Chrome driver or use WebView2 in a C# program. Barring that, one option for adding window control functionality to your existing script is to use the command line tool Cmdow. For example:
ObjShell.Run "cmdow ""Netflix*"" /MAX",1,False
Update:
You can also try the built-in AppActivate method:
ObjShell.AppActivate "Netflix"
The solution to to use a powershell cmdlet to minimize all windows before running the script that launches the browser.
'''powershell -command "(new-object -com shell.application).minimizeall()'''

How to get Window title of newly spawned process thro' Batch-Vbscript hybrid script?

I am trying to automate the Group Policy editing process as much as possible.
I have the following script to spawn the gpedit.msc process but it's window goes out of focus as soon as it opens:
FINDSTR /E "'VbsCode" %~f0 > %temp%\~temp.vbs
CSCRIPT //NOLOGO %temp%\~temp.vbs
Sub GPEditOptions 'VbsCode
On Error Resume Next 'VbsCode
Set WshShell = WScript.CreateObject("WScript.shell") 'VbsCode
WshShell.Visible = False 'VbsCode
WshShell.Run "gpedit.msc",0 'VbsCode
:: WshShell.AppActivate "Local Group Policy Editor" 'VbsCode
End Sub 'VbsCode
GPEditOptions 'VbsCode
:: WScript.Quit 0 'VbsCode
How can I AppActivate the window that has been opened by the newly spawned gpedit.msc process ? Specifically how to know what's the name/title of that window that has been opened ? "Local Group...Editor" doesn't work.
I think I eventually figured out, how to approach this problem. There are different types of processes.
In this case, I first need to select the Microsoft Management Console window, since it's the parent process which spawns the actual "Local Group Policy Editor" child process.
So this code does the job of selecting the first Windows Component starting with letter "W" by sending a ton of keys priorly, and yes you do need Administrator elevation for proper selection of options in the gpedit.msc window:
#echo off
net file 1>nul 2>nul
if not '%errorlevel%' == '0' (
powershell Start-Process -FilePath "%0" -ArgumentList "%cd%" -verb runas >nul 2>&1
exit /b
)
cd /d %1
FINDSTR /E "'VbsCode" %~f0 > %temp%\~temp.vbs
CSCRIPT //NOLOGO %temp%\~temp.vbs
Sub GPEditOptions 'VbsCode
On Error Resume Next 'VbsCode
Set WshShell = WScript.CreateObject("WScript.shell") 'VbsCode
WshShell.Visible = False 'VbsCode
WshShell.Run "gpedit.msc",0 'VbsCode
WScript.Sleep 500 : WshShell.AppActivate "Microsoft Management Console" 'VbsCode
WScript.Sleep 500 : WshShell.AppActivate "Local Group Policy Editor" 'VbsCode
WScript.Sleep 500 : WshShell.sendKeys "% x{TAB}{ENTER}" 'VbsCode
WScript.Sleep 500 : WshShell.sendKeys "{TAB}{TAB}{TAB}{TAB}" 'VbsCode
WScript.Sleep 500 : WshShell.sendKeys "{DOWN}{DOWN}{ENTER}" 'VbsCode
WScript.Sleep 500 : WshShell.sendKeys "{TAB}{TAB}{TAB}{TAB}" 'VbsCode
WScript.Sleep 500 : WshShell.sendKeys "{DOWN}{DOWN}{DOWN}{DOWN}" 'VbsCode
WScript.Sleep 500 : WshShell.sendKeys "{DOWN}{DOWN}{ENTER}" 'VbsCode
WScript.Sleep 500 : WshShell.sendKeys "{TAB}{TAB}{TAB}{TAB}{W}" 'VbsCode
End Sub 'VbsCode
GPEditOptions 'VbsCode
WScript.Quit 0 'VbsCode
Hope this helps anyone facing similar issue.
There is no need of sending bunch of keys and getting the Group policy editor window title.
Actually every group policy setting has equivalent registry keys. And registry can be edited easily from VBScript. To find the equivalent registry key for the group policy setting:
Download a tool named Process Monitor from SysInternals.
Run it and click Filter > Filter.
Now create two filters like: "Process name" - "is" - "mmc.exe" - then "include" and "Operation" - "is" - "RegSetValue" - then "Include".
Now edit the group policy setting and the registry key will appear in Process monitor.
And Function to edit registry in VBScript:
Function RegSetValue(regkey,value)
Dim WshShell
Set WshShell = CreateObject("Wscript.Shell")
WshShell.RegWrite(regkey,value)
End Function

Batch file message box: Carriage return in message body

I'm successfully showing a message box from a batch file using this method given by boflynn for a previous question.
I'm trying to insert a carriage return into the message box body text but all my attempts and combinations of quote marks and Char(13) have thus far failed.
With reference to the above linked answer, I'm looking for a messagbox that would put text on multiple lines, such as:
This will
be shown
in a popup
Is this possible?
VBScript has a builtin constant vbCr for the Carriage Return character. Concatenate your (sub)strings with that constant and display the message box with the result:
MsgBox "This will" & vbCr & "be shown" & vbCr & "in a popup"
To display multiline text from a batch file you need to pass each line as a separate argument
cscript MessageBox.vbs "This will" "be shown" "in a popup"
and concatenate the arguments
ReDim args(WScript.Arguments.Count-1)
For i = 0 To WScript.Arguments.Count-1
args(i) = WScript.Arguments(i)
Next
MsgBox Join(args, vbCr)
You can try this sample example to call the MsgBox from a function :
#echo off
set "Msg=Hey !\nHere is a message !\nThis will\n be shown\n in popup\n with multi-lines !"
Rem 64=vbInformation, 48=vbExclamation, 16=vbCritical 32=vbQuestion
set Type=64 48 16 32
Set "Title=Example of MsgBox in batch with vbscript"
For %%a in (%Type%) Do Call:MsgBox "%Msg%" "%%a" "%Title%"
exit /b
::**********************************************************
:MsgBox <Msg> <Type> <Title>
echo MsgBox Replace("%~1","\n",vbCrLf),"%~2","%~3" > "%tmp%\%~n0.vbs"
Cscript /nologo "%tmp%\%~n0.vbs" & Del "%tmp%\%~n0.vbs"
exit /b
::**********************************************************

write a batch script to press "tab" and "Enter" key

I need to press "TAB" and "Enter" key using either a batch script or VB script.
OK, I'm writing the vb file in notepad. I run it by double clicking icon testVB.vbs in C:.
This is what I have:
testVB.vbs
Set WshShell = CreateObject("WScript.Shell")
WshShell.Run "test.bat"
WScript.Sleep 1000
WshShell.SendKeys (TAB) //to tab from the cancel button to open button
WScript.Sleep 1000
WshShell.SendKeys "~" //clicks open button
test.bat
#ECHO OFF
START MSAccess "C:\path\file.mdb"
I want to open Access and the DB, but a pop up window appears which is what I'm trying to get around. After I figure that out I will need to figure out how to write code to import a .txt file to the DB.
The TAB is what is not working, I have tried {TAB}, "TAB", (TAB), and different combos. I get an error with the first one and the others have no action. The enter works though ("~").
Try this;
#if (#CodeSection == #Batch) #then
#echo off
CScript //nologo //E:JScript "%~F0"
goto :EOF
#end
WScript.Sleep (1000)
WScript.CreateObject("WScript.Shell").SendKeys("{TAB}");
WScript.Sleep (1000)
WScript.CreateObject("WScript.Shell").SendKeys("~");

.vbs(5, 1) Microsoft VBScript runtime error: Subscript out of range Error:800A0009

This is my first question on here, because, although I have searched at least 15 different other posts for the answer to my issue, none have the answer. Please help!
QUESTION: How do I fix Error:800A0009?
DETAILS: I am creating a small program that gathers all local computers and sends them all an audio file to be played. Also, I need to know how to force send, if anyone knows. Lastly, I first run "Get Computers.bat".
My Code:
~~~~~~VBS FILE(Remote Speak.vbs)~~~~~~~~~~~~~~~~~~~
(Obtains variable transferred which contains network name of a computer, and sends it a file to be play using SAPI)
'get ip
Option Explicit
Dim args, strOut
set args = Wscript.arguments
strOut= args(0)
IP = strOut
'get MSG
MSG = InputBox("Type what you want the PC to say:", "Remote Voice Send By X BiLe", "")
If MSG = "" Then WScript.quit: Else
'vbs command to send
A = "on error resume next" & VBCRLF & _
"CreateObject(""SAPI.SpVoice"").speak " & """" & MSG & """" & VBCRLF & _
"CreateObject(""Scripting.FileSystemObject"").DeleteFile (""C:\Voice1.vbs"")"
' Create the vbs on remote C$
CreateObject("Scripting.FileSystemObject").OpenTextFile("\\" & ip & "\C$\Voice1.vbs",2,True).Write A
' Run the VBS through Wscript on remote machine via WMI Object Win32_Process
B = GetObject("winmgmts:\\" & IP & "\root\cimv2:Win32_Process").Create("C:\windows\system32\wscript.exe ""C:\Voice1.vbs""", null, null, intProcessID)
~~~BATCH PRIMARY (Get Computers.bat)~~~~~~~~~~~
(Gathers computer names and assign each one, using net view, filtering the "\" to Computer%num%. Also, :tempcall is just an error handler.)
#echo off
cls
set num=1
echo #echo off > Computers.bat
if "%1"=="loop" (
for /f "delims=\ tokens=*" %%a in ('net view ^| findstr /r "^\\\\"') do (
set comp=%%a
call :number
if exist %%f exit
)
goto :eof
)
cmd /v:on /q /d /c "%0 loop"
:tempcall
call temp.bat
echo.
echo.
echo.
echo You have %num%computers on your network!
pause>nul
del /q temp.bat
start Computers.bat
exit
:number
if %comp% == "" (
goto :tempcall
) else (
echo set Computer%num%=%comp% >> Computers.bat
echo cscript "Remote Speak.vbs" %1 >> Computers.bat
echo call "Remote Speak.vbs" >> Computers.bat
echo set num=%num% > temp.bat
echo Computer%num%: %comp%
set /a num=%num% + 1
)
BATCH SECONDARY (Computers.bat)
(The computers I made up off the top of my head, but they are generally in that format.)
#echo off
set Computer1=040227-CYCVN1
cscript "Remote Speak.vbs" //NoLogo > log.txt
set Computer1=051448-YZVN2
cscript "Remote Speak.vbs" //NoLogo > log.txt
pause>nul
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~END DETAILS~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1.) Temp.bat is literally just temporary, it's deleted, as you can see, almost immediately after it's created, it simply holds the value of %num% after it breaks out of the loop, because it didn't show "You have %num%computers on your network!" correctly.
2.) Don't worry too much about the VBScript file except for the top lines:
Option Explicit
Dim args, strOut
set args = Wscript.arguments
strOut= args(0)
IP = strOut
3.) My main issue is that I am trying to find a safe way to have "Computers.bat" call the "Remote Speak.vbs" file and set it's batch variables to be the exact same names to refer to the individual computers, in VBScript variable format.
The error raises because you are not passing any argument to the vbs file, and it is not passed because when you generate computers.bat you are using %1 (the first argument to the :number subroutine) as a parameter, but in call :number there is not any parameter.
Also, the incrementing computer number is not shown in computers.bat because delayedexpansion is not active. When execution reaches a line or block (the code inside parenthesis), the parser replaces variable reads with the value in the variable and then starts to execute it. As the value of the variable changes inside the block, but there is no variable read, only the value of the variable before starting to execute, changes are not seen. You need to setlocal enabledelayedexpansion to enable it and, where needed, change %var% to !var! to indicate the parser that the variable read needs to be delayed, not replaced at initial parse time.
And anyway, your code does not use it. And what is if exist %%f? And why the loop?
For your third question, the Environment property of the WshShell objects lets you read the required variables
Dim env
Set oEnvironment = WScript.CreateObject("WScript.Shell").Environment("PROCESS")
WScript.Echo oEnvironment("Computer1")
This is a fast cleanup of your code. From your question it seems this is only the starting point. Adapt as needed.
RemoteSpeak.vbs
Option Explicit
If WScript.Arguments.Count < 1 Then
WScript.Quit
End If
'get ip
Dim IP
IP = WScript.Arguments.Item(0)
'get MSG
Dim MSG
MSG = InputBox("Type what you want the PC to say:", "Remote Voice Send By X BiLe", "")
If MSG = "" Then
WScript.Quit
End If
Dim A
A = "on error resume next" & VBCRLF & _
"CreateObject(""SAPI.SpVoice"").speak " & """" & MSG & """" & VBCRLF & _
"CreateObject(""Scripting.FileSystemObject"").DeleteFile(WScript.ScriptFullName)"
' Create the vbs on remote C$
CreateObject("Scripting.FileSystemObject").OpenTextFile("\\" & IP & "\C$\Voice1.vbs",2,True).Write A
' Run the VBS through Wscript on remote machine via WMI Object Win32_Process
Dim B
B=GetObject("winmgmts:\\" & IP & "\root\cimv2:Win32_Process").Create("C:\windows\system32\wscript.exe ""C:\Voice1.vbs""", null, null, intProcessID)
getComputers.bat
#echo off
setlocal enableextensions enabledelayedexpansion
cls
set "num=0"
( echo #echo off
for /f "tokens=* delims=\" %%a in ('net view ^| findstr /r /c:"^\\\\"') do (
set /a "num+=1"
echo set "Computer!num!=%%a"
echo cscript "RemoteSpeak.vbs" %%a
)
) > computers.bat
echo You have %num% computers in your network
pause > nul
start Computers.bat
endlocal
exit /b
Dim env
Set oEnvironment = WScript.CreateObject("WScript.Shell").Environment("PROCESS")
WScript.Echo oEnvironment("Computer1")

Resources