For example I have entered
netsh.exe
in command line (aka cmd.exe)
Now I would like to know which netsh.exe is being run, lets say I have more than one netsh.exe on my PATH (I do know that the first one in the PATH will be run, but lets say I have a very BIG PATH and I don't have time to search for it manually. To be fair its not always your machine you are using and many times PATH is set by admins and many times they are not the best).
Is there any way in windows to find that out from command line? I want to write a BATCH application that is using that.
It's a one-liner batch file:
#for %%e in (%PATHEXT%) do #for %%i in (%1%%e) do #if NOT "%%~$PATH:i"=="" echo %%~$PATH:i
Save this as whereis.cmd, then type
whereis netsh
I think the following blog post does exactly what you want: http://pankaj-k.net/weblog/2004/11/equivalent_of_which_in_windows.html
I would use Windows Management Instrument (WMI) to query:
"SELECT ExecutablePath FROM Win32_Process WHERE Name = 'netsh.exe'"
http://www.activexperts.com/activmonitor/windowsmanagement/wmi/samples/ WMI samples
You will need to find something suitable for your scripting
On Windows Server (at least 2003 and 2008, dont know with 2000) you can use where.exe
Where.exe /?
Description:
Displays the location of files that match the search pattern.
By default, the search is done along the current directory and
in the paths specified by the PATH environment variable.
...
The first file listed is also the first file windows will use.
I use a copy on my XP workstation and it works fine too.
Related
I am working on an application that requires my users to share their fully-qualified-domain-name of their windows machine.
To help my users to extract their machine's FQDN, I want to share simple command line steps that they can copy/paste and execute on their terminals to get the result.
I was thinking of below command to extract local machine's FQDN:
echo %COMPUTERNAME%.%USERDNSDOMAIN%
But there are few problems of this command.
It gives output in ALL CAPS. (I can live with it)
It gives incorrect output if the variable is not set.
For example:
If USERDNSDOMAIN value is not set, then, you'll get following output:
echo %COMPUTERNAME%.%USERDNSDOMAIN% //<- Run this on cmd prompt
ClientComputerName.%USERDNSDOMAIN% //<- wrong output: Notice '%USERDNSDOMAIN%' is appended in o/p
Is there any way to stop echoing a variable if it's value is not set?
Please note that I want to extract "fully qualified domain name" of my windows machine through CMD prompt only.
You can get the FQDN name using PowerShell.
=== Get-FQDN.bat
#ECHO OFF
FOR /F %%A IN ('powershell -NoLogo -NoProfile -Command ^
"([System.Net.Dns]::GetHostByName($Env:COMPUTERNAME)).HostName"') DO (
SET "THEFQDN=%%A"
)
ECHO %THEFQDN%
If you have multiple users, then you surely have some way to get programs and batch files installed on them. Once this batch file script is installed into a directory on the user's PATH, it is a one-line command.
Get-FQDN
1st, please note that the "USER DNS Domain" is NOT the domain the computer is joined to, it is the domain the USER who is logged in belongs to.
If you log in as a user from a trusted domain, or a child or parent domain, then it will display that domain.
So, if you log in as a LOCAL account it will be blank (likely you are running into this)
There is a fairly simple way to get the actual computer domain however, by using NLTest. (For the like of me I could never figure out why Microsoft didn't pre-populate a variable with this info.)
At the CMD Line simply dump this into the command prompt (I believe you will need to run with admin privileges but I haven't tested):
FOR /F "tokens=3" %_ IN ('nltest /DOMAIN_TRUSTS /PRIMARY ^|FIND /I "0:"') DO #(ECHO.%COMPUTERNAME%.%_)
The result will be in all caps because that is how Microsoft displays this info.
Here is an example output:
MYLAPTOP.USERS.MYDOMAIN.LOCAL
But on-re-read you want something the users know how to do themselves, so ymmv if you could just send a reference email, or hand it to them each time they need it.
If you just wan this info and other info easily available you could use BGInfo or other options like that to set the desktop background.
Alternatively you could change the logon scripts to generate a simple text file with all the info each time the user logs on, and placed in a certain folder you tell them to look in.
Redirecting CMD Commands To An EXE File
Long story short, basically I have the problem that every time I run BCDedit on the .BAT that I converted into an .EXE it never worked and I thought that the reason why it wasn't work was because it wasn't on Path but my Path was fine and even if it was on Path is set by default thanks to foxidrive.
Now my main problem is that is there a way I can convert it to an .EXE file with every single command working, is there a technique I could use to get BCDedit working as an .EXE file?
All of the commands do work it just BCDedit and I say if every single command would work so if somebody has a similar command problem like me they know how to figure it out, it works perfectly as batch but is there a way I can convert it and make BCDedit still work as an .EXE?
Please answer As Soon As Possible and if you want to take a look at my Path and Batch the visit the link at the top.
Thank you so much!
Compile this batch file and see if it works:
#echo off
bcdedit /?
pause
Then try this version:
#echo off
c:\Windows\System32\bcdedit.exe /?
pause
Just as the SysWow64 Redirection link you listed states. If you want a x86 application to call the 64-bit system directory you need to call the bcdedit application as follows.
%SystemRoot%\SysNative\bcdedit
This is because of Windows backwards compatibility measures, it is looking at C:\Windows\SysWOW64 instead of C:\Windows\System32. Another alternative would be to compile the script as both x86 and 64-bit, but then you could only use each on the respective systems.
Update for Comments
Even though the path is correct, an x86 application will execute commands or batch scripts against the C:\Windows\SysWOW64\cmd.exe which will cause the path redirection issue. Example to illustrate my point. On a 64-bit version of Windows, open C:\Windows\SysWOW64\cmd.exe and using Windows explorer create two unique files , one is C:\Windows\System32\unique_test64.txt and the other in C:\Windows\SysWOW64\unique_test86.txt. Now on the x86 command prompt enter if exist C:\Windows\System32\unique_test86.txt echo true. You will see that it is being redirected to SysWOW64 and will print true. And if you enter if exist C:\Windows\System32\unique_test64.txt echo true, nothing will be found.
Screenshot Example: http://i.imgur.com/K4kkI29.png
Scenario
Let us assume an application is installed on Windows XP, and on Windows 7, for a single user and that it installs to the following directories in these 2 operating systems:
Windows XP:
C:\Documents and Settings\<user_name>\Local Settings\Application Data\<target-folder>
Windows 7:
C:\Users\<user_name>\AppData\Local\<target-folder>
I want to create a batch script that will assign the target-folder directory to a variable within the script.
Question
What is the simplest and most robust way to set a variable in a batch script based on which version of windows the script is running in?
Example Answer
set targetDir = ?
ver | find "XP" >nul && (
set "TargetDir=%USERPROFILE%\Local Settings\Application Data\[target-folder]"
) || (
set "TargetDir=%USERPROFILE%\AppData\Local\[target-folder]"
)
echo "%TargetDir%"
There is a environment variable named %USERPROFILE% or %APPDATA% which can be used to query the profile path name.
In general use WMIC for to query info like this, it works in XP (Professional but not home), Vista, windows 7, windows 8, and servers. For example to get the OS name use:
WMIC OS GET caption
Or name instead of caption if you want more info. You can ask for other data such as OSArchitecture that would tell you if its 32 or 64 bit. And you can combine queries, like this:
WMIC OS GET caption, osarchitecture, muilanguages
You can get full list with WMIC OS but read the docs on WMIC it can do a lot of different queries and tasks, such as listing all users. But the real catch is that you can query OTHER users environments with:
wmic ENVIRONMENT
:: and
wmic /user user ENVIRONMENT
Last but not least, if even version fails to give you a clue you can use
IF EXISTS C:\Users
To determine if folders exist.
After further research I found this resource to be both simple and robust because it detects all versions of Windows rather than just windows xp or windows 7.
The answer is, "it depends".
For example, I control the computer setups at work and our Windows 7 machines are all 64-bit, so I can check for C:\Program Files (x86).
So, I do something like this:
IF EXIST "C:\Program Files (x86)" (
SET TargetDir=C:\Users\<user_name>\AppData\Local\<target-folder>
) ELSE (
SET TargetDir=C:\Documents and Settings\<user_name>\<target-folder>
)
Granted, these are not foolproof, but they work for my needs.
If you are talking about computers that you don't control or use a different language, then things get more complicated.
I would like to know what are the approaches that you use to manage the executables in your system. For example I have almost everything accessible through the command line, but now I come to the limit of the path string, so i can't add any more dir.
So what do you recommend?
A long time ago, I tried to use softLinks of the executables in a Dir that belonged to the path, but that approach didn't work.
Throw the "executable only" to a known Dir,has the problems that almost any application require a set of files, so this also is bad.
Throw the executable and all his files to a known Dir, mmm this will work, but the possibility to get a conflict in the name of the files is very very high.
Create a HardLink? i don't know. What do you think?
This will parse your %PATH% environment variable and convert each directory to its shortname equivalent and then piece it all back together:
#echo off
SET MyPath=%PATH%
echo %MyPath%
echo --
setlocal EnableDelayedExpansion
SET TempPath="%MyPath:;=";"%"
SET var=
FOR %%a IN (%TempPath%) DO (
IF exist %%~sa (
SET "var=!var!;%%~sa"
) ELSE (
echo %%a does not exist
)
)
echo --
echo !var:~1!
Take the output and update the PATH variable in environment variables.
One way I can think of is to use other environment variables to store partial paths; for example, if you have
C:\this_is_a\long_path\that_appears\in_multiple_places\subdir1;
C:\this_is_a\long_path\that_appears\in_multiple_places\subdir2;
then you can create a new environment variable such as
SET P1=C:\this_is_a\long_path\that_appears\in_multiple_places
after which your original paths become
%P1%\subdir1;
%P1%\subdir2;
EDIT: Another option is to create a bin directory that holds .bat files that point to the appropriate .exe files.
EDIT 2: Ben Voigt's comment to another answer mentions that using other environment variables as suggested might not reduce the length of %PATH% because they would be expanded prior to being stored. This may be true and I have not tested for it. Another option though is to use 8dot3 forms for longer directory names, for example C:\Program Files is typically equivalent to C:\PROGRA~1. You can use dir /x to see the shorter names.
EDIT 3: This simple test leads me to believe Ben Voigt is right.
set test1=hello
set test2=%test1%hello
set test1=bye
echo %test2%
At the end of this, you see output hellohello rather than byehello.
EDIT 4: In case you decide to use batch files to eliminate certain paths from %PATH%, you might be concerned about how to pass on arguments from your batch file to your executable such that the process is transparent (i.e., you won't notice any difference between calling the batch file and calling the executable). I don't have a whole lot of experience writing batch files, but this seems to work fine.
#echo off
rem This batch file points to an executable of the same name
rem that is located in another directory. Specify the directory
rem here:
set actualdir=c:\this_is\an_example_path
rem You do not need to change anything that follows.
set actualfile=%0
set args=%1
:beginloop
if "%1" == "" goto endloop
shift
set args=%args% %1
goto beginloop
:endloop
%actualdir%\%actualfile% %args%
As a general rule, you should be careful about running batch files from the internet, since you can do all sorts of things with batch files such as formatting your hard drive. If you don't trust the code above (which I wrote), you can test it by replacing the line
%actualdir%\%actualfile% %args%
with
echo %actualdir%\%actualfile% %args%
Ideally you should know exactly what every line does before you run it.
if you are using windows vista or higher, you can make a symbolic link to the folder. for example:
mklink /d C:\pf "C:\Program Files"
would make a link so c:\pf would be your program files folder. I shaved off 300 characters from my path by using this trick.
In case anyone's interested...
I find I never really need all those paths at once, so I create a bunch of "initialization" batch files which modify the path accordingly.
For example, if I wanted to do some C++ development in Eclipse, I would do:
> initmingw
> initeclipse
> eclipse
This is also handy for avoiding conflicts between executables with the same name (such as the C++ and D compilers, which both have a make.exe).
My batch files typically look like this:
#echo off
set PATH=C:\Path\To\My\Stuff1;%PATH%
set PATH=C:\Path\To\My\Stuff2;%PATH%
I find this approach relatively clean and have yet to run into any problems with it.
I generally don't have to worry about this (I haven't run into a path size limit - I don't even know what that is on modern Windows systems), but here's what I might do to avoid putting a program's directory in the path:
most command line utilities get thrown into a c:\util directory that's on the path
otherwise, I'll add a simple cmd/batch file to the c:\util directory that looks something like:
#"c:\program files\whereever\foo.exe" %*
which essentially creates an alias for the command. It's not necessarily perfect. Some programs really insist on being in the path (that's pretty rare nowadays), and other programs that try to invoke it might not find it properly. But for most uses it works well.
But generally, I haven't had to worry about avoiding adding directories to the path.
Another idea: Use DIR /X to determine the short names generated for non-8dot3 file
names. Then use these in your %PATH%.
For example, 'C:\Program Files' becomes 'C:\PROGRA~1'.
USe the App Path registry key instead of the path variable for application-specific paths:
http://msdn.microsoft.com/en-us/library/windows/desktop/ee872121(v=vs.85).aspx
I wrote and use on a every-time basis a standard stream (stdin/stderr/stdout) & exit code PROXY program (called dispatcher https://github.com/131/dispatcher)
All CLI program i use (node, php, python, git, svn, rsync, plink ...) i'm using are actually the same exe file (around 10kb, that i just name differently), that i put in the same directory. A dummy static clear text file do the "proxy file name to real exe mapping".
Dispatcher use low level Process management win32 API to be absolutly transparent.
Using this software, i only do have ONE additionnal directory set in my PATH for all programs i might use.
Creating a folder c:\bin adding to your path and hardlinking like you said could shorten the string. Maybe add a variable pf to system vars with value c:\Program Files then replace c:\Program Files with %pf% in path.
Edit:
Create a virtual drive.
subst p: "c:\program files"
I follow these steps to make the entries manageable:
Created different users for different combination of software packages usage.
Example: (a) Created a user web for making available all the web development software; (b) Created a user database for making available all the database and data warehousing software packages. Remember some software may create more than one entry. Or sometime I break this into oracle specific and MSSQL specific and oracle specific users. I put MySQL/PostgreSQL, tomcat, wamp, xamp all into the user account webr.
If possible install common packages like office, photoshop, .. as system specific available for all users and special packages as user specific. Of course I had to log into different users and install them. Not all software may provide this option. If "install for this user only" option is not available, install it for the whole system.
I avoid installing programs in to the folder Program File (x86) or in to Program File. I always install into the base directory. For example MySQL 64 bit goes into "C:\mysql64" and MySQL 32 bit goes into "C:\mysql" folder. I always assume adding a suffix 64 only for 64bit software. If no suffix, then it is a 32 bit. I follow the same thing to Java and others. This way my path will be shorter, not including "C:\Program File (x86)". For some software the configuration file may need to be edited to show where exactly the .exe file is. Only program that demands to be installed into "C:\Program File (x86)" will be installed into that folder. Always I remember to shorten the names. I avoid version number like tomcat/release/version-2.5.0.3 such details. If I need to the know version, I create a file by name version and put it into the tomcat folder. In general shorten the link as much as possible.
Include any batch to replace abbreviated link to the path, if all the above steps passed the Windows limit.
Then Log into usage specific (mobile application, or database/data warehousing or web-development.. ..) user and do the relevant tasks.
You can also create virtual windows within windows. As long as you have one licensed OS copy, creating multiple virtual windows with same key is possible. You can put packages specific for a particular task in that machine. You have to launch separate VM each time. Some memory intensive packages like 3D animation movie makers all should be put into the main machine, not into VM as VM will have only a part of the RAM available for its use. It is a pain to boot each VM though.
The solutions above only work if you can trim down your path. In my case, that wasn't really an option, and it was a hassle to have to run a script every time I opened a command prompt. So I wrote a simple script that runs automatically when opening the command prompt, and appends the contents of a text file to your path.
There are also some contexts where having this script run breaks things (say, in a github or cygwin shell), so I also added a file that contains a list of paths that, if the command prompt is started in them, the path variable isn't changed via the startup script that normally updates the path.
#echo off
:: Modify these to the actual paths of these two files
set dontSetupFile=C:\Users\Yams\Dontsetup.txt
set pathFile=C:\Users\Yams\Path.txt
:: Retrieve the current path (for determining whether or not we should append to our path)
set curDir=%cd%
:: Be done if the current path is listed in the dontSetupFile
SetLocal EnableDelayedExpansion
for /F "delims=" %%i in (%dontSetupFile%) do (
if "%%i"=="%curDir%" GOTO AllDone
)
:: Append the pathFile to our current PATH
set pathAppend=
for /F "delims=" %%i in (%pathFile%) do (set pathAppend=!pathAppend!%%i)
set PATH=%PATH%;%pathAppend%
:: The only way to actually modify a command prompt's path via a batch file is by starting
:: up another command prompt window. So we will do this, however, if this script is
:: automatically called on startup of any command prompt window, it will infinately
:: recurse and bad things will happen.
:: If we already ran, we are done
if "%yams%"=="onion" GOTO AllDone
:: Otherwise, flag that we just ran, and then start up a new command prompt window
:: with this flag set
set yams=onion
cmd \K set PATH=%PATH%;
:: When that command prompt exits, it will load back up this command prompt window, and
:: then the user will need to exit out of this as well. This causes this window to
:: automatically exit once the cmd it just spawned is closed.
exit()
:: Path is set up, we are done!
:AllDone
#echo on
And Path.txt will look something like
C:\Program Files (x86)\Google\google_appengine;
C:\Program Files (x86)\ATI Technologies\ATI.ACE\Core-Static;
C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common;
C:\Program Files\Microsoft SQL Server\110\Tools\Binn;
C:\Program Files\Microsoft DNX\Dnvm;
C:\Program Files (x86)\Windows Kits\8.0\Windows Performance Toolkit;
While Dontsetup.txt will look something like
C:\Program Files (x86)\Windows Kits\8.0\Windows Performance Toolkit
C:\Program Files (x86)\Git\cmd
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin
To make this run automatically on startup, open regedit, navigate to HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Command Processor, then right click on the right and press new -> Multi-String Value. Name it AutoRun. Set it's value to
C:\Users\Yams\setUpPath.bat
or wherever else you stored the batch file above.
Didn't try it, but will splitting PATH in parts work and joining them in final variable work?
Example initially let's say you have something like
PATH={LONGPATH1};{LONGPATH2};....{2048th char}....{LONGPATH_N-1};{LONGPATH_N}
Instead you create:
_PATH1 = {LONGPATH1};{LONGPATH2};....{2048 char}
_PATH2 = {2049th char}...{LONGPATH_N-1};{LONGPATH_N}
rem // may be more parts
PATH = %_PATH1%;%_PATH2%
What is the best way to find out where notepad.exe and mspaint.exe are that will work across various versions of Windows?
Should I get the Windows directory via SHGetFolderPath(NULL, CSIDL_WINDOWS, NULL, SHGFP_TYPE_CURRENT, dir), and then traverse through all the subdirectories to look for the two files?
(Assume that I am not interested in anything outside the Windows folder.)
This works on every Windows box I've got access to (XP+).
c:\> for %i in (cmd.exe) do #echo %~$PATH:i
C:\WINDOWS\system32\cmd.exe
c:\> for %i in (python.exe) do #echo %~$PATH:i
C:\Python25\python.exe
The great thing is, you don't have to use the actual %PATH%, you can substitute your own search path by using a different environment variable.
If you have the Microsoft Platform SDK installed (the February 2003 version is the last one that works with Microsoft VC6), you can grab the where.exe program (it's 38K, only 18K if you gzip it) and run
where notepad.exe
help from the where command:
WHERE [/R dir] [/Q] [/F] [/T] pattern...
Description:
Displays the location of files that match the search pattern.
By default, the search is done along the current directory and
in the paths specified by the PATH environment variable.
Parameter List:
/R Recursively searches and displays the files that match the
given pattern starting from the specified directory.
/Q Returns only the exit code, without displaying the list
of matched files. (quite mode)
/F Displays the matched filename in double quotes.
/T Displays the file size, last modified date and time for all
matched files.
pattern Specifies the search pattern for the files to match.
Wildcards * and ? can be used in the pattern. The
"$env:pattern" and "path:pattern" formats can also be
specified, where "env" is an environment variable and
the search is done in the specified paths of the "env"
environment variable. These formats should not be used
with /R. The search is also done by appending the
extensions of the PATHEXT variable to the pattern.
/? Displays this help message.
NOTE: The tool returns an error level of 0 if the search is
successful, of 1 if the search is unsuccessful and
of 2 for failures or errors.
Examples:
WHERE /?
WHERE myfilename1 myfile????.*
WHERE $windir:*.*
WHERE /R c:\windows *.exe *.dll *.bat
WHERE /Q ??.???
WHERE "c:\windows;c:\windows\system32:*.dll"
WHERE /F /T *.dll
Check if the key HKEY_CLASSES_ROOT\Applications\notepad.exe is the same on localized versions. Maybe the key name is same and the value for edit/open points to the localized exe.
Example:
English:
HKEY_CLASSES_ROOT\Applications\notepad.exe\shell\edit\command
%SystemRoot%\system32**NOTEPAD.EXE** %1
Dutch:
HKEY_CLASSES_ROOT\Applications\notepad.exe\shell\edit\command
%SystemRoot%\system32**kladblok.exe** %1
If thats the case, then its just about to check the registry for that key (same goes for the mspaint).
Type:
%windir%\system32\notepad.exe
in the path bar thingy.
Or
C:\Windows\System32
and find notepad.exe. C is the hard drive where your OS is located.
I think to start off small you should get the windir environment variable and look in the subfolders %windir%\system32\ for mspaint and notepad.
Most likely they will be there.
However if that fails, well then resort to a more brute force search.
Normally, you would just execute them. They are on the system path in every version of Windows.
You can use ExpandEnvironmentStrings. The environment variable you want to expand is WINDIR.
In the past you could have used GetWindowsDirectory or GetSystemDirectory, but I think they are deprecated.
Use the WinAPI function GetWindowsDirectory() to get the Windows folder, and GetSystemDirectory() to get the Windows\System folder. Thely're guaranteed to work with all Windows versions since at least Win95; I think they were available in Win 3.x as well.
Since you tagged the question with WinAPI, I'd use SearchPath() e.g. the following will populate the variable path with the result.
//Get the full path to notepad
char path[MAX_PATH] = { 0 };
LPSTR* ptr = NULL;
DWORD dwRet = SearchPath(NULL, "notepad.exe", NULL, MAX_PATH, (LPSTR)path, ptr);
Try opening a DOS prompt, change to the Windows folder and do:
dir notepad.exe /s
Long live DOS :)
In short I find that the best approach
is to check the
Windows\System32 directory
and the HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths registry keys.
More generally I find that the best approach
is to mimic ShellExecuteEx.
Taken from:
Application Registration (Windows)
https://msdn.microsoft.com/en-us/library/windows/desktop/ee872121(v=vs.85).aspx
The file is sought in the following locations:
•The current working directory.
•The Windows directory only (no subdirectories are searched).
•The Windows\System32 directory.
•Directories listed in the PATH environment variable.
•Recommended: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths
A further possibly is to check Start Menu\Programs\Accessories,
by using SHGetFolderPath with CSIDL_STARTMENU := 11
and CSIDL_COMMON_STARTMENU := 22, and retrieve the targets
from the lnk files.
Go to the system32 folder and type "notepad.exe" into the 'File Name' bar.