[英]How do I programmatically list all projects in a solution?
如何以编程方式列出解决方案中的所有项目? 我将接受脚本、命令行或 API 调用。
这是一个从 .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]
}
}
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 的评论修改正则表达式以包含“.*”
您可以使用 EnvDTE.Solution.Projects 对象以编程方式访问解决方案中的项目。
但有一个问题是,如果您的解决方案中有任何 SolutionFolders,则这些文件夹中的任何项目都不会显示在上述集合中。
我写了一篇文章,其中包含一个关于如何获取所有项目而不考虑任何解决方案文件夹的代码示例
目前,您可以在 VS 中使用包管理器控制台来获取该信息。 使用 powershell Get-Project
命令
Get-Project -All
诀窍是选择正确的 MsBuild.dll。 在 VS2017 下,它确实是“C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Professional\\MSBuild\\15.0\\Bin\\amd64\\Microsoft.Build.dll”(不要在引用中使用标准的 Msbuild ddl。浏览到这个路径)
代码:
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;
}
}
}
电源外壳:
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}
}
}
从 powershelll 和解决方案的文件夹中写入
do.net sln 列表
这里有一个非常优雅的解决方案: 解析 Visual Studio 解决方案文件
John Leidegren 的回答涉及包装内部Microsoft.Build.Construction.SolutionParser
类。
从 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、configuration 等)。 在上面的示例中,我使用 ProjectType 过滤掉解决方案文件夹。
我知道这可能已经回答了问题,但我想分享我阅读 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"
}
希望这会有所帮助。
如果您需要在非 Windows 机器上执行此操作,可以使用以下 Bash 命令:
grep "Project(" NameOfYourSolution.sln | cut -d'"' -f4
要扩展@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
}
}
这仅过滤到.csproj
文件,并根据File
字段和包含sln
文件的路径添加每个文件的完整路径。
使用Get-ProjectInSolution MySolution.sln | Select-Object FullName
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
这是我用来从解决方案第一的立场来看问题的一种修改方法:
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"
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.