AST.psm1
[CmdletBinding()] param() $baseName = [System.IO.Path]::GetFileNameWithoutExtension($PSCommandPath) $script:PSModuleInfo = Test-ModuleManifest -Path "$PSScriptRoot\$baseName.psd1" $script:PSModuleInfo | Format-List | Out-String -Stream | ForEach-Object { Write-Debug $_ } $scriptName = $script:PSModuleInfo.Name Write-Debug "[$scriptName] - Importing module" #region [functions] - [public] Write-Debug "[$scriptName] - [functions] - [public] - Processing folder" #region [functions] - [public] - [Core] Write-Debug "[$scriptName] - [functions] - [public] - [Core] - Processing folder" #region [functions] - [public] - [Core] - [Get-FunctionAST] Write-Debug "[$scriptName] - [functions] - [public] - [Core] - [Get-FunctionAST] - Importing" function Get-FunctionAST { <# .SYNOPSIS Retrieves the abstract syntax tree (AST) of function definitions from a PowerShell script. .DESCRIPTION Parses a specified PowerShell script file and extracts function definitions matching the given name. By default, it returns all function definitions if no specific name is provided. .EXAMPLE Get-FunctionAST -Path "C:\Scripts\MyScript.ps1" Retrieves all function definitions from "MyScript.ps1". .EXAMPLE Get-FunctionAST -Name "Get-Data" -Path "C:\Scripts\MyScript.ps1" Retrieves only the function definition named "Get-Data" from "MyScript.ps1". #> [CmdletBinding()] param ( # The name of the function to search for. Defaults to all functions ('*'). [Parameter()] [string] $Name = '*', # The path to the PowerShell script file to be parsed. [Parameter(Mandatory)] [ValidateScript({ Test-Path -Path $_ -PathType Leaf })] [string] $Path ) begin {} process { # Parse the script file into an AST $ast = Get-ScriptAST -Path $Path # Extract function definitions $ast.FindAll({ $args[0] -is [System.Management.Automation.Language.FunctionDefinitionAst] }, $true) | Where-Object { $_.Name -like $Name } } end {} } Write-Debug "[$scriptName] - [functions] - [public] - [Core] - [Get-FunctionAST] - Done" #endregion [functions] - [public] - [Core] - [Get-FunctionAST] #region [functions] - [public] - [Core] - [Get-ScriptAST] Write-Debug "[$scriptName] - [functions] - [public] - [Core] - [Get-ScriptAST] - Importing" function Get-ScriptAST { <# .SYNOPSIS Parses a PowerShell script or script file and returns its Abstract Syntax Tree (AST). .DESCRIPTION This function parses a PowerShell script from a file or a string input and returns its AST. It can optionally provide token and error information. .EXAMPLE Get-ScriptAST -Path "C:\Scripts\MyScript.ps1" Parses the PowerShell script at "MyScript.ps1" and returns its AST. .EXAMPLE Get-ScriptAST -Script "Get-Process | Select-Object Name" Parses the provided PowerShell script string and returns its AST. .EXAMPLE Get-ScriptAST -Path "C:\Scripts\MyScript.ps1" -Tokens ([ref]$tokens) -Errors ([ref]$errors) Parses the script file while also capturing tokens and errors. #> [outputType([System.Management.Automation.Language.ScriptBlockAst])] [CmdletBinding()] param ( # The path to the PowerShell script file to be parsed. [Parameter( Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName, ParameterSetName = 'Path' )] # Validate using Test-Path [ValidateScript({ Test-Path -Path $_ -PathType Leaf })] [string] $Path, # The PowerShell script to be parsed. [Parameter( Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName, ParameterSetName = 'Script' )] [string] $Script, # Reference variable to store parsed tokens. [Parameter()] [ref] $Tokens, # Reference variable to store parsing errors. [Parameter()] [ref] $Errors ) begin {} process { switch ($PSCmdlet.ParameterSetName) { 'Path' { [System.Management.Automation.Language.Parser]::ParseFile($Path, [ref]$Tokens, [ref]$Errors) } 'Script' { [System.Management.Automation.Language.Parser]::ParseInput($Script, [ref]$Tokens, [ref]$Errors) } } } end {} } Write-Debug "[$scriptName] - [functions] - [public] - [Core] - [Get-ScriptAST] - Done" #endregion [functions] - [public] - [Core] - [Get-ScriptAST] Write-Debug "[$scriptName] - [functions] - [public] - [Core] - Done" #endregion [functions] - [public] - [Core] #region [functions] - [public] - [Functions] Write-Debug "[$scriptName] - [functions] - [public] - [Functions] - Processing folder" #region [functions] - [public] - [Functions] - [Get-FunctionAlias] Write-Debug "[$scriptName] - [functions] - [public] - [Functions] - [Get-FunctionAlias] - Importing" function Get-FunctionAlias { <# .SYNOPSIS Retrieves function aliases from a PowerShell script file. .DESCRIPTION Parses a specified PowerShell script file to identify function definitions and extract their associated aliases. Returns a custom object containing function names and their corresponding aliases. .EXAMPLE Get-FunctionAlias -Path "C:\Scripts\MyScript.ps1" Retrieves all function aliases defined in the specified script file. .EXAMPLE Get-FunctionAlias -Name "Get-Data" -Path "C:\Scripts\MyScript.ps1" Retrieves the alias information for the function named "Get-Data" from the specified script file. #> [CmdletBinding()] param ( # The name of the function to search for. Defaults to all functions ('*'). [Parameter()] [string] $Name = '*', # The path to the PowerShell script file to be parsed. [Parameter(Mandatory)] [ValidateScript({ Test-Path -Path $_ -PathType Leaf })] [string] $Path ) # Extract function definitions $functions = Get-FunctionAST -Path $Path # Process each function and extract aliases $functions | ForEach-Object { $funcName = $_.Name $attributes = $_.FindAll({ $args[0] -is [System.Management.Automation.Language.AttributeAst] }, $true) $aliasAttr = $attributes | Where-Object { $_ -is [System.Management.Automation.Language.AttributeAst] -and $_.TypeName.Name -eq 'Alias' } if ($aliasAttr) { $aliases = $aliasAttr.PositionalArguments | ForEach-Object { $_.ToString().Trim('"', "'") } [PSCustomObject]@{ Name = $funcName Alias = $aliases } } } | Where-Object { $_.Name -like $Name } } Write-Debug "[$scriptName] - [functions] - [public] - [Functions] - [Get-FunctionAlias] - Done" #endregion [functions] - [public] - [Functions] - [Get-FunctionAlias] #region [functions] - [public] - [Functions] - [Get-FunctionName] Write-Debug "[$scriptName] - [functions] - [public] - [Functions] - [Get-FunctionName] - Importing" function Get-FunctionName { <# .SYNOPSIS Extracts function names from a specified PowerShell script. .DESCRIPTION Parses the given PowerShell script file and retrieves all function names defined within it. This function utilizes the PowerShell Abstract Syntax Tree (AST) to analyze the script and extract function definitions. .EXAMPLE Get-FunctionName -Path "C:\Scripts\MyScript.ps1" Retrieves all function names defined in the specified script file. .NOTES Uses PowerShell's AST to analyze script structure. #> [CmdletBinding()] param ( # The path to the script file to parse [Parameter(Mandatory)] [ValidateScript({ Test-Path -Path $_ -PathType Leaf })] [string] $Path ) # Extract function definitions $functions = Get-FunctionAST -Path $Path # Process each function and extract the name $functions | ForEach-Object { $_.Name } } Write-Debug "[$scriptName] - [functions] - [public] - [Functions] - [Get-FunctionName] - Done" #endregion [functions] - [public] - [Functions] - [Get-FunctionName] #region [functions] - [public] - [Functions] - [Get-FunctionType] Write-Debug "[$scriptName] - [functions] - [public] - [Functions] - [Get-FunctionType] - Importing" function Get-FunctionType { <# .SYNOPSIS Extracts function types from a specified PowerShell script. .DESCRIPTION Parses the given PowerShell script file and retrieves all function types defined within it. This function utilizes the PowerShell Abstract Syntax Tree (AST) to analyze the script and extract function definitions. .EXAMPLE Get-FunctionType -Path "C:\Scripts\MyScript.ps1" Retrieves all function types defined in the specified script file. #> [OutputType([pscustomobject])] [CmdletBinding()] param( # The path to the PowerShell script file to be parsed. [Parameter( Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName, ParameterSetName = 'Path' )] [ValidateScript({ Test-Path -Path $_ -PathType Leaf })] [string] $Path ) begin {} process { $functionAST = Get-FunctionAST -Path $Path $functionAST | ForEach-Object { $type = $_.IsFilter ? 'Filter' : $_.IsWorkflow ? 'Workflow' : $_.IsConfiguration ? 'Configuration' : 'Function' [pscustomobject]@{ Name = $_.Name Type = $type } } } end {} } Write-Debug "[$scriptName] - [functions] - [public] - [Functions] - [Get-FunctionType] - Done" #endregion [functions] - [public] - [Functions] - [Get-FunctionType] Write-Debug "[$scriptName] - [functions] - [public] - [Functions] - Done" #endregion [functions] - [public] - [Functions] #region [functions] - [public] - [Scripts] Write-Debug "[$scriptName] - [functions] - [public] - [Scripts] - Processing folder" #region [functions] - [public] - [Scripts] - [Get-ScriptCommand] Write-Debug "[$scriptName] - [functions] - [public] - [Scripts] - [Get-ScriptCommand] - Importing" function Get-ScriptCommand { <# .SYNOPSIS Retrieves the commands used within a specified PowerShell script. .DESCRIPTION Analyzes a given PowerShell script and extracts all command invocations. Optionally includes call operators (& and .) in the results. Returns details such as command name, position, and file reference. .EXAMPLE Get-ScriptCommand -Path "C:\Scripts\example.ps1" Extracts and lists all commands found in the specified PowerShell script. .EXAMPLE Get-ScriptCommand -Path "C:\Scripts\example.ps1" -IncludeCallOperators Extracts all commands, including those executed with call operators (& and .). #> [Alias('Get-ScriptCommands')] [CmdletBinding()] param ( # The path to the PowerShell script file to be parsed. [Parameter(Mandatory)] [ValidateScript({ Test-Path -Path $_ -PathType Leaf })] [string] $Path, # Include call operators in the results, i.e. & and . [Parameter()] [switch] $IncludeCallOperators ) # Extract function definitions $ast = Get-ScriptAST -Path $Path # Gather CommandAsts $commandAST = $ast.FindAll({ $args[0] -is [System.Management.Automation.Language.CommandAst] }, $true) if (-not $IncludeCallOperators) { $commandAST = $commandAST | Where-Object { $_.InvocationOperator -notin 'Ampersand', 'Dot' } } $commandAST | ForEach-Object { $invocationOperator = switch ($_.InvocationOperator) { 'Ampersand' { '&' } 'Dot' { '.' } } $_.CommandElements[0].Extent | ForEach-Object { [pscustomobject]@{ Name = [string]::IsNullOrEmpty($invocationOperator) ? $_.Text : $invocationOperator StartLineNumber = $_.StartLineNumber StartColumnNumber = $_.StartColumnNumber EndLineNumber = $_.EndLineNumber EndColumnNumber = $_.EndColumnNumber File = $_.File } } } } Write-Debug "[$scriptName] - [functions] - [public] - [Scripts] - [Get-ScriptCommand] - Done" #endregion [functions] - [public] - [Scripts] - [Get-ScriptCommand] Write-Debug "[$scriptName] - [functions] - [public] - [Scripts] - Done" #endregion [functions] - [public] - [Scripts] Write-Debug "[$scriptName] - [functions] - [public] - Done" #endregion [functions] - [public] #region Member exporter $exports = @{ Alias = '*' Cmdlet = '' Function = @( 'Get-FunctionAST' 'Get-ScriptAST' 'Get-FunctionAlias' 'Get-FunctionName' 'Get-FunctionType' 'Get-ScriptCommand' ) } Export-ModuleMember @exports #endregion Member exporter |