How do I programmatically list all of the projects in a solution? I'll take a script, command-line, or API calls.
How do I programmatically list all of the projects in a solution? I'll take a script, command-line, or API calls.
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"