Skip to content

Instantly share code, notes, and snippets.

@bruno-brant
Last active September 16, 2022 14:12
Show Gist options
  • Save bruno-brant/7a43e5e57fa7867f5043ea4541c46c98 to your computer and use it in GitHub Desktop.
Save bruno-brant/7a43e5e57fa7867f5043ea4541c46c98 to your computer and use it in GitHub Desktop.
Creates a dependency graph for a .NET assembly.
param (
[System.IO.FileInfo] $First,
[string] $OutputFormat = "dot",
[string] $OutputPath
)
$ErrorActionPreference = "stop"
class NodeRelation {
[string]$Start;
[String]$End;
NodeRelation(
[string] $Start,
[string] $End
) {
$this.Start = $Start;
$this.End = $End;
}
}
class Graph {
[System.Collections.Generic.List[NodeRelation]] $Relations = [System.Collections.Generic.List[NodeRelation]]::new();
[string] $Title;
Graph($title) {
$this.Title = $title;
}
[void]Add([string] $start, [string] $end) {
$relation = [NodeRelation]::new($start, $end)
$this.Relations.Add($relation);
}
<#
.SUMMARY
Formats the graph in dot Language.
#>
[string]ToDot() {
$sb = [System.Text.StringBuilder]::new();
$sb.AppendLine("digraph `"$($this.Title)`" {");
foreach ($relation in $this.Relations) {
$sb.AppendLine([string]::Format("`t`"{0}`" -> `"{1}`"", $relation.Start, $relation.End));
}
$sb.AppendLine("}");
return $sb.ToString();
}
}
<#
.SUMMARY
Gets an assembly from a relative path
#>
function global:Get-Assembly($path) {
try {
if (Test-Path $path) {
return [System.Reflection.Assembly]::LoadFile((ls $path).FullName)
}
elseif (Test-Path "$path.dll") {
return [System.Reflection.Assembly]::LoadFile((ls "$path.dll").FullName)
}
else {
return [System.Reflection.Assembly]::Load($path)
}
}
catch {
Write-Warning "Error loading assembly: $path"
return $null
}
}
# Visited Dll's
$visited = [System.Collections.Generic.HashSet[String]]::new()
# Dll's to visit
$todo = [System.Collections.Generic.Stack[String]]::new()
# Starting Dll
$todo.Push($first);
[Graph]$graph = [Graph]::new($First);
while ($todo.Count -gt 0) {
$next = $todo.Pop()
[System.Reflection.Assembly] $asm = Get-Assembly $next
if ($null -ne $asm) {
foreach ($dependency in $asm.GetReferencedAssemblies()) {
$graph.Add($next, $dependency.Name);
if (-not $visited.Contains($($dependency.Name))) {
$todo.Push($($dependency.Name));
}
}
}
$visited.Add($next) > $null
}
switch ($OutputFormat) {
"dot" {
$graph.ToDot()
}
"svg" {
$dot = $graph.ToDot()
# Use dot to generate the svg
if ($OutputPath) {
[System.Diagnostics.Process]$dotProcess = [System.Diagnostics.Process]::Start("dot.exe", [string]::Format("-Tsvg -o {0}", $OutputPath))
}
else {
[System.Diagnostics.Process]$dotProcess = [System.Diagnostics.Process]::Start("dot.exe", "-Tsvg")
}
$dotProcess.StandardInput.WriteLine($dot)
$dotProcess.WaitForExit()
if ($dotProcess.ExitCode -ne 0) {
Write-Error "Error calling graphviz"
}
if (!$OutputPath) {
$output = [System.IO.StreamReader]::new($dotProcess.StandardOutput.BaseStream)
$output.ReadToEnd()
}
}
Default {
"Invalid OutputFormat. Expected dot or svg."
}
}
[CmdletBinding()]
param (
[Parameter(Mandatory = $true)]
$_
)
Write-Warning $_.GetType()
if ($_.CategoryInfo -ne $null) { Write-Warning "CategoryInfo [$($_.CategoryInfo.GetType())] $($_.CategoryInfo)" } else { Write-Warning "CategoryInfo is null" }
if ($_.ErrorDetails -ne $null) { Write-Warning "ErrorDetails [$($_.ErrorDetails.GetType())] $($_.ErrorDetails)" } else { Write-Warning "ErrorDetails is null" }
if ($_.FullyQualifiedErrorId -ne $null) { Write-Warning "FullyQualifiedErrorId [$($_.FullyQualifiedErrorId.GetType())] $($_.FullyQualifiedErrorId)" } else { Write-Warning "FullyQualifiedErrorId is null" }
if ($_.InvocationInfo -eq $null) { Write-Warning "InvocationInfo is null" } else {
$InvocationInfo = $_.InvocationInfo
Write-Warning ""
Write-Warning " InvocationInfo.BoundParameters: '$($InvocationInfo.BoundParameters)'"
Write-Warning " InvocationInfo.CommandOrigin: '$($InvocationInfo.CommandOrigin)'"
Write-Warning " InvocationInfo.DisplayScriptPosition: '$($InvocationInfo.DisplayScriptPosition)'"
Write-Warning " InvocationInfo.ExpectingInput: '$($InvocationInfo.ExpectingInput)'"
Write-Warning " InvocationInfo.HistoryId: '$($InvocationInfo.HistoryId)'"
Write-Warning " InvocationInfo.InvocationName: '$($InvocationInfo.InvocationName)'"
Write-Warning " InvocationInfo.Line: '$($InvocationInfo.Line)'"
Write-Warning " InvocationInfo.MyCommand: '$($InvocationInfo.MyCommand)'"
Write-Warning " InvocationInfo.OffsetInLine: '$($InvocationInfo.OffsetInLine)'"
Write-Warning " InvocationInfo.PipelineLength: '$($InvocationInfo.PipelineLength)'"
Write-Warning " InvocationInfo.PipelinePosition: '$($InvocationInfo.PipelinePosition)'"
Write-Warning " InvocationInfo.PositionMessage: '$($InvocationInfo.PositionMessage)'"
Write-Warning " InvocationInfo.PSCommandPath: '$($InvocationInfo.PSCommandPath)'"
Write-Warning " InvocationInfo.PSScriptRoot: '$($InvocationInfo.PSScriptRoot)'"
Write-Warning " InvocationInfo.ScriptLineNumber: '$($InvocationInfo.ScriptLineNumber)'"
Write-Warning " InvocationInfo.ScriptName: '$($InvocationInfo.ScriptName)'"
Write-Warning " InvocationInfo.UnboundArguments: '$($InvocationInfo.UnboundArguments)'"
Write-Warning ""
}
if ($_.Exception -eq $null) { Write-Warning "Exception is null" } else {
Write-Warning ""
Write-Warning "Exception [$($_.Exception.GetType())] $($_.Exception)"
if ($_.Data -eq $null) { Write-Warning "Exception.Data is null" } else { Write-Warning "Exception.Data [$($_.Exception.Data.GetType())] '$($_.Exception.Data)'" }
if ($_.HelpLink -eq $null) { Write-Warning "Exception.HelpLink is null" } else { Write-Warning "Exception.HelpLink [$($_.Exception.HelpLink.GetType())] '$($_.Exception.Data)'" }
if ($_.HResult -eq $null) { Write-Warning "Exception.HResult is null" } else { Write-Warning "Exception.HResult [$($_.Exception.HResult.GetType())] '$($_.Exception.Data)'" }
if ($_.InnerException -eq $null) { Write-Warning "Exception.InnerException is null" } else { Write-Warning "Exception.InnerException [$($_.Exception.InnerException.GetType())] '$($_.Exception.Data)'" }
if ($_.Message -eq $null) { Write-Warning "Exception.Message is null" } else { Write-Warning "Exception.Message [$($_.Exception.Message.GetType())] '$($_.Exception.Data)'" }
if ($_.Source -eq $null) { Write-Warning "Exception.Source is null" } else { Write-Warning "Exception.Source [$($_.Exception.Source.GetType())] '$($_.Exception.Data)'" }
if ($_.StackTrace -eq $null) { Write-Warning "Exception.StackTrace is null" } else { Write-Warning "Exception.StackTrace [$($_.Exception.StackTrace.GetType())] '$($_.Exception.Data)'" }
if ($_.TargetSit -eq $null) { Write-Warning "Exception.TargetSit is null" } else { Write-Warning "Exception.TargetSit [$($_.Exception.TargetSite.GetType())] '$($_.Exception.Data)'" }
Write-Warning ""
}
if ($_.PipelineIterationInfo -ne $null) { Write-Warning "PipelineIterationInfo [$($_.PipelineIterationInfo.GetType())] $($_.PipelineIterationInfo)" } else { Write-Warning "PipelineIterationInfo is null" }
if ($_.ScriptStackTrace -ne $null) { Write-Warning "ScriptStackTrace [$($_.ScriptStackTrace.GetType())] $($_.ScriptStackTrace)" } else { Write-Warning "ScriptStackTrace is null" }
if ($_.TargetObject -ne $null) { Write-Warning "TargetObject [$($_.TargetObject.GetType())] $($_.TargetObject)" } else { Write-Warning "TargetObject is null" }
Write-Warning $
Write-Warning "Stacktrace:" + $_.ScriptStackTrace
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment