I want to make an automated powershell script, that reports the references and the referencepaths of a project. When the hintpath in .csproj is not filled in, i can't find a way to get the path to the reference.
-
I could be wrong but i believe the hint path is the only path in the csproj file. If this isn't filled i would expect the compiler to look in the GAC and other usual folders like the bin to find the reference. There for i believe if the hintpath isn't filled it simply cannot be found. – F.B. ten Kate Mar 15 '11 at 15:10
-
You could, of course, look through the common folders that would be searched - like bin/ in the project, and system folders. However, a better question to ask is *why* do you want this? What do you need the paths for? – Tomas Aschan Mar 15 '11 at 15:13
-
There are some references that are not listed with a hintpath and aren't in the GAC but the build service still finds them. e.g. telerik dll's. This is rather annoying because i based myself on the fact that self-added dll's were listed with a hintpath but it seems not all of them are. – woutvdd Mar 15 '11 at 15:14
-
@Tomas Lycken Our goal is to list all the references used in our solutions to eventually solve a bigger problem when reverting to a buildserver with code analysis and mandatory gated check-in. We want to have a nice overview of the references that are self-added. - Eventually we want to copy all the self-added references(dlls) to a project specific folder for each solution on our source control – woutvdd Mar 15 '11 at 15:18
2 Answers
Here's a quick solution. It grabs every .csproj
file under the current directory, and inspects each Reference. For assemblies referenced from the GAC, just the name is output. For assemblies outside the GAC, the full path to the assembly is output.
$projectFiles = get-childitem . *.csproj -Recurse
foreach( $projectFile in $projectFiles )
{
$projectXml = [xml] (get-content $projectFile.FullName)
$projectDir = $projectFile.DirectoryName
Write-Host "# $($projectFile.FullName) #"
foreach( $itemGroup in $projectXml.Project.ItemGroup )
{
if( $itemGroup.Reference.Count -eq 0 )
{
continue
}
foreach( $reference in $itemGroup.Reference )
{
if( $reference.Include -eq $null )
{
continue
}
if( $reference.HintPath -eq $null )
{
Write-Host ("{0}" -f $reference.Include)
}
else
{
$fullpath = $reference.HintPath
if(-not [System.IO.Path]::IsPathRooted( $fullpath ) )
{
$fullPath = (join-path $projectDir $fullpath)
$fullPath = [System.IO.Path]::GetFullPath("$fullPath")
}
Write-Host $fullPath
}
}
}
Write-Host ''
}
Note that by default, there are some registry entries that MSBuild looks in to find the locations of references that don't have hint paths. You can see where MSBuild looks and where it locates assemblies by compiling with verbose logging turned on:
msbuild My.csproj /t:build /v:d

- 25,861
- 15
- 82
- 91
-
Thanks for your script, but can we assume that when there is no hintpath filled in, the file is located in the GAC? Because Telerik dlls are not in the GAC and don't have a hintpath – woutvdd Mar 16 '11 at 08:34
-
-
-
Interesting. You cans do a couple things to find out where MSBuild is finding this reference. First, right-click it in Visual Studio and click Properties. Inspect the properties pane for any clues. Second, build the project from the command-line with verbose logging: `msbuild My.csproj /t:build /v:d`. Search the output for the Telerik assembly name, and you'll find an section saying all the places MSBuild looked and where it found it. – Aaron Jensen Mar 17 '11 at 15:42
-
Thx a lot. With MSBuild i get good information. I have found the telerik. It looks in the registry (based on Microsoft.Common.Targets) to get searchpaths: {Registry:$(FrameworkRegistryBase),$(TargetFrameworkVersion),$(AssemblyFoldersSuffix)$(AssemblyFoldersExConditions)}; In the registry there is a key with the path to the Telerik folder. – woutvdd Mar 21 '11 at 09:39
-
Forgot about those. I have updated my answer to include how to find these magical registry locations. We have a customized command line build that strips out those folders when doing registry lookups, so that all our third-party DLLs are required to be in a well-known spot. – Aaron Jensen Mar 21 '11 at 19:39
One (hacky) solution could be to make sure that all references have "Copy Local" set to true. That way, any dll referenced will always end up in the /bin directory, and thus you have a path to it.
If the intention is to have all referenced assemblies in one place, however, it may or may not make sense to copy even the references that exist in the GAC to a local copy instead, depending on the rest of your environment.

- 58,548
- 56
- 243
- 402