- PVSM.RU - https://www.pvsm.ru -
В данной планируемой статье из нескольких частей я попытаюсь рассказать о PowerShell и о том, как написать расширение для этой оболочки. Мы применим несколько технологий:
И начну я с небольшого введения, прочитав которое, вы сможете понять, о чём всё-таки идёт речь, если вы вдруг что-то запамятовали.
Когда-то Microsoft приступила к разработке новой командной оболочки, которая должна была заменить cmd.exe
— оболочку, возможности которой, мягко говоря, никогда особо не впечатляли. Так появлился PowerShell [1]. Сейчас на дворе 2013-й год, и у нас есть уже 4-я версия не очередного интерпретатора командной строки, но очень мощного, расширяемого средства автоматизации и администрирования.
Windows 7 среди прочего привнёс в систему новшество — библиотеки [2]. По замыслу разработчиков они должны были стать основным хранилищем пользовательских данных — документов, музыки, картинок, видео. Сами по себе библиотеки не хранят никаких файлов. Вместо этого они в одном месте показывают файлы, которые физически находятся в разных местах. Например, если часть музыки хранится в папке My Music, а часть — на внешнем жёстком диске, через библиотеку «Музыка» можно просмотреть всю коллекцию целиком.
На вкус и цвет все фломастеры разные, поэтому оставим в стороне вопросы удобства и популярности этих технологий (думаю, немалое количество людей по тем или иным причинам игнорируют их наличие). Для нас главное, что они есть.
Мы заглянем внутрь PowerShell, посмотрим, как он устроен, и на примере библиотек напишем небольшое расширение.
Почему библиотеки?
Во-первых, один из лучших способов научиться чему-то — как известно, научить этому другого. У меня давно на слуху всякие Shell Extensions, COM-составляющая Windows и пр., теперь пришла пора построить пару велосипедов и систематизировать знания.
Во-вторых, то, каким образом мы видим библиотеки и взаимодействуем с ними (а основное средство взаимодействия — это Проводник), гармоничным и очевидным образом переносится на концепции PowerShell. Чуть позже мы увидим это.
В-третьих, удобных средств работы с библиотеками из командной строки нет. Или, по крайней мере, я плохо искал и не нашёл. То есть, конечно, есть утилиты, например, в тех же Shell SDK Samples [3]: можно создавать библиотеки, переименовывать их, удалять, но самого главного они не умеют. Я хочу просматривать библиотеки и работать с файлами в них так же прозрачно как и в Проводнике. Я хочу делать вот так:
Windows PowerShell
Copyright (C) 2012 Microsoft Corporation. All rights reserved.
C:WindowsSystem32WindowsPowerShellv1.0$ cd Libraries:Documents
Libraries:Documents$ ls
Directory: Libraries:Documents
Mode LastWriteTime Length Name
---- ------------- ------ ----
d---- 07.10.2013 17:51 Bootstrap
d---- 14.08.2013 19:42 Custom Office Templates
d---- 30.08.2013 12:36 OpenTTD
d---- 24.09.2013 11:58 Outlook Files
d---- 08.10.2013 18:28 vfw4
d---- 29.04.2013 13:59 Visual Studio 2008
d---- 05.08.2013 18:05 Visual Studio 2010
d---- 09.10.2013 16:48 Visual Studio 2012
d---- 11.10.2013 13:27 Visual Studio 2013
d---- 17.10.2013 18:40 WindowsPowerShell
-a--- 18.10.2013 16:29 0 1.txt
-a--- 18.10.2013 16:29 0 10.txt
-a--- 18.10.2013 16:29 0 2.txt
-a--- 28.06.2013 16:54 18480 wix.png
Libraries:Documents$ new-item 3.txt -type file
Directory: Libraries:Documents
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 18.10.2013 19:32 0 3.txt
Видите? Мы как будто бы находимся в обычной папке. cmd.exe
так не умеет.
В-четвёртых, просто так.
PS> Get-Item D:Temparchive.zipFolderfile.xmlroot*
PS> Copy-Item D:Temparchive.zipfile.txt D:NewFolderfile.7zFolder
PS> Delete-Item D:Temparchive.7zFolder*.txt
PS> Move-Item D:Tempfile.txt D:TempexistingArchive.7zFolder
PS> Get-ChildItem D:Temparchive.7z
Взято отсюда [5].
Или можно «зайти» в sqlite базу данных, набрать dir
(или ls
, или Get-ChildItem
, или… в общем, как больше нравится) и посмотреть список таблиц. Давайте посмотрим, сколько стоят наушники?
PS C:$ cd Market:Электроника и ФотоПортативная аудиотехникаНаушникиAKG
PS Market:Электроника и ФотоПортативная аудиотехникаНаушникиAKG$ ls
В общем… думаю, понятно.
Сердце объектной модели PowerShell — сборка System.Management.Automation [6].dll. Она не отображается в окне Reference Manager студии, там что искать её нам предстоит самостоятельно. Что, на самом деле, не [7] совсем [8] тривиально [9]. У меня эта сборка лежит в %windir%Microsoft.NetassemblyGAC_MSILSystem.Management.Automationv4.0_3.0.0.0__31bf3856ad364e35
. Обратите внимание, что с .NET Framework 4 GAC переехал [10] в подпапку Microsoft.Net
.
Создаём проект типа Class Library и добавляем ссылку на вышеуказанную сборку. Также для удобства отладки сразу поменяем некоторые параметры. В окне Project Properties › Debug:
C:WindowsSystem32WindowsPowerShellv1.0Powershell.exe
-noexit -command "[Reflection.Assembly]::LoadFrom('LibrariesProvider.dll') | Import-Module"
C:Program FilesConEmuConEmu64.exe
/Single /cmd C:WindowsSystem32WindowsPowerShellv1.0PowerShell.exe -noexit -command "[Reflection.Assembly]::LoadFrom('PowerShell.Libraries.dll') | Import-Module"
В любом случае, в появившейся консоли наберите
[Appdomain]::CurrentDomain.GetAssemblies() | where { $_.FullName -match "LibrariesProvider" }
— если вы увидели вашу сборку, значит, всё нормально и можно продолжать.
Поставщики [11] в экосистеме PowerShell — это интерфейс между пользователем и данными. Данные могут быть различными: файловая система, реестр, переменные окружения, хранилища сертификатов и пр. Всё вышеперечисленное входит в PowerShell «из коробки».
Поставщики различаются функционалом [12], и, как видно на картинке выше, можно выделить пять различных типов:
CmdletProvider
— в конечном счёте этот класс является базовым для любых поставщиков. Как самый простой он даже не предоставляет возможности взаимодействовать с данными. Всё, что вы можете сделать, это узнать, когда ваш поставщик инициализировали и когда он завершает работу.DriveCmdletProvider
добавляет поддержку устройств, которые логически или физически делят данные на разделы. Например, ветки реестра HKCU
и HKLM
представлены PowerShell'ом двумя разными устройствами (или дисками, по аналогии с C:
, D:
и т.д.).ItemCmdletProvider
добавляет поддержку путей и и объектов. Данные-объекты можно получать, очищать, вызывать.ContainerCmdletProvider
добавляет поддержку объектов-контейнеров, то есть таких данных, которые сами содержат данные. Данные можно копировать, удалять и переименовывать. Важно одно обстоятельство: контейнеры не могут содержать другие контейнеры, только простые данные. Один уровень вложенности.NavigationCmdletProvider
— самый «навороченный» тип поставщиков, который предоставляет полную поддержку иерархии. Очевидный пример — файловая система, тут вам и папки (контейнеры), и подпапки («подконтейнеры»), и всё что угодно.
Поскольку библиотеки — это всё та же файловая система, думаю, очевидно, что нам нужен тип NavigationCmdletProvider
.
Давайте для затравки напишем поставщик, который позволит свободно побродить по его виртуальному пространству:
[CmdletProvider("Libraries", ProviderCapabilities.None)] ①
public class LibrariesProvider : NavigationCmdletProvider
{
protected override bool IsValidPath(string path) ②
{
return false;
}
protected override bool ItemExists(string path) ③
{
return true;
}
protected override bool IsItemContainer(string path) ④
{
return true;
}
protected override void GetChildItems(string path, bool recurse) ⑤
{
}
protected override Collection<PSDriveInfo> InitializeDefaultDrives() ⑥
{
var driveInfos = new Collection<PSDriveInfo>();
driveInfos.Add(new PSDriveInfo("Libraries", this.ProviderInfo, string.Empty, "Description", null));
return driveInfos;
}
}
① CmdletProviderAttribute
[13] — это атрибут, без которого PowerShell не найдёт нашего поставщика. Мы указываем название поставщика и его возможности. Так, самой частой возможностью является ShouldProcess
: многие команды (командлеты) поддерживают параметр -WhatIf
, который отменяет непосредственный эффект (удаление, перемещение объекта и т.п.) и вместо этого делает вид, что эффект произошёл, то есть просто выводит строку вида
What if: Performing operation "Create directory" on Target "Destination: XXX".
Пока что нашей задачей является свободное перемещение, стало быть, ② любой путь правилен, ③ существует и ④ является контейнером.
Метод ⑤ позволяет вернуть содержимое контейнера. Пока что все наши подпапки будут пустыми.
Метод ⑥ позволяет на месте создать один или несколько устройств-дисков. Например, при подключении поставщика реальной файловой системы, можно сразу же создать устройства по количеству логических разделов на жёстких дисках. В нашем случае будет одно устройство (месторасположение «Библиотеки» единственно). А можно было бы насоздавать дисков по количеству библиотек (Music:
, Video:
и т.п.) — дело вкуса.
Убедимся, что приведённого кода достаточно; запускаем отладку и набираем в консоли:
PS C:LibrariesProviderbinDebug$ cd Libraries:
PS Libraries:$ cd Documents
PS Libraries:Documents$ dir ①
PS Libraries:Documents$ cd thatlongpathexiststoo
PS Libraries:Documentsthatlongpathexiststoo$ ②
① Действительно пусто.
② Работает.
Дальше всё только интереснее.
На самом деле, я не хотел бы писать огромную статью; думаю, лучше будет её разбить на части. Ну и ко всему прочему я хочу «прощупать» аудиторию: если тема будет интересна, я конечно же продолжу, работы непочатый край.
Исходники предоставлю по первой просьбе.
Спасибо за внимание. Надеюсь увидеться в комментариях.
Автор: withkittens
Источник [14]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/windows/46122
Ссылки в тексте:
[1] PowerShell: http://en.wikipedia.org/wiki/Windows_PowerShell
[2] библиотеки: http://msdn.microsoft.com/en-us/library/windows/desktop/dd797952.aspx
[3] Shell SDK Samples: http://msdn.microsoft.com/en-us/library/dd940379.aspx
[4] старых-добрых: http://en.wikipedia.org/wiki/File_manager#Orthodox_file_managers
[5] отсюда: http://www.extbrain.net/theses/dp-josef-zavisek.pdf
[6] System.Management.Automation: http://msdn.microsoft.com/en-us/library/windows/desktop/system.management.automation.aspx
[7] не: http://stackoverflow.com/q/1186270
[8] совсем: http://stackoverflow.com/q/11656296
[9] тривиально: http://stackoverflow.com/q/13953102
[10] переехал: http://msdn.microsoft.com/en-us/library/yf1d93sz.aspx
[11] Поставщики: http://msdn.microsoft.com/en-us/library/windows/desktop/ee126186.aspx
[12] различаются функционалом: http://msdn.microsoft.com/en-us/library/windows/desktop/ee126198.aspx
[13] CmdletProviderAttribute
: http://msdn.microsoft.com/en-us/library/windows/desktop/system.management.automation.provider.cmdletproviderattribute.aspx
[14] Источник: http://habrahabr.ru/post/198282/
Нажмите здесь для печати.