Для решения этой задачи необходимо решить несколько проблем, чтобы получить букву диска (локального) жесткого диска с менее чем одним TiB (1 099 511 627 776 байт) свободным пространством, которое не является системный диск.
1. Кодировка символов WMI C вывод
WMI C выводит данные всегда с кодировкой UTF-16 Little Endian с меткой порядка байтов , сокращенно UTF-16LE + BOM .
Таким образом, вывод данных
Caption FreeSpace
A:
B: 1098552672256
C: 40824201216
D:
E: 1042498560000
F: 40222941184
является потоком байтов со смещением байта влево на :
и представлением ASCII вправо на ;
:
0000h: FF FE 43 00 61 00 70 00 74 00 69 00 6F 00 6E 00 ; ÿþC.a.p.t.i.o.n.
0010h: 20 00 20 00 46 00 72 00 65 00 65 00 53 00 70 00 ; . .F.r.e.e.S.p.
0020h: 61 00 63 00 65 00 20 00 20 00 20 00 20 00 20 00 ; a.c.e. . . . . .
0030h: 20 00 0D 00 0A 00 41 00 3A 00 20 00 20 00 20 00 ; .....A.:. . . .
0040h: 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00 ; . . . . . . . .
0050h: 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00 ; . . . . . . . .
0060h: 20 00 20 00 20 00 0D 00 0A 00 42 00 3A 00 20 00 ; . . .....B.:. .
0070h: 20 00 20 00 20 00 20 00 20 00 20 00 31 00 30 00 ; . . . . . .1.0.
0080h: 39 00 38 00 35 00 35 00 32 00 36 00 37 00 32 00 ; 9.8.5.5.2.6.7.2.
0090h: 32 00 35 00 36 00 20 00 20 00 0D 00 0A 00 43 00 ; 2.5.6. . .....C.
00a0h: 3A 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00 ; :. . . . . . . .
00b0h: 34 00 30 00 38 00 32 00 34 00 32 00 30 00 31 00 ; 4.0.8.2.4.2.0.1.
00c0h: 32 00 31 00 36 00 20 00 20 00 20 00 20 00 0D 00 ; 2.1.6. . . . ...
00d0h: 0A 00 44 00 3A 00 20 00 20 00 20 00 20 00 20 00 ; ..D.:. . . . . .
00e0h: 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00 ; . . . . . . . .
00f0h: 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00 ; . . . . . . . .
0100h: 20 00 0D 00 0A 00 45 00 3A 00 20 00 20 00 20 00 ; .....E.:. . . .
0110h: 20 00 20 00 20 00 20 00 31 00 30 00 34 00 32 00 ; . . . .1.0.4.2.
0120h: 34 00 39 00 38 00 35 00 36 00 30 00 30 00 30 00 ; 4.9.8.5.6.0.0.0.
0130h: 30 00 20 00 20 00 0D 00 0A 00 46 00 3A 00 20 00 ; 0. . .....F.:. .
0140h: 20 00 20 00 20 00 20 00 20 00 20 00 34 00 30 00 ; . . . . . .4.0.
0150h: 32 00 32 00 32 00 39 00 34 00 31 00 31 00 38 00 ; 2.2.2.9.4.1.1.8.
0160h: 34 00 20 00 20 00 20 00 20 00 0D 00 0A 00 ; 4. . . . .....
Но Windows командный процессор ожидает один байт на кодировку символов с использованием кодовой страницы в качестве вывод при запуске в открывшемся окне командной строки команды chcp
. Кодовая страница зависит от того, какая страна настроена для учетной записи, используемой для запуска командного процесса, обрабатывающего командный файл.
Командная строка chcp 65001>nul
для перехода на кодировку Unicode UTF-8 здесь никакой помощи.
Обработка вывода в кодировке UTF-16LE с помощью FOR напрямую вызывает проблемы, как описано несколько раз в документации по переполнению стека, см., например, Как исправить неправильное поведение при перезаписи переменных при разборе output?
Решением было бы перенаправить вывод WMI C во временный файл, вывести этот временный файл для обработки STDOUT (стандартно вывод) командного процесса, запущенного в фоновом режиме с помощью %ComSpec% /c
с использованием команды TYPE с захватом этого вывода командным процессом, выполняющим пакетный файл, обработайте этот вывод ASCII построчно и, наконец, удалите временный файл .
@echo off
setlocal EnableExtensions DisableDelayedExpansion
%SystemRoot%\System32\wbem\wmic.exe LOGICALDISK GET Caption,FreeSpace >"%TEMP%\%~n0.tmp"
if not exist "%TEMP%\%~n0.tmp" goto EndBatch
for /F "skip=1 tokens=1,2" %%I in ('type "%TEMP%\%~n0.tmp"') do echo %%I %%J
del "%TEMP%\%~n0.tmp"
:EndBatch
endlocal
В этом случае FOR обрабатывает поток байтов ASCII:
000h: 43 61 70 74 69 6F 6E 20 20 46 72 65 65 53 70 61 ; Caption FreeSpa
010h: 63 65 20 20 20 20 20 20 0D 0A 41 3A 20 20 20 20 ; ce ..A:
020h: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 ;
030h: 20 20 0D 0A 42 3A 20 20 20 20 20 20 20 31 30 39 ; ..B: 109
040h: 38 35 35 32 36 37 32 32 35 36 20 20 0D 0A 43 3A ; 8552672256 ..C:
050h: 20 20 20 20 20 20 20 34 30 38 32 34 32 30 31 32 ; 408242012
060h: 31 36 20 20 20 20 0D 0A 44 3A 20 20 20 20 20 20 ; 16 ..D:
070h: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 ;
080h: 0D 0A 45 3A 20 20 20 20 20 20 20 31 30 34 32 34 ; ..E: 10424
090h: 39 38 35 36 30 30 30 30 20 20 0D 0A 46 3A 20 20 ; 98560000 ..F:
0a0h: 20 20 20 20 20 34 30 32 32 32 39 34 31 31 38 34 ; 40222941184
0b0h: 20 20 20 20 0D 0A ; ..
Но это В общем, всегда лучше избегать использования временного файла, поскольку никогда не гарантируется, что временный файл может быть вообще создан во время выполнения командного файла.
2. Системный диск не всегда C:
Windows установлен по умолчанию на диск C: и поэтому системный диск C:
. Но Windows можно установить и на другой диск, в этом случае системный диск не является C:
. Любой код, зависящий от данных по умолчанию вместо использования соответствующих данных, является плохо написанным кодом.
Предопределена переменная среды Windows SystemDrive
с буквой диска и двоеточием диска, на котором установлен активный Windows. Переменная среды SystemRoot
содержит путь к каталогу Windows, в котором находится каталог System32
со всеми исполняемыми файлами из списка Windows Commands , которые не являются внутренними командами cmd.exe
.
Все эти системные переменные окружения можно увидеть по их значениям при открытии командной строки и запуске set system
. Выполнение только set
выводит все переменные среды с их значениями, определенными для текущей учетной записи пользователя.
3. Целочисленный диапазон значений ограничен 32-разрядным целым числом со знаком
. Командный процессор Windows cmd.exe
всегда использует только 32-разрядное целое число со знаком при вычислении арифметического выражения c с set /A
и для сравнения целочисленные значения с помощью команды IF при использовании операторов EQU
, NEQ
, LSS
, LEQ
, GTR
, GEQ
.
Поэтому диапазон целочисленных значений от −2147483648
до 2147483647
. Таким образом, максимум составляет один байт менее 2 ГиБ. Значение 1099511627776
требует 64-разрядного целочисленного диапазона значений, не поддерживаемого cmd.exe
.
Кстати: if [%%Y] neq []
никогда не является хорошим сравнением, поскольку [
и ]
не имеют специального значения для Командный процессор Windows и neq
приводят здесь сначала к подходу преобразования левой строки в 32-разрядное целочисленное значение со знаком, которое завершается ошибкой из-за того, что [
является недопустимым символом для целочисленного значения и, следовательно, запускает следующее сравнение строк при условии, что условие истинно, если сравнение строк возвращает не 0
, т.е. сравниваемые строки не равны. Лучше было бы if not "%%Y" == ""
, который запускает прямое и более безопасное сравнение строк на неравных строках. См. Символ, эквивалентный NEQ, LSS, GTR и т. Д. c. в Windows командных файлах для получения подробных сведений о том, как команда IF выполняет сравнение строк.
Решение для получения дисков с менее чем одним свободным пространством TiB
It Рекомендуется прочитать документацию по классу, свойства которого доступны с помощью утилиты командной строки Windows Management Instrumentation. Это здесь Win32_LogicalDisk класс .
В дополнение к FreeSpace
типа uint64
и DeviceID
типа string
вместо Caption
, возможно, также полезно свойство DriveType
типа uint32
для фильтрации дисков неправильного типа в дополнение к дискам со слишком большим свободным пространством и системному диску с использованием условия where
при выполнении wmic
.
@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "UsableDrive="
for /F "skip=1 tokens=1,2" %%I in ('""%SystemRoot%\System32\wbem\wmic.exe" LOGICALDISK where (DriveType=3 and FreeSpace^<1099511627776 and DeviceID!='C:') GET DeviceID,FreeSpace 2>nul"') do (
echo Drive %%I has %%J free bytes.
if not defined UsableDrive set "UsableDrive=%%I"
)
if defined UsableDrive echo Selected drive %UsableDrive%
endlocal
Важно знать, что FOR запускается в фоновом режиме с %ComSpec% /c
еще одним командным процессом с командной строкой, указанной в '
, добавленной в качестве дополнительных аргументов. По этой причине командная строка с WMI C должна удовлетворять требованиям Windows к процессору команд, описанным в справочном выводе при запуске cmd /?
в окне командной строки при общем трехкратном анализе.
Первый анализ выполняется путем cmd.exe
обработки пакетного файла перед выполнением команды FOR .
Второй анализ выполняется экземпляром cmd.exe
при запуске его в фоновом режиме с помощью экземпляр cmd.exe
, обрабатывающий пакетный файл со следующей командной строкой в Windows, установленной в C:\Windows
.
C:\Windows\System32\cmd.exe /c ""C:\WINDOWS\System32\wbem\wmic.exe" LOGICALDISK where (DriveType=3 and FreeSpace^<1099511627776 and DeviceID!='C:') GET DeviceID,FreeSpace 2>nul"
Третий анализ выполняется фоновым командным процессом перед выполнением wmic.exe
. Оператор <
в предложении where
должен интерпретироваться как литеральный символ, а не как оператор перенаправления, что является причиной того, почему <
экранируется с ^
для запуска wmic.exe
, наконец, с:
"C:\Windows\System32\wbem\wmic.exe" LOGICALDISK where (DriveType=3 and FreeSpace<1099511627776 and DeviceID!='C:') GET DeviceID,FreeSpace
WMI C отфильтровывает с DriveType=3
все сетевые накопители, дисководы гибких дисков, дисководы CD и DVD и другие съемные накопители, RAM-диски и т. Д. c. Жесткие диски, подключенные к компьютеру через внешний USB-порт или порт eSATA, не отфильтровываются, так как для этих дисков также указано значение 3
для типа диска. Windows не может определить, установлен ли жесткий диск внутри корпуса компьютера или снаружи. Таким образом, локальный жесткий диск - это любой жесткий диск, подключенный к компьютеру, внутренним и внешним жестким дискам.
Системный диск отфильтрован со вторым условием DeviceID!='%SystemDrive%'
.
Последнее условие FreeSpace<1099511627776
приводит к игнорированию всех дисков с 1 ТБ или более свободного места.
Таким образом, список уже сокращен до тех дисков, которые удовлетворяют всем трем условиям.
Для понимания используемые команды и как они работают, откройте окно командной строки , выполните там следующие команды и полностью прочитайте все страницы справки, отображаемые для каждой команды.
cmd /?
del /?
echo /?
endlocal /?
for /?
goto /?
if /?
set /?
setlocal /?
type /?
wmic /?
wmic logicaldisk /?
wmic logicaldisk get /?
См. Также статью Microsoft о Использование операторов перенаправления команд для объяснения >
и 2>nul
.