I’m fully back into builds and Visual Studio and even unit testing using MSTest once again, and I’m enjoying it very much. But I’m still working with databases, though less in a DBA-capacity. I recently needed to build and deploy about 40 small database projects that were in 4 or 5 different database solutions. And I needed to do this several times a day, so compiling via Visual Studio would be a boring and tedious process. So to speed up the process I decided to write the build process in an MSBuild target file and call initiate the build process through PowerShell. The targets file was simple enough to put together.

<Project ToolsVersion="4.0"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003"
DefaultTargets="Default">

<ItemGroup>
<ProjectReference Include=".\**\*.sln" Exclude=".\**\DBSolutionToIgnore.sln"/>
</ItemGroup>

<Target Name="Default">
<MSBuild Projects="@(ProjectReference)" Targets="Rebuild"/>
</Target>

</Project>
$msbuild = "C:\Windows\Microsoft.Net\Framework\v4.0.30319\MSBuild.exe"
$MsBuilExists = Test-Path $msbuild
If ($MsBuilExists -ne $true) {write-host "msbuild does not exist at this location. Install Visual Studio 2015 (Community Edition should be adequate)"}
$buildFile = $PSScriptRoot+"\BuildAllDBProjects.targets.xml"
& $msbuild $buildFile

Then run that and it's all good right? Well, I thought so to, but then this error appeared.

C:\Users\Richard\Source\db_.sqlproj(59,3): error MSB4019: The imported project "C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v11.0\SSDT\Microsoft.Data.Tools.Schema.SqlTasks.targets" was not found. Confirm that the path in the <Import> declaration is correct, and that the file exists on disk.

Colour me confused? Well, the error points towards a line in the sqlproj file. So I unloaded the sqlproj in Visual Studio and opened up the file in xml editor to see the offending command.

&lt;PropertyGroup&gt;
&lt;VisualStudioVersion Condition=&quot;'$(VisualStudioVersion)' == ''&quot;&gt;11.0&lt;/VisualStudioVersion&gt;
&lt;!-- Default to the v11.0 targets path if the targets file for the current VS version is not found --&gt;
&lt;SSDTExists Condition=&quot;Exists('$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\SSDT\Microsoft.Data.Tools.Schema.SqlTasks.targets')&quot;&gt;True&lt;/SSDTExists&gt;
&lt;VisualStudioVersion Condition=&quot;'$(SSDTExists)' == ''&quot;&gt;11.0&lt;/VisualStudioVersion&gt;
&lt;/PropertyGroup&gt;
&lt;Import Condition=&quot;'$(SQLDBExtensionsRefPath)' != ''&quot; Project=&quot;$(SQLDBExtensionsRefPath)\Microsoft.Data.Tools.Schema.SqlTasks.targets&quot; /&gt;
&lt;Import Condition=&quot;'$(SQLDBExtensionsRefPath)' == ''&quot; Project=&quot;$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\SSDT\Microsoft.Data.Tools.Schema.SqlTasks.targets&quot; /&gt;

So in case you were not already aware of this, a proj file is basically a MSBuild target file that tells MSBuild what to build. You can even see the properties set for each build configuration. And the lines that are causing an issue here are just some nasty business.

What is happening is that when a project is built in Visual Studio some targets that are external of the whole process that were installed as part of Visual Studio are used as part of the process. Obviously, when we run MSBuild via cmdline, we are not setting the parameter "VisualStudioVersion", because this is pretty much a "headless" build. So the sqlproj file handles this by setting the parameter to 11.0, which is pretty horrible. Given that projects are created in Visual Studio, I would've felt that the version a project was created in would be baked in as the default, as opposed to just some random version number. At the very least, a warning that a default version number has been set would come in useful, especially as this is 2016 now and the sqlproj files default to 2010 targets.

Anyway, we can include a workaround by passing in the VisualStudioVersion like so:

$msbuild = &quot;C:\Windows\Microsoft.Net\Framework\v4.0.30319\MSBuild.exe&quot;
$MsBuilExists = Test-Path $msbuild
If ($MsBuilExists -ne $true) {write-host &quot;msbuild does not exist at this location. Install Visual Studio 2015 (Community Edition should be adequate)&quot;}
$buildFile = $PSScriptRoot+&quot;\BuildAllDBProjects.targets.xml&quot;
$arg = &quot;/p:VisualStudioVersion=14.0&quot;
&amp; $msbuild $buildFile $arg
Write-Host &quot;Press any key to continue ...&quot;
$x = $host.UI.RawUI.ReadKey(&quot;NoEcho,IncludeKeyDown&quot;)

If you're still getting the error, double check that you can compile the solution in Visual Studio and ensure that you have SQL Server Data Tools installed on your machine.