I've been working on a new PowerShell module that incorporates code from a few of my recent posts on converting PowerShell scripts and functions to files. I even whipped up a script, think of it as a meta-script, to create the module using the commands that I am adding to the module. I'll cover that another day. In the process of writing this script, I realized I also wanted to identify aliases for functions defined in the files.
ManageEngine ADManager Plus - Download Free Trial
Exclusive offer on ADManager Plus for US and UK regions. Claim now!
Specifically, I wanted to find aliases defined in the function itself.
Function Get-Foo {
[cmdletbinding()]
[alias("gf")]
Param (...)
...
I could have simply dot sourced the script file and then looked for the aliases. But I didn't want to assume that dot sourcing was an option. Instead, I went back to parsing the file with the AST.
Unfortunately, I couldn't find anything in the AST that specifically retrieved command aliases. If I'm missing something, please let me know. Instead, I relied on regular expressions to parse the function body. Using the code I've shown in the previous posts, it is simple by now to find functions in files.
This is merely a proof-of-concept. I still need to extract the alias names. I'll use a regular expression pattern that uses lookahead and lookbehind.
[regex]$rx = "(?<=alias\().*(?=\)\])"
The expression says to match on anything using .* where the text that comes before (lookbehind) is "alias(" and where the text after (lookahead) is ")]". Parentheses and square brackets are regex characters so I need to escape them with a slash. I can then clean up the match and get the aliases.
Here's my PowerShell function.
Function Get-FunctionAlias {
[cmdletbinding()]
[alias("gfal", "ga")]
[outputType("string")]
Param(
[Parameter(Position = 0, Mandatory, HelpMessage = "Specify the .ps1 or .psm1 file with defined functions.")]
[ValidateScript( {
If (Test-Path $_ ) {
$True
}
Else {
Throw "Can't validate that $_ exists. Please verify and try again."
$False
}
})]
[ValidateScript( {
If ($_ -match "\.ps(m)?1$") {
$True
}
Else {
Throw "The path must be to a .ps1 or .psm1 file."
$False
}
})]
[string]$Path
)
New-Variable astTokens -Force
New-Variable astErr -Force
$Path = Convert-Path -Path $path
[regex]$rx = "(?<=alias\().*(?=\)\])"
Write-Verbose "Parsing $path for functions."
$AST = [System.Management.Automation.Language.Parser]::ParseFile($Path, [ref]$astTokens, [ref]$astErr)
#parse out functions using the AST
$functions = $ast.FindAll( { $args[0] -is [System.Management.Automation.Language.FunctionDefinitionAst] }, $true)
if ($functions.count -gt 0) {
foreach ($f in $functions) {
if ($rx.IsMatch($f.body)) {
[pscustomobject]@{
Name = $f.name
#remove quotes from the alias names and join as a comma-separated array
Alias = ($rx.matches($f.body).value -replace """|'", "") -split ","
}
}
}
}
}
Let's use the function to discover its own aliases.
My PowerShell script file has two functions with defined aliases. I can use this information when scripting the build of a new PowerShell module. That topic is next on the agenda.
In the meantime, I hope you'll give this a spin and let me know how you might use it or what would make it even more helpful.
Update
Shortly after posting this, Przemysław Kłys was kind enough to share some code that uses the PowerShell AST to extract alias information. His approach is much more elegant, although I'm always looking for a way to use regular expressions. Here is a revised version of the function. The output is unchanged.
Function Get-FunctionAlias {
[cmdletbinding()]
[alias("gfal", "ga")]
[outputType("string")]
Param(
[Parameter(Position = 0, Mandatory, HelpMessage = "Specify the .ps1 or .psm1 file with defined functions.")]
[ValidateScript( {
If (Test-Path $_ ) {
$True
}
Else {
Throw "Can't validate that $_ exists. Please verify and try again."
$False
}
})]
[ValidateScript( {
If ($_ -match "\.ps(m)?1$") {
$True
}
Else {
Throw "The path must be to a .ps1 or .psm1 file."
$False
}
})]
[string]$Path
)
New-Variable astTokens -Force
New-Variable astErr -Force
$Path = Convert-Path -Path $path
Write-Verbose "Parsing $path for functions."
$AST = [System.Management.Automation.Language.Parser]::ParseFile($Path, [ref]$astTokens, [ref]$astErr)
#parse out functions using the AST
$functions = $ast.FindAll( { $args[0] -is [System.Management.Automation.Language.FunctionDefinitionAst] }, $true)
if ($functions.count -gt 0) {
foreach ($f in $functions) {
#thanks to https://twitter.com/PrzemyslawKlys for this suggestion
$aliasAST = $f.FindAll( {
$args[0] -is [System.Management.Automation.Language.AttributeAst] -and
$args[0].TypeName.Name -eq 'Alias' -and
$args[0].Parent -is [System.Management.Automation.Language.ParamBlockAst]
}, $true)
if ($aliasAST.positionalArguments) {
[pscustomobject]@{
Name = $f.name
Alias = $aliasAST.PositionalArguments.Value
}
}
}
}
}
2 thoughts on “Discovering Aliases with the PowerShell AST”
Comments are closed.