{"id":8759,"date":"2022-01-05T14:09:50","date_gmt":"2022-01-05T19:09:50","guid":{"rendered":"https:\/\/jdhitsolutions.com\/blog\/?p=8759"},"modified":"2022-01-05T14:09:54","modified_gmt":"2022-01-05T19:09:54","slug":"discovering-pester-tags-with-the-powershell-ast","status":"publish","type":"post","link":"https:\/\/jdhitsolutions.com\/blog\/powershell\/8759\/discovering-pester-tags-with-the-powershell-ast\/","title":{"rendered":"Discovering Pester Tags with the PowerShell AST"},"content":{"rendered":"\n<p>As <a href=\"https:\/\/jdhitsolutions.com\/blog\/powershell\/8750\/powershell-plans-for-2022\/\" target=\"_blank\" rel=\"noreferrer noopener\">I resolved<\/a> at the end of last year, I am doing more with Pester in 2022. I'm getting a bit more comfortable with Pester 5 and as my tests grow in complexity I am embracing the use of tags. You can add tags to different Pester test elements. Then when you invoke a Pester test, you can filter and only run specific tests by their tag. As I was working, I realized it would be helpful to be able to identify all of the tags in a test script. After a bit of work, I came up with a PowerShell function.<\/p>\n\n\n\n<p>My initial thought was to use regular expressions and look for lines with -tag.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"powershell\" class=\"language-powershell\">$path = \"C:\\scripts\\psfunctiontools\\tests\\psfunctiontools.tests.ps1\"\n[regex]$rx=\"(?&lt;=-tag\\s)(\\w(,)?(\\s)?)*\"\n$c = Get-Content $path\n#make all tags lower case\n([System.Text.RegularExpressions.Regex]::Matches($c,$rx,\"IgnoreCase\")).foreach({($_.value -split \",\").Trim().toLower()}) |\nSelect-Object -Unique | Sort-Object<\/code><\/pre>\n\n\n\n<p>This code works but is a bit of a brute-force approach. I had to take into account multiple tags and syntax variations. So I went back to the PowerShell AST.<\/p>\n\n\n\n<p>Parsing the file is simple enough.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"powershell\" class=\"language-powershell\">$AST = [System.Management.Automation.Language.Parser]::ParseFile(\n    $path,\n    [ref]$astTokens,\n    [ref]$astErr\n)<\/code><\/pre>\n\n\n\n<p>In a Pester test, tags are technically part of a -Tag parameter for a Pester command like Describe or It. This means I can discover these command elements.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"powershell\" class=\"language-powershell\">$tags = $AST.FindAll({\n    $args[0] -is [System.Management.Automation.Language.CommandParameterAst] -AND $args[0].parametername -eq 'tag' },\n$true\n)<\/code><\/pre>\n\n\n\n<p>Now for the tricky part. Here's a sample object.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large is-style-default\"><a href=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2022\/01\/sample-tag.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"308\" src=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2022\/01\/sample-tag-1024x308.png\" alt=\"sample AST tag object\" class=\"wp-image-8760\" srcset=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2022\/01\/sample-tag-1024x308.png 1024w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2022\/01\/sample-tag-300x90.png 300w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2022\/01\/sample-tag-768x231.png 768w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2022\/01\/sample-tag-850x256.png 850w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2022\/01\/sample-tag.png 1254w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n\n\n\n<p>It would be nice if the Argument property contained the values \"help\", and \"acceptance\" which you can see in the parent. But that would be too easy. However, I can use the Parent property and its CommandElements.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large is-style-default\"><a href=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2022\/01\/command-elements.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"453\" src=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2022\/01\/command-elements-1024x453.png\" alt=\"tag command elements\" class=\"wp-image-8761\" srcset=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2022\/01\/command-elements-1024x453.png 1024w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2022\/01\/command-elements-300x133.png 300w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2022\/01\/command-elements-768x340.png 768w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2022\/01\/command-elements-850x376.png 850w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2022\/01\/command-elements.png 1297w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n\n\n\n<p>I'm showing you the last two elements. The Tag parameter value is the element after the parameter element. This might make it clearer.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"powershell\" class=\"language-powershell\">for ($i = 0;$i -lt $tags[0].Parent.CommandElements.count;$i++) {\n    if ($tags[0].parent.CommandElements[$i].parametername -eq 'tag') {\n    $tags[0].parent.CommandElements[$i+1].extent.text.split(\",\").trim().tolower()\n    }\n}<\/code><\/pre>\n\n\n\n<p>I can loop through all the command elements using a For enumeration loop. If the parametername property is 'tag', then get the next element ($i+1) and use the Extent.Text property. It might be an array so I'll split it and trim up extra spaces.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full is-style-default\"><a href=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2022\/01\/get-tag-value.png\"><img loading=\"lazy\" decoding=\"async\" width=\"910\" height=\"192\" src=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2022\/01\/get-tag-value.png\" alt=\"get tag value\" class=\"wp-image-8762\" srcset=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2022\/01\/get-tag-value.png 910w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2022\/01\/get-tag-value-300x63.png 300w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2022\/01\/get-tag-value-768x162.png 768w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2022\/01\/get-tag-value-850x179.png 850w\" sizes=\"auto, (max-width: 910px) 100vw, 910px\" \/><\/a><\/figure>\n\n\n\n<p>All I need to do now is step back and do this for all tag elements with a set of nested For loops.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full is-style-default\"><a href=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2022\/01\/get-all-tag-values.png\"><img loading=\"lazy\" decoding=\"async\" width=\"971\" height=\"341\" src=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2022\/01\/get-all-tag-values.png\" alt=\"get all tag values\" class=\"wp-image-8763\" srcset=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2022\/01\/get-all-tag-values.png 971w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2022\/01\/get-all-tag-values-300x105.png 300w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2022\/01\/get-all-tag-values-768x270.png 768w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2022\/01\/get-all-tag-values-850x299.png 850w\" sizes=\"auto, (max-width: 971px) 100vw, 971px\" \/><\/a><\/figure>\n\n\n\n<p>The last step is to get unique items. Notice that I'm also making every entry lowercase to ensure I'm truly getting unique values. <\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Get-PesterTag<\/h2>\n\n\n\n<p>With this core functionality, I built a PowerShell function around it.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"powershell\" class=\"language-powershell\">Function Get-PesterTag {\n    [cmdletbinding()]\n    [OutputType(\"pesterTag\")]\n    Param(\n        [Parameter(\n            Position = 0,\n            Mandatory,\n            HelpMessage = \"Specify a Pester test file\",\n            ValueFromPipeline\n        )]\n        [ValidateScript({\n            #validate file exits\n            if (Test-Path $_) {\n                #now test for extension\n                if ($_ -match \"\\.ps1$\") {\n                    $True\n                }\n                else {\n                    Throw \"The filename must end in '.ps1'.\"\n                }\n            }\n            else {\n                Throw \"Cannot find file $_.\"\n            }\n        })]\n        [string]$Path\n    )\n\n    Begin {\n        Write-Verbose \"[$((Get-Date).TimeofDay) BEGIN  ] Starting $($myinvocation.mycommand)\"\n        New-Variable astTokens -Force\n        New-Variable astErr -Force\n    } #begin\n\n    Process {\n        Write-Verbose \"[$((Get-Date).TimeofDay) PROCESS] Getting tags from $Path \"\n        $AST = [System.Management.Automation.Language.Parser]::ParseFile(\n            $path,\n            [ref]$astTokens,\n            [ref]$astErr\n        )\n        $tags = $AST.FindAll({\n                $args[0] -is [System.Management.Automation.Language.CommandParameterAst] -AND $args[0].parametername -eq 'tag' },\n            $true\n        )\n\n        $all = for ($j = 0; $j -lt $tags.count; $j++) {\n            for ($i = 0; $i -lt $tags[$j].Parent.CommandElements.count; $i++) {\n                if ($tags[$j].parent.CommandElements[$i].parametername -eq 'tag') {\n                    $tags[$j].parent.CommandElements[$i + 1].extent.text.split(\",\").trim().tolower()\n                }\n            }\n        }\n        if ($all) {\n            [pscustomobject]@{\n                PSTypename = \"pesterTag\"\n                Path       = $Path\n                Tags       = $all | Select-Object -Unique | Sort-Object\n            }\n        }\n        else {\n            Write-Warning \"No tags found in $Path\"\n        }\n    } #process\n\n    End {\n        Write-Verbose \"[$((Get-Date).TimeofDay) END    ] Ending $($myinvocation.mycommand)\"\n    } #end\n\n} #close Get-PesterTag<\/code><\/pre>\n\n\n\n<p>The function writes a custom object to the pipeline which includes the file name.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full is-style-default\"><a href=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2022\/01\/get-pestertag.png\"><img loading=\"lazy\" decoding=\"async\" width=\"898\" height=\"130\" src=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2022\/01\/get-pestertag.png\" alt=\"get-pestertag\" class=\"wp-image-8764\" srcset=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2022\/01\/get-pestertag.png 898w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2022\/01\/get-pestertag-300x43.png 300w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2022\/01\/get-pestertag-768x111.png 768w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2022\/01\/get-pestertag-850x123.png 850w\" sizes=\"auto, (max-width: 898px) 100vw, 898px\" \/><\/a><\/figure>\n\n\n\n<p>This was very helpful as I discovered a misspelled tag name. The function includes parameter validation on the path. The validation script first verifies the file exists and then that it ends in .ps1. I used to separate these out into two separate validation tests, but there's no reason not to combine them.  The only other thing I could do is create a custom format file for the pesterTag object type. But I'll leave that to you. I need to get back to working on my tests.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>As I resolved at the end of last year, I am doing more with Pester in 2022. I&#8217;m getting a bit more comfortable with Pester 5 and as my tests grow in complexity I am embracing the use of tags. You can add tags to different Pester test elements. Then when you invoke a Pester&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"New on the blog: Discovering #Pester tags with the #PowerShell AST","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[4,8],"tags":[447,520,534],"class_list":["post-8759","post","type-post","status-publish","format-standard","hentry","category-powershell","category-scripting","tag-ast","tag-pester","tag-powershell"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.5 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Discovering Pester Tags with the PowerShell AST &#8226; The Lonely Administrator<\/title>\n<meta name=\"description\" content=\"I needed a way to identify tags in a Pester test so I turned to the PowerShell AST and wrote a function to do the work for me.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/jdhitsolutions.com\/blog\/powershell\/8759\/discovering-pester-tags-with-the-powershell-ast\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Discovering Pester Tags with the PowerShell AST &#8226; The Lonely Administrator\" \/>\n<meta property=\"og:description\" content=\"I needed a way to identify tags in a Pester test so I turned to the PowerShell AST and wrote a function to do the work for me.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/jdhitsolutions.com\/blog\/powershell\/8759\/discovering-pester-tags-with-the-powershell-ast\/\" \/>\n<meta property=\"og:site_name\" content=\"The Lonely Administrator\" \/>\n<meta property=\"article:published_time\" content=\"2022-01-05T19:09:50+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2022-01-05T19:09:54+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2022\/01\/sample-tag-1024x308.png\" \/>\n<meta name=\"author\" content=\"Jeffery Hicks\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@JeffHicks\" \/>\n<meta name=\"twitter:site\" content=\"@JeffHicks\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Jeffery Hicks\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"4 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/powershell\\\/8759\\\/discovering-pester-tags-with-the-powershell-ast\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/powershell\\\/8759\\\/discovering-pester-tags-with-the-powershell-ast\\\/\"},\"author\":{\"name\":\"Jeffery Hicks\",\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/#\\\/schema\\\/person\\\/d0258030b41f07fd745f4078bdf5b6c9\"},\"headline\":\"Discovering Pester Tags with the PowerShell AST\",\"datePublished\":\"2022-01-05T19:09:50+00:00\",\"dateModified\":\"2022-01-05T19:09:54+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/powershell\\\/8759\\\/discovering-pester-tags-with-the-powershell-ast\\\/\"},\"wordCount\":466,\"commentCount\":3,\"publisher\":{\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/#\\\/schema\\\/person\\\/d0258030b41f07fd745f4078bdf5b6c9\"},\"image\":{\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/powershell\\\/8759\\\/discovering-pester-tags-with-the-powershell-ast\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/wp-content\\\/uploads\\\/2022\\\/01\\\/sample-tag-1024x308.png\",\"keywords\":[\"AST\",\"Pester\",\"PowerShell\"],\"articleSection\":[\"PowerShell\",\"Scripting\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/powershell\\\/8759\\\/discovering-pester-tags-with-the-powershell-ast\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/powershell\\\/8759\\\/discovering-pester-tags-with-the-powershell-ast\\\/\",\"url\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/powershell\\\/8759\\\/discovering-pester-tags-with-the-powershell-ast\\\/\",\"name\":\"Discovering Pester Tags with the PowerShell AST &#8226; The Lonely Administrator\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/powershell\\\/8759\\\/discovering-pester-tags-with-the-powershell-ast\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/powershell\\\/8759\\\/discovering-pester-tags-with-the-powershell-ast\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/wp-content\\\/uploads\\\/2022\\\/01\\\/sample-tag-1024x308.png\",\"datePublished\":\"2022-01-05T19:09:50+00:00\",\"dateModified\":\"2022-01-05T19:09:54+00:00\",\"description\":\"I needed a way to identify tags in a Pester test so I turned to the PowerShell AST and wrote a function to do the work for me.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/powershell\\\/8759\\\/discovering-pester-tags-with-the-powershell-ast\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/powershell\\\/8759\\\/discovering-pester-tags-with-the-powershell-ast\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/powershell\\\/8759\\\/discovering-pester-tags-with-the-powershell-ast\\\/#primaryimage\",\"url\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/wp-content\\\/uploads\\\/2022\\\/01\\\/sample-tag.png\",\"contentUrl\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/wp-content\\\/uploads\\\/2022\\\/01\\\/sample-tag.png\",\"width\":1254,\"height\":377},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/powershell\\\/8759\\\/discovering-pester-tags-with-the-powershell-ast\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"PowerShell\",\"item\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/category\\\/powershell\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Discovering Pester Tags with the PowerShell AST\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/\",\"name\":\"The Lonely Administrator\",\"description\":\"Practical Advice for the Automating IT Pro\",\"publisher\":{\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/#\\\/schema\\\/person\\\/d0258030b41f07fd745f4078bdf5b6c9\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/#\\\/schema\\\/person\\\/d0258030b41f07fd745f4078bdf5b6c9\",\"name\":\"Jeffery Hicks\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/832ae5d438fdcfc1420d720cd1991307927de8a0b12f2342e81c30f773e21098?s=96&d=wavatar&r=pg\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/832ae5d438fdcfc1420d720cd1991307927de8a0b12f2342e81c30f773e21098?s=96&d=wavatar&r=pg\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/832ae5d438fdcfc1420d720cd1991307927de8a0b12f2342e81c30f773e21098?s=96&d=wavatar&r=pg\",\"caption\":\"Jeffery Hicks\"},\"logo\":{\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/832ae5d438fdcfc1420d720cd1991307927de8a0b12f2342e81c30f773e21098?s=96&d=wavatar&r=pg\"}}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Discovering Pester Tags with the PowerShell AST &#8226; The Lonely Administrator","description":"I needed a way to identify tags in a Pester test so I turned to the PowerShell AST and wrote a function to do the work for me.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/jdhitsolutions.com\/blog\/powershell\/8759\/discovering-pester-tags-with-the-powershell-ast\/","og_locale":"en_US","og_type":"article","og_title":"Discovering Pester Tags with the PowerShell AST &#8226; The Lonely Administrator","og_description":"I needed a way to identify tags in a Pester test so I turned to the PowerShell AST and wrote a function to do the work for me.","og_url":"https:\/\/jdhitsolutions.com\/blog\/powershell\/8759\/discovering-pester-tags-with-the-powershell-ast\/","og_site_name":"The Lonely Administrator","article_published_time":"2022-01-05T19:09:50+00:00","article_modified_time":"2022-01-05T19:09:54+00:00","og_image":[{"url":"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2022\/01\/sample-tag-1024x308.png","type":"","width":"","height":""}],"author":"Jeffery Hicks","twitter_card":"summary_large_image","twitter_creator":"@JeffHicks","twitter_site":"@JeffHicks","twitter_misc":{"Written by":"Jeffery Hicks","Est. reading time":"4 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/jdhitsolutions.com\/blog\/powershell\/8759\/discovering-pester-tags-with-the-powershell-ast\/#article","isPartOf":{"@id":"https:\/\/jdhitsolutions.com\/blog\/powershell\/8759\/discovering-pester-tags-with-the-powershell-ast\/"},"author":{"name":"Jeffery Hicks","@id":"https:\/\/jdhitsolutions.com\/blog\/#\/schema\/person\/d0258030b41f07fd745f4078bdf5b6c9"},"headline":"Discovering Pester Tags with the PowerShell AST","datePublished":"2022-01-05T19:09:50+00:00","dateModified":"2022-01-05T19:09:54+00:00","mainEntityOfPage":{"@id":"https:\/\/jdhitsolutions.com\/blog\/powershell\/8759\/discovering-pester-tags-with-the-powershell-ast\/"},"wordCount":466,"commentCount":3,"publisher":{"@id":"https:\/\/jdhitsolutions.com\/blog\/#\/schema\/person\/d0258030b41f07fd745f4078bdf5b6c9"},"image":{"@id":"https:\/\/jdhitsolutions.com\/blog\/powershell\/8759\/discovering-pester-tags-with-the-powershell-ast\/#primaryimage"},"thumbnailUrl":"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2022\/01\/sample-tag-1024x308.png","keywords":["AST","Pester","PowerShell"],"articleSection":["PowerShell","Scripting"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/jdhitsolutions.com\/blog\/powershell\/8759\/discovering-pester-tags-with-the-powershell-ast\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/jdhitsolutions.com\/blog\/powershell\/8759\/discovering-pester-tags-with-the-powershell-ast\/","url":"https:\/\/jdhitsolutions.com\/blog\/powershell\/8759\/discovering-pester-tags-with-the-powershell-ast\/","name":"Discovering Pester Tags with the PowerShell AST &#8226; The Lonely Administrator","isPartOf":{"@id":"https:\/\/jdhitsolutions.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/jdhitsolutions.com\/blog\/powershell\/8759\/discovering-pester-tags-with-the-powershell-ast\/#primaryimage"},"image":{"@id":"https:\/\/jdhitsolutions.com\/blog\/powershell\/8759\/discovering-pester-tags-with-the-powershell-ast\/#primaryimage"},"thumbnailUrl":"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2022\/01\/sample-tag-1024x308.png","datePublished":"2022-01-05T19:09:50+00:00","dateModified":"2022-01-05T19:09:54+00:00","description":"I needed a way to identify tags in a Pester test so I turned to the PowerShell AST and wrote a function to do the work for me.","breadcrumb":{"@id":"https:\/\/jdhitsolutions.com\/blog\/powershell\/8759\/discovering-pester-tags-with-the-powershell-ast\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/jdhitsolutions.com\/blog\/powershell\/8759\/discovering-pester-tags-with-the-powershell-ast\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/jdhitsolutions.com\/blog\/powershell\/8759\/discovering-pester-tags-with-the-powershell-ast\/#primaryimage","url":"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2022\/01\/sample-tag.png","contentUrl":"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2022\/01\/sample-tag.png","width":1254,"height":377},{"@type":"BreadcrumbList","@id":"https:\/\/jdhitsolutions.com\/blog\/powershell\/8759\/discovering-pester-tags-with-the-powershell-ast\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"PowerShell","item":"https:\/\/jdhitsolutions.com\/blog\/category\/powershell\/"},{"@type":"ListItem","position":2,"name":"Discovering Pester Tags with the PowerShell AST"}]},{"@type":"WebSite","@id":"https:\/\/jdhitsolutions.com\/blog\/#website","url":"https:\/\/jdhitsolutions.com\/blog\/","name":"The Lonely Administrator","description":"Practical Advice for the Automating IT Pro","publisher":{"@id":"https:\/\/jdhitsolutions.com\/blog\/#\/schema\/person\/d0258030b41f07fd745f4078bdf5b6c9"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/jdhitsolutions.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/jdhitsolutions.com\/blog\/#\/schema\/person\/d0258030b41f07fd745f4078bdf5b6c9","name":"Jeffery Hicks","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/832ae5d438fdcfc1420d720cd1991307927de8a0b12f2342e81c30f773e21098?s=96&d=wavatar&r=pg","url":"https:\/\/secure.gravatar.com\/avatar\/832ae5d438fdcfc1420d720cd1991307927de8a0b12f2342e81c30f773e21098?s=96&d=wavatar&r=pg","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/832ae5d438fdcfc1420d720cd1991307927de8a0b12f2342e81c30f773e21098?s=96&d=wavatar&r=pg","caption":"Jeffery Hicks"},"logo":{"@id":"https:\/\/secure.gravatar.com\/avatar\/832ae5d438fdcfc1420d720cd1991307927de8a0b12f2342e81c30f773e21098?s=96&d=wavatar&r=pg"}}]}},"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_likes_enabled":true,"jetpack-related-posts":[{"id":8766,"url":"https:\/\/jdhitsolutions.com\/blog\/powershell\/8766\/discovering-pester-tags-revisited\/","url_meta":{"origin":8759,"position":0},"title":"Discovering Pester Tags Revisited","author":"Jeffery Hicks","date":"January 6, 2022","format":false,"excerpt":"Yesterday I shared some PowerShell code I wrote to discover tags in a Pester test. It works nicely and I have no reason to complain. But as usual, there is never simply one way to do something in PowerShell. I got a suggestion from @FrodeFlaten on Twitter on an approach\u2026","rel":"","context":"In &quot;PowerShell&quot;","block_context":{"text":"PowerShell","link":"https:\/\/jdhitsolutions.com\/blog\/category\/powershell\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2022\/01\/container-tags.png?resize=350%2C200&ssl=1","width":350,"height":200},"classes":[]},{"id":8754,"url":"https:\/\/jdhitsolutions.com\/blog\/powershell\/8754\/accelerate-pester-test-development\/","url_meta":{"origin":8759,"position":1},"title":"Accelerate Pester Test Development","author":"Jeffery Hicks","date":"December 28, 2021","format":false,"excerpt":"The other day I shared my PowerShell plans for 2022. And needless to say, I didn't wait to dig in. I am working on a new module and since it won't be published until next month, I went ahead and marked it as Core only. I also started writing a\u2026","rel":"","context":"In &quot;PowerShell&quot;","block_context":{"text":"PowerShell","link":"https:\/\/jdhitsolutions.com\/blog\/category\/powershell\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/12\/new-pesterblock.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/12\/new-pesterblock.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/12\/new-pesterblock.png?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/12\/new-pesterblock.png?resize=700%2C400&ssl=1 2x, https:\/\/i0.wp.com\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/12\/new-pesterblock.png?resize=1050%2C600&ssl=1 3x, https:\/\/i0.wp.com\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/12\/new-pesterblock.png?resize=1400%2C800&ssl=1 4x"},"classes":[]},{"id":7409,"url":"https:\/\/jdhitsolutions.com\/blog\/powershell\/7409\/importing-pester-results-into-powershell\/","url_meta":{"origin":8759,"position":2},"title":"Importing Pester Results into PowerShell","author":"Jeffery Hicks","date":"April 24, 2020","format":false,"excerpt":"Last week, a PowerShell scripting challenge was posted on the Iron Scripter web site.\u00a0 The idea was that when you run a Pester test, you can save the results to a specially formatted\u00a0 XML file. Invoke-Pester C:\\scripts\\sample.test.ps1 -OutputFile d:\\temp\\results.xml -OutputFormat JUnitXml I get this result. The challenge was to write\u2026","rel":"","context":"In &quot;PowerShell&quot;","block_context":{"text":"PowerShell","link":"https:\/\/jdhitsolutions.com\/blog\/category\/powershell\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2020\/04\/informationvariable-1.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2020\/04\/informationvariable-1.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2020\/04\/informationvariable-1.png?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2020\/04\/informationvariable-1.png?resize=700%2C400&ssl=1 2x, https:\/\/i0.wp.com\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2020\/04\/informationvariable-1.png?resize=1050%2C600&ssl=1 3x"},"classes":[]},{"id":8750,"url":"https:\/\/jdhitsolutions.com\/blog\/powershell\/8750\/powershell-plans-for-2022\/","url_meta":{"origin":8759,"position":3},"title":"PowerShell Plans for 2022","author":"Jeffery Hicks","date":"December 27, 2021","format":false,"excerpt":"I'm not much for writing year in review pieces. Nor, to be honest, do I often write New Year's resolutions. But I've been thinking about the work I've done this past year and what I might be doing in 2022 so I thought I'd share some thoughts on what 2022\u2026","rel":"","context":"In &quot;PowerShell&quot;","block_context":{"text":"PowerShell","link":"https:\/\/jdhitsolutions.com\/blog\/category\/powershell\/"},"img":{"alt_text":"binoculars","src":"https:\/\/i0.wp.com\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/07\/pexels-skitterphoto-63901.jpg?resize=350%2C200&ssl=1","width":350,"height":200},"classes":[]},{"id":7559,"url":"https:\/\/jdhitsolutions.com\/blog\/powershell\/7559\/an-expanded-powershell-scripting-inventory-tool\/","url_meta":{"origin":8759,"position":4},"title":"An Expanded PowerShell Scripting Inventory Tool","author":"Jeffery Hicks","date":"June 19, 2020","format":false,"excerpt":"The other day I shared my code that I worked up to solve an Iron Scripter PowerShell challenge. One of the shortcomings was that I didn't address a challenge to include a property that would indicate what file was using a given command. I also felt I could do better\u2026","rel":"","context":"In &quot;PowerShell&quot;","block_context":{"text":"PowerShell","link":"https:\/\/jdhitsolutions.com\/blog\/category\/powershell\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2020\/06\/get-psscriptinventory.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2020\/06\/get-psscriptinventory.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2020\/06\/get-psscriptinventory.png?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2020\/06\/get-psscriptinventory.png?resize=700%2C400&ssl=1 2x, https:\/\/i0.wp.com\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2020\/06\/get-psscriptinventory.png?resize=1050%2C600&ssl=1 3x, https:\/\/i0.wp.com\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2020\/06\/get-psscriptinventory.png?resize=1400%2C800&ssl=1 4x"},"classes":[]},{"id":4994,"url":"https:\/\/jdhitsolutions.com\/blog\/powershell\/4994\/creating-new-powershell-projects\/","url_meta":{"origin":8759,"position":5},"title":"Creating New PowerShell Projects","author":"Jeffery Hicks","date":"May 17, 2016","format":false,"excerpt":"I've been writing scripts since the early days of DOS batch files. Like many of you I simply stick them all in a folder and move on to the next project. Most of my work is just for me or writing projects so this methodology worked just fine for me.\u2026","rel":"","context":"In &quot;PowerShell&quot;","block_context":{"text":"PowerShell","link":"https:\/\/jdhitsolutions.com\/blog\/category\/powershell\/"},"img":{"alt_text":"image","src":"https:\/\/i0.wp.com\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2016\/05\/image_thumb.png?resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2016\/05\/image_thumb.png?resize=350%2C200 1x, https:\/\/i0.wp.com\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2016\/05\/image_thumb.png?resize=525%2C300 1.5x"},"classes":[]}],"_links":{"self":[{"href":"https:\/\/jdhitsolutions.com\/blog\/wp-json\/wp\/v2\/posts\/8759","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/jdhitsolutions.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/jdhitsolutions.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/jdhitsolutions.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/jdhitsolutions.com\/blog\/wp-json\/wp\/v2\/comments?post=8759"}],"version-history":[{"count":0,"href":"https:\/\/jdhitsolutions.com\/blog\/wp-json\/wp\/v2\/posts\/8759\/revisions"}],"wp:attachment":[{"href":"https:\/\/jdhitsolutions.com\/blog\/wp-json\/wp\/v2\/media?parent=8759"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/jdhitsolutions.com\/blog\/wp-json\/wp\/v2\/categories?post=8759"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/jdhitsolutions.com\/blog\/wp-json\/wp\/v2\/tags?post=8759"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}