aboutsummaryrefslogtreecommitdiff
path: root/ScriptModification/Remove-Comments.ps1
blob: 45a97464afbe16e41ea716469ff32a7ec9635369 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
function Remove-Comments
{
<#
.SYNOPSIS

Strips comments and extra whitespace from a script.

PowerSploit Function: Remove-Comments
Author: Matthew Graeber (@mattifestation)
License: BSD 3-Clause
Required Dependencies: None
Optional Dependencies: None
 
.DESCRIPTION

Remove-Comments strips out comments and unnecessary whitespace from a script. This is best used in conjunction with Out-EncodedCommand when the size of the script to be encoded might be too big.

A major portion of this code was taken from the Lee Holmes' Show-ColorizedContent script. You rock, Lee!

.PARAMETER ScriptBlock

Specifies a scriptblock containing your script.

.PARAMETER Path

Specifies the path to your script.

.EXAMPLE

C:\PS> $Stripped = Remove-Comments -Path .\ScriptWithComments.ps1

.EXAMPLE

C:\PS> Remove-Comments -ScriptBlock {
### This is my awesome script. My documentation is beyond reproach!
      Write-Host 'Hello, World!' ### Write 'Hello, World' to the host
### End script awesomeness
}

Write-Host 'Hello, World!'

.EXAMPLE

C:\PS> Remove-Comments -Path Inject-Shellcode.ps1 | Out-EncodedCommand

Description
-----------
Removes extraneous whitespace and comments from Inject-Shellcode (which is notoriously large) and pipes the output to Out-EncodedCommand.

.INPUTS

System.String, System.Management.Automation.ScriptBlock

Accepts either a string containing the path to a script or a scriptblock.

.OUTPUTS

System.Management.Automation.ScriptBlock

Remove-Comments returns a scriptblock. Call the ToString method to convert a scriptblock to a string, if desired.

.LINK

http://www.exploit-monday.com
http://www.leeholmes.com/blog/2007/11/07/syntax-highlighting-in-powershell/
#>

    [CmdletBinding( DefaultParameterSetName = 'FilePath' )] Param (
        [Parameter(Position = 0, Mandatory = $True, ParameterSetName = 'FilePath' )]
        [ValidateNotNullOrEmpty()]
        [String]
        $Path,

        [Parameter(Position = 0, ValueFromPipeline = $True, Mandatory = $True, ParameterSetName = 'ScriptBlock' )]
        [ValidateNotNullOrEmpty()]
        [ScriptBlock]
        $ScriptBlock
    )

    Set-StrictMode -Version 2

    if ($PSBoundParameters['Path'])
    {
        Get-ChildItem $Path -ErrorAction Stop | Out-Null
        $ScriptBlockString = [IO.File]::ReadAllText((Resolve-Path $Path))
        $ScriptBlock = [ScriptBlock]::Create($ScriptBlockString)
    }
    else
    {
        # Convert the scriptblock to a string so that it can be referenced with array notation
        $ScriptBlockString = $ScriptBlock.ToString()
    }

    # Tokenize the scriptblock and return all tokens except for comments
    $Tokens = [System.Management.Automation.PSParser]::Tokenize($ScriptBlock, [Ref] $Null) | Where-Object { $_.Type -ne 'Comment' }

    $StringBuilder = New-Object Text.StringBuilder

    # The majority of the remaining code comes from Lee Holmes' Show-ColorizedContent script.
    $CurrentColumn = 1
    $NewlineCount = 0
    foreach($CurrentToken in $Tokens)
    {
        # Now output the token
        if(($CurrentToken.Type -eq 'NewLine') -or ($CurrentToken.Type -eq 'LineContinuation'))
        {
            $CurrentColumn = 1
            # Only insert a single newline. Sequential newlines are ignored in order to save space.
            if ($NewlineCount -eq 0)
            {
                $StringBuilder.AppendLine() | Out-Null
            }
            $NewlineCount++
        }
        else
        {
            $NewlineCount = 0

            # Do any indenting
            if($CurrentColumn -lt $CurrentToken.StartColumn)
            {
                # Insert a single space in between tokens on the same line. Extraneous whiltespace is ignored.
                if ($CurrentColumn -ne 1)
                {
                    $StringBuilder.Append(' ') | Out-Null
                }
            }

            # See where the token ends
            $CurrentTokenEnd = $CurrentToken.Start + $CurrentToken.Length - 1

            # Handle the line numbering for multi-line strings
            if(($CurrentToken.Type -eq 'String') -and ($CurrentToken.EndLine -gt $CurrentToken.StartLine))
            {
                $LineCounter = $CurrentToken.StartLine
                $StringLines = $(-join $ScriptBlockString[$CurrentToken.Start..$CurrentTokenEnd] -split '`r`n')

                foreach($StringLine in $StringLines)
                {
                    $StringBuilder.Append($StringLine) | Out-Null
                    $LineCounter++
                }
            }
            # Write out a regular token
            else
            {
                $StringBuilder.Append((-join $ScriptBlockString[$CurrentToken.Start..$CurrentTokenEnd])) | Out-Null
            }

            # Update our position in the column
            $CurrentColumn = $CurrentToken.EndColumn
        }
    }

    Write-Output ([ScriptBlock]::Create($StringBuilder.ToString()))
}