Мне нужно изменить запуск командного файла для сайта, написанного на Micro Focus COBOL, чтобы получить доступ к хранилищу ключей Azure. Я написал сценарий PowerShell для доступа к хранилищу ключей. Мне нужно вернуться к данным командного файла, которые командный файл использует для установки переменных среды. Я не хочу передавать переменную на уровне компьютера — это лишит смысла использование хранилища ключей. Как отправить строковую переменную обратно в командный файл?
Я попытался установить переменную среды в PowerShell, которая была бы постоянной на уровне процесса, надеясь, что она будет распознана командным файлом Windows, который ее вызвал. Переменная не была распознана после возвращения из PowerShell.
командный файл запуска
ECHO SETTING ENVIRONMENT SPECIFIC VARIABLES
SET REGION_NAME=theRegion
powershell.exe -File "C:\Util\CallAzure.Ps1"
SET FIRST_ENV_VAR=DSN=DataSet;UID=UserID;PWD=%FromPowerShell%
...
SET SHAREDFILE_LOCATION=\\theServer\theFolder
ECHO DONE SETTING ENVIRONMENT SPECIFIC VARIABLES
сценарий PowerShell
ECHO 'SETTING ENVIRONMENT SPECIFIC VARIABLES - PowerShell'
$Url = "https://lookupdv.site.org/API.KeyVault"
$JSON = "application/json"
$Body = @{
URI = "KeyName"
secretname = "UserID"
}
$Password = Invoke-RestMethod -Method 'Post' -Uri $url -ContentType $JSON -Body ($body | ConvertTo-Json)
[System.Environment]::SetEnvironmentVariable('FromPowerShell', $Password, [System.EnvironmentVariableTarget]::Process)
ECHO 'DONE SETTING ENVIRONMENT SPECIFIC VARIABLES - PowerShell'
это не работает
следует ли мне изменить команду Set на пользователя вместо процесса?
Вы можете посмотреть: Как настроить вывод команды как env. переменная в Windows cmd? или Как настроить вывод команд в виде переменной в пакетном файле
«for» Cmd может установить переменную в качестве вывода команды. Удвойте % в файле .bat.
echo echo hi > script.ps1
for /f %i in ('powershell -file script.ps1') do set a=%i
echo %a%
hi
Как отмечает Люук, дочерний процесс не может изменять среду своего родительского процесса, поэтому любые изменения среды на уровне процесса, сделанные дочерним процессом powershell.exe
, неизменно теряются, когда управление возвращается вызывающему объекту (вашему пакетному файлу).
Однако, если вы знаете, какую переменную среды уровня процесса устанавливает ваш сценарий PowerShell, вы можете вызвать powershell.exe, CLI Windows PowerShell, таким образом, чтобы отображать (выводить) эту переменную (значение) через ее поток stdout, позволяющий вашему пакетному файлу захватить его с помощью оператора for /f
; для этого вы должны использовать параметр -Command
, а не параметр -File
; -Command
позволяет передать фрагмент кода PowerShell.
Вот фрагмент пакетного файла, иллюстрирующий этот подход.
Обратите внимание, что для этого не требуется никаких изменений в вашем скрипте C:\Util\CallAzure.Ps1
, поскольку именно фрагмент кода PowerShell, переданный в -Command
, гарантирует вывод интересующего значения переменной среды:
:: ...
:: Define the PowerShell command line that calls the PowerShell script
:: and then echoes the "FromPowerShell" environment variable that was set
:: in the script.
set pscmd=powershell.exe -Command "C:\Util\CallAzure.Ps1 >$null; $env:FromPowerShell"
:: Invoke the PowerShell command line, and save its only output line in a
:: variable (for the current process.)
for /f "usebackq delims = " %%i in (`%pscmd%`) do set "FromPowerShell=%%i"
:: %FromPowerShell% now contains the value of interest.
:: ...
Примечание:
>$null
выше подавляет вывод успеха сценария .ps1
(stdout) (сообщения о состоянии), так что вызов -Command
выводит только значение переменной среды и ничего больше.
Если вы все еще хотите видеть этот вывод, вам придется перенаправить его на stderr, определив командную строку PowerShell следующим образом:
set pscmd=powershell.exe -NoProfile -Command "[Console]::Error.WriteLine((C:\Util\CallAzure.Ps1) -join [char] 10); $env:FromPowerShell"
Примечание:
Из вышесказанного следует, что альтернативой является изменение вашего .ps1
файла следующим образом:
Заставьте его выводить значение переменной среды.
Убедитесь, что сообщения о состоянии, напечатанные сценарием, используют [Console]::Error.WriteLine()
, а не echo
(также известный как Write-Output), т. е. что сообщения о состоянии не «загрязняют» поток вывода успеха и, следовательно, стандартный вывод.
При таком подходе даже нет строгой необходимости устанавливать значение переменной среды в сценарии PowerShell: просто выведите интересующее значение напрямую.
Затем вы можете вызвать свой .ps1
файл с помощью -File
вызова CLI PowerShell, как и раньше.
Оба решения предполагают, что в пакетный файл должно быть передано только одно интересующее значение.
.ps1
, которые можно будет передать set
в вызывающем пакетном файле, например, вывести 'FOO=BAR'
и 'BAZ=QUX'
из вашего сценария PowerShell, и изменить команду set
в цикле for /f
в пакете. файл в set "%%i"
, как показано ниже.Пример с несколькими значениями:
Пример C:\Util\CallAzure.Ps1
контента:
# Print status messages to stderr, to avoid polluting
# stdout.
[Console]::Error.WriteLine('Outputting name-value pairs.')
# Output name-value pairs, to be set as environment variables
# by the batch file.
'FOO=BAR'
'BAZ=QUX'
Пример содержимого пакетного файла:
@echo off & setlocal
:: Remove `& setlocal` if you want to variables set by this
:: batch file to persist in a `cmd.exe` session.
:: Define the PowerShell command line that calls the .ps1 script
set pscmd=powershell.exe -noprofile -File C:\Util\CallAzure.Ps1
:: Invoke the PowerShell command line, and pass the name-value
:: pairs to `set`, which defines them as process-level
:: environment variables.
for /f "usebackq delims = " %%i in (`%pscmd%`) do set "%%i"
:: Echo the resulting variables for diagnostic purposes.
echo [%FOO%]
echo [%BAZ%]
Среда, созданная в начале
powershell.exe -File "..."
, теряется, когда выполнение сценария PowerShell завершается.