Windows PowerShell. Путаница с сериализацией

Сериализация позволяет экспортировать и восстанавливать объекты средствами Windows PowerShell.

Don Jones (Дон Джонс)

Читая лекции по Windows PowerShell, я всегда советую своим студентам передавать объекты по конвейеру в Get-Member:

Get-Process | Get-Member

Командлет Get-Member предназначен для использования такой возможности Microsoft .NET Framework, как отражение, оторое позволяет отображать информацию об объекте, в том числе его официальное имя, свойства, методы и т. п. Этот командлет дает возможность быстро узнать, что объект «умеет» делать, не прибегая к поиску и не копаясь в необъятных просторах веб-сайта библиотеки MSDN.

Вместе с тем, иногда пытаясь использовать этот командлет, студенты получают что-то типа следующего:

TypeName: Deserialized.System.Diagnostics.Process

Я, конечно, знаю, что такое «процесс», но понятия не имею, что это за зверь такой — десериализованный процесс? Дальнейшее исследование результата работы Get-Member показывает, что, в отличие от обычных процессов, у которых есть методы для остановки процесса и выполнения других действий, у этих десериализованных процессов по-видимому вообще нет методов, а это означает, что их нельзя заставить что-либо делать. В чем здесь дело?

Как сериализуют объекты

В Windows объекты представляют собой работающие биты программы. Процесс — это, в сущности, приложение. Объект в процессе предоставляет свойства, описывающие некоторые атрибуты процесса, такие как имя, использование памяти и т. п; у объекта также могут быть методы для выполнения действий, таких как остановка, обновление и другие.

Объекты очень удобны, когда находятся на компьютере, но не существует реального способа передать целый объект по сети. Сериализация — это способ создания текстового представления объекта, обычно в виде XML. На рис.1 показан результат сериализации объекта в XML.

По существу в процессе сериализации создается моментальный снимок свойств объекта, который затем кодируется в структурированный XML-файл и передается по сети. На этом этапе XML-файл представляет собой обычный текстовый файл. Нет больше прямой связи между реально выполняющимися процессами и этим XML-файлом. Этот файл — представление свойств передаваемого объекта на определенный момент времени.

Figure 1 The XML file will serialize the process objects

Рис. 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 на удаленном компьютере до сериализации объекта и потери его методов. Итак, всякий раз, когда сериализация создает проблемы, можно воспользоваться обходным решением. Надо только знать, когда она происходит.

Don Jones

Дон Джонс (Don Jones) — основатель компании Concentrated Technology.Дон регулярно отвечает на посвященные Windows PowerShell вопросы посетителей своего сайта ConcentratedTech.com. Он также пишет для Nexus.Realtimepublishers.com, поэтому многие из книг Дона доступны в бесплатной электронной форме.

Связанные материалы