How do I programmatically list all projects in a solution?

Viewed 36264

How do I programmatically list all of the projects in a solution? I'll take a script, command-line, or API calls.

14 Answers

from powershelll and in the solution's folder write

dotnet sln list

I know that this is maybe already answered question, but I would like to share my approach of reading sln file. Also during run time I am determining if project is Test project or not

function ReadSolutionFile($solutionName)
{
    $startTime = (Get-Date).Millisecond
    Write-Host "---------------Read Start---------------" 
    $solutionProjects = @()

    dotnet  sln "$solutionName.sln" list | ForEach-Object{     
        if($_  -Match ".csproj" )
        {
            #$projData = ($projectString -split '\\')

            $proj = New-Object PSObject -Property @{

                Project = [string]$_;
                IsTestProject =   If ([string]$_ -Match "test") {$True} Else {$False}  
            }

            $solutionProjects += $proj

        }
    }

    Write-Host "---------------Read finish---------------" 
    $solutionProjects

    $finishTime = (Get-Date).Millisecond
    Write-Host "Script run time: $($finishTime-$startTime) mil" 
}

Hope this will be helpfull.

To expand on the answer by @brianpeiris:

Function Global:Get-ProjectInSolution {
    [CmdletBinding()] param (
        [Parameter()][string]$Solution
    )
    $SolutionPath = Join-Path (Get-Location) $Solution
    $SolutionFile = Get-Item $SolutionPath
    $SolutionFolder = $SolutionFile.Directory.FullName

    Get-Content $Solution |
        Select-String 'Project\(' |
        ForEach-Object {
            $projectParts = $_ -Split '[,=]' | ForEach-Object { $_.Trim('[ "{}]') }
            [PSCustomObject]@{
                File = $projectParts[2]
                Guid = $projectParts[3]
                Name = $projectParts[1]
            }
        } |
        Where-Object File -match "csproj$" |
        ForEach-Object {
            Add-Member -InputObject $_ -NotePropertyName FullName -NotePropertyValue (Join-Path $SolutionFolder $_.File) -PassThru
        }
}

This filters to only .csproj files and adds the full path of each based on the File field and the path containing the sln file.

Use Get-ProjectInSolution MySolution.sln | Select-Object FullName to get each of the full file paths.

The reason I wanted the full path was to be able to access the packages.config files beside each project file and then get the packages from all of them:

Get-ProjectInSolution MySolution.sln |
    %{Join-Path ($_.FullName | Split-Path) packages.config} |
    %{select-xml "//package[@id]" $_ | %{$_.Node.GetAttribute("id")}} |
    select -unique

Here is a modified approach I used to look at the problem from a Solution-first stance:

Function Get-ProjectReferences ($rootFolder) {
    $ns = @{ defaultNamespace = "http://schemas.microsoft.com/developer/msbuild/2003" }
    $solutionFilesWithContent = Get-ChildItem $rootFolder -Filter *.sln -Recurse |
    ForEach-Object {
        New-Object PSObject -Property @{
            SolutionFile    = $_;
            SolutionContent = Get-Content $_;
        }
    }
    $projectFilesWithContent = Get-ChildItem $rootFolder -Filter *.csproj -Recurse |
    ForEach-Object {
        New-Object PSObject -Property @{
            ProjectFile    = $_;
            ProjectContent = [xml](Get-Content $_);
        }  
    }

    $solutionFilesWithContent | ForEach-Object {
        $solutionFileWithContent = $_
        $projectsInSolutionStrings = $solutionFileWithContent.SolutionContent | Select-String 'Project\('
        $projectsInSolution = $projectsInSolutionStrings |
        ForEach-Object {
            $projectParts = $_ -Split '[,=]' | ForEach-Object { $_.Trim('[ "{}]') };
            if ($projectParts[2].Contains(".csproj")) {
                New-Object PSObject -Property @{
                    Name = $projectParts[1];
                    File = $projectParts[2];
                    Guid = $projectParts[3];
                }                    
            }
        }

        $projectsInSolution | ForEach-Object {
            $projectFileSearchName = $_.Name + ".csproj"
            $projectInSolutionFile = $projectFilesWithContent | Where-Object { $_.ProjectFile.Name -eq $projectFileSearchName } | Select-Object -First 1
            if (($null -eq $projectInSolutionFile) -and ($null -eq $projectInSolutionFile.ProjectContent)) {
                Write-Host "Project was null"
            }
            else {
                $projectInSolutionName = $projectInSolutionFile.ProjectFile | Select-Object -ExpandProperty BaseName
                $projectReferences = $projectInSolutionFile.ProjectContent | Select-Xml '//defaultNamespace:ProjectReference/defaultNamespace:Name' -Namespace $ns | Select-Object -ExpandProperty Node | Select-Object -ExpandProperty "#text"
                $projectTarget = $projectInSolutionFile.ProjectContent | Select-Xml "//defaultNamespace:TargetFrameworkVersion" -Namespace $ns | Select-Object -ExpandProperty Node | Select-Object -ExpandProperty "#text"
        
                $projectReferences | ForEach-Object {
                    $projectFileName = $_ + ".csproj"
                    $referenceProjectFile = $projectFilesWithContent | Where-Object { $_.ProjectFile.Name -eq $projectFileName } | Select-Object -First 1
                    if ($null -eq $referenceProjectFile) {
                        $referenceProjectTarget = "Unknown"
                    }
                    else {
                        $referenceProjectTarget = $referenceProjectFile.ProjectContent | Select-Xml "//defaultNamespace:TargetFrameworkVersion" -Namespace $ns | Select-Object -ExpandProperty Node | Select-Object -ExpandProperty "#text"                    
                    }
                    "[" + $solutionFileWithContent.SolutionFile.Name + "] -> [" + $projectInSolutionName + " " + $projectTarget + "] -> [" + $_ + " " + $referenceProjectTarget + "]"
                }
            }
        }
    }
}

Get-ProjectReferences "C:\src\repos\MyRepo" | Out-File "C:\src\repos\FrameworkDependencyAnalysis\FrameworkDependencyAnalysis.txt"
Related