Whilst having a play with someone else’s code I wanted to quickly find all the function definitions within a module, and then all the function calls within a function definition.
Having had a quick bingle around for a prewritten regex example I didn’t come up with much that fitted the bill. So in the hope that this will help the next person trying to do this here they are:
Assumptions:
- A PowerShell function name is of the form Word-Word
- A PowerShell function definition is of the form “Function Word-Word”
- A Powershell function call can be preceeded by a ‘|’,'(‘, or ‘ ‘
- The script is written using a reasonable style, so there is a ‘ ‘ post call
So to find the function definition I ended up using:
-match 'function\s(\w+-\w+)'
The function name ends up in $Matches[1]
And for a PowerShell function call:
-match '[^\s|(]\w+-\w+'}
The function name ends up in $Matches[0]
This works accurately enough for what I needed it to do. Feel free to let me know if you can spot any improvements on it.
Sunny
I would recommend using AST instead of Regex for finding PS Functions /Cmdlets in scripts.
https://blogs.technet.microsoft.com/heyscriptingguy/2012/09/26/learn-how-it-pros-can-use-the-powershell-ast/
Stuart Moore
Yes, you can:
[System.Management.Automation.Language.Parser]::ParseFile('C:\github\dbatools\functions\restore-dbadatabase.ps1',[ref]$null,[ref]$Null).FindAll({$args[0] -is [System.Management.Automation.Language.CommandAst]}, $true) | ForEach {$_.commandelements[0].value} | Sort-Object -Unique
which is faster, even when doing it recursively across an entire tree:
Get-ChildItem C:\github\dbatools -Filter '*.ps1' -recurse | ForEach {
[System.Management.Automation.Language.Parser]::ParseFile($_.fullname,[ref]$null,[ref]$Null).FindAll({$args[0] -is [System.Management.Automation.Language.CommandAst]}, $true) | ForEach {$_.commandelements[0].value} | Sort-Object -Unique
}
The only issue with that is that it matches more than just the cmdlets I was looking for. Running it recursively down the dbatools tree I’m also catching things like InModuleScope, System.Data.SqlClient.SqlException, git, TryNativeCommandOptionCompletion, ProgressBarHelper and lots of others that I didn’t want. So I’d have probably still have needed to pipe the output through a match to drop those. That’s not an issue, it’s working as designed, just not quite what I wanted 🙂