Читая лекции по Windows PowerShell, я всегда советую своим студентам передавать объекты по конвейеру в Get-Member:
Командлет Get-Member предназначен для использования такой возможности Microsoft .NET Framework, как отражение, оторое позволяет отображать информацию об объекте, в том числе его официальное имя, свойства, методы и т. п. Этот командлет дает возможность быстро узнать, что объект «умеет» делать, не прибегая к поиску и не копаясь в необъятных просторах веб-сайта библиотеки MSDN.
Вместе с тем, иногда пытаясь использовать этот командлет, студенты получают что-то типа следующего:
TypeName: Deserialized.System.Diagnostics.Process
Я, конечно, знаю, что такое «процесс», но понятия не имею, что это за зверь такой — десериализованный процесс? Дальнейшее исследование результата работы Get-Member показывает, что, в отличие от обычных процессов, у которых есть методы для остановки процесса и выполнения других действий, у этих десериализованных процессов по-видимому вообще нет методов, а это означает, что их нельзя заставить что-либо делать. В чем здесь дело?
Как сериализуют объекты
В Windows объекты представляют собой работающие биты программы. Процесс — это, в сущности, приложение. Объект в процессе предоставляет свойства, описывающие некоторые атрибуты процесса, такие как имя, использование памяти и т. п; у объекта также могут быть методы для выполнения действий, таких как остановка, обновление и другие.
Объекты очень удобны, когда находятся на компьютере, но не существует реального способа передать целый объект по сети. Сериализация — это способ создания текстового представления объекта, обычно в виде XML. На рис.1 показан результат сериализации объекта в XML.
По существу в процессе сериализации создается моментальный снимок свойств объекта, который затем кодируется в структурированный XML-файл и передается по сети. На этом этапе XML-файл представляет собой обычный текстовый файл. Нет больше прямой связи между реально выполняющимися процессами и этим XML-файлом. Этот файл — представление свойств передаваемого объекта на определенный момент времени.
Рис. 1 XML-файл — результат сериализации объекта в процессе
При сериализации методы объекта не сохраняются. Нет способа вернуть исходный объект и заставить его выполнить метод. Когда оболочке нужно считать сериализованный объект, она его десериализует. Для этого она считывает XML-текст и создает что-то очень похожее на исходный объект, но, конечно, без каких-либо его методов.
Стандартные сценарии сериализации объектов
Windows PowerShell v2 использует сериализацию в двух стандартных ситуациях:
- при экспорте объекта в формат XML с помощью командлета;
- при восстановлении объекта с удаленного компьютера, используя удаленный доступ Windows PowerShell.
Например, следующая команда получит список всех процессов на удаленном компьютере, отсортирует их по использованию виртуальной памяти и отобразит первую десятку:
invoke-command { ps } -computer server-r2 | sort vm -desc | select -first 10
Все операции сортировки и выбора можно выполнять на удаленном компьютере, что позволяет передавать по сети меньше сериализованных объектов:
invoke-command { ps | sort vm -desc | select -first 10 } -computer server-r2
Дело в том, что полученные по сети объекты больше не являются реальными процессами, так как преобразованы в формат XML. Нельзя взять и заставить остановиться один из указанных процессов, потому что нет никакой связи между тем, что есть на локальном и что выполняется на удаленном компьютере.
Сериализация может также быть полезной для сохранения информации объекта. Допустим, вы экспортировали конфигурации всех своих служб в XML-файл:
get-wmiobject win32_service | export-clixml baseline.xml
Этот моментальный снимок можно было бы использовать для сравнения текущей конфигурации сервера в с конфигурацией в будущем, чтобы узнать об изменениях в конфигурации, внесенных специально или по неосторожности.
Эта команда сравнивает текущие объекты-службы с имеющимися в моментальном снимке:
compare-object (get-wmiobject win32_service) (import-clixml baseline.xml)
В данном случае тот факт, что у десериализованных объектов нет методов, не имеет значения. Вся конфигурационная информация хранится в свойствах, такая как тип запуска, учетная запись для входа в систему и т. п.
Осторожно — сериализованные объекты!
Сериализация может создавать проблемы, когда нужны методы объекта. Например, эта команда перезагрузки прекрасно сработает на локальном компьютере (не выполняйте ее, если не готовы к перезагрузке машины):
Get-WmiObject Win32_OperatingSystem | ForEach-Object { $_.Reboot() }
А эта команда работать не будет:
Invoke-Command { Get-WmiObject Win32_OperatingSystem } –computer Server-R2 | ForEach-Object { $_.Reboot() }
Дело в том, что результатом работы Invoke-Command является десериализованный объект без методов. Метод Reboot выполнить не удастся. Однако можно сделать так:
Invoke-Command { Get-WmiObject Win32_OperatingSystem | ForEach-Object { $_.Reboot() }} –computer Server-R2
Так мы вызываем метод Reboot на удаленном компьютере до сериализации объекта и потери его методов. Итак, всякий раз, когда сериализация создает проблемы, можно воспользоваться обходным решением. Надо только знать, когда она происходит.