【问题标题】:How do I programmatically list all projects in a solution?如何以编程方式列出解决方案中的所有项目?
【发布时间】:2011-04-17 15:39:06
【问题描述】:

如何以编程方式列出解决方案中的所有项目?我将接受脚本、命令行或 API 调用。

【问题讨论】:

    标签: c# visual-studio-2008 scripting projects-and-solutions


    【解决方案1】:

    只需从 *.sln 文件中读取列表。有“项目”-“结束项目”部分。
    这里是an article from MSDN.

    【讨论】:

    【解决方案2】:

    如果您将程序编写为 Visual Studio 插件,您可以访问 EnvDTE 以查找当前打开的解决方案中的所有项目。

    【讨论】:

      【解决方案3】:

      这是一个从 .sln 文件中检索项目详细信息的 PowerShell 脚本:

      Get-Content 'Foo.sln' |
        Select-String 'Project\(' |
          ForEach-Object {
            $projectParts = $_ -Split '[,=]' | ForEach-Object { $_.Trim('[ "{}]') };
            New-Object PSObject -Property @{
              Name = $projectParts[1];
              File = $projectParts[2];
              Guid = $projectParts[3]
            }
          }
      

      【讨论】:

      • 我知道这是旧的,但它很漂亮。为我节省了很多时间。
      • 如果需要,您可以通过在第 2 行和第 3 行之间添加额外的 Select-String 来过滤解决方案文件夹,如下所示:Select-String "{2150E333-8FDC-42A3-9474-1A3956D46DE8}" -NotMatch |
      【解决方案4】:

      您可以使用 EnvDTE.Solution.Projects 对象以编程方式访问解决方案中的项目。

      一个问题是,如果您的解决方案中有任何解决方案文件夹,则这些文件夹中的任何项目都不会显示在上述集合中。

      我写了一篇文章,其中包含一个代码示例,说明 to get all projects 不考虑任何解决方案文件夹

      【讨论】:

      • 这只能在 VS 扩展中使用,因此对于任何想要一个独立工具来读取解决方案中的源项目的人来说都是无用的。
      • 您可以获得对running instance of VS 的引用,或者您可以从包管理器控制台访问$dte。如果您根本没有运行 VS,那么您需要一个替代解决方案。新的 MSBuild 包现在包含用于解析解决方案和项目文件的类,但这些仍然是 RTM 之前的
      【解决方案5】:
          var Content = File.ReadAllText(SlnPath);
          Regex projReg = new Regex(
              "Project\\(\"\\{[\\w-]*\\}\"\\) = \"([\\w _]*.*)\", \"(.*\\.(cs|vcx|vb)proj)\""
              , RegexOptions.Compiled);
          var matches = projReg.Matches(Content).Cast<Match>();
          var Projects = matches.Select(x => x.Groups[2].Value).ToList();
          for (int i = 0; i < Projects.Count; ++i)
          {
              if (!Path.IsPathRooted(Projects[i]))
                  Projects[i] = Path.Combine(Path.GetDirectoryName(SlnPath),
                      Projects[i]);
              Projects[i] = Path.GetFullPath(Projects[i]);
          }
      

      编辑:根据 Kumar Vaibhav 的评论修改正则表达式以包含“.*”

      【讨论】:

      • 上述方法可行,但有一个小问题。如果您的项目命名为“AB.CD” - 我的意思是当“。”在那里,那么正则表达式将无法识别那些。下面的小改动可以使它起作用 - Regex projReg = new Regex("Project\(\"\\{[\\w-]*\\}\"\) = \"([\\w _]*. *)\", \"(.*\\.(cs|vcx|vb)proj)\"" , RegexOptions.Compiled);
      • 像魅力一样工作!
      【解决方案6】:

      这里有一个非常优雅的解决方案:Parsing Visual Studio Solution files

      John Leidegren 的回答涉及包装内部 Microsoft.Build.Construction.SolutionParser 类。

      【讨论】:

        【解决方案7】:

        目前您可以在 VS 中使用Package Manager Console 来获取该信息。使用 powershell Get-Project 命令

        Get-Project -All
        

        【讨论】:

        • 哪个 Visual Studio version ?
        【解决方案8】:

        如果您需要在非 Windows 机器上执行此操作,可以使用以下 Bash 命令:

        grep "Project(" NameOfYourSolution.sln | cut -d'"' -f4

        【讨论】:

          【解决方案9】:

          自 Visual Studio 2013 起,Microsoft.Build.dll 提供了一个具有一些非常方便的功能的 SolutionFile 对象。

          这里是一个使用 v14.0 版本的例子,按照它们在解决方案中出现的顺序列出所有项目的相对路径。

          Add-Type -Path (${env:ProgramFiles(x86)} + '\Reference Assemblies\Microsoft\MSBuild\v14.0\Microsoft.Build.dll')
          $solutionFile = '<FULL PATH TO SOLUTION FILE>'
          $solution = [Microsoft.Build.Construction.SolutionFile] $solutionFile
          ($solution.ProjectsInOrder | Where-Object {$_.ProjectType -eq 'KnownToBeMSBuildFormat'}).RelativePath
          

          项目对象上还有许多其他可能有用的属性(ProjectName、AbsolutePath、配置等)。在上面的示例中,我使用 ProjectType 过滤掉解决方案文件夹。

          【讨论】:

          • 对于VS2017来说,是在VS2017下"C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\MSBuild\15.0\Bin\amd64\Microsoft.Build.dll" 和烦人,但是对于sqlprojs文件,项目类型是Unknown [SolutionProjectType]::Unknown
          【解决方案10】:

          诀窍是选择正确的 MsBuild.dll。 在 VS2017 下确实是“C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\MSBuild\15.0\Bin\amd64\Microsoft.Build.dll” (不要在引用中使用标准的 Msbuild ddl。浏览到此路径)

          c#:

          var solutionFile =    
          SolutionFile.Parse(@"c:\NuGetApp1\NuGetApp1.sln");//your solution full path name
          var projectsInSolution = solutionFile.ProjectsInOrder;
          foreach(var project in projectsInSolution)
          {
             switch (project.ProjectType)
             {
                case SolutionProjectType.KnownToBeMSBuildFormat:
               {
                   break;
               }
               case SolutionProjectType.SolutionFolder:
               {
                   break;
               }
            }
          }
          

          powershell:

          Add-Type -Path (${env:ProgramFiles(x86)} + '\Microsoft Visual 
          Studio\2017\Professional\MSBuild\15.0\Bin\amd64\Microsoft.Build.dll')
          
          $slnPath = 'c:\NuGetApp1\NuGetApp1.sln'
          $slnFile = [Microsoft.Build.Construction.SolutionFile]::Parse($slnPath)
          $pjcts = $slnFile.ProjectsInOrder
          
          foreach ($item in $pjcts)
          {
          
              switch($item.ProjectType)
              {
                  'KnownToBeMSBuildFormat'{Write-Host Project  : $item.ProjectName}
                  'SolutionFolder'{Write-Host Solution Folder : $item.ProjectName}
              }
          }  
          

          【讨论】:

            【解决方案11】:

            我知道这可能是已经回答的问题,但我想分享我阅读 sln 文件的方法。同样在运行时我正在确定项目是否是测试项目

            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" 
            }
            

            希望这会有所帮助。

            【讨论】:

              【解决方案12】:

              通过@brianpeiris扩展answer

              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
                      }
              }
              

              这会过滤到仅.csproj 文件,并根据File 字段和包含sln 文件的路径添加每个文件的完整路径。

              使用Get-ProjectInSolution MySolution.sln | Select-Object FullName 获取每个完整的文件路径。

              我想要完整路径的原因是能够访问每个项目文件旁边的packages.config 文件,然后从所有这些文件中获取包:

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

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2011-07-19
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多