copy path to Windows file or directory with automagic conversion to Linux mountpoint
On a day-to-day basis, I’m working in Windows and Linux on various physical and virtual machines on my network, but no matter where I am, I’m usually in VS Code. I love Code’s extensions and integrated terminal, and it’s plenty enough IDE for me to get real work done in Python no matter which ecosystem I happen to be in. My favorite little timesaver in VS Code these days is right-clicking in the Explorer pane to “Copy path” for a file or directory. This small feature sparks a lot of joy for me!
Of course Windows Explorer has a similar feature: if you hold down Shift while you right-click, you can “Copy as path” to get the absolute path.
But for a while I had a very specific pain point when copying paths in Windows. At least a few times a week I’m in the situation where I’m using both Windows and Linux machines to work on the same set of files on one of my NASes. On Windows, my NASes are the Y: and Z: drives. On all my Linux containers and VMs, they’re /mnt/shalom-share-1 and /mnt/synology, respectively. It was a growing annoyance to copy a path on Windows and have to manually alter it so I could have the corresponding /mnt path to use in my bash script or .conf file or whatnot on Linux.
At last, enough was enough, and last week I wrote a couple of registry entries to supplement Windows Explorer’s “Copy as path” feature. I named them, imaginatively enough, “Copy as path (/mnt).” They let me right-click on a file or directory on a network drive from Windows, but what gets saved to the clipboard is the /mnt version of the path. A little inline PowerShell changes the drive letter to the mountpoint and reverses the slashes.
See below for the .reg file, and it’s very straightforward if anyone wanted to modify it for their own network purposes.
Windows Registry Editor Version 5.00
[HKEY_CLASSES_ROOT\*\shell\CopyLinuxPathToFile]
@="Copy as path (/mnt)"
"Icon"="imageres.dll,-5302"
[HKEY_CLASSES_ROOT\*\shell\CopyLinuxPathToFile\command]
@="powershell.exe -NoProfile -ExecutionPolicy Bypass -Command \"$driveMap = @{ 'Y:'='/mnt/shalom-share-1'; 'Z:'='/mnt/synology' }; $path = '%1'; $drive = $path.Substring(0, 2); if ($driveMap.ContainsKey($drive)) { $path = $path.Replace($drive + '\\', $driveMap[$drive] + '/').Replace('\\', '/'); $path | Set-Clipboard; } else { \\\"no /mnt path available\\\" | Set-Clipboard; } \""
[HKEY_CLASSES_ROOT\Directory\shell\CopyLinuxPathToDir]
@="Copy as path (/mnt)"
"Icon"="imageres.dll,-5302"
[HKEY_CLASSES_ROOT\Directory\shell\CopyLinuxPathToDir\command]
@="powershell.exe -NoProfile -ExecutionPolicy Bypass -Command \"$driveMap = @{ 'Y:'='/mnt/shalom-share-1'; 'Z:'='/mnt/synology' }; $path = '%1'; $drive = $path.Substring(0, 2); if ($driveMap.ContainsKey($drive)) { $path = $path.Replace($drive + '\\', $driveMap[$drive] + '/').Replace('\\', '/'); $path | Set-Clipboard; } else { \\\"no /mnt path available\\\" | Set-Clipboard; } \""
There were a couple of design decisions along the way. Should spaces on the Windows side be escaped during the conversion to the /mnt path? (I decided I wanted the cleaner-looking string. I can always enclose it in quotes on the Linux side.) Should I signal to the user when a /mnt path isn’t available? (I decided to put the error in the clipboard when a Windows path has no /mnt equivalent.)
The two trickiest bits were nesting and escaping the quotation marks correctly and picking out the icon.
The inline PowerShell reminded me of the time I put a Python script into a heredoc so I could execute it from bash.
Ideas for possible future improvements:
- Rather than creating/customizing the .reg file itself, another idea would be to write a PowerShell script that accepted drive letter and mountpoint pairs and programmatically created the requisite .reg file. That, or the drive letter/mountpoint pairs could be pulled from a config file.
- Riding on the preceding idea of having a PowerShell script create the .reg file, the .ps1 management script could add new pairs (or remove existing ones) of drive letters/mountpoints by first reading in the existing pairs from the registry file. (This might be verging on overkill though.)