How to Create a Mount Point for a Volume in Batch Script
When you run out of drive letters (there are only 26) or when you want to transparently expand a folder's capacity by placing it on a separate physical disk, you create a mount point. This is a folder on an existing drive that acts as a portal to another volume. For example, you can mount a 2 TB data disk at C:\Data\Archive\, making it appear to applications as if it's just a subfolder of your C: drive. The mountvol command creates these mappings, providing flexible storage expansion without changing any application paths.
This guide will explain how to create and manage mount points.
How Mount Points Work
Before mount point:
C:\Data\Archive\ → (empty folder on C: drive)
E:\ → (2 TB data disk, separate physical drive)
After mount point:
C:\Data\Archive\ → (portal to the 2 TB disk - E:'s content appears here)
E:\ → (same disk, now also accessible at C:\Data\Archive\)
The volume remains physically separate but is accessible through both its drive letter (if assigned) and the mount point folder. Applications reading from C:\Data\Archive\ are transparently redirected to the mounted volume.
Mount points created with mountvol are stored in the Windows registry and persist across reboots. You do not need to re-run the script after restarting the computer.
Method 1: Interactive Mount Point Creation
This method guides the user through identifying the target volume and creating the mount point with proper validation.
Implementation
@echo off
setlocal EnableDelayedExpansion
:: Verify admin privileges
net session >nul 2>&1
if errorlevel 1 (
echo [ERROR] Creating mount points requires administrator privileges. >&2
echo Right-click and select "Run as administrator." >&2
endlocal
exit /b 1
)
echo ============================================================
echo MOUNT POINT CREATION TOOL
echo ============================================================
echo.
:: =============================================
:: Step 1: Show available volumes
:: =============================================
echo [1/3] Available volumes:
echo.
powershell -NoProfile -Command ^
"$volumes = Get-CimInstance Win32_Volume | Where-Object {" ^
" $_.Capacity -gt 0 -and $_.FileSystem" ^
"};" ^
"$volumes | ForEach-Object {" ^
" $sizeGB = [math]::Round($_.Capacity / 1GB, 1);" ^
" $freeGB = [math]::Round($_.FreeSpace / 1GB, 1);" ^
" $mount = if ($_.DriveLetter) { $_.DriveLetter } else { '(no letter)' };" ^
" $label = if ($_.Label) { $_.Label } else { '-' };" ^
" [PSCustomObject]@{" ^
" Mount = $mount;" ^
" Label = $label;" ^
" FileSystem = $_.FileSystem;" ^
" 'Size GB' = $sizeGB;" ^
" 'Free GB' = $freeGB;" ^
" 'Volume GUID' = ($_.DeviceID -replace '\\\\\\?\\\\', '' -replace '\\\\$', '')" ^
" }" ^
"} | Format-Table -AutoSize"
echo [INFO] You need the Volume GUID of the volume you want to mount.
echo [INFO] Run "mountvol" to see the full GUID paths if not shown above.
echo.
:: =============================================
:: Step 2: Get inputs
:: =============================================
set /p "VolumeGUID=Enter Volume GUID (e.g., \\?\Volume{12345678-abcd-...}\): "
if "!VolumeGUID!"=="" (
echo [ERROR] No Volume GUID entered. >&2
endlocal
exit /b 1
)
:: Ensure trailing backslash
if not "!VolumeGUID:~-1!"=="\" set "VolumeGUID=!VolumeGUID!\"
echo.
set /p "MountPath=Enter mount folder path (e.g., C:\Data\Archive): "
if "!MountPath!"=="" (
echo [ERROR] No mount path entered. >&2
endlocal
exit /b 1
)
:: =============================================
:: Step 3: Validate and create
:: =============================================
:: Create the folder if it doesn't exist
if not exist "!MountPath!\" (
echo [INFO] Creating folder: !MountPath!
mkdir "!MountPath!"
if errorlevel 1 (
echo [ERROR] Could not create folder: !MountPath! >&2
endlocal
exit /b 1
)
)
:: Verify the folder is empty
set "FolderEmpty=TRUE"
for /f %%f in ('dir /a /b "!MountPath!\" 2^>nul') do set "FolderEmpty=FALSE"
if "!FolderEmpty!"=="FALSE" (
echo [ERROR] Folder "!MountPath!" is not empty. >&2
echo Mount points must use empty folders. Existing files would be hidden. >&2
endlocal
exit /b 1
)
:: Verify the volume GUID looks valid
echo !VolumeGUID! | findstr /r "\\\\?\\Volume{" >nul 2>&1
if errorlevel 1 (
echo [WARNING] Volume GUID doesn't match expected format. >&2
echo Expected: \\?\Volume{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}\ >&2
echo.
set /p "Proceed=Proceed anyway? (YES/no): "
if /i not "!Proceed!"=="YES" (
echo [INFO] Cancelled.
endlocal
exit /b 0
)
)
echo.
echo [INFO] Mount configuration:
echo Volume: !VolumeGUID!
echo Folder: !MountPath!
echo.
set /p "Confirm=Create this mount point? (YES/no): "
if /i not "!Confirm!"=="YES" (
echo [INFO] Cancelled. No changes made.
endlocal
exit /b 0
)
:: Create the mount point
echo [ACTION] Creating mount point...
mountvol "!MountPath!" !VolumeGUID!
if errorlevel 1 (
echo [ERROR] Mount point creation failed. >&2
echo Common causes: >&2
echo - Volume GUID is incorrect (copy from mountvol output^) >&2
echo - Volume is already mounted elsewhere >&2
echo - Folder is not on an NTFS volume >&2
endlocal
exit /b 1
)
:: Verify the mount point works
if exist "!MountPath!\" (
echo [OK] Mount point created successfully.
echo [OK] "!MountPath!" now points to the target volume.
echo.
:: Show the mounted volume's space
powershell -NoProfile -Command ^
"$vol = Get-CimInstance Win32_Volume | Where-Object { $_.Name -eq '!MountPath!\' };" ^
"if ($vol) {" ^
" Write-Host \" Total: $([math]::Round($vol.Capacity / 1GB, 1)) GB\";" ^
" Write-Host \" Free: $([math]::Round($vol.FreeSpace / 1GB, 1)) GB\"" ^
"}"
) else (
echo [WARNING] Mount command completed but the folder may not be accessible yet. >&2
echo Check Disk Management for details. >&2
)
:: Log the operation
for /f "delims=" %%t in (
'powershell -NoProfile -Command "Get-Date -Format ''yyyy-MM-dd HH:mm:ss''"'
) do echo [%%t] MOUNT: !VolumeGUID! at !MountPath! by %USERNAME% on %COMPUTERNAME% >> "%~dp0mount_operations.log"
endlocal
exit /b 0
Identifying the correct Volume GUID:
The Volume GUID is the \\?\Volume{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}\ path that uniquely identifies a volume. There are two ways to find it:
-
From
mountvoloutput: Runmountvolwith no arguments. Each volume's GUID is displayed above its current mount path (drive letter or folder). -
From PowerShell:
Get-CimInstance Win32_Volume | Select-Object DriveLetter, Label, DeviceID | Format-List
The Volume GUID must include the \\?\Volume{ prefix and a trailing backslash (\). Example:
\\?\Volume{12345678-abcd-1234-abcd-1234567890ab}\
Copying this from mountvol output is the safest approach. Typing it manually almost always introduces errors.
Method 2: Scripted Mount Point Creation
For automation scenarios where the volume GUID and mount path are known in advance.
@echo off
setlocal
set "MountPath=%~1"
set "VolumeGUID=%~2"
if "%VolumeGUID%"=="" (
echo Usage: %~nx0 ^<mount_folder^> ^<volume_guid^>
echo.
echo Example:
echo %~nx0 C:\Data\Archive "\\?\Volume{12345678-abcd-1234-abcd-1234567890ab}\"
echo.
echo Run "mountvol" to find Volume GUIDs.
endlocal
exit /b 1
)
net session >nul 2>&1
if errorlevel 1 (
echo [ERROR] Administrator privileges required. >&2
endlocal
exit /b 1
)
:: Ensure trailing backslash on GUID
if not "%VolumeGUID:~-1%"=="\" set "VolumeGUID=%VolumeGUID%\"
:: Create the folder if needed
if not exist "%MountPath%\" (
mkdir "%MountPath%"
if errorlevel 1 (
echo [ERROR] Could not create folder: %MountPath% >&2
endlocal
exit /b 1
)
)
:: Verify folder is empty
dir /a /b "%MountPath%\" 2>nul | findstr "." >nul
if not errorlevel 1 (
echo [ERROR] Folder "%MountPath%" is not empty. Mount points require empty folders. >&2
endlocal
exit /b 1
)
:: Create the mount point
echo [ACTION] Mounting volume at %MountPath%...
mountvol "%MountPath%" %VolumeGUID%
if errorlevel 1 (
echo [ERROR] Mount point creation failed. >&2
endlocal
exit /b 1
)
echo [OK] Mount point created: %MountPath%
:: Log
for /f "delims=" %%t in (
'powershell -NoProfile -Command "Get-Date -Format ''yyyy-MM-dd HH:mm:ss''"'
) do echo [%%t] MOUNT: %VolumeGUID% at %MountPath% by %USERNAME% >> "%~dp0mount_operations.log"
endlocal
exit /b 0
Method 3: Remove a Mount Point
This detaches the volume from the folder. The data on the volume is NOT deleted: the volume simply loses its folder-based access path and can be reassigned a drive letter or mounted elsewhere.
@echo off
setlocal
set "MountPath=%~1"
if "%MountPath%"=="" (
echo Usage: %~nx0 ^<mount_folder_path^>
echo.
echo Removes a mount point. The volume's data is NOT deleted.
echo.
echo Example: %~nx0 C:\Data\Archive
endlocal
exit /b 1
)
net session >nul 2>&1
if errorlevel 1 (
echo [ERROR] Administrator privileges required. >&2
endlocal
exit /b 1
)
:: Verify the path exists and is a mount point
if not exist "%MountPath%\" (
echo [ERROR] Path does not exist: %MountPath% >&2
endlocal
exit /b 1
)
:: Check if it's actually a mount point (has a different volume than its parent)
powershell -NoProfile -Command ^
"$vol = Get-CimInstance Win32_Volume | Where-Object { $_.Name -eq '%MountPath%\' };" ^
"if (-not $vol) { exit 1 } else { exit 0 }" >nul 2>&1
if errorlevel 1 (
echo [WARNING] "%MountPath%" does not appear to be a mount point. >&2
echo It may be a regular folder. Proceed with caution. >&2
echo.
set /p "Confirm=Remove anyway? (YES/no): "
if /i not "!Confirm!"=="YES" (
echo [INFO] Cancelled.
endlocal
exit /b 0
)
)
echo [ACTION] Removing mount point: %MountPath%
mountvol "%MountPath%" /d
if errorlevel 1 (
echo [ERROR] Failed to remove mount point. >&2
echo The volume may be in use. Close any programs using files at this path. >&2
endlocal
exit /b 1
)
echo [OK] Mount point removed. The folder is now empty.
echo [INFO] The volume's data is preserved: it can be reassigned a drive letter
echo or mounted to a different folder.
:: Log
for /f "delims=" %%t in (
'powershell -NoProfile -Command "Get-Date -Format ''yyyy-MM-dd HH:mm:ss''"'
) do echo [%%t] UNMOUNT: %MountPath% by %USERNAME% on %COMPUTERNAME% >> "%~dp0mount_operations.log"
endlocal
exit /b 0
The volume still exists but may have no access path. To assign it a drive letter:
:: In DiskPart
select volume [number]
assign letter=E
Or mount it to a different folder:
mountvol "C:\NewLocation\" \\?\Volume{guid}\
Method 4: Mount Point Setup for Server Provisioning
For server deployments where a standardized mount point layout is needed, for example, mounting separate disks for SQL data, logs, and backups at predefined paths.
@echo off
setlocal EnableDelayedExpansion
net session >nul 2>&1
if errorlevel 1 (
echo [ERROR] Administrator privileges required. >&2
endlocal
exit /b 1
)
echo ============================================================
echo SERVER MOUNT POINT PROVISIONING
echo ============================================================
echo.
:: =============================================
:: Define the mount point layout
:: Format: FolderPath|VolumeLabel
:: The script finds the volume by its label
:: =============================================
set "Mount[0]=C:\SQLData|SQLData"
set "Mount[1]=C:\SQLLogs|SQLLogs"
set "Mount[2]=C:\Backups|BackupVol"
set "MountCount=3"
set "Succeeded=0"
set "Failed=0"
for /L %%i in (0, 1, 2) do (
for /f "tokens=1-2 delims=|" %%a in ("!Mount[%%i]!") do (
set "Folder=%%a"
set "Label=%%b"
echo [INFO] Mounting volume "!Label!" at !Folder!...
:: Find the volume GUID by label
set "GUID="
for /f "delims=" %%g in (
'powershell -NoProfile -Command ^
"$vol = Get-CimInstance Win32_Volume | Where-Object { $_.Label -eq ''!Label!'' };" ^
"if ($vol) { $vol.DeviceID } else { Write-Output ''NOT_FOUND'' }"'
) do set "GUID=%%g"
if "!GUID!"=="NOT_FOUND" (
echo [SKIP] Volume with label "!Label!" not found.
set /a "Failed+=1"
) else (
:: Create folder if needed
if not exist "!Folder!\" mkdir "!Folder!"
:: Check if already mounted here
powershell -NoProfile -Command ^
"$v = Get-CimInstance Win32_Volume | Where-Object { $_.Name -eq '!Folder!\' };" ^
"if ($v) { exit 0 } else { exit 1 }" >nul 2>&1
if not errorlevel 1 (
echo [SKIP] !Folder! already has a mount point.
set /a "Succeeded+=1"
) else (
mountvol "!Folder!" !GUID!
if not errorlevel 1 (
echo [OK] Mounted at !Folder!
set /a "Succeeded+=1"
) else (
echo [FAIL] Could not mount at !Folder!
set /a "Failed+=1"
)
)
)
echo.
)
)
echo ============================================================
echo Results: !Succeeded! mounted, !Failed! failed
echo ============================================================
:: Log
for /f "delims=" %%t in (
'powershell -NoProfile -Command "Get-Date -Format ''yyyy-MM-dd HH:mm:ss''"'
) do echo [%%t] PROVISION: !Succeeded! mounted, !Failed! failed on %COMPUTERNAME% by %USERNAME% >> "%~dp0mount_operations.log"
endlocal
exit /b 0
Why identify volumes by label instead of GUID:
GUIDs are unique to each system, a script with hardcoded GUIDs won't work on another server. Volume labels (set during formatting with format /v:SQLData) are human-readable and can be standardized across your fleet. The provisioning script finds the correct volume by its label, making it portable across servers that use the same labeling convention.
Server provisioning workflow:
- Initialize and format the disks with descriptive labels:
format D: /fs:ntfs /v:SQLData /a:65536 /q - Remove the drive letters (optional):
mountvol D: /P - Run the provisioning script to mount each labeled volume at its designated path.
How to Avoid Common Errors
Wrong Way: Mounting to a Non-Empty Folder
:: HIDES EXISTING FILES - they become invisible until unmount
mountvol "C:\Users\Downloads\" \\?\Volume{...}\
Any files already in the folder are hidden (not deleted) when a volume is mounted on top. Users lose access to the original files until the mount point is removed.
Correct Way: Always mount to an empty, dedicated folder. All methods in this guide verify the folder is empty before mounting.
Problem: "The Parameter Is Incorrect"
This almost always means the Volume GUID is malformed. Common mistakes:
- Missing
\\?\Volume{prefix - Missing trailing backslash
- Typo in the hex digits
- Copied from a different computer (GUIDs are unique per system)
Solution: Copy the GUID directly from mountvol output. Do not type it manually.
Problem: Mount Point Folder Must Be on NTFS
Mount points can only be created on NTFS volumes. The target folder (e.g., C:\Data\Archive) must reside on an NTFS-formatted drive. FAT32 and exFAT do not support mount points.
Solution: Verify the parent drive's file system before creating the mount point:
powershell -NoProfile -Command "(Get-Volume -DriveLetter C).FileSystemType"
Problem: Volume Already Mounted Elsewhere
A volume can have multiple access paths (a drive letter AND a mount point), but attempting to mount a volume that is already mounted to the same folder produces an error.
Solution: Method 4 checks for existing mount points before attempting to create new ones.
Problem: Programs Holding Open File Handles
Removing a mount point while programs have files open at that path may fail or cause those programs to lose access to their files.
Solution: Close all programs using files at the mount point path before removing it. Check for open handles with:
powershell -NoProfile -Command "Get-Process | Where-Object { $_.Modules.FileName -like 'C:\Data\Archive\*' }"
Best Practices and Rules
1. Always Mount to Empty, Dedicated Folders
Create a folder specifically for the mount point. Never mount to a folder that already contains data, the existing files become invisible.
2. Use Descriptive Folder Names
Name mount point folders to reflect their purpose: C:\SQLData, C:\Backups\NightlyBackup, C:\Data\VideoArchive. This makes the storage topology self-documenting.
3. Document the Mount Point Layout
Maintain a record of which volumes are mounted where, especially on servers. If the server needs to be rebuilt, the mount points must be recreated in the correct order. Log every mount and unmount operation (all methods include logging).
4. Monitor Space on Mounted Volumes Separately
Mount points make a separate disk look like a subfolder. Standard disk space checks on the parent drive won't reflect the mounted volume's space. Use Get-CimInstance Win32_Volume or Get-Volume to check space on each mounted volume independently.
5. Standardize Volume Labels for Fleet Provisioning
If you deploy the same mount point layout across multiple servers, use consistent volume labels (e.g., SQLData, SQLLogs, BackupVol) and the label-based provisioning approach (Method 4) for portable automation.
6. Use Mount Points When Drive Letters Are Exhausted
Windows has 26 drive letters. Servers with many volumes, SAN LUNs, or iSCSI targets can exhaust this limit. Mount points provide unlimited additional access paths without consuming letters.
Conclusions
Creating mount points provides elegant, transparent storage expansion that applications never need to know about. By mounting volumes to dedicated folders with proper validation, empty-folder checks, GUID verification, existing-mount detection, and operation logging, you build scalable storage architectures that go beyond the 26-letter limit. For server provisioning, label-based volume identification makes the process portable across machines, enabling standardized deployment workflows.