How to convert windows short name path to long name in batch script


Debenham

I'm writing a Windows batch script and I have a parameter or variable that contains a path using a short 8.3 name. The path may represent a file or folder.

How to convert 8.3 paths to long name paths? At least I want to be able to simply print out the full long name path. But ideally I'd like to safely add the long name path to a new variable.

For example, given a path C:\PROGRA~1\AVASTS~1\avast\BROWSE~1.INI, I want to return C:\Program Files\AVAST Software\avast\BrowserCleanup.ini.

As a batch geek, I'm most interested in pure batch solutions using only native Windows commands. But other native scripting tools like PowerShell and JScript are also available.

Note: I'll post my own answer to this question. I searched online and was surprised to find very little precious material on the subject. I developed a variety of work strategies and thought others might be interested in my findings.

Debenham

First, I'll demonstrate how to convert batch file parameters %1and print the results to the screen.

power case

The easiest solution is to use PowerShell. I found the following code on Sergey Babkin 's MSDN blog

$long_path = (Get-Item -LiteralPath $path).FullName

Putting the code in a batch script and printing the results is as simple as:

@echo off
powershell "(Get-Item -LiteralPath '%~1').FullName"

However, I try to avoid using PowerShell in batch for two reasons

  • PowerShell is not native to XP
  • PowerShell takes quite a while to start making the batch hybrid relatively slow


CSCRIPT(JScript或VBS)

I found this VBS snippet on the Computer Hope forums that uses a dummy shortcut to convert from short to long format.

set oArgs = Wscript.Arguments
wscript.echo LongName(oArgs(0))
Function LongName(strFName)
Const ScFSO = "Scripting.FileSystemObject"
Const WScSh = "WScript.Shell"
   With WScript.CreateObject(WScSh).CreateShortcut("dummy.lnk")
     .TargetPath = CreateObject(ScFSO).GetFile(strFName)
     LongName = .TargetPath
   End With
End Function

I found similar code in Microsoft newsgroup archives and old vbscript forums .

The code only supports file paths, and it's slightly easier to embed JScript in batch. After converting to JScript and adding an exception handler to get the folder on file failure, I get the following mixed code:

@if (@X)==(@Y) @end /* Harmless hybrid line that begins a JScript comment

::----------- Batch Code-----------------
@echo off
cscript //E:JScript //nologo "%~f0" %1
exit /b

------------ JScript Code---------------*/
var shortcut = WScript.CreateObject("WScript.Shell").CreateShortcut("dummy.lnk");
var fso = new ActiveXObject("Scripting.FileSystemObject");
var folder='';
try {
  shortcut.TargetPath = fso.GetFile(WScript.Arguments(0));
}
catch(e) {
  try {
    shortcut.TargetPath = fso.GetFolder(WScript.Arguments(0));
    folder='\\'
  }
  catch(e) {
    WScript.StdErr.WriteLine(e.message);
    WScript.Quit(1);
  }
}
WScript.StdOut.WriteLine(shortcut.TargetPath+folder);


pure batch

Surprisingly, my web searches have failed to find a pure batch solution. So I am alone.

If you know the path represents a file, then just use to convert 8.3 filenames to long names dir /b "yourFilePath". However, this does not resolve the name of the parent folder.

It's even worse if the path represents a folder. There is no way to list a specific folder using the DIR command alone - it always lists the contents of the folder, not the folder name itself.

I've tried multiple strategies to handle folder paths, but none of them work:

  • CD or PUSHD to the path and see the prompt - it keeps the short folder name
  • XCOPY with /L and /F options - it also preserves short folder names
  • parameter or FOR variable modifier %~f1or %%~fA- reserved for short name
  • FORFILES - It seems that short names are not supported.

The only solution I can think of is to use DIR to iteratively convert each folder in the path, one at a time. This requires me to use to DIR /X /B /ADlist all folders in the parent folder, including their 8.3 names, and then use FINDSTR to find the correct short folder name. I rely on the fact that the short filename always appears in the exact same place after the <DIR>text . Once the correct line is found, you can use variable substrings or find/replace operations, or use FOR /F to parse long folder names. I choose to use FOR /F.

Another stumbling block I ran into was determining whether the original path represented a file or a folder. Adding backslashes and using inappropriate methods are often used to report files as folders IF EXIST "yourPath\" echo FOLDERif the path involves symbolic links or junctions (common in corporate network environments) .

I chose to use IF EXIST "yourPath\*", at https://stackoverflow.com/a/1466528/1012053 .

But it is also possible to use the FOR variable %%~aFattribute modifier to find the d(directory) attribute, which is available at https://stackoverflow.com/a/372​​8742/1012053 and https://stackoverflow.com/a/8669636/1012053 .

So here is a pure batch solution that works perfectly

@echo off
setlocal disableDelayedExpansion

:: Validate path
set "test=%~1"
if "%test:**=%" neq "%test%" goto :err
if "%test:?=%"  neq "%test%" goto :err
if not exist "%test%"  goto :err

:: Initialize
set "returnPath="
set "sourcePath=%~f1"

:: Resolve file name, if present
if not exist "%~1\*" (
  for /f "eol=: delims=" %%F in ('dir /b "%~1"') do set "returnPath=%%~nxF"
  set "sourcePath=%~f1\.."
)

:resolvePath :: one folder at a time
for %%F in ("%sourcePath%") do (
  if "%%~nxF" equ "" (
    for %%P in ("%%~fF%returnPath%") do echo %%~P
    exit /b 0
  )
  for %%P in ("%sourcePath%\..") do (
    for /f "delims=> tokens=2" %%A in (
      'dir /ad /x "%%~fP"^|findstr /c:">          %%~nxF "'
    ) do for /f "tokens=1*" %%B in ("%%A") do set "returnPath=%%C\%returnPath%"
  ) || set "returnPath=%%~nxF\%returnPath%"
  set "sourcePath=%%~dpF."
)
goto :resolvePath

:err
>&2 echo Path not found
exit /b 1

If there are many folders, the GOTO used to iterate over a single folder will slow down the operation. If I really wanted to optimize for speed, I could use FOR /F to call another batch process and parse each folder in an infinite FOR /L %%N IN () DO...loop and EXITuse to break the loop after reaching the root. But I didn't bother.


Develop powerful utilities that can return results into variables

There are many advantages to allow for complex and powerful script development ^, %and !the fact that file/folder names are all legal characters.

  • CALL doubles the characters enclosed in quotation marks . There is no good solution other than using variables instead of string literals to pass values ​​by reference. This is not a problem if the input path only uses short names. However, problems can arise if the path mixes short and long names.^

  • %Passing literals in batch parameters can be tricky. It can be confusing if it should be doubled multiple times (if at all). Also, it might be easier to pass values ​​by reference in variables.

  • CALLer can call utilities from FOR loops. Expansion of a loop or expansion within a loop in a utility causes a FOR variable to expand if the variable or argument contains %, because the scope of a FOR variable is a global variable. The utility must not expand arguments within a FOR loop, and can only safely expand variables within a FOR loop if delayed expansion is used.%var%%1

  • !If delayed expansion is enabled, expansions containing FOR variables will be broken.

  • The calling environment may have delay expansion enabled or disabled. Passing a value that contains !and ^crosses the ENDLOCAL barrier to a deferred expansion environment requires !escaping the reference as ^!. Also, quote ^must be escaped ^^, but only if the line contains it !. Of course, these characters should not be escaped if the CALLing environment has delayed expansion disabled.

I've developed a robust JScript and pure batch solution in the form of a utility taking into account all the above edge cases.

The utility defaults to expecting the path as a string literal, but accepts a variable name containing the path if the /Voption is used .

By default, the utility just prints the result to stdout. However, if you pass the name of the return variable as an additional parameter, the result can be returned in a variable. Whether you enable or disable delayed expansion in the CALLing environment, the correct value is guaranteed to be returned.

The full documentation is embedded in the utility and can be accessed using this /?option .

There are some vague restrictions:

  • Return variable name must not contain !or %characters
  • Likewise, /Voption input variable names must not contain the !or %characters.
  • The input path must not contain inner double quotes. The path can be enclosed in a set of double quotes, but should not contain any other quotes.

I haven't tested whether the utilities use unicode in path names, or if they work with UNC paths.


jLongPath.bat - Hybrid JScript/Batch

@if (@X)==(@Y) @end /* Harmless hybrid line that begins a JScript comment
:::
:::jLongPath  [/V]  SrcPath  [RtnVar]
:::jLongPath  /?
:::
:::  Determine the absolute long-name path of source path SrcPath
:::  and return the result in variable RtnVar.
:::
:::  If RtnVar is not specified, then print the result to stderr.
:::
:::  If option /V is specified, then SrcPath is a variable that
:::  contains the source path.
:::
:::  If the first argument is /?, then print this help to stdout.
:::
:::  The returned ERROLEVEL is 0 upon success, 1 if failure.
:::
:::  jLongPath.bat version 1.0 was written by Dave Benham
:::

::----------- Batch Code-----------------
@echo off
setlocal disableDelayedExpansion
if /i "%~1" equ "/?" (
  for /f "tokens=* delims=:" %%A in ('findstr "^:::" "%~f0"') do @echo(%%A
  exit /b 0
)
if /i "%~1" equ "/V" shift /1
(
  for /f "delims=* tokens=1,2" %%A in (
    'cscript //E:JScript //nologo "%~f0" %*'
  ) do if "%~2" equ "" (echo %%A) else (
    endlocal
    if "!!" equ "" (set "%~2=%%B" !) else set "%~2=%%A"
  )
) || exit /b 1
exit /b 0

------------ JScript Code---------------*/
try {
  var shortcut = WScript.CreateObject("WScript.Shell").CreateShortcut("dummy.lnk"),
      fso = new ActiveXObject("Scripting.FileSystemObject"),
      path=WScript.Arguments(0),
      folder='';
  if (path.toUpperCase()=='/V') {
    var env=WScript.CreateObject("WScript.Shell").Environment("Process");
    path=env(WScript.Arguments(1));
  }
  try {
    shortcut.TargetPath = fso.GetFile(path);
  }
  catch(e) {
    shortcut.TargetPath = fso.GetFolder(path);
    folder='\\'
  }
  var rtn = shortcut.TargetPath+folder+'*';
  WScript.StdOut.WriteLine( rtn + rtn.replace(/\^/g,'^^').replace(/!/g,'^!') );
}
catch(e) {
  WScript.StdErr.WriteLine(
    (e.number==-2146828283) ? 'Path not found' :
    (e.number==-2146828279) ? 'Missing path argument - Use jLongPath /? for help.' :
    e.message
  );
}


longPath.bat - pure batch processing

:::
:::longPath  [/V]  SrcPath  [RtnVar]
:::longPath  /?
:::
:::  Determine the absolute long-name path of source path SrcPath
:::  and return the result in variable RtnVar.
:::
:::  If RtnVar is not specified, then print the result to stderr.
:::
:::  If option /V is specified, then SrcPath is a variable that
:::  contains the source path.
:::
:::  If the first argument is /?, then prints this help to stdout.
:::
:::  The returned ERROLEVEL is 0 upon success, 1 if failure.
:::
:::  longPath.bat version 1.0 was written by Dave Benham
:::
@echo off
setlocal disableDelayedExpansion

:: Load arguments
if "%~1" equ "" goto :noPath
if "%~1" equ "/?" (
  for /f "tokens=* delims=:" %%A in ('findstr "^:::" "%~f0"') do @echo(%%A
  exit /b 0
)
if /i "%~1" equ "/V" (
  setlocal enableDelayedExpansion
  if "%~2" equ "" goto :noPath
  if not defined %~2!! goto :notFound
  for /f "eol=: delims=" %%F in ("!%~2!") do (
    endlocal
    set "sourcePath=%%~fF"
    set "test=%%F"
  )
  shift /1
) else (
  set "sourcePath=%~f1"
  set "test=%~1"
)

:: Validate path
if "%test:**=%" neq "%test%" goto :notFound
if "%test:?=%"  neq "%test%" goto :notFound
if not exist "%test%" goto :notFound

:: Resolve file name, if present
set "returnPath="
if not exist "%sourcePath%\*" (
  for /f "eol=: delims=" %%F in ('dir /b "%sourcePath%"') do set "returnPath=%%~nxF"
  set "sourcePath=%sourcePath%\.."
)

:resolvePath :: one folder at a time
for /f "delims=* tokens=1,2" %%R in (^""%returnPath%"*"%sourcePath%"^") do (
  if "%%~nxS" equ "" for %%P in ("%%~fS%%~R") do (
    if "%~2" equ "" (
      echo %%~P
      exit /b 0
    )
    set "returnPath=%%~P"
    goto :return
  )
  for %%P in ("%%~S\..") do (
    for /f "delims=> tokens=2" %%A in (
      'dir /ad /x "%%~fP"^|findstr /c:">          %%~nxS "'
    ) do for /f "tokens=1*" %%B in ("%%A") do set "returnPath=%%C\%%~R"
  ) || set "returnPath=%%~nxS\%%~R"
  set "sourcePath=%%~dpS."
)
goto :resolvePath

:return
set "delayedPath=%returnPath:^=^^%"
set "delayedPath=%delayedPath:!=^!%"
for /f "delims=* tokens=1,2" %%A in ("%delayedPath%*%returnPath%") do (
  endlocal
  if "!!" equ "" (set "%~2=%%A" !) else set "%~2=%%B"
  exit /b 0
)

:noPath
>&2 echo Missing path argument - Use longPath /? for help.
exit /b 1

:notFound
>&2 echo Path not found
exit /b 1

Related


How to convert short date to long date in windows batch file?

Samuel Finney I've been searching on various sites to convert a date string Dec17to December2017, Jul18using July2018a Windows batch file. But I can't find the exact command that meets this requirement. How to convert short date to long date in windows batch f

How to convert short date to long date in windows batch file?

Samuel Finney I've been searching on various sites to convert a date string Dec17to December2017, Jul18using July2018a Windows batch file. But I can't find the exact command that meets this requirement. How to convert short date to long date in windows batch f

How to convert short date to long date in windows batch file?

Samuel Finney I've been searching on various sites to convert a date string Dec17to December2017, Jul18using July2018a Windows batch file. But I can't find the exact command that meets this requirement. How to convert short date to long date in windows batch f

How to convert short date to long date in windows batch file?

Samuel Finney I've been searching on various sites to convert a date string Dec17to December2017, Jul18using July2018a Windows batch file. But I can't find the exact command that meets this requirement. How to convert short date to long date in windows batch f

How to convert short date to long date in windows batch file?

Samuel Finney I've been searching on various sites to convert a date string Dec17to December2017, Jul18using July2018a Windows batch file. But I can't find the exact command that meets this requirement. How to convert short date to long date in windows batch f

How to convert short date to long date in windows batch file?

Samuel Finney I've been searching on various sites to convert a date string Dec17to December2017, Jul18using July2018a Windows batch file. But I can't find the exact command that meets this requirement. How to convert short date to long date in windows batch f

How to convert short date to long date in windows batch file?

Samuel Finney I've been searching on various sites to convert a date string Dec17to December2017, Jul18using July2018a Windows batch file. But I can't find the exact command that meets this requirement. How to convert short date to long date in windows batch f

How to convert short date to long date in windows batch file?

Samuel Finney I've been searching on various sites to convert a date string Dec17to December2017, Jul18using July2018a Windows batch file. But I can't find the exact command that meets this requirement. How to convert short date to long date in windows batch f

How to convert short date to long date in windows batch file?

Samuel Finney I've been searching on various sites to convert a date string Dec17to December2017, Jul18using July2018a Windows batch file. But I can't find the exact command that meets this requirement. How to convert short date to long date in windows batch f

How to convert short date to long date in windows batch file?

Samuel Finney I've been searching on various sites to convert a date string Dec17to December2017, Jul18using July2018a Windows batch file. But I can't find the exact command that meets this requirement. How to convert short date to long date in windows batch f

Pandas, convert long name date to short format

Jonny Boy I have a date input and want to convert it to short format. IE. August 2021arriveAug 2021 monthyear = input("Enter Month and Year: ") How to convert to its abbreviated version monthyearin Pandas ? What I have tried: smalldate = monthyear.strftime("%b

Windows short name doesn't match long name

R3d Chief I'm copying a list of files with a prefix (ie ABCD*) to match files in a batch script. However, some files that appeared to match were left behind, while others that didn't match were snatched away. I ran dir /X and found a handful of files whose sho

Windows short name doesn't match long name

R3d Chief I'm copying a list of files with a prefix (ie ABCD*) to match files in a batch script. However, some files that appeared to match were left behind, while others that didn't match were snatched away. I ran dir /X and found a handful of files whose sho

Split Elrang long name into short name and host

abyss I've needed this a few times, and I don't have a good solution nor have I found one. Split a full node name, for example: node() The form is as follows FullName = 'node_name@localhost' I want to split node name, hostname { 'node_name', 'localhost'} = s

Split Elrang long name into short name and host

abyss I've needed this a few times, and I don't have a good solution nor have I found one. Split a full node name, for example: node() The form is as follows FullName = 'node_name@localhost' I want to split node name, hostname { 'node_name', 'localhost'} = s

How to convert Windows ProductType to name?

Alex Dragokas The function returns as a numeric type parameter .GetProductInfo()pdwReturnedProductType Is there a function to convert this number to a name? Alternatively, can you suggest me a complete list of such product name constants? The MSDN article is m

How to convert Windows ProductType to name?

Alex Dragokas The function returns as a numeric type parameter .GetProductInfo()pdwReturnedProductType Is there a function to convert this number to a name? Alternatively, can you suggest me a complete list of such product name constants? The MSDN article is m

How to convert Windows ProductType to name?

Alex Dragokas The function returns as a numeric type parameter .GetProductInfo()pdwReturnedProductType Is there a function to convert this number to a name? Alternatively, can you suggest me a complete list of such product name constants? The MSDN article is m