REG ADD syntax issue - batch-file

I'm trying to make a batch file that creates a entry in the registry.
The entry must be link to a executable. It needs two parameters :
(path) The folder to process (see below project1)
(path) The folder that will contain the file returned by the process. I want this to be the parent folder of the first parameter (see below DirectoryProject)
Tree :
../somewhere/my/program/program.exe
../DirectoryProject
../DirectoryProject/project1
../DirectoryProject/output.data
Exemple :
"../somewhere/my/program/program.exe" "../DirectoryProject/project1" "../DirectoryProject"
The first parameter is easy, it is %%1. It has the folder's path I right clicked as value. The last parameter is however harder to get.
I first tried to manipulate the variable %%1.
reg add "%RootKey%\Software\Classes\Directory\shell\%KeyName%\command" /VE /D "cmd /c cd \"%%1\" & \"%Exec%\" \"%%1\" \"%%~dp1\"" /F
The program logs the parameters it reveice. The last parameter is equal to %%~dp1 so it does not work.
Then I tried a tricky way using the first parameter and the CD command
reg add "%RootKey%\Software\Classes\Directory\shell\%KeyName%\command" /VE /D "cmd /c cd \"%%1\" & \"%Exec%\" \"%%1\" \"%CD%\"" /F
In this case %CD% will always be the path of the batch file so clearly not what I want nether
I'm still looking
Thanks for your interest and help

If the value of %1 is a fully qualified and existing path then the root folder would generally be the drive letter followed by a backslash, normally denoted by %~d1\. However, given your latest clarification, it appears your looking for the current working directory, commonly denoted as %CD%.
I'm assuming that you wanted to manipulate the second instance of %1, so based on my assessment, here's how I'd do it:
#Echo Off
Set "ExePath=C:\SomePathTo\MadeUp.exe"
Set "MenuTxt=Process with MadeUp"
Set "KeyName=LaunchTest"
Set "RootKey=HKCU"
Reg Add "%RootKey%\Software\Classes\Directory\shell\%KeyName%" /VE /D "%MenuTxt%" /F >Nul
Reg Add "%RootKey%\Software\Classes\Directory\shell\%KeyName%\command" /VE /D "\"%ExePath%\" \"%%~1\" \"%CD%\"" /F >Nul
Please make sure that you modify your specific executable path on line 2 as required.
Note that the text description you want in the context menu, currently Process with MadeUp can be changed to suit your preference, you can do that on line 3.
I have left your registry key name as you had it, LaunchTest, this can be changed in line 4, (when it's no longer a test).
A user menu entry should be entered into the HKCU key, so I'm using that.(If you want it for all users then change HKCU to HKLM on line 5. Whilst it does not match your provided key, it is the correct way to do it. Entries from both HKCU\Software\Classes and HKLM\SOFTWARE\Classes are auto propagated to HKCR, you shouldn't add things directly to it.If you change it to HKLM be aware that there's a likelihood the script will need to be run As administrator)
If you had wanted the root directory of the right clicked folder then you'd change \"%CD%\" to \"%%~d1\\\" on line 7.

Related

Copy File's Parent directory path from context menu

I am learning batch scripting since it's very useful for setting some quick custom context menu options of Windows user's choice to get file and it's parent directory's path.
Now I know following command to get the passed argument as file path and copy it to clipboard:
cmd /c (echo.|set /p=""%1"") | clip
But then why isn't following syntax working as expected when set in Context menu ?
cmd /c (echo.|set /p=""%~dp1"") | clip
Is it a variable expansion issue ? Please guide as to why it isn't working and how to resolve it so that it expands properly.
Sample of registry entry wherein I am permanently setting the command to be run, with switches, variable expansions etc.
Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\Software\Classes\*\shell\Copy File's Parent Path]
#="Copy File's Parent Path"
[HKEY_CURRENT_USER\Software\Classes\*\shell\Copy File's Parent Path\Command]
#="cmd.exe /c (echo.|set /p=\"\"%~dp1\"\") | clip"
Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\Software\Classes\*\shell\Copy Files Path\command]
#="cmd /c (echo. | set /p =\"\"%1\"\") | clip"
[HKEY_CURRENT_USER\Software\Classes\*\shell\Copy Files Parent Path\command]
#="cmd /c (echo. | set /p =\"\"%w\"\") | clip"
Replace %1 with %w. 2 registry entries to demonstrate
%1 as Copy Files Path and %w as Copy Files Parent Path.
Reference from Extending Shortcut Menus at the bottom of the page.
%0 or %1 the first file parameter. For example “C:\Users\Eric\Desktop\New Text Document.txt”. Generally this should be in quotes and the applications command line parsing should accept quotes to disambiguate files with spaces in the name and different command line parameters (this is a security best practice and I believe mentioned in MSDN).
%N (where N is 2 - 9), replace with the nth parameter
%* replace with all parameters
%~ replace with all parameters starting with and following the second parameter
%d desktop absolute parsing name of the first parameter (for items that don’t have file system paths)
%h hotkey value
%i IDList stored in a shared memory handle is passed here.
%l long file name form of the first parameter. Note win32 applications will be passed the long file name, win16 applications get the short file name. Specifying %L is preferred as it avoids the need to probe for the application type.
%s show command
%v for verbs that are none implies all, if there is no parameter passed this is the working directory
%w the working directory
Variables like %1, %*, %V in registry, are placeholders which will be resolve and replaced by Windows Shell component (Win32 Shell). They just happened to be similar to the variables that is used by Windows Command Processor(CMD.EXE) at Command Prompt or in batch files, But they are in no way related to each other.
For instance with CMD.EXE %1 can only be used within batch files it has no meaning at Command Prompt or when passed as a command by /C or /K switch. In your registry sample %1 will be resolved by Windows Shell not by CMD.EXE so you can not use things like %~dp0 or %~dp1 in registry, They have no meaning to Windows Shell.
So you have to take %1 by CMD.EXE (which have been automatically replaced by its actual value) and do processing with it in a FOR loop to obtain the directory path of the file.
This is the actual command that will extract path information from file name:
cmd.exe /e:on /d /s /c "for %%a in ("%1") do #(set /p "=%%~dpa")<nul | clip"
It can be entered as is, in Registry Editor to the (default) value of the appropriate Key e.g: HKEY_CURRENT_USER\Software\Classes\*\shell\Copy Path to clipboard\Command for current user or HKEY_CLASSES_ROOT\*\shell\Copy Path to clipboard\Command for all users.
And the string for registry script:
#="cmd.exe /e:on /d /s /c \"for %%a in (\"%1\") do #(set /p \"=%%~dpa\")<nul | clip\""
A sample .REG script will look like this:
Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\Software\Classes\*\shell\Copy Path to clipboard\Command]
#="cmd.exe /e:on /d /s /c \"for %%a in (\"%1\") do #(set /p \"=%%~dpa\")<nul | clip\""
When you want to pass a string that contains percents(%) you have to escape the percents by doubling them, pretty much the same as you do in batch files.
%W, which generally holds the working directory, when you right click on a file, would be the files' parent.
You could therefore try this:
Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\Software\Classes\*\shell\HoldParent]
#="Parent to Clipboard"
[HKEY_CURRENT_USER\Software\Classes\*\shell\HoldParent\command]
#="Cmd /C \"Echo %W|Clip\""
You could extend this a little for potential unicode/character issues, but in general it should perfom as required without.
Edit
To extend it a little, (including no newline), perhaps:
Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\Software\Classes\*\shell\HoldParent]
#="Parent to Clipboard"
[HKEY_CURRENT_USER\Software\Classes\*\shell\HoldParent\command]
#="Cmd /Q /D /U /C \"Set/P \"=%W\"<Nul|Clip\""

Creating Registry Using Batch Files

I am working on creating a batch file that adds will create registry entries in order to add custom commands into the UI of our file management software.
The issue is that the location of the key varies based on the version of the software a user is on.
Is it possible to create a patch file that will search within registry keys/sub keys and create new values there?
Here is an example of the registry location, the portion surrounded by ** will change based on version:
[HKEY_CURRENT_USER\Software\Motive\M-Files\**12.0.6550.8**\Client\MFShell\Rombald\TasksBar\ShellCommands\1]
"Name"="Calendar"
"Executable"="\\\\mfiles-server\\M-Files setup\\M-Files
Calendar\\MFCalendar_v1.2.6\\MFCalendar_v1.2.6\\M-Files Calendar.exe"
"Icon"="\\\\mfiles-server\\M-Files setup\\M-Files
Calendar\\MFCalendar_v1.2.6\\MFCalendar_v1.2.6\\M-Files Calendar.exe,0"
"Arguments"="{B1438CAB-2E53-474E-AA82-3D48F787F6B7}"
Essentially I would have to look for the version of the software and insert that into the key. If more than one exists it would be the largest value.
Thanks in advance for the help!
#echo off
setlocal
for /f "delims=" %%A in (
'reg query HKCU\SOFTWARE\Motive\M-Files'
) do set "root=%%~A" & set "version=%%~nxA"
echo root: %root%
echo version: %version%
if defined root (
echo Write new reg information.
reg add "%root%\testkey" /v testvalue /d data /f
reg add "%root%\testkey" /v testversion /d "%version%" /f
)
The for loop uses the command reg query to search through
the entries in the registry key. The last entry is saved as
root and version. The variable root will have the full key path
while the variable version will be the last segment of the path
which will be just the key name. These are echoed to console.
If defined root, subkey testkey will be added with values and
data as the code shows.
So long as you only have version keys under the key of M-Files
then this may be all you may need. If not, then you may need more
code to skip the other keys.

Renaming multiple files in a for loop with user input Windows batchfile

I want to create a program that can loop through multiple pdf files and have the user rename each file a unique name like so:
234324.pdf to Batch150.pdf
32154687.pdf to AdvancedPayment.pdf
and so on...
Here is my code:
setlocal EnableDelayedExpansion
echo rename pdf files
FOR %%F IN (*.pdf) DO (
set /p x=Enter:
move %%F !x!
)
endlocal
This seems to work for the first file and then when I try to rename the second one it says: The syntax of the command is incorrect..
I have tried using the rename command and haven't had much luck with it.
FOR %%F IN (*.pdf) DO (
SET "x=%%F"
set /p "x=%%F Enter: "
IF /i "!x!.pdf" neq "%%F" ren "%%F" "!x!.pdf"
)
Your code worked fine for me. Since you don't indicate what the "to" and "from" names you used were, we're reduced to guessing.
I developed the above code to perform the rename in the manner you originated. Note that it works as I expect. Using ren the "to" filename must be a filename within the directory where the "from" file resides [ie. it simply renames the file]. If you use "move" then the file can be moved to another directory if you specify that in the "to" name.
The first fix is purely cosmetic. By enclosing the variablename and prompt in the set /p in quotes, you can include a terminal space in the prompt (which I prefer), and including the %%F in the prompt shows you which file is about to be renamed.
The next fix is to quote the arguments to the ren or move. This ensures the syntax remains properly constructed in the case of eithr "to" or "from" name containing a space.
The next is to initialise x with the "from" filename. It's enclosed in quotes so any invisible trailing spaces are not included in the value assigned to x. Note that set /p does not alter the variable if Enter alone is keyed, so setting x ensures that if a file is not to be renamed, all you need do is press Enter
The next is to detect whether the "to" and "from" names are equal. ren will generate an error report if you attempt to rename a file to itself; equally, you can't move a file to itself. Hence, /i=ignore case, and only attempt the operation if the names are different.
Finally, add the .pdf to each usage of !x! in order that you don't need to key it in. Naturally, you could omit this change if you want to alter extensions or you could put .pdf into another variable and use that variable in place of the constant .pdf so that the extension being selected can be easily varied by being changed in one plaace rather than using a mass-edit. You could even use a set /p to assign the extension being processed dynamically at the start of the routine.
Note that if you rename say one.pdf to yellow.pdf then this construct is very likely to propose yellow.pdf for a rename later on. This is because the next-filename logic locates the next filename currently in the directory,then processes the loop, then locates the next filename currently in the directory, and so on.
You would need
For /f "delims=" %%F in ('dir /b/a-d "*.pdf" ') do (
to ensure that each filename is only presented once. This mechanism performs a directory scan of filenames-only in basic form, and stores the list in memory, then processes the list item-by-item and since that list is created and then processed, any subsequent alterations to the directory do not affect the list.

batch command copy or move a folder to parent folder as many level/s specified

My new question is related to my old question i had posted.
I had posted this question
7zip command to extract a folder with path intact to specific folder but excluding parent source path.
i get "i:\delete\rising\dawn\folder2"
Thus a new question aroused.
i want to copy/move the folder "folder2" to the parent folder 2 level (it means two times to parent folder)
i:\delete\folder2
OR in cases 3 level up.
i:\folder2
i.e. "folder2" shall be copied/moved to upper level (parent folder) the number of times i specify
Thank you
The Batch file below move the folder specified in the first parameter as many levels up as the number specified in second parameter:
#echo off
setlocal EnableDelayedExpansion
for %%a in ("%~1") do set "newPath=%%~DPa" & set "folder=%%~Na"
for /L %%i in (1,1,%2) do for %%a in ("!newPath:~0,-1!") do set "newPath=%%~DPa"
ECHO move "%~1" "%newPath%%folder%"
For example, if previous Batch file is named MoveUp.bat:
MoveUp "i:\delete\rising\dawn\folder2" 2
If the move command shown is correct, delete the ECHO part in order to execute the command.
EDIT: Reply to the comment
Output example:
C:\> MoveUp "i:\delete\rising\dawn\folder2" 2
move "i:\delete\rising\dawn\folder2" "i:\delete\folder2"
C:\> MoveUp "i:\delete\rising\dawn\folder2" 3
move "i:\delete\rising\dawn\folder2" "i:\folder2"
Run the program in the same way of the examples above and confirm that you get the same output.
If you get a different output, please post it besides your Windows version.
If you get the same output, please explain why this output does not solve your problem and specify what should be the desired output.
Remember that the program just DISPLAY the command! It does NOT execute it. If you want the program to execute the move command, you must delete the ECHO part from the last line this way:
move "%~1" "%newPath%%folder%"

DOS- keeping portion of directory structure during xcopy?

I am a bit new to DOS batch files, and I am having a hard time wrapping my head around ways to solve my problem.
What I need to do: I have a large, nested source folder structure, let's say it lives here:
C:\dir1\dir2\dir3\file.txt
And I have a mirrored destination structure, although a portion of the root is different:
x:\dirA\dirB\dir1\dir2\dir3\file.txt
My current batch copies all files in the source structure to a destination folder, keeping the folder structure, which is what I want.
The problem:
The intention of my script is to drag a folder from the source structure above onto the bat file, and have it copy the files to the destination. What I want to do, is to allow the user to drag a folder from source dir, let's say /dir2 and all of its subfolders/files onto the batch file, and have it copy the contents over to the SAME spot in the destination structure...
So in this example, the batch file should copy everything in and below:
C:\dir1\dir2\
into
x:\dirA\dirB\dir1\dir2\.
Fortunately (I think) my destination folder structure won't be changing, although the source might be in a different location on each machine. So, if there is a clever way to detect where in the source tree I am, and then replace a portion of the destination path... ???
Here's my simple script so far:
#echo off
set /p FILETYPE="What file type do you want to copy? (For example use txt, max, f3d, or * to copy all files.)"
xcopy %1\*.%FILETYPE% c:\output /s
pause
Thanks so much for any help you guys can give! :)
Ken
UPDATE: Adding updated code sample here because I cannot get my comment to format or allow me enough chars. The stuff below may not be completely correct, I am just trying my best to be clear. I have figured out more since I posted this, basically I need to figur out how (or if possible) to use a string after delims, it only seems to check for each character...
#echo off
rem user drag folder onto .bat (left click, move folder using mouse onto .bat icon)
rem %1 in ex is C:\random_folder\another_folder\proj1\area1\scene23
set destRoot=X:\companyname\allprojects\proj1
set rootDir=proj1
rem assume %1 is folder dragged onto .bat file
for /f "tokens=2* delims=<foldername???>" %%a in ("%1") do (
set part1=%%a
set chunk=%%b
)
set finalDest=destRoot+chunk
xcopy %1\* %finalDest% /E /EXCLUDE:exclusions.txt
pause
I am hoping to create this: "X:\companyname\allprojects\proj1\area1\scene23"
Is the x:\dirA\dirB\ part of the destination folder known? If so, the solution is easy:
#echo off
rem Get current directory, ie: "C:\dir1\dir2"
set curDir=%cd%
rem Eliminate the disk drive, ie: "\dir1\dir2"
set curDir=%curDir:~2%
rem Copy to right destination, ie: "x:\dirA\dirB\dir1\dir2"
xcopy *.%FILETYPE% "x:\dirA\dirB%curDir%"
I hope it helps...
EDIT: Clarification to new comments requested
Ok. There is a source folder and a destination folder. The program above assume that the current folder for the program is source folder, but this may be provided as a parameter if needed. The program achieve the following copy processes:
From source folder -> To destination folder
C:\dir1\dir2 -> x:\dirA\dirB\dir1\dir2
C:\dir1\dir2\dir3 -> x:\dirA\dirB\dir1\dir2\dir3
C:\dir1\dir2\dir3\what\ever -> x:\dirA\dirB\dir1\dir2\dir3\what\ever
C:\XYZ -> x:\dirA\dirB\XYZ
If this is not what you want then explain it as concise as possible (use "files", "folder", "part of name" terms, not "I like", "what if", etc), and include three or four examples.
Also, note that for me drag a folder mean a drag&drop operation taking the source folder pressing the right button of the mouse and leave it over the icon of the Batch file. If you are NOT refering to this operation, please do NOT use "drag" term; use "copy" instead (please also clarify this point).
EDIT: Solution to new requirements
OK! You have not explained correctly before your last example! This problem is just about matching two names: last part of first name must match the same part in second name, and combine first name and the rest of second name. Right?:
First name: X:\companyname\allprojects\proj1
Second name: C:\random_folder\another_folder\proj1\area1\scene23
Result: X:\companyname\allprojects\proj1\area1\scene23
This is the solution:
#echo off
setlocal EnableDelayedExpansion
rem user drag folder onto .bat (left click, move folder using mouse onto .bat icon)
rem %1 in ex is C:\random_folder\another_folder\proj1\area1\scene23
set sourceFolder=%~1
set destRoot=X:\companyname\allprojects\proj1
rem Get last part of First name (destRoot) ie: lastPart=proj1
for %%a in (%destRoot%) do set lastPart=%%~Na
rem Delete from beginning of second name until that part, ie: result=\area1\scene23
set result=!sourceFolder:*%lastPart%=!
rem And insert the First name before the rest
set result=%destRoot%%result%
Or, combining the three steps in just one line:
#echo off
rem user drag folder onto .bat (left click, move folder using mouse onto .bat icon)
rem %1 in ex is C:\random_folder\another_folder\proj1\area1\scene23
set sourceFolder=%~1
set destRoot=X:\companyname\allprojects\proj1
for %%a in (%destRoot%) do set result=%destRoot%%sourceFolder:*%%~Na=%
Please note that if destRoot may contain spaces, it must be enclosed in quotes in the FOR command: for %%a in ("%destRoot%") do ...
Got this on another forum, seems to contain the answr I was looking for, sharing here for others:
#echo off
REM YOU NEED THIS
setlocal enabledelayedexpansion
REM If the passed parameter string has any spaces you must quote it
REM we unquote it using ~
set PassedString=%~1
REM May as well do the same with string to split on
set DelimString=%~2
REM The delim string must appear exactly ONCE in the passed string
REM Replace the delim string with a symbol which will not be in the
REM path to be split, in this example I use #
set splitsub=#
call set tempstring=!PassedString:%DelimString%=%splitsub%!
REM Use FOR to split the modified string
for /f "tokens=1* delims=%splitsub%" %%A in ("%tempstring%") do set part1=%%A & set part2=%%B
REM Show that the 2 variables contain the desired substrings
echo Passed = %PassedString%
echo Part1 = %part1%
echo Part2 = %part2%
Example output:
C:\>splitstring.bat "D:\Backup\mystuff\programming\Visual Basic\project\ABCDE\DEF" "project"
Passed = D:\Backup\mystuff\programming\Visual Basic\project\ABCDE\DEF
Part1 = D:\Backup\mystuff\programming\Visual Basic\
Part2 = \ABCDE\DEF
C:\>splitstring.bat "D:\Backup\mystuff\programming\Visual Basic\project\ABCDE\DEF" "mystuff"
Passed = D:\Backup\mystuff\programming\Visual Basic\project\ABCDE\DEF
Part1 = D:\Backup\
Part2 = \programming\Visual Basic\project\ABCDE\DEF

Resources