[英]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.