Ebeid ElSayed
Ebeid ElSayed

Reputation: 1156

Locate MSTest.exe using powershell

I'm in the process of automating my .Net solution build to be completely in PowerShell. I want to locate MSTest.exe using PowerShell.

I used the following script to locate MSBuild.exe and I hope that I can have something similar to locate MSTest.exe

$msBuildQueryResult = reg.exe query "HKLM\SOFTWARE\Microsoft\MSBuild\ToolsVersions\4.0" /v MSBuildToolsPath
$msBuildQueryResult = $msBuildQueryResult[2]
$msBuildQueryResult = $msBuildQueryResult.Split(" ")
$msBuildLocation = $msBuildQueryResult[12] + "MSBuild.exe"

Any directions ?

Upvotes: 2

Views: 1081

Answers (4)

Jevgenij Kononov
Jevgenij Kononov

Reputation: 1239

My way of getting mstest path. GetMSTestPath function is main function which you call and then if first GetMsTestPathFromVswhere function will find something it returns path if not your will be making a long search for mstest.exe. Usually, it takes approximately 10 sec. I know that this is not the best but at least it is something when you struggle to find mstest.exe. Hope it will be helpful for somebody. :)))

 function GetMSTestPath
    {
        function GetTime()
        {
            $time_now = Get-Date -format "HH:mm:ss"
            return $time_now;
        }
        function GetMsTestPathFromVswhere {
            $vswhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe"
            $path = & $vswhere -latest -prerelease -products * -requires Microsoft.Component.MSBuild -property installationPath
            #write-host $path
            if ($path) {
                $tool = join-path $path 'Common7\IDE\MSTest.exe'
                if (test-path $tool) {
                    return $tool
                }
                return ""
            }
        }

        function SeachForMsTestPath
        {

            write-host $(GetTime)
            $path =  Get-ChildItem C:\ -Filter MSTest.exe -Recurse -ErrorAction Ignore | ? { $_.VersionInfo.FileDescription -eq 'Test Execution Command Line Tool' } | Select -First 1
            write-host $(GetTime)
            return $path
        }

        $msTestExePath = GetMsTestPathFromVswhere
        if ([string]::IsNullOrEmpty($msTestExePath))
        {
            $msTestExePath = SeachForMsTestPath;
            if ([string]::IsNullOrEmpty($msTestExePath))
            {
                Write-host "MsTest path is not found. Exiting with error"
                Exit -1
            }
        }
        return $msTestExePath;
    }

Upvotes: 0

mklement0
mklement0

Reputation: 437823

The following works with Visual Studio 2010 and higher[1]:

# Get the tools folder location:

# Option A: Target the *highest version installed*:
$vsToolsDir = (
  Get-Item env:VS*COMNTOOLS | Sort-Object {[int]($_.Name -replace '[^\d]')}
)[-1].Value

# Option B: Target a *specific version*; e.g., Visual Studio 2010,
# internally known as version 10.0.
# (See https://en.wikipedia.org/wiki/Microsoft_Visual_Studio#History)
$vsToolsDir = $env:VS100COMNTOOLS

# Now locate msbuild.exe in the "IDE" sibling folder.
$msTestExe = Convert-Path -EA Stop (Join-Path $vsToolsDir '..\IDE\MSTest.exe')

The approach is based on this answer and is generalized and adapted to PowerShell.

  • It is based on system environment variables VS*COMNTOOLS, created by Visual Studio setup, where * represents the VS version number (e.g., 100 for VS 2010).

    • Re option A: Sort-Object is used to ensure that the most recent Visual Studio installation is targeted, should multiple ones be installed side by side:
      • The script block used for sorting first extracts only the embedded version number from the variable name ($_.Name -replace '[^\d]'; e.g., 100 from VS100COMNTOOLS) and converts the result to an integer ([int]); [-1] then extracts the last element from the sorted array - i.e., the variable object whose names has the highest embedded version number - and accesses its value (.Value).
  • The IDE subfolder, in which MSTest.exe is located is a sibling folder of the tools folder that VS*COMNTOOLS points to.

  • If MSTest.exe is NOT in the expected location, Convert-Path will throw a non-terminating error by default; adding -EA Stop (short for: -ErrorAction Stop) ensures that the script is aborted instead.


[1]
- I've tried up to Visual Studio 2015; do let me know whether or not it works on higher versions.
- Potentially also works with VS 2008.


Upvotes: 2

Ebeid ElSayed
Ebeid ElSayed

Reputation: 1156

Thanks @Bill_Stewart , I used your comments to write this working function:

function Get-MSTest-Location {
    $msTests = @()
    $searchResults = Get-ChildItem C:\* -Filter MSTest.exe -Recurse -ErrorAction Ignore
    foreach($searchResult in $searchResults) {
        try{ 
            if(($searchResult.VersionInfo -ne $null) -and ($searchResult.VersionInfo.FileDescription -eq "Test Execution Command Line Tool"))
            { $msTests = $msTests + $searchResult.FullName }
        }
        catch{}
        }
    if($msTests.Length -eq 0)
    {return "MSTest not found."}
    return $msTests[0]
}

Upvotes: -1

Bill_Stewart
Bill_Stewart

Reputation: 24555

Perhaps you are wanting something like this?

$regPath = "HKLM:\SOFTWARE\Microsoft\MSBuild\ToolsVersions\4.0"
$regValueName = "MSBuildToolsPath"
$msBuildFilename = "MSBUild.exe"
if ( Test-Path $regPath ) {
  $toolsPath = (Get-ItemProperty $regPath).$regValueName
  if ( $toolsPath ) {
    $msBuild = Join-Path $toolsPath $msBuildFilename
    if ( -not (Test-Path $msBuild -PathType Leaf) ) {
      Write-Error "File not found - '$msBuild'"
    }
  }
}
# Full path and filename of MSBuild.exe in $msBuild variable

Upvotes: 1

Related Questions