Запустите Powershell с параметрами из командного файла

Для удобства использования мне нужно поместить свой powershell-скрипт в bat-файл. Содержимое bat-файла следующее:

# 2>NUL & @CLS & PUSHD "%~dp0" & powershell -COMMAND "Start-Process powershell -Verb RunAs -ArgumentList '-windowstyle hidden -nol -nop -ep bypass ""[IO.File]::ReadAllText(''%~f0'')|iex""'"
# powershell script

Однако в сценарии PowerShell мне нужно получить путь к bat-файлу. Я знаю, что могу получить полный путь с помощью 'SET "batFilePath=%~f0"'... но я не знаю, что мне следует делать дальше, чтобы иметь возможность передать и использовать аргумент batFilePath в сценарии powershell. Пожалуйста, помогите мне, большое спасибо.

P/s: Дело не в том, что я ленивый, я пробовал искать похожие темы, но ответы меня все очень сбивают с толку, не знаю, что делать в моем случае. Прошу прощения.

Похоже, было бы гораздо удобнее не использовать bat-файл. Какова настоящая причина? Какая проблема возникает, если вы не сохраняете сценарий PowerShell в пакетном файле?

Mathias R. Jessen 19.06.2024 16:36

У вас есть аргументы внутри одинарных кавычек вместо двойных.

jdweng 19.06.2024 17:29

@MathiasR.Jessen Я создал небольшое программное обеспечение и хочу поделиться им с друзьями, которые не знают, как использовать код. Я хочу, чтобы для них все было максимально просто: просто кликни и беги. Я пытался упаковать exe-файл с помощью PS2EXE, но AV всегда получал ложные срабатывания, поэтому я решил создать bat-файл. Если вам интересно, я опубликую исходный код на GitHub и надеюсь, что вы дадите мне отзыв. Спасибо.

NqHai 20.06.2024 01:53
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
3
128
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Если вы запустите «SET «batFilePath=%~f0»» в cmd, вы можете получить доступ к переменной в PowerShell, запустив «$env:batFilePath».

Вот пример кода

# 2>NUL & @CLS & SET "batFilePath=%~f0" & powershell -Command "Start-Process powershell -Verb RunAs -ArgumentList ""-windowstyle hidden -nol -nop  Invoke-Expression (Get-Content -Path $env:batFilePath -Raw)"""

Обновлять: Чтобы передать $batFilePath в текущий процесс PowerShell, вы можете использовать этот код

# 2>NUL & @CLS & SET "batFilePath=%~f0" & powershell -Command "Start-Process powershell -Verb RunAs -ArgumentList \"-NoLogo -NoProfile -Command `$batFilePath='$env:batFilePath'; Invoke-Expression (Get-Content -Path $env:batFilePath -Raw)\"" & exit

На самом деле вам не нужно устанавливать «batFilePath» в cmd, вы можете просто использовать «~f0» вот так

# 2>NUL & @CLS & powershell -Command "Start-Process powershell -Verb RunAs -ArgumentList \"-NoLogo -NoProfile -Command `$batFilePath='%~f0'; Invoke-Expression (Get-Content -Path %~f0 -Raw)\"" & exit

Большое спасибо. Но я хочу использовать $batFilePath внутри сценария PowerShell, например, для регистрации запуска Windows «New-ItemProperty -Path $regKeyPath -Name $regKeyName -Value $batFilePath -PropertyType String -Force». Итак, как мне передать аргумент $batFilePath? Пожалуйста, просто помогите мне.

NqHai 20.06.2024 02:41

@NqHai, что ты не понимаешь в переменных окружающей среды? Доступ к переменным среды осуществляется так же, как показано в примере: $env:batFilePath

Squashman 20.06.2024 05:25

@Squashman Да, мои знания очень ограничены. Я попробовал протестировать код, используя содержимое bat-файла, следующим образом: #2>NUL... (удалить -windowstyle скрытый и добавить -noexit). 2-я строка: Write-Host «Hello $env:batFilePath». Но я получаю только «Привет». Я не знаю способа передать в скрипт $env:batFilePath.

NqHai 20.06.2024 07:40

@yy Большое спасибо за терпеливое руководство, я понял на вашем примере. Хорошего дня!

NqHai 21.06.2024 02:48

Ваша задача сложна, поскольку она требует передачи значения процессу, который запущен с повышенными правами (запускается с правами администратора), используя
‼Старт-Процесс -Verb RunAs.

В этом случае вы не можете использовать переменные среды, поскольку процесс с повышенными правами (в целях безопасности) не наследует переменные среды вызывающего объекта:[1]

  • Поэтому вам придется «встроить» интересующие значения в (подразумеваемый) -Command аргумент, который передается экземпляру powershell.exe с повышенными правами, что может оказаться затруднительным с точки зрения цитирования и экранирования.

  • Кроме того, в Windows PowerShell процесс с повышенными правами не наследует рабочий каталог вызывающего объекта и по умолчанию имеет значение C:\Windows\System32; к счастью, эта проблема исправлена ​​в PowerShell (Core) 7.

Ниже приведена модифицированная версия гибридного пакетного файла, которая наглядно демонстрирует определение переменной (только для оболочки) $batFilePath с полным путем к исходному пакетному файлу (%~f0), а также сначала переход к рабочему каталогу вызывающего объекта (%~dp0) с помощью Установить-Местоположение:

<# ::
@echo off & setlocal
powershell -NoProfile Start-Process powershell -Verb RunAs -ArgumentList '-NoExit -WindowStyle Normal -NoProfile -ExecutionPolicy Bypass Set-Location \\\"%~dp0\\"; $batFilePath = \\\"%~f0\\\"; Invoke-Expression (Get-Content -Raw \\\"%~f0\\\")'
exit /b
#>

# PowerShell code goes below; it is executed in the context of an 
# elevated PowerShell session based on the `powershell` call above.

[pscustomobject] @{
  batFilePath = $batFilePath
  workingDir = $PWD
}

То есть, приведенное выше создает видимый и открытый экземпляр PowerShell с повышенными правами, который демонстрирует, что (а) рабочий каталог совпадает с каталогом вызывающего объекта и (б) эта переменная $batFilePath отражает полный путь к исходному пакетному файлу.

Примечание:

  • %~f0 и %~dp0 используются для обозначения полного пути к файлу вызывающего пакетного файла и полного пути к каталогу, в котором он находится, с использованием синтаксиса расширения аргументов cmd.exe, как описано в выводе cmd /c call /?

  • Интерфейс командной строки PowerShell с -Command/-c, который является подразумеваемым параметром в CLI Windows PowerShell, powershell.exe, требует символов ". экранироваться как \", чтобы дословно передаваться как часть кода.

    • Напротив, pwsh, CLI PowerShell (Core) 7 по умолчанию имеет значение -File и требует явного использования -Command / -c для передачи исходного кода PowerShell в качестве аргумента. Здесь применяются те же правила экранирования, хотя pwsh.exe в Windows также принимает "" как экранированный ", что на самом деле предпочтительнее при вызове из cmd.exe (пакетных файлов), чтобы избежать нарушения синтаксиса cmd.exe.
  • Поскольку используется вложенный вызов powershell.exe, в приведенном выше примере используется \\\" для экранирования символов ". чтобы в конечном итоге перейти к вложенному экземпляру с повышенными правами powershell.exe. Однако, поскольку %~dp0 всегда расширяется до пути к каталогу с завершающим \, за ним следует только \\" выше.


[1] By contrast, a directly launched PowerShell instance implicitly inherits all of the caller's environment variables, and since using the SET statement in a batch file to define a variable invariably creates an environment variable, such a PowerShell instance automatically sees such variables, using $env: namespace variable notation - see the conceptual about_Environment_Variables help topic.
E.g., calling SET FOO=bar in the calling batch file before invoking the PowerShell CLI allows the latter to reference said variable('s value) as $env:FOO.

Отлично, ваш ответ помог мне понять гораздо больше. Мне еще предстоит многому научиться. Искренне спасибо!

NqHai 21.06.2024 02:56

Потому что я попробовал использовать строку кода yy. Результаты, которые я получил, были именно теми, которые мне были нужны, поэтому я думаю, что это подходящий и самый ранний ответ в данном случае. Я не знаю достаточно, чтобы прокомментировать, какой ответ лучше, поэтому я просто выбираю ответ, который могу понять, и сразу же практикую. Несмотря на это, ваш ответ очень проницателен, и я буду тратить больше времени на обучение у вас. Большое спасибо.

NqHai 21.06.2024 10:04

Рад это слышать, @NqHai, и ценю обратную связь. Кроме того, я ошибся в ответе yy - последняя команда устанавливает переменную, как и было запрошено.

mklement0 21.06.2024 12:24

Другие вопросы по теме