public/Read-VisualStudioSolution.ps1
$vsWebGuids = @{ "ASP.NET 5" = "{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}"; "ASP.NET MVC 1" = "{603C0E0B-DB56-11DC-BE95-000D561079B0}"; "ASP.NET MVC 2" = "{F85E285D-A4E0-4152-9332-AB1D724D3325}"; "ASP.NET MVC 3" = "{E53F8FEA-EAE0-44A6-8774-FFD645390401}"; "ASP.NET MVC 4" = "{E3E379DF-F4C6-4180-9B81-6769533ABE47}"; "ASP.NET MVC 5" = "{349C5851-65DF-11DA-9384-00065B846F21}"; "WebSite" = "{E24C65DC-7377-472B-9ABA-BC803B73C61A}"; } $vsWpfGuid = "{60dc8134-eba5-43b8-bcc9-bb4bc16c2548}"; $languageGuids = @{ "C#" = "{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}" "C++" = "{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}" "F#" = "{F2A71F9B-5D33-465A-A702-920D77279786}" "J#" = "{E6FDF86B-F3D1-11D4-8576-0002A516ECE8}" "VB.NET" = "{F184B08F-C81C-45F6-A57F-5ABD9991F28F}" } $fmgVsProjectFiles = @{ '.csproj' = '.cs' '.vcxproj' = '.cpp' '.vbproj' = '.vb' '.fsproj' = '.fs' '.vsjproj' = '.jsl' '.wixproj' = '.wxs' '.njsproj' = '.js' '.ccproj' = '.csdef' } $testRefs = @("Microsoft.VisualStudio.QualityTools.UnitTestFramework", "xunit", "NUnit.Framework", "NUnitLite") $testPackageRef = @("Microsoft.NET.Test.Sdk") $tsImport = "`$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v`$(VisualStudioVersion)\TypeScript\Microsoft.TypeScript.targets" $vslibSdkValue = "Microsoft.NET.Sdk" $vsWebSdkValue = "Microsoft.NET.Sdk.Web" $ns = @{"msb" = "http://schemas.microsoft.com/developer/msbuild/2003"} $serviceRef = "System.ServiceProcess" function Read-VisualStudioSolution() { <# .SYNOPSIS Reads a Visual Studio solution file and returns meta information including the version of Visual Studio for the solution file and a hashtable of projects with meta info about the projects. .DESCRIPTION Reads a Visual Studio solution file and returns meta information including the version of Visual Studio for the solution file and a hashtable of projects with meta info about the projects. The hashtable key will be the project names. The value will have meta info about the project including: - Name: name of the project - File: the relative path to the project file - Id: the id of project e.g. guid - IsWebProject: true if the project is a web project - WebProjectType: the type of web project - IsTestProject: true if the project is a test project - IsWindowsService: true if the project is a windows service - IsCloudService: true if the project is a cloud service - IsWixSharpProject: true if the project is a wix sharp project - IsWixProject: true if the project is a wix project. - Ext: project extension e.g. csproj - LanguageExt: the code file extension e.g. .cs - IsSdk: true if the project is a dotnet standard/core project .PARAMETER WebProjects Optional. The switch instructs the cmdlet to test for web projects in the solution. .PARAMETER WindowsServiceProjects Optional. The switch instructs the cmdlet to test for windows service projects in the solution. .PARAMETER TestProjects Optional. The switch instructs the cmdlet to test for test projects in the solution. .PARAMETER WixSharpProjects Options. The switch instructs the cmdlet to test for Wix Sharp projects in the solution. .EXAMPLE PS C:\> info = Read-VisualStudioSolution "$Home/Projects/Project.sln" .OUTPUTS a custom object with meta information about the projects in the solution and the version of Visual Studio that created the sln. #> [CmdletBinding()] Param( [Parameter(Position = 0)] [string] $Path, [Switch] $WebProjects, [Switch] $WindowServiceProjects, [Switch] $TestProjects, [Switch] $WixSharpProjects, [Switch] $All ) $projects = @{}; $sln = Get-Item $Path -Ea SilentlyContinue if(!$sln) { throw [System.IO.FileNotFoundException] $Path } Write-Host $sln.FullName $parentDir = Split-Path $Path $lines = Get-Content ($sln.FullName) $version = $null; foreach($line in $lines) { if($line.StartsWith("VisualStudioVersion =")) { $version = $line.Substring($line.IndexOf("=") + 1).Trim() } if($line.StartsWith("Project(")) { $data = $line.Substring($line.IndexOf("=") + 1); $data = $data.Split(",") if($data.Length -lt 3) { continue; } $projName = $data[0].Trim().Trim('"') $projFile = $data[1].Trim().Trim('"') $projFile = "$parentDir\$projFile" $projId = $data[2].Trim().Trim('"') $webProject = $false; $webProjectType = $false; $testProject = $false; $windowsServiceProject = $false; $wixSharpProject = $false; $ext = [System.IO.Path]::GetExtension($projFile) $languageExt = $null $isSdk = $false; if($fmgVsProjectFiles.ContainsKey($ext)) { $languageExt = $fmgVsProjectFiles[$ext] } if(![IO.Path]::HasExtension($projFile)) { continue; } try { $xml = [xml](Get-Content $projFile) if($xml.DocumentElement.HasAttribute("Sdk")) { $isSdk = $true; } } catch { } $xml = $null if($WebProjects.ToBool() -or $All.ToBool()) { $webProject = $false; if($xml -eq $null) { $xml = [xml](Get-Content $projFile) } if($xml.DocumentElement.HasAttribute("Sdk")) { $isSdk = $true; $sdk = $xml.DocumentElement.Attributes["Sdk"]; if($sdk -eq $vsWebSdkValue) { $webProject = $true; $webProjectType = "ASP.NET Core" $selection = $xml | Select-Xml "//TargetFramework" if($selection) { $value = $selection.Node.Value; $value = $value.Replace("netcoreapp", ""); $webProjectType = "$webProjectType $value" } } } else { $selection = $xml | Select-Xml "//msb:ProjectTypeGuids" -Namespace $ns $guids = @(); if($selection) { $guids = $selection.Node.InnerText if($guids -and $guids.Length -gt 0) { $guids = $guids.Split(";"); } } foreach($guid in $guids) { foreach($key in $vsWebGuids.Keys) { $value = $vsWebGuids[$key]; if($value -eq $guid) { $webProject = $true; $webProjectType = $key; break; } } if($webProject) { break; } } } } if($WixSharpProjects.ToBool()-or $All.ToBool()) { $wixSharpProject = $false; if($xml -eq $null) { $xml = [xml](Get-Content $projFile) } $xml | Select-Xml -XPath "//msb:Reference" -Namespace $ns | ForEach-Object { if($wixSharpProject) { return; } $value = "" if($_.Node.HasAttribute("Include")) { $value = $_.Node.Attributes["Include"].Value; } if($value -eq "WixSharp.Msi") { $selection = $xml | Select-Xml "//msb:OutputType" -Namespace $ns if($selection) { $value = $selection.Node.InnerText if($value -eq "Exe" -or $value -eq "WinExe") { $wixSharpProject = $true; } } return; } } } if($WindowServiceProjects.ToBool() -or $All.ToBool()) { $windowsServiceProject = $false; if($xml -eq $null) { $xml = [xml](Get-Content $projFile) } $xml | Select-Xml -XPath "//msb:Reference" -Namespace $ns | ForEach-Object { if($windowsServiceProject) { return; } $value = $null; if($_.Node.HasAttribute("Include")) { $value = $_.Node.Attributes["Include"].Value } if($value -eq "System.ServiceProcess") { $selection = $xml | Select-Xml -XPath "//msb:OutputType" -Namespace $ns if($selection -ne $null) { $value = $selection.Node.InnerText if($value -eq "Exe" -or $value -eq "WinExe") { $windowsServiceProject = $true; return; } } return; } } } if($TestProjects.ToBool() -or $All.ToBool()) { $testProject = $false; if($xml -eq $null) { $xml = [xml](Get-Content $projFile) } if($xml.DocumentElement.HasAttribute("Sdk")) { $isSdk = $true; $xml | Select-Xml "//PackageReference" | ForEach-Object { if($testProject) { return; } $package = $null if($_.Node.HasAttribute("Include")) { $package = $_.Node.Attributes["Include"].Value; } if($package -eq $testPackageRef) { $testProject = $true; } } } else { $xml | Select-Xml "//msb:Reference" -Namespace $ns | ForEach-Object { if($testProject) { return; } $value = "" if($_.Node.HasAttribute("Include")) { $value = $_.Node.Attributes["Include"].Value } foreach($testRef in $testRefs) { if($value.StartsWith($testRef)) { $testProject = $true; break; } } } } } if($xml -and $xml.DocumentElement.HasAttribute("Sdk")) { $isSdk = $true; } $model = New-Object PsObject -Property @{ 'Name' = $projName 'File' = $projFile 'Id' = $projId 'IsWebProject' = $webProject 'WebProjectType' = $webProjectType 'IsTestProject' = $testProject 'IsWindowsService' = $windowsServiceProject 'IsCloudService' = $ext -eq '.ccproj' 'IsWixSharpProject' = $wixSharpProject 'IsWixProject' = $ext -eq ".wixproj" 'Ext' = $ext 'LanguageExt' = $languageExt 'IsSdk' = $isSdk } $projectDir = Split-Path $projFile $packageJson = $null; $bowerrc = $null; $gulpfile = $null; $gruntfile = $null; if(Test-Path "$projectDir/package.json") { $packageJson = "$projectDir/package.json" } if(Test-Path "$projectDir/.bowerrc") { $bowerrc = "$projectDir/.bowerrc" } if(Test-Path "$projectDir/gulpfile.js") { $gulpfile = "$projectDir/gulpfile.js" } if(Test-Path "$projectDir/Gruntfile.js") { $gruntfile = "$projectDir/Gruntfile.js" } $model | Add-Member -MemberType NoteProperty -Name "PackageJson" -Value $packageJson $model | Add-Member -MemberType NoteProperty -Name "Bower" -Value $bowerrc $model | Add-Member -MemberType NoteProperty -Name "Gulp" -Value $gulpfile $model | Add-Member -MemberType NoteProperty -Name "Grunt" -Value $gruntfile $nuspec = Get-Item "$projectDir/*.nuspec" -ErrorAction SilentlyContinue if($nuspec) { $nuspec = $nuspec.FullName } else { $nuspec = $false } $model | Add-Member -MemberType NoteProperty -Name "NuSpec" -Value $nuspec $projects.Add($projName, $model); } } $meta = [PSCustomObject] (New-Object PSCustomObject -Property @{ Version = $version Projects = $projects }) return $meta; } Set-Alias -Name "Read-VsSolution" -Value Read-VisualStudioSolution |