ReflectCmdlet.psm1

function Get-CommandSource {
    <#
        .SYNOPSIS
         Gets command source code.
         
        .DESCRIPTION
         The Get-CommandSource cmdlet finds the source code/implementation for a cmdlet.
             
        .PARAMETER Name
         Specifies the path or name of the command to retrieve the source code. Accepts pipeline input.

        .PARAMETER Decompiler
         Specifies which decompiler or source will be used for browsing the source code.

        .INPUTS
         System.Management.Automation.CommandInfo
         System.String
            You can pipe command names to this cmdlet.

        .OUTPUTS
         System.Management.Automation.PSObject

        .Example
         Get-CommandSource Write-Host

        .Example
         Get-Command Write-Host | Get-CommandSource -Decompiler ILSpy

        .LINK
         https://github.com/aberus/ReflectCmdlet
    #>


    [CmdletBinding()]
    [OutputType([string],[PSObject])]
    [Alias('gcmso')]
    param(
        [Parameter(Position = 0, Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
        [ValidateNotNullOrEmpty()]
        [String]$Name,

        [Decompiler]$Decompiler
    )

    $commandInfo = if ($_ -is [System.Management.Automation.CommandInfo]) {$_} else {Get-Command -Name $Name}

    if($commandInfo -is [System.Management.Automation.AliasInfo]) {
        $commandInfo = $commandInfo.ResolvedCommand
    }

    if($commandInfo -is [System.Management.Automation.FunctionInfo]) {
        $object = New-Object PSObject -Property @{
            Name = $commandInfo.Name
        }

        $functionPath = $commandInfo.ScriptBlock.File
        if ($functionPath) {
            $object | Add-Member -MemberType NoteProperty -Name Location -Value $functionPath
            Invoke-Item $functionPath
        }
        else {
            $modulePath = $commandInfo.Module.Path
            if ($modulePath) {
                $modulePath = Split-Path -Path $modulePath
                $object | Add-Member -MemberType NoteProperty -Name Location -Value $modulePath
                Invoke-Item $modulePath
            }
            else {
                Write-Error "Unable to find this function's file or module location"
            }
        }

        return $object
    }

    if($commandInfo -is [System.Management.Automation.CmdletInfo]) {
        $assembly = $commandInfo.ImplementingType.Assembly.Location
        if(!$assembly) {
            $assembly = $commandInfo.DLL
        }
        $type = $commandInfo.ImplementingType.FullName

        if (($Decompiler -eq [Decompiler]::dnSpy -or !$Decompiler) -and (Get-Command dnSpy -ErrorAction SilentlyContinue)) {
            Start-Process -FilePath dnSpy -ArgumentList "$assembly --select T:$type"
        } elseif (($Decompiler -eq [Decompiler]::ILSpy -or !$Decompiler) -and (Get-Command ILSpy -ErrorAction SilentlyContinue)) {
            Start-Process -FilePath ILSpy -ArgumentList "$assembly /navigateTo:T:$type"
        } elseif (($Decompiler -eq [Decompiler]::dotPeek -or !$Decompiler) -and (Get-Command dotPeek32 -ErrorAction SilentlyContinue)) {
            dotPeek32 /select=$assembly!$type
        } elseif (($Decompiler -eq [Decompiler]::JustDecompile -or !$Decompiler) -and (Get-Command JustDecompile -ErrorAction SilentlyContinue)) {
            Start-Process -FilePath JustDecompile -ArgumentList "/target:$assembly"
        } elseif (($Decompiler -eq [Decompiler]::Reflector -or !$Decompiler) -and (Get-Command reflector -ErrorAction SilentlyContinue)) {
            Start-Process -FilePath reflector -ArgumentList "/select:$type $assembly"
        } elseif ($Decompiler -eq [Decompiler]::GitHub -or !$Decompiler) {
            $class = $commandInfo.ImplementingType.Name
            $uri = "https://api.github.com/search/code?q=`"class+${class}`"+in:file+repo:powershell/powershell"
            [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
            $result = Invoke-RestMethod -Uri $uri -Method Get
            if ($result) {
                $url = $result.items | Select-Object -ExpandProperty html_url
                Start-Process -FilePath $url
            }       
        } else {
            throw 'Unable to find decompiler in your path'
        }

        $object = New-Object PSObject -Property @{
            Name     = $commandInfo.Name
            Type     = $type
            Location = $assembly
        }

       return $object
    }
}

enum Decompiler {
    dnSpy
    ILSpy
    dotPeek
    JustDecompile
    Reflector
    GitHub
}