Permalink
Browse files

PowerShell cmdlets for ILSpy

  • Loading branch information...
christophwille committed Oct 31, 2017
1 parent ec677b0 commit bb286b3cfc1c74341c246ae89ce096add01791c1
View
@@ -17,6 +17,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ICSharpCode.Decompiler.Console", "ICSharpCode.Decompiler.Console\ICSharpCode.Decompiler.Console.csproj", "{8FDA011E-FAF8-4C1F-A695-21E2C6B5375F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ICSharpCode.Decompiler.PowerShell", "ICSharpCode.Decompiler.PowerShell\ICSharpCode.Decompiler.PowerShell.csproj", "{FF7D6041-3C52-47D1-A32A-0BFE8EE4EEEB}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -27,6 +29,10 @@ Global
{8FDA011E-FAF8-4C1F-A695-21E2C6B5375F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8FDA011E-FAF8-4C1F-A695-21E2C6B5375F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8FDA011E-FAF8-4C1F-A695-21E2C6B5375F}.Release|Any CPU.Build.0 = Release|Any CPU
{FF7D6041-3C52-47D1-A32A-0BFE8EE4EEEB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FF7D6041-3C52-47D1-A32A-0BFE8EE4EEEB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FF7D6041-3C52-47D1-A32A-0BFE8EE4EEEB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FF7D6041-3C52-47D1-A32A-0BFE8EE4EEEB}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -8,7 +8,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="ICSharpCode.Decompiler" Version="3.0.0.3201-beta1" />
<PackageReference Include="ICSharpCode.Decompiler" Version="3.0.0.3206-beta1" />
<PackageReference Include="McMaster.Extensions.CommandLineUtils" Version="2.0.1" />
</ItemGroup>
@@ -0,0 +1,15 @@
Import-Module .\bin\Debug\netstandard2.0\ICSharpCode.Decompiler.PSCore.dll
$decompiler = Get-Decompiler .\bin\Debug\netstandard2.0\ICSharpCode.Decompiler.PSCore.dll
$classes = Get-DecompiledTypes $decompiler -Types class
$classes.Count
foreach ($c in $classes)
{
Write-Output $c.FullName
}
Get-DecompiledSource $decompiler -TypeName ICSharpCode.Decompiler.PSCore.GetDecompilerCmdlet
Get-DecompiledProject $decompiler -OutputPath .\decomptest
@@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace ICSharpCode.Decompiler.PowerShell
{
public static class ErrorIds
{
public static readonly string AssemblyLoadFailed = "1";
public static readonly string DecompilationFailed = "2";
}
}
@@ -0,0 +1,46 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Management.Automation;
using System.Text;
using ICSharpCode.Decompiler.CSharp;
using Mono.Cecil;
namespace ICSharpCode.Decompiler.PowerShell
{
[Cmdlet(VerbsCommon.Get, "DecompiledProject")]
[OutputType(typeof(string))]
public class GetDecompiledProjectCmdlet : PSCmdlet
{
[Parameter(Position = 0, Mandatory = true)]
public CSharpDecompiler Decompiler { get; set; }
[Parameter(Position = 1, Mandatory = true)]
[Alias("PSPath", "OutputPath")]
[ValidateNotNullOrEmpty]
public string LiteralPath { get; set; }
protected override void ProcessRecord()
{
string path = GetUnresolvedProviderPathFromPSPath(LiteralPath);
if (!Directory.Exists(path))
{
WriteObject("Destination directory must exist prior to decompilation");
return;
}
try
{
string assemblyFileName = Decompiler.TypeSystem.Compilation.MainAssembly.UnresolvedAssembly.Location; // just to keep the API "the same" across all cmdlets
ModuleDefinition module = UniversalAssemblyResolver.LoadMainModule(assemblyFileName);
WholeProjectDecompiler decompiler = new WholeProjectDecompiler();
decompiler.DecompileProject(module, path);
WriteObject("Decompilation finished");
} catch (Exception e) {
WriteVerbose(e.ToString());
WriteError(new ErrorRecord(e, ErrorIds.DecompilationFailed, ErrorCategory.OperationStopped, null));
}
}
}
}
@@ -0,0 +1,40 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Management.Automation;
using System.Text;
using ICSharpCode.Decompiler.CSharp;
using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.Decompiler.PowerShell
{
[Cmdlet(VerbsCommon.Get, "DecompiledSource")]
[OutputType(typeof(string))]
public class GetDecompiledSourceCmdlet : PSCmdlet
{
[Parameter(Position = 0, Mandatory = true)]
public CSharpDecompiler Decompiler { get; set; }
[Parameter]
public string TypeName { get; set; } = string.Empty;
protected override void ProcessRecord()
{
try
{
StringWriter output = new StringWriter();
if (TypeName == null) {
output.Write(Decompiler.DecompileWholeModuleAsString());
} else {
var name = new FullTypeName(TypeName);
output.Write(Decompiler.DecompileTypeAsString(name));
}
WriteObject(output.ToString());
} catch (Exception e) {
WriteVerbose(e.ToString());
WriteError(new ErrorRecord(e, ErrorIds.DecompilationFailed, ErrorCategory.OperationStopped, null));
}
}
}
}
@@ -0,0 +1,41 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Management.Automation;
using System.Text;
using ICSharpCode.Decompiler.CSharp;
using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.Decompiler.PowerShell
{
[Cmdlet(VerbsCommon.Get, "DecompiledTypes")]
[OutputType(typeof(ITypeDefinition[]))]
public class GetDecompiledTypesCmdlet : PSCmdlet
{
[Parameter(Position = 0, Mandatory = true)]
public CSharpDecompiler Decompiler { get; set; }
[Parameter(Mandatory = true)]
public string[] Types { get; set; }
protected override void ProcessRecord()
{
HashSet<TypeKind> kinds = TypesParser.ParseSelection(Types);
try {
List<ITypeDefinition> output = new List<ITypeDefinition>();
foreach (var type in Decompiler.TypeSystem.Compilation.MainAssembly.GetAllTypeDefinitions()) {
if (!kinds.Contains(type.Kind))
continue;
output.Add(type);
}
WriteObject(output.ToArray());
} catch (Exception e) {
WriteVerbose(e.ToString());
WriteError(new ErrorRecord(e, ErrorIds.DecompilationFailed, ErrorCategory.OperationStopped, null));
}
}
}
}
@@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.Management.Automation;
using System.Text;
using ICSharpCode.Decompiler.CSharp;
namespace ICSharpCode.Decompiler.PowerShell
{
[Cmdlet(VerbsCommon.Get, "Decompiler")]
[OutputType(typeof(CSharpDecompiler))]
public class GetDecompilerCmdlet : PSCmdlet
{
[Parameter(Position = 0, Mandatory = true, HelpMessage = "Path to the assembly you want to decompile")]
[Alias("PSPath")]
[ValidateNotNullOrEmpty]
public string LiteralPath { get; set; }
protected override void ProcessRecord()
{
string path = GetUnresolvedProviderPathFromPSPath(LiteralPath);
try {
var decompiler = new CSharpDecompiler(path, new DecompilerSettings());
WriteObject(decompiler);
} catch (Exception e) {
WriteVerbose(e.ToString());
WriteError(new ErrorRecord(e, ErrorIds.AssemblyLoadFailed, ErrorCategory.OperationStopped, null));
}
}
}
}
@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
<RootNamespace>ICSharpCode.Decompiler.PowerShell</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="ICSharpCode.Decompiler" Version="3.0.0.3206-beta1" />
<PackageReference Include="PowerShellStandard.Library" Version="3.0.0-preview-01" />
</ItemGroup>
</Project>
@@ -0,0 +1,13 @@
# ILSpy PowerShell Module
Built using https://github.com/PowerShell/PowerShell/blob/master/docs/cmdlet-example/command-line-simple-example.md as guideline
Sample usage: Demo.ps1
Tested with: PowerShell 5.1 on Windows, PowerShell Core on Windows and Mac (Beta9)
## Missing
.psd1 for deploying to https://www.powershellgallery.com/
@@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.Decompiler.PowerShell
{
public static class TypesParser
{
public static HashSet<TypeKind> ParseSelection(string[] values)
{
var possibleValues = new Dictionary<string, TypeKind>(StringComparer.OrdinalIgnoreCase) { ["class"] = TypeKind.Class, ["struct"] = TypeKind.Struct, ["interface"] = TypeKind.Interface, ["enum"] = TypeKind.Enum, ["delegate"] = TypeKind.Delegate };
HashSet<TypeKind> kinds = new HashSet<TypeKind>();
if (values.Length == 1 && !possibleValues.Keys.Any(v => values[0].StartsWith(v, StringComparison.OrdinalIgnoreCase))) {
foreach (char ch in values[0]) {
switch (ch) {
case 'c':
kinds.Add(TypeKind.Class);
break;
case 'i':
kinds.Add(TypeKind.Interface);
break;
case 's':
kinds.Add(TypeKind.Struct);
break;
case 'd':
kinds.Add(TypeKind.Delegate);
break;
case 'e':
kinds.Add(TypeKind.Enum);
break;
}
}
} else {
foreach (var value in values) {
string v = value;
while (v.Length > 0 && !possibleValues.ContainsKey(v))
v = v.Remove(v.Length - 1);
if (possibleValues.TryGetValue(v, out var kind))
kinds.Add(kind);
}
}
return kinds;
}
}
}

0 comments on commit bb286b3

Please sign in to comment.