8

I am using Ubuntu with WSL with a zsh/bash shell. My host OS is Windows 10. I already figured out how to mount a Windows external drive:

sudo mkdir /mnt/d
sudo mount -t drvfs D: /mnt/d

I rarely plug this drive in, so I'd like to automatically mount it when I do. It's fine if this occurs after I plug the drive in, then start a new WSL terminal.

I don't want to put this command in a .bashrc type of file because having to type in my password every time I open a terminal would be more trouble than it's worth, especially if 99% of the time, the command will fail anyway. Putting it in a bash script won't help either, because I'd run it so infrequently, by the time I need to use it, I'll forget I created it in the first place.

So, is there a way to mount an external drive when it becomes available in WSL?


I don't know if this is a good solution, but this tells you how to turn off the password request for sudo. This is the route I took: https://superuser.com/a/1492456/89165

2
  • @NotTheDr01ds Windows 10 (note the 2nd sentence). Commented Jul 29, 2022 at 22:42
  • Oops! Scanned it twice, but missed it both times. Thanks! I think I can still come up with something that should work for you on Win 10, but I'll need to noodle on it a bit. Commented Jul 30, 2022 at 0:00

3 Answers 3

7

It looks to me like this will need two different approachs:

  • First we need to handle the case when WSL starts up while the drive is already attached.
  • And we also need to handle the case when the drive is attached while WSL is already running.

Drive already attached when WSL starts

The first part should be pretty easy.

I don't want to put this command in a .bashrc type of file because having to type in my password every time I open a terminal

That's simple to overcome. Add the following to your ~/.bashrc instead:

wsl.exe -u root -e mount -t drvfs D: /mnt/d > /dev/null 2>&1

That will mount the drive if it's available. If not, it will silently fail.

Drive is attached while WSL is running

It's not easy, and it probably needs more error handling to be "robust", but I was able to get this to work by creating a PowerShell script to:

  • Register an action when a USB drive is attached
  • Run wsl -u root -e mount -t drvfs /mnt/<driveletter> <Drive> when the event fires.
$query = "select * from __InstanceCreationEvent within 5 where TargetInstance ISA 'Win32_LogicalDisk' and TargetInstance.DriveType = 2"

$action = {
    $drivePath = $event.SourceEventArgs.NewEvent.TargetInstance.Name
    $driveLetter = $drivePath.ToLower()[0]
    wsl -u root -e mount -t drvfs $drivePath /mnt/$driveLetter
}

Register-WmiEvent -Query $Query -Action $Action -SourceIdentifier USBFlashDriveWSLMount

Note that this needs to run in Windows PowerShell (rather than PowerShell Core) since it uses WMIEvent. I'm sure there's a PowerShell Core equivalent using CIM, but I haven't tried it that way yet.

If you run into a problem, check the output. From PowerShell:

Get-Job
# Get the Id of the job then
Receive-Job <job_id>

In theory, you can set this script to run at Windows Login via Task Scheduler, but I haven't tried it. I'm 80% confident it will work. You'll need to call it through the powershell command (not pwsh since it uses WMIEvent).

Note, there's also apparently a way to register the event listener permanently though CIM. I spent some time on this last week, but got rabbit-trailed when I followed some documentation that created a CIM class on my system that I couldn't get rid of. I may come back to it eventually, but hopefully this works for you as a Scheduled Task. I just didn't want to hold off posting until I got it "just right", because I might never finish it up.

10
  • Still on the first paragraph, but "And we also need to handle the case when the drive is attached while WSL is already running" isn't a requirement for me, just a nice to have. Commented Aug 9, 2022 at 21:11
  • @DanielKaplan Excellent - Then that should make it pretty easy! Commented Aug 9, 2022 at 21:12
  • @DanielKaplan And while I'm thinking about it (since I just answered another related question), see this Ask Ubuntu answer for a slight tweak on the mount command. Commented Aug 9, 2022 at 21:13
  • I just tried this and it didn't work. It errors, saying User not found. Commented Aug 19, 2022 at 4:55
  • @DanielKaplan Hmm - You mean the wsl.exe -u root part? What happens if you run wsl -u root without the rest of it? I would expect that to essentially be the same as sudo -s, but without requiring a password. Commented Aug 19, 2022 at 19:24
1

This 1 liner will remove password request for sudo.

sudo sed -i 's|^%sudo.*$|%sudo    ALL=(ALL:ALL) NOPASSWD: ALL|' -i /etc/sudoers

This 1 liner will list drives not mounted.

echo -e "$(cmd.exe /C "wmic logicaldisk get name" 2>/dev/null | sed '1d;$d')\n$(mount | grep drvfs | sed 's|\(^.:\).*|\1|')" | tr '\r' ' ' |sed 's| ||g' | sort | uniq -u

Therefore we can define a function in ~/.bashrc or create a bash script to mount them. It is up to you if you call the function manually or add it to ~/.bashrc

mountext(){ # Find unmounted windows drives and mount them.
    ds=$(echo -e "$(cmd.exe /C "wmic logicaldisk get name" 2>/dev/null | sed '1d;$d')\n$(mount | grep drvfs | sed 's|\(^.:\).*|\1|')" | tr '\r' ' ' |sed 's| ||g' | sort | uniq -u | cut -c1)
    if [ ! $ds = $'\n' ] || [ ! -z "${ds}" ]; then
        for d in $ds; do
        sudo bash -c "mkdir -p /mnt/${d,} && mount -t drvfs ${d}: /mnt/${d,}"
        echo "Mounted drive ${d}: at /mnt/${d,}." 
        done
        else echo "No drives to mount."
    fi
}
2
  • despite the message bash: [: too many arguments using mountext only, my drives get mounted Commented Mar 29 at 13:15
  • despite the message bash: [: too many arguments (some quotes may be missing somewhere) using mountext only, mounts al my drives. thanks Commented Mar 29 at 14:37
1

This command:

cmd.exe /C "wmic logicaldisk get name"

will show network mounts as well as drive letters that don't actually have media loaded. For example, I have a multiformat memory card reader that reserves five drive letters (one for each slot, e.g., SD, micro-SD, etc.), all of which are returned by this query even if no card is mounted. So I use the following to obtain local drive letters that have media in them:

powershell.exe -Command "gdr -PSProvider 'FileSystem'"|grep '[0-9]\+'|grep -o '[A-Z]:'

Assuming you have powershell.exe in your path and are running as sudo.

The first grep statement selects lines in the list of filesystems that show space available (i.e. a proxy for mounted media); the second grep just pulls out the drive letter at the end. You should be able to feed the output of this into the same script provided above for mounting as drvfs in WSL.

To put it all together, you could run this as a cronjob as root:

#!/bin/bash
ds=$(echo -e "$(powershell -Command "gdr -PSProvider 'FileSystem'"|grep '[0-9]\+'|grep -o '[A-Z]:' 2>/dev/null | sed '1d;$d')\n$(mount | grep drvfs | sed 's|\(^.:\).*|\1|')" | tr '\r' ' ' |sed 's| ||g' | sort | uniq -u | cut -c1)
if [ ! $ds = $'\n' ] || [ ! -z "${ds}" ]; then
  for d in $ds; do
    bash -c "mkdir -p /mnt/${d,} && mount -t drvfs ${d}: /mnt/${d,}"
    echo "Mounted drive ${d}: at /mnt/${d,}."
  done
else echo "No drives to mount."
fi
0

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .