WScript.Shell seems to be ignoring escaped quotes [duplicate] - vbscript

This question already has an answer here:
Filename string space issue in VBScript
(1 answer)
Closed 5 years ago.
In the following script:
Set WshShell = WScript.CreateObject("WScript.Shell")
WshShell.Run "%comspec% /k" & _
" ""C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\TF.exe"" " & _
"move ""C:\Automation\Custom_UiPath_Activities\NuPackages\*.nupkg"" ""C:\Automation\Custom_UiPath_Activities\NuPackages\Old""", 1, True
it gives the error
'C:\Program' is not recognized as an internal or external command.
Seemingly because the escaped quotes around the first argument is ignored.
I've tried logging the string to a text file, and when copying the outputted string into CMD it works as intended.
I cannot see what I have done wrong.

If you want to daisy-chain commands in CMD you need to put an ampersand (&) between them as part of the commandline. Your code is using the ampersand just as the VBScript string concatenation operator. Also, for running multiple commands via cmd /k (or cmd /c) you need to put an additional set of double quotes around them. Also, using variables and a quoting function helps with keeping your code readable.
Function qq(s) : qq = """" & s & """" : End Function
tf = "C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\TF.exe"
src = "C:\Automation\Custom_UiPath_Activities\NuPackages"
dst = "C:\Automation\Custom_UiPath_Activities\NuPackages\Old"
Set WshShell = CreateObject("WScript.Shell")
WshShell.Run "%comspec% /k """ & qq(tf) & " & " & _
"move " & qq(src & "\*.nupkg") & " " & qq(dst) & """", 1, True

Related

How do I use 7-zip command line in vb script to delete file from zip folder?

I have this vb script:
Dim Fso
Set Fso = WScript.CreateObject("Scripting.FileSystemObject")
set WshShell = WScript.CreateObject("WScript.Shell")
'Run the 7-zip command line instruction via thw WshShell to delete files in Tableau Export Packaged Workbook
desfile = "C:\Tableau_Dashboards\Partner_Life_Cycle\ALL_PARTNERS\twbx\Partner_Life_Cycle_ALL_PARTNERS.zip"
srfile = "C:\Tableau_Dashboards\Partner_Life_Cycle\ALL_PARTNERS\twbx\Data"
strCommand = "C:\Program Files\7-Zip\7z.exe d -tzip & desfile & srfile & "
' Run 7-Zip in shell
WshShell.Run strCommand,0,true
WScript.Sleep 5000
I get the error "Line 15: The system cannot find the file specified"
Line 15 is the WshShell.Run strCommand,0,true part.
How can I fix this?
Thanks
Rick
In your code, the concatenation operator & will be treated as a part of the string since you are not closing the previous string with a quote.
It should be:
strCommand = "C:\Program Files\7-Zip\7z.exe d -tzip" & " " & desfile & " " & srfile
(With space added between the paths.)
As the path to the exe contains space (Program Files), it will have to be enclosed in quotes as: "C:\Program Files\7-Zip\7z.exe"
To get a quote within a string in vbscript, the quote has to be doubled .
strCommand = """C:\Program Files\7-Zip\7z.exe"" d -tzip" & " " & desfile & " " & srfile

Slashes in windows registry key

I'm trying to set full app path of test.exe in registry as name. But it gives me wrong result.
Expected Output :
Output :
This is the code I'm using
Dim WshShell, bKey
Set WshShell = WScript.CreateObject("WScript.Shell")
WshShell.RegWrite "HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers\D:\\\Program Files\\\test.exe", "RUNASADMIN", "REG_SZ"
Is there any workaround for this?
This MSDN KB article says:
Due to the limitations of the RegWrite method of Windows Script Host (WSH) it is not possible to write a "\" (backslash) in a key name or value name.
This is by design and there is no workaround with WSH. The article goes on to suggest using alternative scripting objects (WMI, RegObj.dll) to set such key and value names.
Still using vbscript, try to create a .reg file and execute it.
Some code that does it in another path of the registry:
Set fs = CreateObject("Scripting.FileSystemObject")
Set shell = CreateObject("WScript.Shell")
'create .reg file:
Set reg_file = fs.CreateTextFile("slash.reg")
reg_file.WriteLine "Windows Registry Editor Version 5.00"
reg_file.WriteLine "[HKEY_CLASSES_ROOT\.txt]" 'put your path here
key_name = "D:\\Program Files\\test.exe" 'must be escaped inside the .reg file, so they enter as single slash in the registry
key_value = "RUNASADMIN"
reg_file.WriteLine """" & key_name & """=""" & key_value & """" 'escaping quotes inside vbscript string literal
reg_file.Close
'run it automatically to insert data (may ask for elevated privileges):
path = Replace(WScript.ScriptFullName, WScript.ScriptName, "")
shell.run "regedit.exe /s """ & path & "slash.reg"""
Just click OK when asked for elevation. You may want to check the created file, so I am not deleting it in my code.
Another approach is to use WMI Registry provider
Const REG_HIVE_HKLM = &H80000002
Const ROOT = "Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers"
Set SWBemlocator = CreateObject("WbemScripting.SWbemLocator")
Set SWbemServicesReg = SWBemlocator.ConnectServer(".", "root\DEFAULT","","")
Set reg = SWbemServicesReg.Get("StdRegProv")
' if key is missing - create first, otherwise value won't be saved (without exception)
reg.CreateKey REG_HIVE_HKLM, ROOT
' set value
reg.SetStringValue REG_HIVE_HKLM, ROOT, "D:\Program Files\test.exe", "RUNASADMIN"
Try using slash (/) as your file system path separator. WSH will correctly write A *nix style path to a registry value while a Windows style path will write as a sequence of sub keys. However this depends on the software that is reading the registry value to grok the path correctly. Many components of Windows will now accept either path separator. Give it a try.
You can use .ShellExecute to edit the registry with reg.exe.
ShellExecute guide
Syntax:
CreateObject("Shell.Application").ShellExecute "application", "parameters", "dir", "verb", window
CreateObject("Shell.Application").ShellExecute 'some program.exe', '"some parameters with spaces"', , "runas", 1
Key:
Keyword
Action
application
The file to execute (required)
parameters
Arguments for the executable
dir
Working directory
verb
The operation to execute (runas/open/edit/print)
window
(1=normal, 0=hide, 2=Min, 3=max, 4=restore, 5=current, 7=min/inactive, 10=default) View mode application window
Example:
CreateObject("Shell.Application").ShellExecute "reg.exe", "add " & """HKCU\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers""" & " /v " & """" & Command & """" & " /t REG_SZ /d " & """~ DISABLEDXMAXIMIZEDWINDOWEDMODE RUNASADMIN HIGHDPIAWARE""" & " /f ", , , 0
Where the Command is a path with a backslash to a .exe (like D:\Path with backslash\some program.exe) that passed to your application as command line parameters (like start "" "C:\Path\your application.exe" "D:\Path with backslash\some program.exe".
I used MsgBox to ensure that is correct:
MsgBox "add " & """HKCU\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers""" & " /v " & """" & Command & """" & " /t REG_SZ /d " & """~ DISABLEDXMAXIMIZEDWINDOWEDMODE RUNASADMIN HIGHDPIAWARE""" & " /f "
You can also use CreateObject("WScript.Shell").Run as an alternative to run reg.exe and edit the registry.
Example:
CreateObject("WScript.Shell").Run "reg.exe" & " delete " & """HKCU\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers""" & " /v " & """" & Command & """" & " /f ", 0

Escaping spaces in folder path

I have a backup script the copies from one server to another via scheduled task. Most of the folders copy ok. However, there is one folder that has a space in the name and it blows the whole thing up.
This runs on the destination server (pulls data in).
I've tried various escape patterns, and they all fail.
(vars are dimmed, code truncated)
sArchiveFolder = "D:\Backup\" & year(now) & "-" & month(now) & "-" & day(now) & "\"
sDataFolder = "\\Server\Share\System Library"
sDestFolder = sArchiveFolder & "System Library\"
Call subCopyFolder(fso, objShell, sDataFolder, sDestFolder)
sub subCopyFolder(fso, objShell, sDataFolder, sArchiveFolder)
dim iCounter, excludedDirs
if not(fso.folderexists(sArchiveFolder)) then
fso.createfolder(sArchiveFolder)
excludedDirs = " /XD Logs"
if(right(sDataFolder,7)="Library") then
'this fails
'sDataFolder = """"&sDataFolder&""""
'sArchiveFolder = """"&sArchiveFolder&""""
'so does this
'sDataFolder = chr(34)&sDataFolder&chr(34)
'sArchiveFolder = chr(34)&sArchiveFolder&chr(34)
end if
Dim sRoboCopyCommand
sRoboCopyCommand = "robocopy " & sDataFolder & " " & sArchiveFolder & " /E "& excludedDirs &" /R:5 /W:1 /log+:log.txt"
objShell.Run (sRoboCopyCommand)
end sub
How do I properly escape this? I also tried putting the literal quotes in the robocopy command line itself and that broke the folders that don't need the quotes too.
As noted in the code, I tried the "4 quotes method" and it does not work within the robocopy command line.
with 4 quotes method:
(stripped out private stuff not relevant to issue, ie full paths and other eXcludeD fodlers)
For posteriority: apparently trailing backslashes in source or destination path mess up robocopy's parameter handling, so the paths need to be specified without them:
sArchiveFolder = "D:\Backup\" & year(now) & "-" & month(now) & "-" & day(now)
sDataFolder = "\\Server\Share\System Library"
sDestFolder = sArchiveFolder & "\System Library"
...
sRoboCopyCommand = "robocopy """ & sDataFolder & """ """ & sArchiveFolder & _
""" /E " & excludedDirs & " /R:5 /W:1 /log+:log.txt"
objShell.Run sRoboCopyCommand

Passing Caret to command line using VBScript

Having a hard time figuring this one out. I have a vbscript that asks for username and password. Then the script runs PSExec.exe passing those to the command line like this.
strUser = Inputbox("Username:","Username")
strPassword = Inputbox("Password:","Password")
Set objShell = WScript.CreateObject("WScript.Shell")
objShell.Run "%comspec% /K psexec.exe \\workstation -u " & struser _
& " -p " & strPassword & " -d calc.exe", 1, false
This works fine if the password doesn't have a caret in it. BUT if it does have one, for example if the password is "Pass)(*&^%$##!" I get the following error from psexec.
'%$##!' is not recognized as an internal or external command,
operable program or batch file.
The caret is being read by the command line as a space so it thinks it's trying to run this command.
psexec.exe \\workstation64 -u User -p Pass)(*& %$##! -d Calc.exe
As you can see there is a space instead of a caret so psexec see's %$##! as the command.
I've seen an example for passing it when using a batch file but it doesn't work in this case. It said adding an extra ^ like this ^^ works in a bat file.
How can I pass a caret to the command line????
UPDATE......
I worked on this for about 45 minutes today at work and couldn't get it to work. First thing I tried was to add quotes to the password and it still didn't work. I just tested it here at the house and it worked fine....... OS at work is Windows XP and at home I run Windows 7. I will try again in the morning to make sure I didn't mistype something. Here is what I did to make it work at home on Windows 7.
strUser = Inputbox("Username:","Username")
strPassword = Inputbox("Password:","Password")
strPassword = chr(34) & strPassword & chr(34)
Set objShell = WScript.CreateObject("WScript.Shell")
objShell.Run "%comspec% /K psexec.exe \\workstation -u " & struser _
& " -p " & strPassword & " -d calc.exe", 1, false
The problem lays in using of ampersand, not caret: single ampersand is used as a command separator, so rest of the line after &-sign considered to be a next command by cmd interpreter.
In next example I have used SET command instead of PSExec, as I will not experiment with PSExec.
All goes well with SET command, even if escaped all characters:), but I'm not sure about percentage sign, which is said "must be doubled to use literally".
Dim strPssw: strPssw = "/Pass"")=(*&^%$##!"
Dim ii, strChar, strEscape
Dim strPassword: strPassword = ""
For ii = 1 To Len( strPssw) 'cannot use Replace() function
strChar = Mid( strPssw, ii, 1)
Select Case strChar
Case "&", """", "^", "%", "=", _
"#", "(", ")", "!", "*", "?", _
".", "\", "|", ">", "<", "/"
strEscape = "^"
Case Else
strEscape = "" 'all goes well even if strEscape = "^" here
End Select
strPassword = strPassword & strEscape & strChar
Next
Dim objShell: Set objShell = WScript.CreateObject("WScript.Shell")
objShell.Run "%comspec% /C set varia=" & strPassword & "&set varia&pause&set varia=", 1, false
' # - At Symbol: be less verbose
' & - Single Ampersand: used as a command separator
' ^ - Caret: general escape character in batch
' " - Double Quote: surrounding a string in double quotes escapes all of the characters contained within it
' () - Parentheses: used to make "code blocks" of grouped commands
' % - Percentage Sign: are used to mark some variables, must be doubled to use literally
' ! - Exclamation Mark: to mark delayed expansion environment variables !variable!
' * - Asterisk: wildcard matches any number or any characters
' ? - Question Mark: matches any single character
' . - Single dot: represents the current directory
' \ - Backslash: represent the root directory of a drive dir ^\
' | - Single Pipe: redirects the std.output of one command into the std.input of another
' > - Single Greater Than: redirects output to either a file or file like device
' < - Less Than: redirect the contents of a file to the std.input of a command
''
' && - Double Ampersand: conditional command separator (if errorlevel 0)
' .. - Double dot: represents the parent directory of the current directory
' || - Double Pipe: conditional command separator (if errorlevel > 0)
' :: - Double Colon: alternative to "rem" for comments outside of code blocks
' >> - Double Greater than: output will be added to the very end of the file
' thanks to http://judago.webs.com/batchoperators.htm
'

Psexec not outputting to log file in VB script

I have a VB script which needs to run psexec to launch an app called md5 on a remote server. Md5 generates a hash key of a file and takes one parameter - the file path\name. I need to retrieve the has key that is generated to store in a variable. Below is the code I am using:
Set objShell = CreateObject("Wscript.Shell")
strcomputer = "remotecomputer"
tempDest = "C:\somedir"
filename = "somefile"
strCommand = "psexec -accepteula \\" & strcomputer & " -c md5.exe " & tempDest & "\" & filename & " > log.txt"
Set objExecObject = objShell.Exec("%comspec% /c " & strCommand)
Do While objExecObject.Status <> 1 'loop until previous process has finished
WScript.Sleep 100
Loop
The MD5 command is run however nothing is written to the log file. When I copy and paste strCommand (substituting all the variables for the actual data) into a cmd prompt and run it, it successfully writes the output of Md5 to the log file.
At the end of the day I just need the output of Md5, if anyone knows a better way than writing it to a log file please let me know. I have already tried using objExecObject.StdOut.Readall() to try and catch the output which resulted in random failures - sometimes it would catch the output, sometimes it wouldn't, without changing anything in the script.
Just a guess: Are you sure about what the current directory is when the script is running? Try giving an absolute path to the log file and see if it helps.
I found a solution for this. Instead of using the following code:
strCommand = "psexec -accepteula \\" & strcomputer & " -c md5.exe " & tempDest & "\" & filename & " > log.txt"
Set objExecObject = objShell.Exec("%comspec% /c " & strCommand)
Do While objExecObject.Status <> 1 'loop until previous process has finished
WScript.Sleep 100
Loop
I used this instead:
strCommand = "psexec -accepteula \\" & strcomputer & " -c md5.exe " & tempDest & "\" & filename & " > log.txt"
objShell.Run "%comspec% /c " & strCommand, 0, true
The script is now redirecting to log.txt properly.

Resources