PowerShell и другие скрипты

31.3.2009

Bcdedit.exe из PowerShell

Рубрика: Command line parsing — Метки: , , — Xaegr @ 14:48

Недавно я столкнулся с необходимостью отредактировать элементы загрузки с помощью утилиты bcdedit.exe. Эта утилита используется в системах начиная с Vista, для управления хранилищем конфигурации загрузки, которое заменило boot.ini.

Разумеется я решил запускать утилиту из PowerShell (так как дело происходило на Windows Server 2008R2, то PowerShell было запустить даже проще и быстрее чем cmd.exe ;) ).

Я ознакомился со справкой программы, вызвав её с ключём /?, и хотел выполнить простое действие – переименовать элемент загрузки. Сначала вызвал bcdedit /enum чтобы посмотреть на список элементов, и узнать идентификатор того который буду переименовывать (identifier).

PS C:\Windows\System32> bcdedit /enum
...
Windows Boot Loader
-------------------
identifier              {c2b02f79-36b4-11dd-9e1b-99d426d57382}
device                  partition=Q:
path                    \Windows\system32\winload.exe
description             Microsoft Windows Vista
...

И затем попробовал вызвать непосредственно команду переименования.

PS C:\Windows\System32> bcdedit /set {c2b02f79-36b4-11dd-9e1b-99d426d57382} description "Windows Vista"
The set command specified is not valid.
Run "bcdedit /?" for command line assistance.
The parameter is incorrect.

В чём же проблема? Вроде бы и синтаксис соответствует указанному в справке, и идентификатор системы я скопировал через буфер обмена, так что ошибок в нём быть не должно… Попробуем создать простой файл .cmd выводящий имена полученных аргументов, и попробовать ту же команду на нём. Я назвал его testargs.cmd и поместил в него следующий текст:

@echo Arg1: [%1]
@echo Arg2: [%2]
@echo Arg3: [%3]
@echo Arg4: [%4]
@echo Arg5: [%5]

Весьма просто, неправда ли? Попробуем на нём ту же команду

PS C:\Windows\System32> testargs.cmd /set {c2b02f79-36b4-11dd-9e1b-99d426d57382} description "Windows Vista"
Arg1: [/set]
Arg2: [-encodedCommand]
Arg3: [YwAyAGIAMAAyAGYANwA5AC0AMwA2AGIANAAtADEAMQBkAGQALQA5AGUAMQBiAC0AOQA5AGQANAAyADYAZAA1ADcAMwA4ADIA]
Arg4: [description]
Arg5: ["Windows Vista"]

Неудивительно что bcdedit ругался на синтаксис. Насколько я понимаю, PowerShell увидев конструкцию в фигурных скобках, посчитал её блоком кода (scriptblock), и решил перед отправкой команде назначения закодировать с помощью base64 и передать после параметра –encodedCommand. Сам то PowerShell.exe без проблем разобрался бы с такой конструкцией, но вот bcdedit.exe удивился ;)

Как же обойти этот неприятный эффект? Ну напеример поместить идентификатор в кавычки:

PS C:\Windows\System32> testargs.cmd /set "{c2b02f79-36b4-11dd-9e1b-99d426d57382}" description "Windows Vista"
Arg1: [/set]
Arg2: [{c2b02f79-36b4-11dd-9e1b-99d426d57382}]
Arg3: [description]
Arg4: ["Windows Vista"]
Arg5: []

Двойные, или одинарные, в данном случае не важно. Главное что PowerShell теперь будет считать этот аргумент обычной строчкой, и передаст дальше в неизменном виде:

PS C:\Windows\System32> bcdedit /set "{c2b02f79-36b4-11dd-9e1b-99d426d57382}" description "Windows Vista"
The operation completed successfully.

Второй вариант решения – просто напросто экранировать фигурные скобки, раз уж они смущают PowerShell. Экранирование в PowerShell выполняется с помощью символа ` (обратный апостроф):

PS C:\Windows\System32> bcdedit /set `{c2b02f79-36b4-11dd-9e1b-99d426d57382`} description "Windows Vista"
The operation completed successfully.

Проблема решена! :) Но тема к сожалению не закрыта. Я постараюсь разобрать другие случаи взаимодействия PowerShell с всевозможными реализациями синтаксиса внешних утилит в других постах. А вы можете рассказать о встретившихся вам ситуациях, в комментариях :)

Комментарии (5) »

  1. А вот я как раз сегодня впёрся в проблему как раз со скобками, только с квадратными.
    То есть когда надо скопировать, прочесть или переименовать — проблем по большей части нет: ставь -LiteralPath где надо и вся недолга.
    А вот проблема: надо обработать файл некоей внешней утилиткой. А файл этот может находиться в каталоге, в названии которого присутствуют [].
    Пробовал я так:
    type.exe «d:\work\num[1]\file.txt»
    Не работает. Не работает также, если поставить перед [ и ] знак ` в различных количествах и комбинациях.
    type.exe ‘d:\work\num[1]\file.txt’
    Также не работает и с `.

    Может, есть какая-то команда типа execute -LiteralPath [имяпроги] [параметры]?

    type.exe здесь чисто для иллюстрации, естественно и для лёгкости проверки.
    powershell 2.0 CTP.

    Комментарий от Oleg Medvedev — 1.4.2009 @ 10:32

  2. У меня работает вариант:

    gc ‘tst`[2`]\hooy.txt’

    Комментарий от itanko — 2.4.2009 @ 8:13

  3. Интересно а каких либо .Net интерфейсов делающих тоже что и bcdedit нет? Может проще было бы их напрямую вызывать?

    Комментарий от abeshkov — 2.4.2009 @ 23:11

  4. [...] как эта команда выглядит для net.exe поможет файл testargs.cmd который я описал в предыдущем посте из [...]

    Уведомление от Особенности Net.exe Share « PowerShell и другие скрипты — 15.4.2009 @ 12:52

  5. 2 Oleg Medvedev: А где вы взяли type.exe? :) У меня нигде нет такой утилиты :)
    В PowerShell – type является псевдонимом для Get-Content, а в Cmd.exe это встроенная команда.

    Комментарий от Vasily Gusev — 23.4.2009 @ 8:46


RSS-лента комментариев к этой записи. URI для обратной ссылки

Оставить комментарий

Блог на WordPress.com.