Недавно я столкнулся с необходимостью отредактировать элементы загрузки с помощью утилиты 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 с всевозможными реализациями синтаксиса внешних утилит в других постах. А вы можете рассказать о встретившихся вам ситуациях, в комментариях 🙂
1.4.2009 в 10:32
А вот я как раз сегодня впёрся в проблему как раз со скобками, только с квадратными.
То есть когда надо скопировать, прочесть или переименовать — проблем по большей части нет: ставь -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.
2.4.2009 в 8:13
У меня работает вариант:
gc ‘tst`[2`]\hooy.txt’
2.4.2009 в 23:11
Интересно а каких либо .Net интерфейсов делающих тоже что и bcdedit нет? Может проще было бы их напрямую вызывать?
15.4.2009 в 12:52
[…] как эта команда выглядит для net.exe поможет файл testargs.cmd который я описал в предыдущем посте из […]
23.4.2009 в 8:46
2 Oleg Medvedev: А где вы взяли type.exe? 🙂 У меня нигде нет такой утилиты 🙂
В PowerShell — type является псевдонимом для Get-Content, а в Cmd.exe это встроенная команда.