How to Extract Metadata (EXIF, Properties) from a File in Batch Script
Extracting metadata, such as the "Date Taken" from a photograph (EXIF data), the "Author" of a Word document, or the "Bitrate" of an MP3 file, is invaluable for automated file sorting and archiving. Batch scripts do not natively decode file headers. However, Windows has a built-in mechanism via PowerShell and the Shell.Application COM object to read file properties.
In this guide, we will demonstrate how to extract metadata from files using a PowerShell bridge.
Method 1: The PowerShell Bridge (Shell COM Object)
The Windows Shell indexes files and exposes hundreds of properties. By calling the Shell.Application namespace via PowerShell from your Batch script, you can retrieve any attribute.
Implementation Script
@echo off
setlocal enabledelayedexpansion
:: Target File Details
set "targetFolder=C:\Users\Public\Pictures"
set "targetFile=vacation.jpg"
:: Check if file exists
if not exist "!targetFolder!\!targetFile!" (
echo [ERROR] File not found: !targetFolder!\!targetFile!
pause
exit /b 1
)
echo Extracting properties for: !targetFile!...
echo.
:: Extracting EXIF "Date Taken" (Property ID 12)
for /f "usebackq delims=" %%A in (`
powershell -NoProfile -Command ^
"$sh = New-Object -ComObject Shell.Application; " ^
"$folder = $sh.Namespace('!targetFolder!'); " ^
"$file = $folder.ParseName('!targetFile!'); " ^
"$val = $folder.GetDetailsOf($file, 12); " ^
"if ($val) { $val -replace '[^\x20-\x7E]','' } else { 'N/A' }"
`) do set "dateTaken=%%A"
:: Extracting Image "Dimensions" (Property ID 31)
for /f "usebackq delims=" %%A in (`
powershell -NoProfile -Command ^
"$sh = New-Object -ComObject Shell.Application; " ^
"$folder = $sh.Namespace('!targetFolder!'); " ^
"$file = $folder.ParseName('!targetFile!'); " ^
"$val = $folder.GetDetailsOf($file, 31); " ^
"if ($val) { $val -replace '[^\x20-\x7E]','' } else { 'N/A' }"
`) do set "dimensions=%%A"
echo ==========================================
echo DATE TAKEN: !dateTaken!
echo DIMENSIONS: !dimensions!
echo ==========================================
pause
The GetDetailsOf method returns localized strings that often contain invisible left-to-right marks (Unicode U+200E, U+200F). These characters are invisible in the console but cause failures when used in file renaming or string comparisons. The -replace '[^\x20-\x7E]','' filter strips all non-printable ASCII characters from the output.
Extracting Multiple Properties Efficiently
To avoid launching PowerShell multiple times (each call adds ~200–500ms overhead), extract all properties in a single call:
@echo off
setlocal enabledelayedexpansion
set "targetFolder=C:\Users\Public\Pictures"
set "targetFile=vacation.jpg"
if not exist "!targetFolder!\!targetFile!" (
echo [ERROR] File not found.
pause
exit /b 1
)
:: Extract multiple properties in a single PowerShell call
set "propIndex=0"
for /f "usebackq delims=" %%A in (`
powershell -NoProfile -Command ^
"$sh = New-Object -ComObject Shell.Application; " ^
"$folder = $sh.Namespace('!targetFolder!'); " ^
"$file = $folder.ParseName('!targetFile!'); " ^
"foreach ($id in @(0,1,2,3,4,12,31)) { " ^
" $name = $folder.GetDetailsOf($null, $id) -replace '[^\x20-\x7E]',''; " ^
" $val = $folder.GetDetailsOf($file, $id) -replace '[^\x20-\x7E]',''; " ^
" if (-not $val) { $val = 'N/A' }; " ^
" Write-Output \"$name=$val\" " ^
"}"
`) do (
echo %%A
)
pause
Property ID numbers can vary slightly between Windows versions. To list all available properties and their IDs for a given file, run this PowerShell command:
$sh = New-Object -ComObject Shell.Application
$folder = $sh.Namespace('C:\Your\Folder')
$file = $folder.ParseName('yourfile.jpg')
0..350 | ForEach-Object {
$name = $folder.GetDetailsOf($null, $_)
$val = $folder.GetDetailsOf($file, $_)
if ($val) { "$_`: $name = $val" }
}
Method 2: Basic File Properties (Native PowerShell)
If you only need basic file system properties (CreationTime, LastWriteTime, Length) instead of EXIF/Document properties, you don't need the COM object:
@echo off
setlocal enabledelayedexpansion
set "filePath=C:\Temp\document.txt"
if not exist "!filePath!" (
echo [ERROR] File not found: !filePath!
pause
exit /b 1
)
for /f "usebackq delims=" %%A in (`
powershell -NoProfile -Command "(Get-Item -LiteralPath '!filePath!').LastWriteTime.ToString('yyyy-MM-dd HH:mm:ss')"
`) do set "lastWrite=%%A"
for /f "usebackq delims=" %%A in (`
powershell -NoProfile -Command "(Get-Item -LiteralPath '!filePath!').Length"
`) do set "sizeBytes=%%A"
echo File Size: !sizeBytes! bytes
echo Last Modified: !lastWrite!
pause
-LiteralPath vs. -PathAlways use -LiteralPath instead of -Path when working with user-provided file paths. The -Path parameter interprets wildcard characters like [] and *, which causes errors for files with brackets in their names. -LiteralPath treats the path exactly as written.
Why Extract Metadata?
- Photo Organization: Automatically renaming
.jpgfiles to include their EXIF "Date Taken" (e.g.,2024-05-12_Image01.jpg) rather than the date they were copied to the disk. - Audio Archiving: Sorting MP3 files into folders based on the "Artist" or "Album" metadata rather than random filenames.
- Document Auditing: Extracting the true "Author" or "Company" tag embedded inside Word documents or PDFs.
Common Shell Property IDs
When using the Shell.Application COM object (Method 1), the property ID numbers vary slightly depending on the Windows version, but these are standard on Windows 10/11:
| ID | Property | File Types |
|---|---|---|
0 | Name | All |
1 | Size | All |
2 | Item type | All |
3 | Date modified | All |
4 | Date created | All |
12 | Date taken | Photos |
13 | Contributing artists | Audio |
14 | Album | Audio |
27 | Length (duration) | Video, Audio |
31 | Dimensions | Images |
Important Considerations
If a photo was downloaded from a social media site that strips EXIF data, or if a document was created without author information, the property will return an empty string. The scripts above substitute N/A for empty values. Always check for this placeholder before using extracted metadata in file operations:
if "!dateTaken!"=="N/A" (
echo [WARNING] No Date Taken metadata found. Using file creation date instead.
)
Each PowerShell invocation adds approximately 200–500ms of startup overhead. When extracting metadata from many files in a loop, use the batch extraction approach (single PowerShell call with multiple property IDs) or process all files within a single PowerShell session to avoid launching PowerShell hundreds of times.
Conclusion
Combining Batch logistics with PowerShell's Shell COM object enables robust metadata extraction. By reading EXIF data, audio tags, and document properties directly from the command line, you elevate your file management scripts from simple name-based sorters to intelligent, content-aware archivers. This capability is indispensable for digital asset management and automated organization.