Skip to content

Commit c791558

Browse files
committed
is_removable: make work on Windows with USB drives too
1 parent 88af186 commit c791558

File tree

4 files changed

+70
-6
lines changed

4 files changed

+70
-6
lines changed

+stdlib/+sys/isRemovableDrive.ps1

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
function IsRemovableDrive {
2+
# Detect USB flash drive or CD / DVD drives
3+
# If the DVD drive is empty (no media), returns false
4+
[CmdletBinding()]
5+
param (
6+
# Expects only a single letter (e.g., 'D' or 'E').
7+
[Parameter(Mandatory=$true, Position=0)]
8+
[ValidatePattern('^[a-zA-Z]$')]
9+
[string]$DriveLetter
10+
)
11+
12+
# Format the letter into the 'D:' format.
13+
$deviceID = "${DriveLetter}:"
14+
15+
try {
16+
17+
$logicalDisk = Get-CimInstance -ClassName Win32_LogicalDisk -Filter "DeviceID='$deviceID'" -ErrorAction Stop
18+
19+
# Write-Host $logicalDisk
20+
21+
if ($logicalDisk.DriveType -eq 5) { return $true } # CD-ROM drive
22+
23+
$partition = $logicalDisk |
24+
Get-CimAssociatedInstance -Association Win32_LogicalDiskToPartition
25+
26+
# Write-Host $partition
27+
28+
$physicalDisk = $partition |
29+
Get-CimAssociatedInstance -Association Win32_DiskDriveToDiskPartition -ErrorAction Stop
30+
31+
# Write-Host $physicalDisk
32+
# Write-Host "InterfaceType: $($physicalDisk.InterfaceType)"
33+
34+
return ($null -ne $physicalDisk) -and ($physicalDisk.InterfaceType -eq 'USB')
35+
}
36+
catch {
37+
return $false
38+
}
39+
}

+stdlib/+sys/is_removable.m

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,20 @@
1+
%% SYS.IS_REMOVABLE
2+
13
function y = is_removable(filepath)
24

35
y = false;
46

57
if ispc()
6-
drive = stdlib.root_name(filepath);
7-
cmd1 = sprintf('wmic logicaldisk where "DeviceID=''%s''" get DriveType', drive);
8+
r = stdlib.root_name(filepath);
9+
if ~strlength(r), return, end
10+
r = extractBefore(r, 2);
11+
12+
psFile = fullfile(fileparts(mfilename('fullpath')), "isRemovableDrive.ps1");
13+
mustBeFile(psFile)
14+
15+
psCmd = sprintf(". '%s'; IsRemovableDrive -DriveLetter '%s'", psFile, r);
16+
17+
cmd1 = sprintf('powershell -ExecutionPolicy Bypass -Command "& {%s}"', psCmd);
818
else
919
cmd1 = sprintf('df "%s" | tail -n 1 | awk ''{print $1}''', filepath);
1020
end
@@ -17,8 +27,7 @@
1727

1828
if ispc()
1929

20-
y = any(ismember(strip(extractAfter(m1, "DriveType")), ["2", "5"]));
21-
% https://learn.microsoft.com/en-us/windows/win32/cimwin32prov/win32-logicaldisk
30+
y = contains(m1, "True");
2231

2332
elseif ismac()
2433

@@ -37,3 +46,19 @@
3746
end
3847

3948
end
49+
50+
% We use Powershell .ps1 function because:
51+
%
52+
% drive = stdlib.root_name(filepath);
53+
% WMIC is not available on all systems e.g. GA windows-2025 runner image
54+
% WMIC doesn't detect USB flash drives -- it sees them as Fixed drives
55+
% cmd1 = sprintf('wmic logicaldisk where "DeviceID=''%s''" get DriveType', drive);
56+
%
57+
% (Get-Volume -DriveLetter H).DriveType also detects USB thumb drives as Fixed like HDD
58+
%
59+
% Get-WmiObject also sees USB as type 3 fixed disk
60+
% cmd1 = sprintf('pwsh -c "Get-WmiObject Win32_LogicalDisk -Filter ''DeviceID=''%s'''' | Select-Object -ExpandProperty DriveType"', drive);
61+
62+
63+
% WMIC: y = any(ismember(strip(extractAfter(m1, "DriveType")), ["2", "5"]));
64+
% https://learn.microsoft.com/en-us/windows/win32/cimwin32prov/win32-logicaldisk

+stdlib/+sys/read_symlink.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
if isunix()
88
cmd = sprintf('readlink -fn "%s"', p);
99
else
10-
cmd = sprintf('pwsh -command "(Get-Item -Path %s).Target"', p);
10+
cmd = sprintf('pwsh -c "(Get-Item -Path %s).Target"', p);
1111
end
1212

1313
[s, m] = system(cmd);

+stdlib/+sys/set_modtime.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
if ~isfile(file), return, end
66

77
if ispc()
8-
cmd = sprintf('pwsh -Command "(Get-Item ''%s'').LastWriteTime = ''%s''"', file, string(dt, "yyyy-MM-dd HH:mm:ss"));
8+
cmd = sprintf('pwsh -c "(Get-Item ''%s'').LastWriteTime = ''%s''"', file, string(dt, "yyyy-MM-dd HH:mm:ss"));
99
elseif ismac()
1010
cmd = sprintf("touch -mt %s %s", string(dt, "yyyyMMddHHmm"), file);
1111
else

0 commit comments

Comments
 (0)