Enter-VisualStudioShell.ps1
#Requires -Module VSSetup using module VSSetup <# .Synopsis Start a Visual Studio Developer Command Prompt .Description Finds the latest (preview) version of Visual Studio unless an instance of Visual Studio is provided as an argument and starts a Developer Command prompt for it. .Parameter ExcludePrerelease Do not allow selection of Preview versions of Visual Studio. (Passed through negated to Get-VSSetupInstance) .Parameter Architecture The target processor architecture. This is the architecture for compiled binaries/libraries. Optional. Valid values are "x86", "amd64", "arm", "arm64". The default is "x86". .Parameter HostArchitecture The processor architecture of the compiler binaries. Optional. Valid values are "x86", "amd64". The default is "x86". .Parameter WindowsSdkVersion Version of Windows SDK to select. - 10.0.xxyyzz.0 : Windows 10 SDK (e.g 10.0.10240.0) [default : Latest Windows 10 SDK] - 8.1 : Windows 8.1 SDK - none : Do not setup Windows SDK variables. For use with build systems that prefer to determine Windows SDK version independently. Optional. Valid values are "none", "8.1", "10.0.xxyyzz.0". However if a Visual Studio Setup intance is specified, its package list will be used to verify that the version of the SDK that is requested is installed. .Parameter AppPlatform Application Platform Target Type. Optional. Valid values are "Desktop", "UWP". Desktop : Classic Win32 Apps [default] UWP : Universal Windows Platform Apps .Parameter NoExtensions Only scripts from [VS160COMNTOOLS]\VsDevCmd\Core directory are run during initialization. .Parameter NoLogo Suppress printing of the developer command prompt banner. .Parameter Product One or more products to select. Wildcards are supported. (Passed through to Select-VSSetupInstance) Run `Get-VSSetupInstance | Select-Object Product` to obtain a list of available valid values albeit with a version number. .Parameter StartDirectoryMode The startup directory mode. Optional. Valid values are "none", "auto". none : the command prompt will exist in the same current directory as when invoked auto : the command prompt will search for [USERPROFILE]\Source and will change directory if it exists. If -startdir=mode is not provided, the developer command prompt scripts will additionally check for the [VSCMD_START_DIR] environment variable. If not specified, the default behavior will be 'none' mode. .Parameter Test Run smoke tests to verify environment integrity in an already-initialized command prompt. Executing with -test will NOT modify the environment, so it must be used in a separate call to vsdevcmd.bat (all other parameters should be the same as when the environment was initialied) .Parameter VisualStudio The Visual Studio Setup Instance. Use the VSSetup module or Get-VisualStudio CmdLet to obtain this instance. .Parameter SkipExistingEnvironmentVariables Passed through to Enter-VsDevShell. .Parameter StartInPath Passed through to Enter-VsDevShell. The default is $PWD. .Parameter Force Never ask for confirmation interactively. Combining -WhatIf and -Force will still do nothing. Used to force installation of the VSSetup module from the Internet. .Parameter RemainingArguments Receives all parameters not bound to one of the other, named arguments. These values will be passed unmodified to Enter-VsDevShell. #> function Enter-VisualStudioShell { [CmdLetBinding( SupportsShouldProcess = $true, ConfirmImpact = [System.Management.Automation.ConfirmImpact]::Medium )] Param( [ValidateSet($null, "x86", "amd64", "arm", "arm64")] [Alias("arch")] [string]$Architecture = $null, [ValidateSet($null, "x86", "amd64")] [Alias("host_arch")] [string]$HostArchitecture = $null, [ValidateScript({ Confirm-WindowsSdkVersion -WindowsSdkVersion $_ -AllowNullOrEmpty -VisualStudio $VisualStudio })] [Alias("winsdk")] [string]$WindowsSdkVersion = $null, [ValidateSet($null, "Desktop", "UWP")] [Alias("app_platform")] [string]$AppPlatform, [Alias("no_ext")] [switch]$NoExtensions = [switch]::new($false), [Alias("no_logo")] [switch]$NoLogo = [switch]::new($false), [string[]]$Product = $null, [ValidateSet($null, "none", "auto")] [Alias("startdir")] [string]$StartDirectoryMode = $null, # [Alias("test")] can't be the same case-insensitively [switch]$Test = [switch]::new($false), [Microsoft.VisualStudio.Setup.Instance]$VisualStudio = $null, [switch]$SkipExistingEnvironmentVariables = [switch]::new($false), [string]$StartInPath = $PWD, [switch]$Force = [switch]::new($false), [switch]$ExcludePrerelease = [switch]::new($false), [Parameter(ValueFromRemainingArguments)] [object[]]$RemainingArguments = $null ) Process { if ($null -eq $VisualStudio) { if ($null -eq $Product) { $VisualStudio = Get-VisualStudio -ExcludePrerelease:($ExcludePrerelease.IsPresent) } else { $VisualStudio = Get-VisualStudio -ExcludePrerelease:($ExcludePrerelease.IsPresent) -Product:$Product } } elseif (-not (Confirm-VisualStudio $VisualStudio)) { Write-Error "The Visual Studio parameter is not valid. Remove the parameter or specify a valid value." return; } if (-not (Import-VisualStudioShellModule -VisualStudio $VisualStudio)) { Write-Error "Could not load the Visual Studio Shell module." } $DevCmdArguments = Format-VisualStudioShellArguments ` -VisualStudio $VisualStudio ` -Architecture $Architecture ` -HostArchitecture $HostArchitecture ` -WindowsSdkVersion $WindowsSdkVersion ` -AppPlatform $AppPlatform ` -StartDirectoryMode $StartDirectoryMode ` -RemainingArguments $RemainingArguments ` -NoExtensions:($NoExtensions.IsPresent) ` -NoLogo:($NoLogo.IsPresent) ` -Test:($Test.IsPresent) $target = "{0} [{1}]" -f @( $VisualStudio.DisplayName $VisualStudio.InstallationName $VisualStudio.InstallationPath ) $action = "{0} -{1} '{2}' -{3} '{4}' -{5} '{6}' -{7} '{8}'" -f @( "Enter-VsDevShell" "VsInstallPath" $VisualStudio.InstallationPath "SkipExistingEnvironmentVariables" $SkipExistingEnvironmentVariables.IsPresent "StartInPath" $StartInPath "DevCmdArguments" $DevCmdArguments ) # Since Enter-VsDevShell also SupportsShouldProcess, invoke it even if ShouldProcess returns false but hide the logo $ShouldProcess = $PSCmdlet.ShouldProcess($target, $action) if (-not $ShouldProcess) { if (-not $NoLogo.IsPresent) { $DevCmdArguments += " -no_logo" $DevCmdArguments = $DevCmdArguments.Trim() Write-Verbose "Adding -no_logo because ShouldProcess is false and -NoLogo was not specified." } if ($StartInPath -ne $PWD.Path) { Write-Verbose "Changing StartInPath from '$StartInPath' to '$PWD' because ShouldProcess is false and StartInPath is different from the current working directory." $StartInPath = $PWD.Path } } # On older Visual Studios, on PowerShell Core, only the first time, MethodNotFoundException occurs while ($true) { try { Enter-VsDevShell ` -VsInstallPath $VisualStudio.InstallationPath ` -SkipExistingEnvironmentVariables:$SkipExistingEnvironmentVariables ` -StartInPath $StartInPath ` -DevCmdArguments $DevCmdArguments break; } catch { $e = $_ $x = $e.Exception while ($x -is [System.AggregateException]) { $x = $x.InnerException } if ($x -is [System.MissingMethodException] -and ($x.Message -match "GetAccessControl")) { $m = "Ignoring expected exception {0} with message '{1}' " + "because the environment has been successfully initialized." $m = $m -f @( $x.GetType().Name $x.Message ) Write-Verbose $m break } throw } } } } |