Bash on Windows: практические опыты по скрещиванию ежей и ужей

В прилетевшем обновлении Windows 10 Creators Update появилась интереснейшая возможность — запускать виндовые программы в этом их линуксе. Официальные примеры меня категорически не устроили — евангелисты Microsoft предложили мне рисовать корову в PowerShell и запускать Notepad из bash. Чё, правда? Это всё до чего вы додумались?

image

Как человек страстно ждавший возможность запуска exe-файлов внутри WSL, я хочу поделиться опытом правильного использования новой фичи.

Bash on Windows я использую для всякой мелкой механизации — выкачать, распарсить, проанализировать. Взять 10–20 гигов логов и поколдовать над ними в поисках чего нибудь этакого. Взять 200 гигов исходных данных, сделать ВЖУХ и пульнуть пару мегов результатов в базу сайта. Вобщем, обычная бытовуха, как у всех. Разве нет?

Итак, мой опыт

Кейс номер один

Вот то ради чего именно я ждал возможность запуска exe-файлов на WSL.

Имеется некоторое количество веб-сайтов для разных программ, требуется проверить что все ссылки «download» ведут на актуальные версии.

image

Пропустив этап поиска ссылок и скачивания файлов перейдём к извлечению нужной информации.
Делаем это двумя путями.

Путь первый — обращение к WMIC

В CMD вызов данной информации выглядит вот так:

wmic datafile where name="c:\\Windows\\System32\\cmd.exe" GET /VALUE

/VALUE — что бы получить всю возможную информацию

В bash это выглядит вот так

cmd.exe /C "wmic datafile where name='c:\\\\Windows\\\\System32\\\\cmd.exe' GET /VALUE"

слэшей много и все нужные

Но мне то нужно не просто на экран вывести, а получить и обработать.

Поэтому, в PHP это выглядит вот так:

// имя файла
$file='c:\Windows\System32\cmd.exe';

// получение данных через WMI
$q="/mnt/c/Windows/System32/cmd.exe /C \"wmic datafile where name='".addslashes(addslashes($file))."' GET /VALUE\"";
$a=exec($q,$b);
$ini=implode("\n",$b);

/mnt/c/Windows/System32/cmd.exe — полный путь, что бы наверняка
$b — результат многострочный, поэтому получаем его в виде массива (в $a попадает лишь последняя строчка)
$ini — формат результата совместим с ini-файлом, грех этим не воспользоваться — превращаем полученный массив $b в текст для последующего преобразования с помощью parse_ini_string ()

Путь второй — использование Scripting.FileSystemObject

Данной решение я нашёл здесь и немножко допилил.

В исходном варианте был вызов короткого списка с результатами, что меня не устроило

WScript.Echo(objFolder.GetDetailsOf(objItem,-1));

Я заменил эту строчку на цикл извлекающий ВСЕ возможные свойства файла

var folder=objShell.NameSpace(namespace);
for (var i=0; i<0xFFFF; i++)
	{
	fileinfo=folder.GetDetailsOf(null, i);
	if (!fileinfo)
		{
		break;
		}
	WScript.Echo( fileinfo+" = "+objFolder.GetDetailsOf(objItem,i) );
	}

формат вывода сделан совместимым с ini-файлом

PHP код, вызывающий bat-файл, получился вот такой

$q1="/mnt/c/Windows/System32/cmd.exe /C \"C:\\test_exe\\test_exe.bat ".addslashes($file)."\"";
$a1=exec($q1,$b1);
$ini1=implode("\n",$b1);
$ini1=iconv("CP866","UTF-8",  $ini1);

Почти так же как как в случае с WMI, только приходится перекодировать результат в юникод. (CP866 — всплакнул)

Склеиваем полученные результаты в единый текст и парсим

$result_ini="[WMIC]\n".$ini."\n[FileSystemObject]\n".$ini1;
$result_arr = parse_ini_string($result_ini, true, INI_SCANNER_RAW);
print_r($result_arr);

Делаем разбиение на секции (второй параметр — true) и во избежании проблем включаем — INI_SCANNER_RAW

ВЖУХ и получаем массив всех возможных свойств файла с которым удобно работать.

~$ cd /mnt/c/test_exe/
/mnt/c/test_exe$ php test_exe.php

Array
(
[WMIC] => Array
(
[AccessMask] => 1179817
[Archive] => TRUE
[Caption] => c:\windows\system32\cmd.exe
[Compressed] => FALSE
[CompressionMethod] =>
[CreationClassName] => CIM_LogicalFile
[CreationDate] => 20170318235750.921718+180
[CSCreationClassName] => Win32_ComputerSystem
[CSName] =>
[Description] => c:\windows\system32\cmd.exe
[Drive] => c:
[EightDotThreeFileName] => c:\windows\system32\cmd.exe
[Encrypted] => FALSE
[EncryptionMethod] =>
[Extension] => exe
[FileName] => cmd
[FileSize] => 271872
[FileType] => Application
[FSCreationClassName] => Win32_FileSystem
[FSName] => NTFS
[Hidden] => FALSE
[InstallDate] => 20170318235750.921718+180
[InUseCount] =>
[LastAccessed] => 20170318235750.921718+180
[LastModified] => 20170318235750.921718+180
[Manufacturer] => Microsoft Corporation
[Name] => c:\windows\system32\cmd.exe
[Path] => \windows\system32\
[Readable] => TRUE
[Status] => OK
[System] => FALSE
[Version] => 10.0.15063.0
[Writeable] => TRUE
)

[FileSystemObject] => Array
(
[Имя] => cmd.exe
[Размер] => 265 КБ
[Тип элемента] => Приложение
[Дата изменения] => 18.03.2017 23:57
[Дата создания] => 18.03.2017 23:57
[Дата доступа] => 18.03.2017 23:57
[Атрибуты] => A
[Автономность] =>
[Доступность] => Доступен автономно
[Распознанный тип] => Приложение
[Владелец] => TrustedInstaller
[Вид] => Программа
[Дата съемки] =>
[Исполнители] =>
[Альбом] =>
[Год] =>
[Жанр] =>
[Дирижер] =>
[Теги] =>
[Оценка] => Без оценки
[Авторы] =>
[Название] =>
[Тема] =>
[Категории] =>
[Комментарии] =>
[Авторские права] => c Microsoft Corporation. All rights reserved.
[№] =>
[Продолжительность] =>
[Скорость потока] =>
[С защитой] =>
[Камера, модель] =>
[Размеры] =>
[Камера, изготовитель] =>
[Организация] => Microsoft Corporation
[Описание файла] => Windows Command Processor
[Ключевые слова образцов] =>
[Имя программы] =>
[Длительность] =>
[В сети] =>
[Повторяется] =>
[Место] =>
[Адреса необязательных участников] =>
[Необязательные участники] =>
[Адрес организатора] =>
[Имя организатора] =>
[Время оповещения] =>
[Адреса обязательных участников] =>
[Обязательные участники] =>
[Ресурсы] =>
[Состояние собрания] =>
[Свободно/Занято] =>
[Общий размер] => 227 ГБ
[Учетная запись] =>
)

)

К чему был весь этот стрёмнокод?
А вот к чему.

Как я уже упомянул ранее, на сайте майкрософта поведали, что теперь мы можем рисовать коров в PowerShell и запускать notepad.exe из баша.

А в обсуждении перевода этого майкрософтовского текста люди выясняют насколько там честный линукс и можно ли на него взгромоздить Докера.

Люди, вы не туда смотрите!
Я в bash выполнил PHP-скрипт который через exec () запустил bat-файл в котором JScript создал ActiveXObject.

It’s Kind Of Magic!

А ещё я могу из CMD сделать вот так:

C:\test_exe>bash -c "php test_exe.php"

А-а-а-а-а-а!

Кейс номер два

Обновление Windows 10 Creators Update я накатил 6 числа, а на прошлой недели был отвлечён от новой игрушки бухгалтерией. Бухгалтерия запросила оригиналы первички.

Эврика, подумал я и поставил консольную печаталку

Лезем в bash и просто запускаем программу

~$ 2Printer.exe -s "c:\2Printer\_input\*.*"

Результат — из принтера ползут листочки
image
(данный скриншот — последующая имитация на виртуальном принтере, но на реальном HP тоже сработало)

В результате имеем:

  • программа проявила интерактивность (триалка запросила нажать кнопочку)
  • из башевского окошка полезла по своим виндовым путям
  • взяла оттуда файлы с русскими названиями
  • вызвала офисный редактор через COM-объекты
  • отправила результат на принтер

То есть можно не только писать простейшие скриптики, но и использовать сложные программы.

РЕЗЮМЕ

Я ещё не до конца осознал что ещё с этим можно делать, но эта штука может гораздо больше чем просто беседа с коровами и запуск LAMP.

Надо просто самому себе разрешить вырваться из дихотомиии «либо Linux, либо Windows» и начать скрещивать ежей и ужей в самых невероятных пропорциях и последовательностях.

Комментарии (1)

  • 17 апреля 2017 в 06:11

    0

    Они еще и копипасту в cmd сделали нормальную, и ресайз, и цвета и воообще удивляют.

© Habrahabr.ru