Question:
I’m trying to parse through a Pester script and extract values from the -Tag
parameter. Anyone know how to do this using [System.Management.Automation.PSParser]
?. I’m was thinking I’d have to loop through the tokens returned from [System.Management.Automation.PSParser]::Tokenize()
but that seems pretty kludgy and given that the values for -Tag
could be given in many different formats, not very practical.
At the end of the day, I’m hoping to return a collection with the Describe
block name, and the list of tags (if any) for that block.
1 2 3 4 5 6 7 |
Name Tags ---- ---- Section1 {tag1, tag2} Section2 {foo, bar} Section3 {asdf} Section4 {} |
Here are the sample Pester tests that I’m working with.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
describe 'Section1' -Tag @('tag1', 'tag2') { it 'blah1' { $true | should be $true } } describe 'Section2' -Tag 'foo', 'bar' { it 'blah2' { $true | should be $true } } describe 'Section3' -Tag 'asdf'{ it 'blah3' { $true | should be $true } } describe 'Section4' { it 'blah4' { $true | should be $true } } |
Anyone have any ideas on how to solve this? Is [System.Management.Automation.PSParser]
the right way to go or is there a better way?
Cheers
Answer:
Using PS3.0+ Language namespace AST parser:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
$text = Get-Content 'pester-script.ps1' -Raw # text is a multiline string, not an array! $tokens = $null $errors = $null [Management.Automation.Language.Parser]::ParseInput($text, [ref]$tokens, [ref]$errors). FindAll([Func[Management.Automation.Language.Ast,bool]]{ param ($ast) $ast.CommandElements -and $ast.CommandElements[0].Value -eq 'describe' }, $true) | ForEach { $CE = $_.CommandElements $secondString = ($CE | Where { $_.StaticType.name -eq 'string' })[1] $tagIdx = $CE.IndexOf(($CE | Where ParameterName -eq 'Tag')) + 1 $tags = if ($tagIdx -and $tagIdx -lt $CE.Count) { $CE[$tagIdx].Extent } New-Object PSCustomObject -Property @{ Name = $secondString Tags = $tags } } |
1234567 Name Tags---- ----'Section1' @('tag1', 'tag2')'Section2' 'foo', 'bar''Section3' 'asdf''Section4'
The code doesn’t interpret the tags as a list of strings, but simply uses the original text extent
.
Use the debugger in PowerShell ISE / Visual Studio / VSCode to inspect the various data type cases.