Slashes in windows registry key - windows

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

Related

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

How to start java program (from .jar) elevated only using VBScript

There is a great answer providing a batch file what will allways do it's best to run elevated and will not elevate if already elevated.
I don't want to distribute the batch file with my program though. The whole core of the answer is this VBSScript:
Set UAC = CreateObject("Shell.Application")
UAC.ShellExecute "[path to the batch file which will run elevated]", "ELEV", "", "runas", 1
Pretty simple. So just instead of the path to the batch file, I want to use the path to a jar file. But it doesn't seem to work:
Set UAC = CreateObject("Shell.Application")
UAC.ShellExecute "AutoClient.jar", "ELEV", "", "runas", 1
Set UAC = CreateObject("Shell.Application")
UAC.ShellExecute "javaw -jar AutoClient.jar", "ELEV", "", "runas", 1
Set UAC = CreateObject("Shell.Application")
UAC.ShellExecute "javaw", "ELEV", "-jar AutoClient.jar", "runas", 1
So well, how can I run the jar from the vbs file? Both files share the same directory. It's necessary that java application's working directory is that directory.
Edit:
So thanks #MCND (and this) I now know that the arguments go as follows:
path to executable to run
command line parameters sent to the program
working directory of the new process
'runas' command which invokes elevation
0 means do not show the window, 1 to show the window
And thanks to his code:
Set UAC = CreateObject("Shell.Application")
UAC.ShellExecute "javaw.exe", "-jar AutoClient.jar", "", "runas", 1
I can add another error in my collection:
The documentation states that the first parameter in the call is the file to start, leaving the arguments to the second parameter. So it should be (sorry, not tested)
Set UAC = CreateObject("Shell.Application")
UAC.ShellExecute "javaw.exe", "-jar AutoClient.jar", "", "runas", 1
So far, the only way I made this work without crazy popup errors is:
' Get the script location, the directorry where it's running
Set objShell = CreateObject("Wscript.Shell")
strPath = Wscript.ScriptFullName
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.GetFile(strPath)
strFolder = objFSO.GetParentFolderName(objFile)
' Args:
' path to executable to run
' command line parameters - first parameter of this file, which is the jar file name
' working directory (this doesn't work but I use it nevertheless)
' runas command which invokes elevation
' 0 means do not show the window. Normally, you show the window, but not this console window
' which just blinks and disappears anyway
UAC.ShellExecute "run-normally.bat", "SomeFile.jar, strFolder, "runas", 0
Because the working directory parameter doesn't work, I have following two lines in the bat file:
rem Used as a helper for the elevating VBS script. Runs the jar file
rem given as 1st argument as if the file was double clicked.
rem Make sure we're on our CURRENT directory
cd /d %~dp0
rem Run java, expecting the jar file to be given as the 1st argument
javaw -jar %1
I am not satisfied with this solution for cosmetic reasons. I want to display the UAC message for JRE, not windows command line:
I don't use Java but you aren't specifing full paths. You can't expect things to work reliably. Also whatever you are starting will need to have on it's right click menu Run As Administrator because the VBS code runs that menu command as if you clicked it. If it's not there you can't click it. EXE have it. So specify the correct paths to both Javaw and the jar file.
One issue is that the current directory is different depending on what technique you are using. ALWAYS specify full paths.
Here's a script that lists what verbs are available for an object (not we are not working with files but with objects). The graphical shell (explorer) is an object browser and has no idea what a file is apart from the fact it's an object of some type.
---------------------------
Windows Script Host
---------------------------
ShVerb
Lists or runs an explorer verb (right click menu) on a file or folder
ShVerb <filename> [verb]
Used without a verb it lists the verbs available for the file or folder
The program lists most verbs but only ones above the first separator
of the menu work when used this way
The Properties verb can be used. However the program has to keep running
to hold the properties dialog open. It keeps running by displaying
a message box.
---------------------------
OK
---------------------------
The script
HelpMsg = vbcrlf & " ShVerb" & vbcrlf & vbcrlf & " David Candy 2014" & vbcrlf & vbcrlf & " Lists or runs an explorer verb (right click menu) on a file or folder" & vbcrlf & vbcrlf & " ShVerb <filename> [verb]" & vbcrlf & vbcrlf & " Used without a verb it lists the verbs available for the file or folder" & vbcrlf & vbcrlf
HelpMsg = HelpMsg & " The program lists most verbs but only ones above the first separator" & vbcrlf & " of the menu work when used this way" & vbcrlf & vbcrlf
HelpMsg = HelpMsg & " The Properties verb can be used. However the program has to keep running" & vbcrlf & " to hold the properties dialog open. It keeps running by displaying" & vbcrlf & " a message box."
Set objShell = CreateObject("Shell.Application")
Set Ag = WScript.Arguments
set WshShell = WScript.CreateObject("WScript.Shell")
Set fso = CreateObject("Scripting.FileSystemObject")
If Ag.count = 0 then
wscript.echo " ShVerb - No file specified"
wscript.echo HelpMsg
wscript.quit
Else If Ag.count = 1 then
If LCase(Replace(Ag(0),"-", "/")) = "/h" or Replace(Ag(0),"-", "/") = "/?" then
wscript.echo HelpMsg
wscript.quit
End If
ElseIf Ag.count > 2 then
wscript.echo vbcrlf & " ShVerb - To many parameters" & vbcrlf & " Use quotes around filenames and verbs containing spaces" & vbcrlf
wscript.echo HelpMsg
wscript.quit
End If
If fso.DriveExists(Ag(0)) = True then
Set objFolder = objShell.Namespace(fso.GetFileName(Ag(0)))
' Set objFolderItem = objFolder.ParseName(fso.GetFileName(Ag(0)))
Set objFolderItem = objFolder.self
msgbox ag(0)
ElseIf fso.FolderExists(Ag(0)) = True then
Set objFolder = objShell.Namespace(fso.GetParentFolderName(Ag(0)))
Set objFolderItem = objFolder.ParseName(fso.GetFileName(Ag(0)))
ElseIf fso.fileExists(Ag(0)) = True then
Set objFolder = objShell.Namespace(fso.GetParentFolderName(Ag(0)))
Set objFolderItem = objFolder.ParseName(fso.GetFileName(Ag(0)))
Else
wscript.echo " ShVerb - " & Ag(0) & " not found"
wscript.echo HelpMsg
wscript.quit
End If
Set objVerbs = objFolderItem.Verbs
'If only one argument list verbs for that item
If Ag.count = 1 then
For Each cmd in objFolderItem.Verbs
If len(cmd) <> 0 then CmdList = CmdList & vbcrlf & replace(cmd.name, "&", "")
Next
wscript.echo mid(CmdList, 2)
'If two arguments do verbs for that item
ElseIf Ag.count = 2 then
For Each cmd in objFolderItem.Verbs
If lcase(replace(cmd, "&", "")) = LCase(Ag(1)) then
wscript.echo(Cmd.doit)
Exit For
End If
Next
'Properties is special cased. Script has to stay running for Properties dialog to show.
If Lcase(Ag(1)) = "properties" then
WSHShell.AppActivate(ObjFolderItem.Name & " Properties")
msgbox "This message box has to stay open to keep the " & ObjFolderItem.Name & " Properties dialog open."
End If
End If
End If

invalid Directory name used in property "CurrentDirectory" vbscript

I'm trying to compile au3 script through vbscript which located in another directory, so I used "CurrentDirectory" property to change the working directory from script directory to au3 file directory using this code
drivepath = "K"
strTempTarget = "New Folder"
filename = "gate.jpg"
IconName = "102.ico"
Comm = "cmd /c " & "Aut2Exe.exe /in " & filename & ".au3" & " /out " & filename & ".exe" & " /icon " & IconName
Path = """" & drivepath & "\" & strTempTarget & """"
MsgBox(Path)
Set objShell = WScript.CreateObject("WScript.Shell")
objShell.CurrentDirectory = Path
objShell.Run(Comm), 0, True
But I got an error "invalid file name or directory name"
since there is an empty space in "strTempTarget" value I should put a double quotes at the start and at the end of directory name "Path" I even tried to use ASCII : something like
Path = Chr(34) & drivepath & "\" & strTempTarget & Chr(34)
but the same error keep raising
So how to make this script work fine ?
The shell needs quoted pathes, because it uses space as separator; .CurrentDirectory 'knows' the whole string (included any spaces) is meant to be a folder path; so don't quote the string for .CurrentDirectory.
Evidence:
>> Set objShell = WScript.CreateObject("WScript.Shell")
>> Path = """C:\Documents and Settings"""
>> objShell.CurrentDirectory = Path
>>
Error Number: -2147024773
Error Description:
>> Path = "C:\Documents and Settings"
>> objShell.CurrentDirectory = Path
>>
>> <-- no news are good news

changing owner of subfolders using icacls in a vbscript

I have a network with over 700 users and I want to create a script that could change the owner of the home folders to domain admins and the sub-folders to the users themselves.
This is what I could create with the help of my colleges, but this doesn't work for some reason. Can anyone help me please. Thanks.
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.OpenTextFile("G:\Userhome\userdirlist.txt", 1)
Set oShell = WScript.CreateObject("WSCript.shell")
Do Until objFile.AtEndOfStream
struserfolder = objFile.ReadLine
oshell.run ("icacls G:\userhome\"+ struserfolder +"\*.* /setowner domainname\" + "struserfolder" + " /t")
oshell.run ("icacls G:\userhome\"+ struserfolder +"\*.* /setowner domainname\Domain Admins")
Loop
You use the string "struserfolder" when you probably mean to use the variable struserfolder. Change this:
oshell.run ("icacls G:\userhome\"+ struserfolder +"\*.* /setowner domainname\" _
+ "struserfolder" + " /t")
into this:
oshell.run "icacls G:\userhome\"+ struserfolder +"\*.* /setowner domainname\" _
+ struserfolder + " /t"
Also, you must quote arguments with spaces. Lack of quotes is probably what prevents the second command from working, because icacls tries to set the owner to domainname\Domain instead of domainname\Domain Admins. This should do:
oshell.run "icacls G:\userhome\" + struserfolder _
+ "\*.* /setowner ""domainname\Domain Admins"""
BTW, why are you trying to change the owner twice? Any object can have just one owner, and you don't gain anything if you make the domain admins group the owner of just the top-level objects in the folder.
If you want to give domain admins access to the users' home directories, change the owner to the local administrators group (domain admins are automatically members of that group) and grant full control on the folder to Administrators, SYSTEM and the user. Then propagate the changed permissions down the directory tree:
path = Chr(34) & "G:\userhome\" & struserfolder & Chr(34)
oshell.run "icacls " & path & " /setowner Administrators /t /c"
oshell.run "icacls " & path & " /grant Administrators:(OI)(CI)F " _
& "SYSTEM:(OI)(CI)F domainname\" & struserfolder & ":(OI)(CI)F"
oshell.run "icacls " & path & " /reset /t /c"
Edit: The Run method returns the exit status of the executed command, which may give you some pointers when things don't work as expected:
rc = oshell.run("icacls " & path & " /setowner Administrators /t /c", 0, True)
WScript.Echo "icacls returned with exit code " & rc & "."
One issue might be that by default Run is asynchronous (parameter bWaitOnReturn defaults to False), i.e. the call returns immediately while the command (icacls) is still running in the background. This may lead to situations where subsequent commands try to change permissions on objects where ownership hasn't been taken yet.
Even more helpful than the return code is ususally the output of the command. However, the way you execute the commands, the command window isn't displayed, and even if it were, it would automatically close as soon as the command finishes. You can force the command window to become visible and stay open after the command finishes, though.
oshell.run "%COMSPEC% /k icacls " & path & " /setowner Administrators /t /c" _
, 1, True
Of course you don't normally want this in production, but it's quite useful when debugging a script.
Another option would be to avoid Run entirely and run the commands via the Exec method. That way you have access to the StdOut and StdErr of the created process:
Set icacls = oshell.Exec("icacls " & path & " /setowner Administrators /t /c")
Do While icacls.Status = 0
WScript.Sleep 100
Loop
WScript.Echo "icacls returned with exit code " & icacls.ExitCode & "."
WScript.Echo icacls.StdOut.ReadAll & icacls.StdErr.ReadAll

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