Como posso usar o PowerShell com o Prompt de Comando do Visual Studio?

119

Estou usando o Beta 2 há algum tempo e está me deixando maluco que preciso acessar cmd.exe ao executar o prompt de comando do VS2010. Eu costumava ter um script vsvars2008.ps1 legal para Visual Studio 2008. Alguém tem um vsvars2010.ps1 ou algo semelhante?

Andy S
fonte

Respostas:

223

Roubando livremente daqui: http://allen-mack.blogspot.com/2008/03/replace-visual-studio-command-prompt.html , consegui fazer isso funcionar. Adicionei o seguinte ao meu profile.ps1 e está tudo bem com o mundo.

pushd 'c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC'
cmd /c "vcvarsall.bat&set" |
foreach {
  if ($_ -match "=") {
    $v = $_.split("="); set-item -force -path "ENV:\$($v[0])"  -value "$($v[1])"
  }
}
popd
write-host "`nVisual Studio 2010 Command Prompt variables set." -ForegroundColor Yellow

Isso funcionou bem por anos - até o Visual Studio 2015. vcvarsall.bat não existe mais. Em vez disso, você pode usar o arquivo vsvars32.bat, que está localizado na pasta Common7 \ Tools.

pushd 'C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\Tools'    
cmd /c "vsvars32.bat&set" |
foreach {
  if ($_ -match "=") {
    $v = $_.split("="); set-item -force -path "ENV:\$($v[0])"  -value "$($v[1])"
  }
}
popd
write-host "`nVisual Studio 2015 Command Prompt variables set." -ForegroundColor Yellow

As coisas mudaram mais uma vez para o Visual Studio 2017. vsvars32.batparece ter sido abandonado em favor de VsDevCmd.bat. O caminho exato pode variar dependendo de qual edição do Visual Studio 2017 você está usando.

pushd "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\Common7\Tools"
cmd /c "VsDevCmd.bat&set" |
foreach {
  if ($_ -match "=") {
    $v = $_.split("="); set-item -force -path "ENV:\$($v[0])"  -value "$($v[1])"
  }
}
popd
Write-Host "`nVisual Studio 2017 Command Prompt variables set." -ForegroundColor Yellow
Andy S
fonte
6
Apenas uma observação rápida de que essa mesma técnica funciona para o Visual Studio 2012. Basta alterar "Microsoft Visual Studio 10.0" para "Microsoft Visual Studio 11.0"
Andy S
9
echo $Profilepara ver o caminho pretendido para o seu profile.ps1, se você nunca o criou
Matt Stephenson,
5
O próprio script funciona maravilhosamente bem. Porém, uma nota de cautela (possivelmente): como o Console do gerenciador de pacotes no Visual Studio é um host do PowerShell, esse script também será executado lá. Isso não parece ser um problema até que você perceba que "Executar sem depuração" ou quaisquer outras funções ou plug-ins executados que iniciem um console padrão do Windows não funcionarão após a inicialização do PMC. Eu contornei isso, em vez de salvar o script nesta resposta em "profile.ps1", salvei-o em "Microsoft.PowerShell_profile.ps1" para que ele seja executado apenas em uma sessão PowerShell "adequada".
Chris Simmons
3
É uma prática muito ruim codificar os caminhos quando há variáveis ​​de ambiente perfeitamente boas (VS140COMNTOOLS para VS2015) para usar. Isso funcionará até mesmo para instalações VS personalizadas.
Voo de
5
Agradeço o desejo de usar variáveis ​​de ambiente, mas essas variáveis ​​parecem ser inicializadas pelo próprio arquivo em lote do qual estamos tentando extrair variáveis. Eu ficaria feliz em ver evidências em contrário. Tenho uma instalação limpa do Windows 10 com uma instalação limpa do Visual Studio 2017 e nenhuma variável de ambiente VS150COMNTOOLS até executar VsDevCmd.bat.
Andy S
26

A opção mais simples é executar o prompt de comando do VS 2010 e, em seguida, iniciar o PowerShell.exe. Se você realmente deseja fazer isso de seu prompt do PowerShell "inicial", a abordagem que você mostra é o caminho a percorrer. Eu uso um script que Lee Holmes escreveu há algum tempo:

<#
.SYNOPSIS
   Invokes the specified batch file and retains any environment variable changes
   it makes.
.DESCRIPTION
   Invoke the specified batch file (and parameters), but also propagate any  
   environment variable changes back to the PowerShell environment that  
   called it.
.PARAMETER Path
   Path to a .bat or .cmd file.
.PARAMETER Parameters
   Parameters to pass to the batch file.
.EXAMPLE
   C:\PS> Invoke-BatchFile "$env:VS90COMNTOOLS\..\..\vc\vcvarsall.bat"       
   Invokes the vcvarsall.bat file to set up a 32-bit dev environment.  All 
   environment variable changes it makes will be propagated to the current 
   PowerShell session.
.EXAMPLE
   C:\PS> Invoke-BatchFile "$env:VS90COMNTOOLS\..\..\vc\vcvarsall.bat" amd64      
   Invokes the vcvarsall.bat file to set up a 64-bit dev environment.  All 
   environment variable changes it makes will be propagated to the current 
   PowerShell session.
.NOTES
   Author: Lee Holmes    
#>
function Invoke-BatchFile
{
   param([string]$Path, [string]$Parameters)  

   $tempFile = [IO.Path]::GetTempFileName()  

   ## Store the output of cmd.exe.  We also ask cmd.exe to output   
   ## the environment table after the batch file completes  
   cmd.exe /c " `"$Path`" $Parameters && set > `"$tempFile`" " 

   ## Go through the environment variables in the temp file.  
   ## For each of them, set the variable in our local environment.  
   Get-Content $tempFile | Foreach-Object {   
       if ($_ -match "^(.*?)=(.*)$")  
       { 
           Set-Content "env:\$($matches[1])" $matches[2]  
       } 
   }  

   Remove-Item $tempFile
}

Observação: esta função estará disponível na versão baseada em módulo PowerShell Community Extensions 2.0 em breve.

Keith Hill
fonte
22

Encontrei um método simples aqui : modificar o atalho.

O atalho original é mais ou menos assim:

%comspec% /k ""C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\Tools\VsDevCmd.bat""

Adicione & powershellantes da última citação, assim:

%comspec% /k ""C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\Tools\VsDevCmd.bat" & powershell"

Se você quiser torná-lo mais parecido com PS, vá para a guia Cores das propriedades do atalho e defina os valores de Vermelho, Verde e Azul para 1, 36 e 86 respectivamente.

captura de tela

user247702
fonte
Simples e funciona como um encanto. Esta resposta merece mais votos positivos.
Mark Meuer
2
A única coisa que não gosto nisso é que mantém um processo cmd.exe redundante carregado. Fora isso, é uma boa solução.
orad
17

Uma pergunta antiga, mas vale outra resposta para (a) fornecer suporte VS2013; (b) combinar o melhor de duas respostas anteriores; e (c) fornecer um wrapper de função.

Isso se baseia na técnica de @Andy (que se baseia na técnica de Allen Mack conforme Andy indicou (que por sua vez se baseia na técnica de Robert Anderson conforme Allen indicou (todos os quais tiveram uma pequena falha, conforme indicado nesta página pelo usuário conhecido apenas como "eu- - ", então eu levei isso em consideração também))).

Aqui está meu código final - observe o uso do quantificador não ganancioso na regex para lidar com qualquer igual embutido nos valores. Isso também simplifica o código: uma única correspondência em vez de uma correspondência e então dividida como no exemplo de Andy ou uma correspondência e indexof e substrings como no exemplo de "me -").

function Set-VsCmd
{
    param(
        [parameter(Mandatory, HelpMessage="Enter VS version as 2010, 2012, or 2013")]
        [ValidateSet(2010,2012,2013)]
        [int]$version
    )
    $VS_VERSION = @{ 2010 = "10.0"; 2012 = "11.0"; 2013 = "12.0" }
    $targetDir = "c:\Program Files (x86)\Microsoft Visual Studio $($VS_VERSION[$version])\VC"
    if (!(Test-Path (Join-Path $targetDir "vcvarsall.bat"))) {
        "Error: Visual Studio $version not installed"
        return
    }
    pushd $targetDir
    cmd /c "vcvarsall.bat&set" |
    foreach {
      if ($_ -match "(.*?)=(.*)") {
        Set-Item -force -path "ENV:\$($matches[1])" -value "$($matches[2])"
      }
    }
    popd
    write-host "`nVisual Studio $version Command Prompt variables set." -ForegroundColor Yellow
}
Michael Sorens
fonte
Para compatibilidade com PowerShell 2.0, a seção param requer [parameter(Mandatory=$true,...
sakra
1
Legal, mas seria melhor sem o pushd / popd. Basta usar algo comocmd /c """$targetDir\vcvarsall.bat""&set"
stijn
9

Keith já mencionou PowerShell Community Extensions (PSCX), com seu Invoke-BatchFilecomando:

Invoke-BatchFile "${env:ProgramFiles(x86)}\Microsoft Visual Studio 12.0\VC\vcvarsall.bat"

Também percebi que o PSCX também tem uma Import-VisualStudioVarsfunção:

Import-VisualStudioVars -VisualStudioVersion 2013
Tahir Hassan
fonte
4
A partir do PSCX 3.2.0, o VS 2015 não é compatível com este cmdlet. Eu abri um problema para ele.
orad
3

Parabéns a Andy S por sua resposta. Estou usando a solução dele há um tempo, mas tive um problema hoje. Qualquer valor com um sinal de igual é truncado no sinal de igual. Por exemplo, eu tinha:

JAVA_TOOL_OPTIONS=-Duser.home=C:\Users\Me

Mas minha sessão PS relatou:

PS C:\> $env:JAVA_TOOL_OPTIONS
-Duser.home

Corrigi isso modificando meu script de perfil para o seguinte:

pushd 'c:\Program Files (x86)\Microsoft Visual Studio 11.0\VC'
cmd /c "vcvarsall.bat&set" |
foreach {
  if ($_ -match "=") {
    $i = $_.indexof("=")
    $k = $_.substring(0, $i)
    $v = $_.substring($i + 1)
    set-item -force -path "ENV:\$k"  -value "$v"
  }
}
popd
mim--
fonte
Ei boa adição. Atualizar também com as versões VS2015 / 17 ? Este é o primeiro resultado do google, acho que sua adição vai ajudar as pessoas.
Squirrelkiller de
1

Para alguém que ainda está lutando com isso em 2020 e no Visual Studio Code 1.41.1, um pouco fora do assunto aqui.

Usando todas as diferentes partes do código acima e da Internet, por exemplo, de https://help.appveyor.com/discussions/questions/18777-how-to-use-vcvars64bat-from-powershell e com uma abordagem passo a passo consegui tenha o script abaixo funcionando.

Salvo no VSCode "settings.json" e com a extensão Code Runner instalada.

Com o Microsoft (R) C / C ++ Otimizando Compiler Versão "cl.exe" do Visual Studio 2015 / 14.0:

"code-runner.runInTerminal": true,
"code-runner.executorMap": {
  "cpp": "cd $dir; pushd \"C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\"; cmd.exe /c \"call vcvarsall.bat x86_amd64 & set > %temp%\\vcvars.txt\"; Get-Content \"$env:temp\\vcvars.txt\" | Foreach-Object { if ($_ -match \"^(.*?)=(.*)$\") {   Set-Content \"env:\\$($matches[1])\" $matches[2]  }}; popd; cls; cl *.cpp; .\\\"$fileNameWithoutExt.exe\"; Write-Host -NoNewLine 'Press any key to continue...';  $null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown'); del \"$fileNameWithoutExt.exe\"; del \"$fileNameWithoutExt.obj\""}

Com Microsoft (R) C / C ++ Optimizing Compiler versão "cl.exe" do Visual Studio 2019 / 16.4.3:

"code-runner.runInTerminal": true,
"code-runner.executorMap": {
  "cpp": "cd $dir; pushd \"c:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Auxiliary\\Build\"; cmd.exe /c \"call vcvarsall.bat x86_amd64 & set > %temp%\\vcvars.txt\"; Get-Content \"$env:temp\\vcvars.txt\" | Foreach-Object { if ($_ -match \"^(.*?)=(.*)$\") {   Set-Content \"env:\\$($matches[1])\" $matches[2]  }}; popd; cls; cl *.cpp; .\\\"$fileNameWithoutExt.exe\"; Write-Host -NoNewLine 'Press any key to continue...';  $null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown'); del \"$fileNameWithoutExt.exe\"; del \"$fileNameWithoutExt.obj\""}

HTH

olin000
fonte
0

Eu gosto de passar os comandos para um shell filho assim:

cmd /c "`"${env:VS140COMNTOOLS}vsvars32.bat`" && <someCommand>"

Ou alternativamente

cmd /c "`"${env:VS140COMNTOOLS}..\..\VC\vcvarsall.bat`" amd64 && <someCommand> && <someOtherCommand>"  
MatrixManAtYrService
fonte