joseville
joseville

Reputation: 953

PowerShell command to extract `<ProjectReference Include=(...)` from all `.csproj` files in a directory and its subdirectories

Get list of .csproj in directory and subdirectories of D:\repos\M\Test

[1] PS D:\repos\M\Test> ls -r -filter "*.csproj" | select Directory, Name

Sample output

Directory                       Name
---------                       ----
D:\repos\M\Test\M.Common        M.Common.csproj
D:\repos\M\Test\M.Mocks         M.Mocks.csproj
D:\repos\M\Test\M.StateMachines M.StateMachines.csproj

Get list of files containing line(s) that match <ProjectReference\s*Include="([^"]+)" in directory and subdirectory

[2] PS D:\repos\M\Test> ls | sls '<ProjectReference\s*Include="([^"]+)"' | ForEach-Object {New-Object PSObject -Property @{Project=$_.Filename; DirectDep=$_.Matches.Groups[1].Value}}

Sample output

Project                DirectDeps
-------                ----------
dirs.proj              D:\repos\M\Test\M.Common
dirs.proj              D:\repos\M\Test\M.Mocks.csproj
dirs.proj              D:\repos\M\Test\M.StateMachines.csproj
M.Common.csproj        D:\repos\S\Common\Common.csproj
M.Common.csproj        D:\repos\Q\Contracts\Contracts.csproj
M.Mocks.csproj         D:\repos\S\Controller\Controller.csproj
M.StateMachines.csproj D:\repos\M\Common\Common.csproj
M.StateMachines.csproj D:\repos\T\Auth\Auth.csproj

Questions

Q1: How can I feed the output of [1] to [2] to limit [2]'s search to .csproj files (i.e. exclude dirs.proj) to get the following output

Project                DirectDeps
-------                ----------
M.Common.csproj        D:\repos\S\Common\Common.csproj
M.Common.csproj        D:\repos\Q\Contracts\Contracts.csproj
M.Mocks.csproj         D:\repos\S\Controller\Controller.csproj
M.StateMachines.csproj D:\repos\M\Common\Common.csproj
M.StateMachines.csproj D:\repos\T\Auth\Auth.csproj

Q2: And then how can I take output of [2] and make it group by Project/Filename? To get the following output (or similar)

M.Common.csproj, D:\repos\S\Common\Common.csproj, D:\repos\Q\Contracts\Contracts.csproj
M.Mocks.csproj, D:\repos\S\Controller\Controller.csproj
M.StateMachines.csproj, D:\repos\M\Common\Common.csproj, D:\repos\T\Auth\Auth.csproj

Attempts

Attempts @ Q1

Attempts @ Q2

The second of the 3 has the closest output to what I'm looking for

Name                   Group
----                   -----
dirs.proj              {@{Project=dirs.proj; DirectDep=...M.Common.csproj}, {Project=dirs.proj; DirectDep=...M.Mocks.csproj}, {Project=dirs.proj; DirectDep=...M.StateMachines.csproj}
M.Common.csproj        {@{Project=M.Common.csproj; DirectDep=...Common.csproj}, {Project=M.Common.csproj; DirectDep=...Contracts.csproj}}
M.Mocks.csproj         {@{Project=M.Mocks.csproj; DirectDep=...Controller.csproj}
M.StateMachines.csproj {@{Project=M.StateMachines.csproj; DirectDep=...Common.csproj}, {Project=M.StateMachines.csproj; DirectDep=...Auth.csproj}}

Upvotes: 1

Views: 80

Answers (1)

Santiago Squarzon
Santiago Squarzon

Reputation: 61113

So assuming you do have the .NET SDK installed, you can simply use dotnet list reference command to get all reference projects.

The code would be something like:

Get-ChildItem -Recurse -Filter *.csproj | ForEach-Object {
    $references = dotnet list $_.FullName reference
    if ($references.Count -gt 2) {
        # When there are references found the first 2 lines will be:

        # Project reference(s)
        # --------------------

        # you can choose to skip them here if you want to or just remove this condition
        $references = $references | Select-Object -Skip 2
    }

    [pscustomobject]@{
        ProjectName       = $_.BaseName
        ProjectPath       = $_.FullName
        PackageReferences = $references
    }
}

As for the previous question, "how to exclude for example, dirs.proj", if you use -Filter *.csproj it shouldn't list it at all but for the sake of answering, you can use -Exclude:

Get-ChildItem -Recurse -Filter *.csproj -Exclude dirs.proj |
    ForEach-Object { .... } # same code shown above

Or Where-Object:

Get-ChildItem -Recurse -Filter *.csproj |
    Where-Object Name -NE dirs.proj |
    ForEach-Object { .... } # same code shown above

Upvotes: 3

Related Questions