├── .vs └── AstHelper │ └── v14 │ └── .suo ├── ArgumentCompleters └── Get-AstObject_Type.ps1 ├── AstHelper.psd1 ├── AstHelper.psm1 ├── AstHelper.pssproj ├── AstHelper.sln ├── LICENSE.md ├── Public ├── Get-AstObject.ps1 ├── Get-AstType.ps1 └── Invoke-ScriptTokenize.ps1 └── README.md /.vs/AstHelper/v14/.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasrayner/AstHelper/529f4f8b33eee22a8cc328e6208f6b2d07d3d0d7/.vs/AstHelper/v14/.suo -------------------------------------------------------------------------------- /ArgumentCompleters/Get-AstObject_Type.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Provides Argument Completion for the 'Get-AstObject' Function, 'Type' parameter. 4 | #> 5 | Register-ArgumentCompleter -CommandName Get-AstObject -ParameterName Type -ScriptBlock { 6 | param($CommandName, $ParameterName, $WordToComplete, $CommandAst, $FakeBoundParameter) 7 | 8 | if ([System.IO.File]::Exists($FakeBoundParameter.ScriptPath)) { 9 | $types = Get-AstType -ScriptPath $FakeBoundParameter.ScriptPath 10 | $names = $types.Where({$_.Name -like "$WordToComplete*"}).Name | Sort-Object 11 | 12 | foreach ($name in $names) { 13 | [System.Management.Automation.CompletionResult]::new($name, $name, 'ParameterValue', $name) 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /AstHelper.psd1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasrayner/AstHelper/529f4f8b33eee22a8cc328e6208f6b2d07d3d0d7/AstHelper.psd1 -------------------------------------------------------------------------------- /AstHelper.psm1: -------------------------------------------------------------------------------- 1 | $paths = @( 2 | 'ArgumentCompleters', 3 | 'Public' 4 | ) 5 | 6 | foreach ($path in $paths) { 7 | Get-ChildItem -Path "$PSScriptRoot\$path\*.ps1" | ForEach-Object { 8 | . $_.FullName 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /AstHelper.pssproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | 2.0 6 | 6CAFC0C6-A428-4d30-A9F9-700E829FEA51 7 | Exe 8 | MyApplication 9 | MyApplication 10 | AstHelper 11 | 12 | 13 | true 14 | full 15 | false 16 | bin\Debug\ 17 | DEBUG;TRACE 18 | prompt 19 | 4 20 | 21 | 22 | pdbonly 23 | true 24 | bin\Release\ 25 | TRACE 26 | prompt 27 | 4 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /AstHelper.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.25420.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{F5034706-568F-408A-B7B3-4D38C6DB8A32}") = "AstHelper", "AstHelper.pssproj", "{6CAFC0C6-A428-4D30-A9F9-700E829FEA51}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {6CAFC0C6-A428-4D30-A9F9-700E829FEA51}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {6CAFC0C6-A428-4D30-A9F9-700E829FEA51}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {6CAFC0C6-A428-4D30-A9F9-700E829FEA51}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {6CAFC0C6-A428-4D30-A9F9-700E829FEA51}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2017 Thomas Rayner 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /Public/Get-AstObject.ps1: -------------------------------------------------------------------------------- 1 | function Get-AstObject { 2 | <# 3 | .SYNOPSIS 4 | Returns all the AST objects in a script that are of a specified type. 5 | .DESCRIPTION 6 | Takes the content of a script, parses it, and returns all the objects in a script that are of that type. 7 | .EXAMPLE 8 | Get-AstObject -ScriptPath .\MyScript.ps1 -Type CommandAst 9 | .NOTES 10 | Author: Thomas Rayner (@MrThomasRayner), workingsysadmin.com 11 | .LINK 12 | http://workingsysadmin.com 13 | #> 14 | 15 | [CmdletBinding()] 16 | [OutputType([PSCustomObject[]])] 17 | param ( 18 | [Parameter(Mandatory)] 19 | [ValidateNotNullOrEmpty()] 20 | [string]$ScriptPath, 21 | 22 | [Parameter(Mandatory)] 23 | [ValidateNotNullOrEmpty()] 24 | [string]$Type, 25 | 26 | [Parameter()] 27 | [switch]$ExactType 28 | ) 29 | process { 30 | try { 31 | [System.Type]$FullType = "System.Management.Automation.Language.$Type" 32 | $astTypeFilter = if($ExactType.IsPresent){ 33 | { $args[0].GetType() -eq $FullType } 34 | } 35 | else { 36 | { $args[0] -is $FullType} 37 | } 38 | $FullPath = (Resolve-Path -Path $ScriptPath).ProviderPath 39 | $ast = [System.Management.Automation.Language.Parser]::ParseFile( $FullPath, [ref]$null, [ref]$null ) 40 | $ast.FindAll( $astTypeFilter, $true ) | 41 | ForEach-Object { 42 | $_ 43 | } 44 | } 45 | catch { 46 | $PSCmdlet.ThrowTerminatingError( $_ ) 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Public/Get-AstType.ps1: -------------------------------------------------------------------------------- 1 | function Get-AstType { 2 | <# 3 | .SYNOPSIS 4 | Returns all of the types of AST objects in a script. 5 | .DESCRIPTION 6 | Parses the contents of a provided script and gets a list of all the AST object types. 7 | .EXAMPLE 8 | Get-AstType -ScriptPath .\MyScript.ps1 9 | .NOTES 10 | Author: Thomas Rayner (@MrThomasRayner), workingsysadmin.com 11 | .LINK 12 | http://workingsysadmin.com 13 | #> 14 | 15 | [CmdletBinding()] 16 | [OutputType([PSCustomObject[]])] 17 | param ( 18 | [Parameter(Mandatory)] 19 | [ValidateNotNullOrEmpty()] 20 | [string]$ScriptPath 21 | ) 22 | process { 23 | try { 24 | $FullPath = (Resolve-Path -Path $ScriptPath).ProviderPath 25 | $ast = [System.Management.Automation.Language.Parser]::ParseFile( $FullPath, [ref]$null, [ref]$null ) 26 | $ast.FindAll( { $args[0] -ne $null }, $true ) | 27 | ForEach-Object { 28 | $_.GetType() 29 | } | Select-Object -Unique 30 | } 31 | catch { 32 | $PSCmdlet.ThrowTerminatingError( $_ ) 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Public/Invoke-ScriptTokenize.ps1: -------------------------------------------------------------------------------- 1 | function Invoke-Tokenize { 2 | <# 3 | .SYNOPSIS 4 | Tokenizes a script. 5 | .DESCRIPTION 6 | Gets the content of a script located at a given path and tokenizes it. 7 | .EXAMPLE 8 | Invoke-Tokenize -ScriptPath .\MyScript.ps1 9 | .NOTES 10 | Author: Thomas Rayner (@MrThomasRayner), workingsysadmin.com 11 | .LINK 12 | http://workingsysadmin.com 13 | #> 14 | 15 | [CmdletBinding()] 16 | param ( 17 | # The path to the script to be tokenized 18 | [Parameter(Mandatory)] 19 | [ValidateNotNullOrEmpty()] 20 | [string]$ScriptPath 21 | ) 22 | 23 | $code = Get-Content $ScriptPath 24 | [System.Management.Automation.PSParser]::Tokenize($code,[ref]$null) | 25 | ForEach-Object { 26 | $_ 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AstHelper 2 | AstHelper is a module that aims to make working with Abstract Syntax Trees (ASTs) a more convenient process. If you're writing a tool that parses PowerShell artifacts, it is valuable to know how to analyze AST. 3 | 4 | ## To Do 5 | - Write better help 6 | - Write tests 7 | - Add more features 8 | - Figure out which features need to be added 9 | - A real release pipeline 10 | --------------------------------------------------------------------------------