Comment puis-je utiliser PowerShell avec l'invite de commandes Visual Studio?

119

J'utilise la bêta 2 depuis un certain temps maintenant et cela me rend fou de devoir punt à cmd.exe lors de l'exécution de l'invite de commande VS2010. J'avais l'habitude d'avoir un joli script vsvars2008.ps1 pour Visual Studio 2008. Quelqu'un a un vsvars2010.ps1 ou quelque chose de similaire?

Andy S
la source

Réponses:

223

Volant libéralement d'ici: http://allen-mack.blogspot.com/2008/03/replace-visual-studio-command-prompt.html , j'ai pu faire fonctionner cela. J'ai ajouté ce qui suit à mon profile.ps1 et tout va bien avec le monde.

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

Cela a bien fonctionné pendant des années - jusqu'à Visual Studio 2015. vcvarsall.bat n'existe plus. Au lieu de cela, vous pouvez utiliser le fichier vsvars32.bat, qui se trouve dans le dossier 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

Les choses ont encore changé pour Visual Studio 2017. vsvars32.batsemble avoir été abandonné en faveur de VsDevCmd.bat. Le chemin exact peut varier en fonction de l'édition de Visual Studio 2017 que vous utilisez.

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
la source
6
Juste une note rapide que cette même technique fonctionne pour Visual Studio 2012. Il suffit de changer "Microsoft Visual Studio 10.0" en "Microsoft Visual Studio 11.0"
Andy S
9
echo $Profile pour voir le chemin prévu pour votre profile.ps1, si vous ne l'avez jamais créé
Matt Stephenson
5
Le script lui-même fonctionne à merveille. Attention cependant (éventuellement): comme la console du gestionnaire de packages de Visual Studio est elle-même un hôte PowerShell, ce script y sera également exécuté. Cela ne semble pas être un problème jusqu'à ce que vous remarquiez que "Exécuter sans débogage" ou toute autre fonction ou plug-in exécutés qui lancent une console Windows standard ne fonctionnera pas après l'initialisation du PMC. J'ai contourné cela en, au lieu d'enregistrer le script de cette réponse dans "profile.ps1", je l'ai enregistré dans "Microsoft.PowerShell_profile.ps1" afin qu'il ne soit exécuté que dans une session PowerShell "appropriée".
Chris Simmons
3
C'est vraiment une mauvaise pratique de coder en dur les chemins lorsqu'il y a des variables d'environnement parfaitement fines (VS140COMNTOOLS pour VS2015) à utiliser. Cela fonctionnera même pour les installations VS personnalisées.
Voo le
5
J'apprécie le désir d'utiliser des variables d'environnement, mais ces variables semblent être initialisées par le fichier batch même dont nous essayons d'extraire les variables. Je serais heureux de voir des preuves du contraire. J'ai une installation propre de Windows 10 avec une installation propre de Visual Studio 2017 et aucune variable d'environnement VS150COMNTOOLS jusqu'à ce que j'exécute VsDevCmd.bat.
Andy S
26

L'option la plus simple consiste à exécuter l'invite de commande VS 2010, puis à démarrer PowerShell.exe. Si vous voulez vraiment faire cela à partir de votre invite PowerShell «d'accueil», l'approche que vous montrez est la voie à suivre. J'utilise un script que Lee Holmes a écrit il y a quelque temps:

<#
.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
}

Remarque: cette fonction sera bientôt disponible dans la version basée sur le module PowerShell Community Extensions 2.0.

Keith Hill
la source
22

J'ai trouvé une méthode simple ici : modifier le raccourci.

Le raccourci d'origine est quelque chose comme ceci:

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

Ajoutez & powershellavant le dernier devis, comme ceci:

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

Si vous voulez le faire ressembler davantage à PS, allez dans l' onglet Couleurs des propriétés du raccourci et définissez les valeurs Rouge, Vert et Bleu sur 1, 36 et 86 respectivement.

capture d'écran

user247702
la source
Simple et fonctionne comme un charme. Cette réponse mérite plus de votes positifs.
Mark Meuer
2
La seule chose que je n'aime pas à ce sujet, c'est qu'il garde un processus cmd.exe redondant chargé. Autre que cela, c'est une bonne solution.
orad
17

Une vieille question mais qui mérite une autre réponse pour (a) fournir un support VS2013; (b) combiner la meilleure des deux réponses précédentes; et (c) fournir un wrapper de fonction.

Cela s'appuie sur la technique de @ Andy (qui s'appuie sur la technique d'Allen Mack comme Andy l'a indiqué (qui à son tour s'appuie sur la technique de Robert Anderson comme Allen l'a indiqué (qui avait tous un léger problème comme indiqué sur cette page par l'utilisateur connu uniquement sous le nom de "me- - ", alors j'en ai aussi tenu compte))).

Voici mon code final - notez l'utilisation du quantificateur non gourmand dans l'expression régulière pour gérer tous les égaux incorporés possibles dans les valeurs. Cela arrive aussi à simplifier le code: une seule correspondance au lieu d'une correspondance puis fractionnée comme dans l'exemple d'Andy ou une correspondance puis indexof et sous-chaînes comme dans l'exemple 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
la source
Pour la compatibilité PowerShell 2.0, la section param nécessite [parameter(Mandatory=$true,...
sakra
1
Bien, mais je serais plus gentil sans le pushd / popd. Il suffit d'utiliser quelque chose commecmd /c """$targetDir\vcvarsall.bat""&set"
stijn
9

Keith a déjà mentionné les extensions de communauté PowerShell (PSCX), avec sa Invoke-BatchFilecommande:

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

J'ai également remarqué que PSCX a également une Import-VisualStudioVarsfonction:

Import-VisualStudioVars -VisualStudioVersion 2013
Tahir Hassan
la source
4
À partir de PSCX 3.2.0, VS 2015 n'est pas pris en charge dans cette applet de commande. J'ai ouvert un numéro pour cela.
orad
3

Félicitations à Andy S pour sa réponse. J'utilise sa solution depuis un certain temps, mais j'ai rencontré un problème aujourd'hui. Toute valeur qui a un signe égal est tronquée au signe égal. Par exemple, j'avais:

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

Mais ma session PS a rapporté:

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

J'ai résolu ce problème en modifiant mon script de profil comme suit:

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
moi--
la source
Hé bel ajout. Le mettre à jour avec les versions VS2015 / 17 aussi? C'est le premier résultat Google, je pense que votre ajout aidera les gens.
Squirrelkiller
1

Pour quelqu'un qui a encore du mal avec cela en 2020 et Visual Studio Code 1.41.1, donc un peu hors sujet ici.

En utilisant toutes les différentes parties du code ci-dessus et Internet, par exemple à partir de https://help.appveyor.com/discussions/questions/18777-how-to-use-vcvars64bat-from-powershell et avec une approche étape par étape, j'ai réussi à faire fonctionner le script ci-dessous.

Enregistré dans VSCode "settings.json" et avec l'extension Code Runner installée.

Avec Microsoft (R) C / C ++ Optimizing Compiler Version "cl.exe" de 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\""}

Avec Microsoft (R) C / C ++ Optimizing Compiler Version "cl.exe" de 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
la source
0

J'aime passer les commandes dans un shell enfant comme ceci:

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

Ou bien

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