How windows(7) gets executable location (from task manager)? - windows

I have a Portable VirtualBox set up on one of my hard drives (Portable Virtual Box). And I have another VirtualBox installed in my system (this one is NOT portable, but classic installation in C:\Program Files)
I'm trying to use a BATCH Script to retrieve the location of the running VirtualBox:
#echo off
cls
setlocal enabledelayedexpansion
ECHO Please make sure you have VirtualBox running, so the script
ECHO will be able to detect VirtualBox.exe process running
rem because of a bug in wmic, I have to get the Input Locale first.
rem I could have had it hardcoded, but I think this is better (more flexible)
for /f "tokens=2 delims=:,;" %%s in ('systeminfo ^| find /i "Input Locale:"') DO (
SET locale=%%~ns
set locale=!locale: =!
)
rem this is the actual search for the executable location
FOR /f "tokens=2 delims=," %%I IN ('wmic process where "name='virtualbox.exe'" get ExecutablePath^,Handle /Format:"%WINDIR%/System32/wbem/!locale!/csv" ^| FIND /i "virtualbox.exe"') DO SET "exepath=%%~I"
ECHO Detected Path: !exepath!
endlocal
But I always get
"C:\Program Files\Oracle\VirtualBox\VirtualBox.exe".
I tried from Task Manager (right click > Open File Location) and it happens the same, no matter which of the VirtualBox instances is running.
Uninstalling the version in my "C:\Program Files" enabled proper detection of the portable one.
Is it any way (using BATCH) to correctly detect running process executable location (VirtualBox.exe, in my case), when the situation is similar with the one described above (running a portable version of an already installed program)?

Related

Access system32 from VisualStudio 2019 build script

In a post build step i want check if OpenSSH.Client and OpenSSH.Server is installed and install it if it is not there. Checking the installed features with Powershell needs administrative privileges.
Therefore i test the existence of the relevant OpenSSH commands with the following code (extract of long script)
SET /a res=0
SET /a three=3
%windir%\system32\OpenSSH\ssh-keygen.exe /?
echo Errorlevel %ERRORLEVEL%
IF %ERRORLEVEL%==%three% (SET /a res=%res%+1)
%windir%\system32\OpenSSH\ssh-keyscan.exe /?
echo Errorlevel %ERRORLEVEL%
IF %ERRORLEVEL%==%three% (SET /a res=%res%+1)
SET /a check=0
IF %res% == %check% (
echo already installed
goto skipopenSSH
)
echo installation
:skipopenSSH
By checking the existence of the commands no admin privileges are necessary for the check so a normal build will not cause a administrative popup.
On cmd.exe it works fine, but as a post build step in Visual Studio both commands in %windir%\systrem32\OpenSSH are not found, although the variable is expanded to the same c:\Windows\System32\OpenSSH\*.exe as if executed on commandline.
After trying the different find mechanisms which all fail i made a test batch file C:\Windows\System32\OpenSSH\ssh-keyscan.exe /?
which leads to a file not found error if executed as a post build step. So the real question should be: Modifies the visual studio build step commandline the path?
The directory OpenSSH exists in directory %SystemRoot%\System32 with the files ssh-keygen.exe and ssh-keyscan.exe depending on version of Windows 10. The directory %SystemRoot%\System32 is for 64-bit applications on 64-bit Windows. But Visual Studio is a 32-bit application and for that reason 32-bit Windows command processor in directory %SystemRoot%\SysWOW64 is executed to process the batch file with the commands to execute as post build step.
Microsoft documented with WOW64 Implementation Details, File System Redirector and Registry Keys Affected by WOW64 and other documentation pages how Windows on Windows 64 works.
All file system accesses to %windir%\system32\OpenSSH in the batch file processed by 32-bit %SystemRoot%\SysWOW64\cmd.exe being started by 32-bit Visual Studio results in the approach to access %SystemRoot%\SysWOW64\OpenSSH which does not exist at all. There is no subdirectory OpenSSH in Windows system directory for 32-bit applications.
One solution would be using the following code for the batch file executed as post build step.
rem This simple check is for 32-bit Windows and for 64-bit Windows with batch
rem file executed in 64-bit environment by 64-bit Windows command processor.
set FolderSSH=%SystemRoot%\System32\OpenSSH
if exist %FolderSSH%\ssh-keygen.exe if exist %FolderSSH%\ssh-keyscan.exe goto UseOpenSSH
rem This check is for 64-bit Windows with batch file executed
rem in 32-bit environment by 32-bit Windows command processor.
if exist %SystemRoot%\Sysnative\cmd.exe set FolderSSH=%SystemRoot%\Sysnative\OpenSSH
if exist %FolderSSH%\ssh-keygen.exe if exist %FolderSSH%\ssh-keyscan.exe goto UseOpenSSH
rem Search entire system drive on machines without Windows 10 or with older
rem versions of Windows 10 with OpenSSH not installed at all by default.
for /F "delims=" %%I in ('%SystemRoot%\System32\where.exe /R %SystemDrive%\ ssh-keygen.exe 2^>nul') do (
if exist "%%~dpIssh-keyscan.exe" for %%J in ("%%~dpI.") do set "FolderSSH=%%~fJ" & goto UseOpenSSH
)
echo ERROR: ssh-keygen.exe AND ssh-keyscan.exe not found.
rem More code to handle this use case.
goto :EOF
:UseOpenSSH
echo Found ssh-keygen and ssh-keyscan in: "%FolderSSH%"
rem More code to handle this use case with existing SSH tools.
The remarks explain most of the code. The inner FOR loop is used to get the full qualified name of the directory containing ssh-keygen.exe and ssh-keyscan.exe without backslash at end of the folder path to have FolderSSH defined always without a backlash at end for further usage in the batch file.
Please note that it is safe to use %FolderSSH%\ssh-keygen.exe and %FolderSSH%\ssh-keyscan.exe without surrounding " at beginning of the batch script as it is impossible that %FolderSSH% expands to a folder path containing a space or one of these characters &()[]{}^=;!'+,`~.
But "%FolderSSH%\ssh-keygen.exe" and "%FolderSSH%\ssh-keyscan.exe" must be used on the command lines below the label UseOpenSSH because it could happen that WHERE was used to find the two executables anywhere on system drive and for that reason %FolderSSH% could expand now to a folder path containing a space or a character with a special meaning for Windows command processor outside a double quoted argument string.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
echo /?
for /?
goto /?
if /?
rem /?
set /?
where /?
Read also the Microsoft article about Using command redirection operators for an explanation of 2>nul. The redirection operator > must be escaped with caret character ^ on FOR command line to be interpreted as literal character when Windows command interpreter processes this command line before executing command FOR which executes the embedded where command line with using a separate command process started in background with %ComSpec% /c and the command line between ' appended as additional arguments on which 2^>nul became already 2>nul.
The following idea also uses the where.exe command, as mentioned in the comments. This one will search the system drive for ssh-keyscan.exe, and if found will ensure that ssh-keygen.exe is also located there. If both are located in the same place, then it is considered as already installed:
#Set "dirOpenSSH="
#For /F Delims^= %%G In (
'%__AppDir__%where.exe /R %SystemDrive%\ ssh-keyscan.exe 2^>NUL'
)Do #For /F Delims^= %%H In (
'%__AppDir__%where.exe "%%~dpG.":ssh-keygen.exe 2^>NUL'
)Do #Set "dirOpenSSH=%%~dpH"
#If Defined dirOpenSSH (
Echo OpenSSH is available at %dirOpenSSH%.
%__AppDir__%timeout.exe 3 /NoBreak>NUL
GoTo skipopenSSH
)
#Echo OpenSSH is not available, beginning installation.
#%__AppDir__%timeout.exe 3 >NUL
:skipopenSSH
Please note that where.exe and timeout.exe require a minimum OS version of Windows NT 6.x
As your application is currently a 32-bit one, the console session it is using is not accessing the 64-bit locations. To fix that you could replace %__AppDir__%where.exe, with %SystemRoot%\SysNative\where.exe
It is probably worth mentioning that in the versions of windows-10 with OpenSSH part of the base OS, the location, %SYSTEMROOT%\System32\OpenSSH\, should exist in %PATH%, so you should be able to find your files directly using them:
%__AppDir__%where.exe ssh-keygen.exe
%__AppDir__%where.exe ssh-keyscan.exe
For %I In (ssh-keygen.exe) Do #Echo %~$PATH:I
For %I In (ssh-keyscan.exe) Do #Echo %~$PATH:I
I have found on the systems which have upgraded from an earlier version of Windows, that many of the default locations using C:\Windows were replicated, but using %SYSTEMROOT%/%SystemRoot% instead.
In that state, the Where command and For's %~$PATH: failed to locate some items which did exist and should have been found.
Removing the duplicated items, I removed those which were carried over, (those not using variables), although removing either format seems to have worked fine.
Both where and %~$PATH: were then functioning as intended.

How to find where windows is installed using batch file

Is there a way to create a simpel batchfile that finds the drive where windows is installed?
Use %SystemDrive% from the command prompt or in a batch file.
echo %SystemDrive%
or
d:>%SystemDrive%
c:>
Ken White has the "normal" way to get the system drive via %SystemDrive%. But that variable can easily be corrupted by setting your own value.
An alternative that should "always" work for any Win version later than XP is to use:
for %%A in ("%__APPDIR__%") do echo %%~dA
Of course you can set your own InstallDrive variable to the value of %%~dA.
The %__APPDIR__% variable is one of two special dynamic "variables" that always report the correct value, even if a user tries to override the value by explicitly defining their own variable of that name. However, the value can be overridden on XP. See Why can't I access a variable named __CD__ on Windows 7? for more info about dynamic variables %__CD__% and %__APPDIR__%.
Just in case 'finds the drive' doesn't just mean the drive letter:
#Echo Off
For /F "Tokens=2,5,6 Delims=\|" %%I In ('WMIC OS Get Name') Do Echo=%%I %%J %%K
Timeout -1
…and for no real reason:
#Echo Off
For /F "Tokens=2,5,6 Delims=\|" %%I In ('WMIC OS Get Name') Do (
Set _di=%%I %%K %%J )
Set/A _dn=%_di:~-1%+1
For /F "UseBackQ Tokens=2 Delims==" %%L In (`WMIC DiskDrive Where^
"DeviceID Like '%%PHYSICALDRIVE%_dn%'" Get Model /Value`) Do Echo=%_di% %%L
Timeout -1
Type cd %windir% in a dos command prompt, and then press ENTER.
Note the current folder. This is the folder in which Windows is installed.
You actually do not need a batch file for that. Just hold the windows key and press R to open up a small window in which you type %windir% and hit Enter.
A Windows Explorer window will pop up showing the directory of the Windows installation. You can the click onto the bar, where the directory is shown (like the URL-bar of the browser) to get the direct path including any parent folders and the drive letter.

Update a batch file based on the last modified timestamp on a file in a network share

I have a batch file on my network share, say \Sids\Awesome\Network\Share.bat. I have copies of this bat file on multiple computers. I want to set up the file in such a way that I can update Share.bat on my network share, and when I run Share.bat on a local machine, it can check the last modified time for the copy in the network share and update it self. Any suggestions on how to do this?
All my search results have led to doing some sort of directory listing and then picking the file. Unfortunately, this is not possible on a network share. For now, I have a work around by writing a small app in C# that is called from within the script. If the app believes an update it necessary, it exits with an error and I update the script if the app exited with an error code. I'd like to remove this dependency.
Hardcode a version number (second line here). Get the server version and the local version and compare them. If the version numbers are different, copy the file from the server and restart it.
#echo off
REM version=5.1
for /f "tokens=2 delims==" %%a in ('findstr /b /c:"REM version=" "\\Sids\Awesome\Network\%~nx0"') do set sv=%%a
for /f "tokens=2 delims==" %%a in ('findstr /b /c:"REM version=" "%~f0"') do set lv=%%a
echo Server: %sv%
echo Local: %lv%
if "%sv%" == "%lv%" goto :continue
echo updating...
(xcopy /y "\\Sids\Awesome\Network\%~nx0" >nul || goto :eof) & "%~f0"
[should never arive at this line]
:continue
echo current version.
you can omit the >nul, if you want to see the "1 file(s) copied" message.

Running Multiple Installations with System-Reboot Inbetween them

Currently I have a set of software-Installations(and their paths) that i have to install on my Windows Machine.
What I do now is -- Hit RUN every time and type in the software installation path into it..
What I want is to design a Batch file which would install all the applications and REBOOT my system after every successful installation and then continue with the NEXT item in the list..
Is it possible using a .bat file ??
This really isn't something batch was designed for, so this will be a bit hacky. It's not elegant by any means but give it a shot, it might work for you.
for /f %%a in (C:\files.txt) do (
start /wait %%a
exit /b
)
for /f "skip=1" %%b in ("C:\files.txt) do (
echo %%b >>C:\newfiles.txt
)
xcopy C:\newfiles.txt C:\files.txt /y
del C:\newfiles.txt /f /q
shutdown /r /t 0 /f
The idea being that you have a text file with the paths of the executables that you want to install. It will go through and execute the first file in the list, wait for it to complete, then re-write the list without the file it just installed.
This is dependend on the setup file having no user interaction and exiting by itself, or maybe it's just to make things easier - in which case just go through each install yourself, and when it finishes the batch file will do the rest.
On the note of rebooting and continuing you will either need to run the batch file again yourself or put it in the registry to start up itself, the latter command being
reg add HKCU\Software\Microsoft\Windows\CurrentVersion\Run /v "MyBatchInstaller" /d "C:\MyBatchFile.bat" /f
Hope this helps

What's the environment variable for the path to the desktop?

I'm writing a Windows batch file and want to copy something to the desktop. I think I can use this:
%UserProfile%\Desktop\
However, I'm thinking, that's probably only going to work on an English OS. Is there a way I can do this in a batch file that will work on any internationalized version?
UPDATE
I tried the following batch file:
REG QUERY "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders" /v Desktop
FOR /F "usebackq tokens=3 skip=4" %%i in (`REG QUERY "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders" /v Desktop`) DO SET DESKTOPDIR=%%i
FOR /F "usebackq delims=" %%i in (`ECHO %DESKTOPDIR%`) DO SET DESKTOPDIR=%%i
ECHO %DESKTOPDIR%
And got this output:
S:\>REG QUERY "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders" /v Desktop
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders
Desktop REG_EXPAND_SZ %USERPROFILE%\Desktop
S:\>FOR /F "usebackq tokens=3 skip=4" %i in (`REG QUERY "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folder
s" /v Desktop`) DO SET DESKTOPDIR=%i
S:\>FOR /F "usebackq delims=" %i in (`ECHO ECHO is on.`) DO SET DESKTOPDIR=%i
S:\>SET DESKTOPDIR=ECHO is on.
S:\>ECHO ECHO is on.
ECHO is on.
To be safe, you should use the proper APIs in Powershell (or VBScript)
Using PowerShell:
[Environment]::GetFolderPath("Desktop")
Copy something using Powershell:
Copy-Item $home\*.txt ([Environment]::GetFolderPath("Desktop"))
Here is a VBScript-example to get the desktop path:
dim WSHShell, desktop, pathstring, objFSO
set objFSO=CreateObject("Scripting.FileSystemObject")
Set WSHshell = CreateObject("WScript.Shell")
desktop = WSHShell.SpecialFolders("Desktop")
pathstring = objFSO.GetAbsolutePathName(desktop)
WScript.Echo pathstring
I found that the best solution is to use a vbscript together with the batch file.
Here is the batch file:
#ECHO OFF
FOR /F "usebackq delims=" %%i in (`cscript findDesktop.vbs`) DO SET DESKTOPDIR=%%i
ECHO %DESKTOPDIR%
Here is findDesktop.vbs file:
set WshShell = WScript.CreateObject("WScript.Shell")
strDesktop = WshShell.SpecialFolders("Desktop")
wscript.echo(strDesktop)
There may be other solutions but I personally find this one less hackish.
I tested this on an English PC and also a French PC - it seems to work (Windows XP).
EDIT: Use the accepted answer, this will not work if the default location isn't being used, for example: The user moved the desktop to another drive like D:\Desktop
At least on Windows XP, Vista and 7 you can use the "%UserProfile%\Desktop" safely.
Windows XP en-US it will expand to "C:\Documents and Settings\YourName\Desktop"
Windows XP pt-BR it will expand to "C:\Documents and Settings\YourName\Desktop"
Windows 7 en-US it will expand to "C:\Users\YourName\Desktop"
Windows 7 pt-BR it will expand to "C:\Usuarios\YourName\Desktop"
On XP you can't use this to others folders exept for Desktop
My documents turning to Meus Documentos and Local Settings to Configuracoes locais Personaly I thinks this is a bad thing when projecting a OS.
KB's answer to use [Environment]::GetFolderPath("Desktop") is obviously the official Windows API for doing this.
However, if you're working interactively at the prompt, or just want something that works on your machine, the tilda (~) character refers to the current user's home folder. So ~/desktop is the user's desktop folder.
Not only would that not work for an International version of Windows, it would fail if the user had edited the Registry to make their Desktop folder reside somewhere else. You can query the Registry for the file location using the REG command:
REG QUERY "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders" /v Desktop
To get this into a variable use something like this:
FOR /F "usebackq tokens=3 skip=4" %%i in (`REG QUERY "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders" /v Desktop`) DO SET DESKTOPDIR=%%i
FOR /F "usebackq delims=" %%i in (`ECHO %DESKTOPDIR%`) DO SET DESKTOPDIR=%%i
ECHO %DESKTOPDIR%
you could also open a DOS command prompt and execute the set command.
This will give you an idea what environment variables are available on your system.
E.g. - since you where specifically asking for a non-english Windows - heres is an example of my own German Edition (Window7-64bit) :
set > env.txt
type env.txt
ALLUSERSPROFILE=C:\ProgramData
APPDATA=C:\Users\SOF\AppData\Roaming
CommonProgramFiles=C:\Program Files\Common Files
CommonProgramFiles(x86)=C:\Program Files (x86)\Common Files
CommonProgramW6432=C:\Program Files\Common Files
COMPUTERNAME=VMSOF
ComSpec=C:\Windows\system32\cmd.exe
FP_NO_HOST_CHECK=NO
HOMEDRIVE=C:
HOMEPATH=\Users\SOF
LOCALAPPDATA=C:\Users\SOF\AppData\Local
LOGONSERVER=\\VMSOF
NUMBER_OF_PROCESSORS=2
OS=Windows_NT
Path=C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Program Files\TortoiseSVN\bin;C:\Program Files (x86)\CMake 2.8\bin;C:\Program Files (x86)\emacs-22.3\bin;C:\Program Files (x86)\GnuWin32\bin;
PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC
PROCESSOR_ARCHITECTURE=AMD64
PROCESSOR_IDENTIFIER=AMD64 Family 15 Model 67 Stepping 3, AuthenticAMD
PROCESSOR_LEVEL=15
PROCESSOR_REVISION=4303
ProgramData=C:\ProgramData
ProgramFiles=C:\Program Files
ProgramFiles(x86)=C:\Program Files (x86)
ProgramW6432=C:\Program Files
PROMPT=$P$G
PSModulePath=C:\Windows\system32\WindowsPowerShell\v1.0\Modules\
PUBLIC=C:\Users\Public
SESSIONNAME=Console
SystemDrive=C:
SystemRoot=C:\Windows
TEMP=C:\Users\SOF\AppData\Local\Temp
TMP=C:\Users\SOF\AppData\Local\Temp
USERDOMAIN=VMSOF
USERNAME=SOF
USERPROFILE=C:\Users\SOF
VBOX_INSTALL_PATH=C:\Program Files\Sun\VirtualBox\
VS90COMNTOOLS=C:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\Tools\
windir=C:\Windows
in windows 7 this returns the desktop path:
FOR /F "usebackq tokens=3 " %%i in (`REG QUERY "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders" /v Desktop`) DO SET DESKTOPDIR=%%i
FOR /F "usebackq delims=" %%i in (`ECHO %DESKTOPDIR%`) DO SET DESKTOPDIR=%%i
ECHO %DESKTOPDIR%
If you wish to use the
[Environment]::GetFolderPath("Desktop")
from within a cmd.exe, you may do so (thanks to MS User Marian Pascalau on this thread)
set dkey=Desktop
set dump=powershell.exe -NoLogo -NonInteractive "Write-Host $([System.Environment]::GetFolderPath([System.Environment+SpecialFolder]::%dkey%))"
for /F %%i in ('%dump%') do set dir=%%i
echo Desktop directory is %dir%
This is not a solution but I hope it helps: This comes close except that when the KEY = %userprofile%\desktop the copy fails even though zdesktop=%userprofile%\desktop. I think because the embedded %userprofile% is not getting translated.
REG QUERY "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders" /v Desktop>z.out
for /f "tokens=3 skip=4" %%t in (z.out) do set zdesktop=%%t
copy myicon %zdesktop%
set zdesktop=
del z.out
So it sucessfully parses out the REG key but if the key contains an embedded %var% it doesn't get translated during the copy command.
I had a similar problem (and VBScript or PowerShell was not an option) and the code I found in this article did not work for me. I had problems with OS versions and language versions. After some experiments I've come to this solution:
for /f "usebackq tokens=2,3*" %%A in (`REG QUERY "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders" /v "Desktop"`) do if %%A==REG_EXPAND_SZ call :reparse set desktopdir=%%B
echo %desktopdir%
goto :EOF
:reparse
%*
goto :EOF
This code works for me in English and Polish versions of Windows 7 and Windows XP.
The :reparse subroutine allows for delayed expansion of environment variables.
While I realize this is a bit of an older post, I thought this might help people in a similar situation. I made a quick one line VBScript to pull info for whatever special folder you would like (no error checking though) and it works like this:
Create a file "GetShellFolder.vbs" with the following line:
WScript.Echo WScript.CreateObject("WScript.Shell").SpecialFolders(WScript.Arguments(0))
I always make sure to copy cscript.exe (32-bit version) to the same folder as the batch file I am running this from, I will assume you are doing the same (I have had situations where users have somehow removed C:\Windows\system32 from their path, or managed to get rid of cscript.exe, or it's infected or otherwise doesn't work).
Now copy the file to be copied to the same folder and create a batch file in there with the following lines:
for /f "delims=" %%i in ('^""%~dp0cscript.exe" "%~dp0GetShellFolder.vbs" "Desktop" //nologo^"') DO SET SHELLDIR=%%i
copy /y "%~dp0<file_to_copy>" "%SHELLDIR%\<file_to_copy>"
In the above code you can replace "Desktop" with any valid special folder (Favorites, StartMenu, etc. - the full official list is at https://msdn.microsoft.com/en-us/library/0ea7b5xe%28v=vs.84%29.aspx) and of course <file_to_copy> with the actual file you want placed there. This saves you from trying to access the registry (which you can't do as a limited user anyway) and should be simple enough to adapt to multiple applications.
Oh and for those that don't know the "%~dp0" is just the directory from which the script is being called. It works for UNC paths as well which makes the batch file using it extremely portable. That specifically ends in a trailing "\" though so it can look a little odd at first glance.
#Dave Webb's answer is probably the way to go. The only other thing I can think of are the CSIDLs:
CSIDL_DESKTOPDIRECTORY
The file system directory used to
physically store file objects on the
desktop (which should not be confused
with the desktop folder itself). A
typical path is C:\Documents and
Settings\username\Desktop.
I have no idea how to get hold of those from the command line, though.
Multilingual Version, tested on Japanese OS Batch File
set getdesk=REG QUERY "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders" /v Desktop
FOR /f "delims=(=" %%G IN ('%getdesk% ^|find "_SZ"') DO set desktop=%%G
set desktop1=%desktop:*USERPROFILE%\=%
cd "%userprofile%\%desktop1%"
set getdesk=
set desktop1=
set desktop=
This should work no matter what language version of Windows it is and no matter where the folder is located. It also doesn't matter whether there are any spaces in the folder path.
FOR /F "tokens=2*" %%A IN ('REG QUERY "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders" /v Desktop^|FIND/I "desktop"') DO SET Desktop=%%B
ECHO %Desktop%
In case of Windows 2000 (and probably NT 4.0) you need to copy reg.exe to the %windir% folder manually since it is not available there by default.
I use this code to get the User desktop and Public desktop paths from the registry, tested on Windows XP SP2 pt-PT and Windows 10 b14393 en-US, so it probably works in Vista/7/8 and other languages.
:: get user desktop and public desktop paths
for /f "tokens=* delims= " %%a in ('reg query "HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders" /v Desktop ^|find /i "REG_"') do set "batch_userdesktop=%%a"
for /f "tokens=* delims= " %%a in ('reg query "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders" /v "Common Desktop" ^|find /i "REG_"') do set "batch_publicdesktop=%%a"
:: remove everything up to and including "_SZ"
set "batch_userdesktop=%batch_userdesktop:*_sz=%"
set "batch_publicdesktop=%batch_publicdesktop:*_sz=%%
:: remove leading spaces and TABs
:loop
if "%batch_userdesktop:~0,1%"==" " set "batch_userdesktop=%batch_userdesktop:~1%" & goto loop
if "%batch_publicdesktop:~0,1%"==" " set "batch_publicdesktop=%batch_publicdesktop:~1%" & goto loop
if "%batch_userdesktop:~0,1%"==" " set "batch_userdesktop=%batch_userdesktop:~1%" & goto loop
if "%batch_publicdesktop:~0,1%"==" " set "batch_publicdesktop=%batch_publicdesktop:~1%" & goto loop
The last two lines include a TAB inside the " ", some text editors add spaces when you press TAB, so make sure you have an actual TAB instead of spaces.
I'm not sure the code requires setlocal enabledelayedexpansion, it's part of my SETVARS.CMD which I call from other batches to set common variables like cpu architecture, account language, windows version and service pack, path to user/public desktop, etc.
I know this is kind of an old topic, but I would use the Powershell variable
$env:UserProfile
To use it to get to the desktop, it would be:
cd $env:UserProfile\desktop
This works both locally and remotely on windows 7. Hope this is useful as I ran across a situation where a client machine didn't have a value in $home.
Quite old topic. But I want to give my 2 cents...
I've slightly modified tomasz86 solution, to look in the old style "Shell Folders" instead of "User Shell Folders", so i don't need to expand the envvar %userprofile%
Also there is no dependency from powershell/vbscript/etc....
for /f "usebackq tokens=2,3*" %%A in (`REG QUERY "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders" /v "Desktop"`) do if %%A==REG_SZ set desktopdir=%%B
echo %desktopdir%
Hope it helps.
TL;DR
%HOMEDRIVE%%HOMEPATH%\Desktop seems to be the safest way.
Discussion
Assumptions about which drive a thing is on are quite fragile in Windows as it lacks a unified directory tree where mounts would map to directories internally. Therefore the %HOMEDRIVE% variable is important to reference to make sure you're on the right one (it isn't always C:\!).
Non-English locales will usually have localized names for things like "Desktop" and "Pictures" and whatnot, but fortunately they are all aliases that point to Desktop, which seems to be the underlying canonical directory name regardless of locale (we use this safely here in Japan, Thailand, Israel and the US).
The big quirk comes with determining whether %UserProfile% points to the user's actual profile base dir, or their Desktop or somewhere completely different. I'm not really a Windows dev, but what I've found is the profile dir is for settings, but the %HOMEPATH% is for the user's own files, so this points to the directory root that leads to Desktop/Downloads/Pictures/etc. This tends to make %HOMEDRIVE%%HOMEPATH%\Desktop the safest way.

Resources