Мне нравится время от времени писать на PowerShell. В основном это задачи администрирования и развертывания. В этой заметке я хочу рассказать о решении одной интересной проблемы связанной с работой модуля WebAdministration. Итак, суть проблемы: при выполнении любого командлета из этого модуля возникает ошибка:
Скрипт запускается на 64-битной Windows 7. И это ключевой момент. Но прежде чем приступить к описанию решения, я бы хотел сказать пару слов об инфраструктуре, в которой используются PowerShell скрипты. Наиболее часто используемые сценарии (например, создание и настройка локального сайта, создание очередей и т.п.) оформлены в виде функций модуля. Этот модуль разработчик может загрузить в PowerShell сессию и использовать экспортируемые им функции в консоли. Но так же для них сделаны обёртки в виде batch-файлов, чтобы запускать просто по клику. При использовании их и обнаружилась эта проблема. НО только при условии, что batch-файл запускается из Total Commander.
Пример команды, в которой вызывается командлет Get-WebSite, чтобы отобразить список всех локальных сайтов:
Что ж выглядит неплохо. Теперь попробуем запустить это же batch-файл в Total Commander:
Когда была выпущена 64-битная версия Windows, библиотеки, существовавшие ранее, не были переименованы. Их адаптировали, перекомпилировали и оставили жить в каталоге %windir%\System32. А их 32-битные аналоги переместили в директорию %windir%\SysWOW64. Теперь, когда 32-битный процесс пытается получить доступ к файлам в %windir%\System32, система автоматически перенаправляет вызов в %windir%\SysWOW64. В том случае, если 32-битному процессу нужен доступ именно к директории %windir%\System32, он может обратиться к ней через псевдоним %windir%\Sysnative. Такой вызов не будет переадресован.
Запуская скрипт из Total Commander, мы запускаем 32-битную версию PowerShell, для которой модуль WebAdministration не зарегистрирован корректно по каким-то причинам. Или он может быть зарегистрирован только для одной архитектуры? К сожалению, найти точные причины мне не удалось.
Как бы то ни было у нас есть ценная информация. Можно, используя %windir%\Sysnative, запустить нужную нам версию PowerShell и использовать все возможности WebAdministration. Но учесть, что %windir%\Sysnative существует только в 32-битном процессе. Итоговый batch-файл принимает вид:
Такой скрипт будет запускать 64-битный PowerShell и из TotalCommander, и из Far, и из проводника (то в чём удалось проверить). В 32-битной ОС так же проблем не возникнет.
Несколько примечаний:
Примечание 1. Вместо модуля WebAdministration можно использовать ServerManager из сборки Microsoft.Web.Administration.dll. Почитать про использование можно в этой статье.
Примечание 2. Возможно, Total Commander поддается настройке таким образом, чтобы он запускал %windir%\System32\cmd.exe, но я таких опций не нашел.
Примечание 3. Это не похоже на локальную проблему, т.к. ошибка появлялась на всех машинах сети, на которых я пробовал запускать скрипт. Я далек от администрирования локальных сетей, возможно, влияют какие-то настройки в домене?
Спасибо, за внимание!
Cannot retrieve the dynamic parameters for the cmdlet.
Retrieving the COM class factory for component with CLSID {688EEEE5-6A7E-422F-B2E1-6AF00DC944A6} failed due to the following error: 80040154.
Скрипт запускается на 64-битной Windows 7. И это ключевой момент. Но прежде чем приступить к описанию решения, я бы хотел сказать пару слов об инфраструктуре, в которой используются PowerShell скрипты. Наиболее часто используемые сценарии (например, создание и настройка локального сайта, создание очередей и т.п.) оформлены в виде функций модуля. Этот модуль разработчик может загрузить в PowerShell сессию и использовать экспортируемые им функции в консоли. Но так же для них сделаны обёртки в виде batch-файлов, чтобы запускать просто по клику. При использовании их и обнаружилась эта проблема. НО только при условии, что batch-файл запускается из Total Commander.
Пример команды, в которой вызывается командлет Get-WebSite, чтобы отобразить список всех локальных сайтов:
powershell -noexit -command "& { Import-Module WebAdministration; Get-WebSite }"
* This source code was highlighted with Source Code Highlighter.
Давайте сохраним её в файл и попробуем запустить из проводника. С флагом “-noexit” сессия не завершится после выполнения команды и у нас будет время, чтобы проанализировать запущенный процесс с помощью Process Explorer. Мы увидели список локальных сайтов, а в Process Explorer посмотрели свойства процесса:Что ж выглядит неплохо. Теперь попробуем запустить это же batch-файл в Total Commander:
Когда была выпущена 64-битная версия Windows, библиотеки, существовавшие ранее, не были переименованы. Их адаптировали, перекомпилировали и оставили жить в каталоге %windir%\System32. А их 32-битные аналоги переместили в директорию %windir%\SysWOW64. Теперь, когда 32-битный процесс пытается получить доступ к файлам в %windir%\System32, система автоматически перенаправляет вызов в %windir%\SysWOW64. В том случае, если 32-битному процессу нужен доступ именно к директории %windir%\System32, он может обратиться к ней через псевдоним %windir%\Sysnative. Такой вызов не будет переадресован.
Запуская скрипт из Total Commander, мы запускаем 32-битную версию PowerShell, для которой модуль WebAdministration не зарегистрирован корректно по каким-то причинам. Или он может быть зарегистрирован только для одной архитектуры? К сожалению, найти точные причины мне не удалось.
Как бы то ни было у нас есть ценная информация. Можно, используя %windir%\Sysnative, запустить нужную нам версию PowerShell и использовать все возможности WebAdministration. Но учесть, что %windir%\Sysnative существует только в 32-битном процессе. Итоговый batch-файл принимает вид:
if not exist %windir%\Sysnative\nul goto 64bit
set ps="%windir%\Sysnative\WindowsPowerShell\v1.0\powershell.exe"
goto start
:64bit
set ps="%windir%\System32\WindowsPowerShell\v1.0\powershell.exe"
:start
%ps% -noexit -command "& { Import-Module WebAdministration; Get-WebSite }"
* This source code was highlighted with Source Code Highlighter.
Такой скрипт будет запускать 64-битный PowerShell и из TotalCommander, и из Far, и из проводника (то в чём удалось проверить). В 32-битной ОС так же проблем не возникнет.
Несколько примечаний:
Примечание 1. Вместо модуля WebAdministration можно использовать ServerManager из сборки Microsoft.Web.Administration.dll. Почитать про использование можно в этой статье.
Примечание 2. Возможно, Total Commander поддается настройке таким образом, чтобы он запускал %windir%\System32\cmd.exe, но я таких опций не нашел.
Примечание 3. Это не похоже на локальную проблему, т.к. ошибка появлялась на всех машинах сети, на которых я пробовал запускать скрипт. Я далек от администрирования локальных сетей, возможно, влияют какие-то настройки в домене?
Спасибо, за внимание!