Как вызвать пакетный скрипт из Powershell? - PullRequest
23 голосов
/ 08 декабря 2010

У меня есть один большой пакетный скрипт, который устанавливает кучу переменных среды.Я хочу вызвать этот пакетный сценарий из powershell, чтобы получить преимущества как переменной окружения, установленной моим сценарием, так и powershell.

Ответы [ 5 ]

21 голосов
/ 08 декабря 2010

Если вы берете PowerShell Community Extensions , в нем есть команда Invoke-BatchFile, которая запускает пакетный файл, но, что более важно, она сохраняет любые изменения переменных среды, сделанные пакетным файлом, например:

>Invoke-BatchFile 'C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\vcvarsall.bat'
Setting environment for using Microsoft Visual Studio 2008 x86 tools.
12 голосов
/ 08 декабря 2010

Идея приходит из этого поста в блоге: Ничто не решает все - PowerShell и другие технологии

Вот моя версия этого скрипта. Он вызывает командный файл (или любую команду native ) и распространяет свою среду:


ОБНОВЛЕНИЕ: улучшенная и лучше протестированная версия этого скрипта находится здесь: Invoke-Environment.ps1

<#
.SYNOPSIS
    Invokes a command and imports its environment variables.

.DESCRIPTION
    It invokes any cmd shell command (normally a configuration batch file) and
    imports its environment variables to the calling process. Command output is
    discarded completely. It fails if the command exit code is not 0. To ignore
    the exit code use the 'call' command.

.PARAMETER Command
        Any cmd shell command, normally a configuration batch file.

.EXAMPLE
    # Invokes Config.bat in the current directory or the system path
    Invoke-Environment Config.bat

.EXAMPLE
    # Visual Studio environment: works even if exit code is not 0
    Invoke-Environment 'call "%VS100COMNTOOLS%\vsvars32.bat"'

.EXAMPLE
    # This command fails if vsvars32.bat exit code is not 0
    Invoke-Environment '"%VS100COMNTOOLS%\vsvars32.bat"'
#>

param
(
    [Parameter(Mandatory=$true)] [string]
    $Command
)

cmd /c "$Command > nul 2>&1 && set" | .{process{
    if ($_ -match '^([^=]+)=(.*)') {
        [System.Environment]::SetEnvironmentVariable($matches[1], $matches[2])
    }
}}

if ($LASTEXITCODE) {
    throw "Command '$Command': exit code: $LASTEXITCODE"
}

P.S. Вот предложение добавить аналогичную возможность в PowerShell: Расширить концепцию точечного поиска для файлов cmd

2 голосов
/ 08 декабря 2010

Возможно ли преобразовать ваш пакетный скрипт в скрипт PowerShell? Если вы запустите файл bat, он будет запущен в отдельном сеансе, который не изменяет переменные env PowerShell.

Вы можете работать с переменными env очень плавно:

PS> Get-ChildItem env:

Name                           Value
----                           -----
ALLUSERSPROFILE                C:\ProgramData
APPDATA                        C:\Users\xyz\AppData\Roaming
CommonProgramFiles             C:\Program Files (x86)\Common Files
CommonProgramFiles(x86)        C:\Program Files (x86)\Common Files
CommonProgramW6432             C:\Program Files\Common Files
COMPUTERNAME                   xyz
ComSpec                        C:\Windows\system32\cmd.exe
DXSDK_DIR                      D:\prgs\dev\Microsoft DirectX SDK (August 2009)\
FP_NO_HOST_CHECK               NO
HOMEDRIVE                      Z:
HOMEPATH                       \
...

PS> Get-Item env:path
Name  Value
----  -----
Path  c:\dev\CollabNet\SubversionClient;C:\Windows\system32;...

Или даже (намного короче, возвращает только строку):

PS> $env:path
c:\dev\CollabNet\Subversion Client;C:\Windows\system32;...

Вы можете изменить путь к среде следующим образом:

PS> $env:path += ";c:\mydir"

И вы даже можете установить переменные окружения на уровне машины следующим образом:

# fist arg = env variable name, second = value, third = level, available are 'Process', 'User', 'Machine'
PS> [Environment]::SetEnvironmentVariable('test', 'value', 'machine')
0 голосов
/ 05 июля 2019

@ Решение Романа Кузьмина прекрасно работает, но передача вывода команды в nul может оставить вас в неведении.Поэтому я сделал несколько настроек, чтобы вывод команды отображался нормально, и вместо этого направил переменные env во временный файл для последующего чтения:

param
(
    [Parameter(Mandatory=$true)] [string]
    $Command
)
$VarsPath = [IO.Path]::GetTempFileName()
cmd /c "$Command && set > $VarsPath"
if (-not $LASTEXITCODE) {
    Get-Content $VarsPath | ForEach-Object {
        if ($_ -match '^([^=]+)=(.*)') {
            [System.Environment]::SetEnvironmentVariable($matches[1], $matches[2])
        }
    }
}
Remove-Item $VarsPath
0 голосов
/ 08 декабря 2010

Вы можете запустить пакетный скрипт из Powershell, просто указав его имя, но это вам не поможет. Переменные среды, заданные в пакетном скрипте, будут видны только из этого пакета и всего, что пакетный запускает . Как только элемент управления возвращается обратно в Powershell, переменные среды исчезают. Вы можете запустить пакетный скрипт set в конце, а затем проанализировать его вывод в переменных среды PSH.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...