---
title: "PowerShell AST: Meta Scripting Unleashed"
description: "Learn how to use PowerShell AST to analyze and manipulate PowerShell scripts in this intriguing tutorial."
canonical: "https://adamtheautomator.com/powershell-ast/"
---

# PowerShell AST: Meta Scripting Unleashed

> Learn how to use PowerShell AST to analyze and manipulate PowerShell scripts in this intriguing tutorial.

Source: https://adamtheautomator.com/powershell-ast/

---

ATA Learning

Tap to hide

[

ATA Learning

](/)

*   [Home](/)
*   [Tutorials](/tutorials/)
*   [Instructors](/author/)
*   [Advertising](/advertising/)
*   [Recommended Resources](/resources/)
*   [About Adam](/about-adam/)

Search for:  

*   [](https://twitter.com/adbertram)
*   [](https://github.com/Adam-the-Automator)
*   [](https://www.linkedin.com/company/adam-the-automator-llc)
*   [](/feed/)

![PowerShell AST: Meta Scripting Unleashed](https://adamtheautomator.com/wp-content/uploads/2019/07/5d238ae5c824b514689ea65e.jpg)

# PowerShell AST: Meta Scripting Unleashed

[![](https://secure.gravatar.com/avatar/d0b9d42e21e5622713f8b693aa5c0f9244d5f7dd200ed29b8398f52dee5de337?s=192&d=mm&r=g)Adam Bertram](https://adamtheautomator.com/author/adam-bertram/)1 July 20194 min. read

Categories: [IT Ops](/category/it-ops/)

Tags:[PowerShell](/tag/powershell/)

Table of Contents

*   [Understanding the Language.Parser Class](#h-understanding-the-language-parser-class)
*   [Finding Items with the FindAll() Method](#h-finding-items-with-the-findall-method)

The PowerShell AST essentially breaks down the code into a hierarchical tree with each element representing a part of the tree, making the scripts self aware.

**_Related: Want more PowerShell goodness? We have [dozens of tutorials on all things PowerShell](https://adamtheautomator.com/tag/powershell/)!_**

Have you ever seen the movie Inception? It’s about a guy that can enter someone’s dreams and steal stuff from their subconscious. It’s a trip that will leave you questioning the reality around you. It gave me that same feeling as The Matrix did like reality is not what you believe it to be. It’s some deep stuff. This has nothing to do with PowerShell, but it gives you a sense of what the PowerShell Abstract Syntax Tree (AST) does.

Imagine a PowerShell script that is self-aware. Imagine a PowerShell script that can read itself, or even generate other scripts based on what’s contained in itself. Think of it as meta-scripting. It’s a neat concept and has a lot of practical uses! This is what the PowerShell AST can do. The PowerShell AST essentially breaks down the code into a hierarchical tree with each element representing a part of the tree.

In this article, I’m going to go over how you can use the PowerShell AST and go over a few examples of how it works to parse PowerShell code.

## Understanding the Language.Parser Class

To get started, you’ll need to get familiar with the [System.Management.Automation.Language.Parser class](https://msdn.microsoft.com/en-us/library/system.management.automation.language.parser\(v=vs.85\).aspx). This is a class that contains a few applicable static methods that we can use to read scripts and code. This class has two methods that you’ll routinely use called `ParseInput()` and `ParseFile()`, which essentially do the same thing. `ParseInput()` reads code as a big string while `ParseFile()` assists you in converting a text file containing PowerShell code and converts it into a string for parsing. Both end up with the same result.

Let’s say I have a simple script with the following lines:

```powershell
Write-Host 'I am doing something here'
Write-Verbose 'I am doing something here too'
Write-Host 'Again, doing something.'
$var1 = 'abc'
$var2 = '123'
```

From within the script itself, I’d like to determine all the references to each cmdlet I have and each variable. To do this, I’ll first need to figure out a way to get the entire script contents as one, big string. I can do that by using the PowerShell AST object’s `$MyInvocation.MyCommand.ScriptContents` property. I’ll just add this as the last line in the script and execute it.

Once I have the script contents, I can then pass this to the `ParseInput()` method as mentioned above to build a “tree” from my script. I’ll replace that `$MyInvocation.MyCommand.ScriptContents` reference with below:

```powershell
[System.Management.Automation.Language.Parser]::ParseInput($MyInvocation.MyCommand.ScriptContents, [ref]$null, [ref]$null)
```

This gets me an output that looks like this:

```powershell
PS> C:\test.ps1
 I am doing something here
 Again, doing something.
 
 
 Attributes         : {}
 UsingStatements    : {}
 ParamBlock         :
 BeginBlock         :
 ProcessBlock       :
 EndBlock           : Write-Host 'I am doing something here'
                      Write-Verbose 'I am doing something here too'
                      Write-Host 'Again, doing something.'
                      $var1 = 'abc'
                      $var2 = '123'
                      [System.Management.Automation.Language.Parser]::ParseInput($MyInvocation.MyCommand.ScriptContents,
                       [ref]$null, [ref]$null)
 DynamicParamBlock  :
 ScriptRequirements :
 Extent             : Write-Host 'I am doing something here'
                      Write-Verbose 'I am doing something here too'
                      Write-Host 'Again, doing something.'
                      $var1 = 'abc'
                      $var2 = '123'
                      [System.Management.Automation.Language.Parser]::ParseInput($MyInvocation.MyCommand.ScriptContents,
                       [ref]$null, [ref]$null)
 
 Parent             
```

This doesn’t do much good, though. I’d like a way to look into this and find only the function and variables contained in my script. To do that, I’ll need to assign our AST to a variable. I’ll call mine `$ast`.

`PS> $ast = C:\test.ps1`

This gets me an object that has various methods and properties I can now use.

```powershell
PS> $ast | gm
 
 
    TypeName: System.Management.Automation.Language.ScriptBlockAst
 
 Name               MemberType Definition
 ----               ---------- ----------
 Copy               Method     System.Management.Automation.Language.Ast Copy()
 Equals             Method     bool Equals(System.Object obj)
 Find               Method     System.Management.Automation.Language.Ast Find(System.Func[System.Management.Automatio...
 FindAll            Method     System.Collections.Generic.IEnumerable[System.Management.Automation.Language.Ast] Find...
 -- SNIP --
```

## Finding Items with the FindAll() Method

The most useful method to use is the `FindAll()` method. This is a method that allows you to query the AST itself looking for particular types of language constructs. In our case, we’re looking for function calls and variable assignments.

To only find the language constructs we’re looking for, we must first figure out what class is represented by each type. In our examples, those classes are `CommandAst` for function calls and `VariableExpression` for variable assignments. You can view all of the different class types at the [MSDN System.Management.Automation.Language namespace page](https://msdn.microsoft.com/en-us/library/system.management.automation.language\(v=vs.85\).aspx).

Here I will find all of the function references.

```powershell
PS> $ast.FindAll({$args[0] -is [System.Management.Automation.Language.CommandAst]}, $true)
 
 CommandElements    : {Write-Host, 'I am doing something here'}
 InvocationOperator : Unknown
 DefiningKeyword    :
 Redirections       : {}
 Extent             : Write-Host 'I am doing something here'
 Parent             : Write-Host 'I am doing something here'
 
 CommandElements    : {Write-Verbose, 'I am doing something here too'}
 InvocationOperator : Unknown
 DefiningKeyword    :
 Redirections       : {}
 Extent             : Write-Verbose 'I am doing something here too'
 Parent             : Write-Verbose 'I am doing something here too'
 
 CommandElements    : {Write-Host, 'Again, doing something.'}
 InvocationOperator : Unknown
 DefiningKeyword    :
 Redirections       : {}
 Extent             : Write-Host 'Again, doing something.'
 Parent             : Write-Host 'Again, doing something.'
```

Let’s now find all of the variable assignments as well.

```powershell
PS> $ast.FindAll({$args[0] -is [System.Management.Automation.Language.VariableExpressionAst]},$true)
 
 ariablePath : var1
 Splatted.   : False
 StaticType  : System.Object
 Extent.     : $var1
 Parent.     : $var1 = 'abc'
 
 VariablePath : var2
 Splatted.    : False
 StaticType.  : System.Object
 Extent.      : $var2
 Parent.      : $var2 = '123'
 
 VariablePath : MyInvocation
 Splatted.    : False
 StaticType.  : System.Object
 Extent.      : $MyInvocation
 Parent.      : $MyInvocation.MyCommand
 
 VariablePath : null
 Splatted.    : False
 StaticType.  : System.Object
 Extent.      : $null
 Parent.      : [ref]$null
 
 VariablePath : null
 Splatted.    : False
 StaticType.  : System.Object
 Extent.      : $null
 Parent.      : [ref]$null
```

You can see that each construct now becomes an object you can work with. You now have the knowledge to break apart your script in just about any way you’d like. By using the AST, your PowerShell scripts now can become self-aware. Just don’t blame me when your scripts start trying to take your job themselves!

Share this article

[Share on X](https://twitter.com/intent/tweet?url=https%3A%2F%2Fadamtheautomator.com%2Fpowershell-ast%2F&text=PowerShell%20AST%3A%20Meta%20Scripting%20Unleashed)[Share on Facebook](https://www.facebook.com/sharer/sharer.php?u=https%3A%2F%2Fadamtheautomator.com%2Fpowershell-ast%2F)[Share on LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fadamtheautomator.com%2Fpowershell-ast%2F)

## Related Posts

![](https://adamtheautomator.com/wp-content/uploads/2026/06/26995-troubleshoot-dns-issues-powershell-codex.webp)

### [Troubleshoot DNS Issues with PowerShell](/troubleshoot-dns-issues-powershell/)

Troubleshoot DNS issues with PowerShell by testing name resolution, DNS client settings, cache entries, and network connectivity in a repeatable workflow.

![](https://adamtheautomator.com/wp-content/uploads/2025/10/image_2025-10-24_095322075.png)

### [Migrating from PowerShell 6 to 7.5: Breaking Changes/New Features](/migrating-powershell-6-to-7-5/)

Migrate from PowerShell Core 6 to 7.5: breaking changes, features, and testing tips.

![](https://adamtheautomator.com/wp-content/uploads/2025/06/featured-image-6.png)

### [How to Add Timeouts to Pester Tests with PowerShell Runspaces](/pester-test-timeout-runspaces/)

Prevent Pester tests from hanging indefinitely using PowerShell runspaces. Learn to handle variable scoping, module loading, TestDrive access, and stream capture challenges with timeout protection.

## Categories

*   [IT Ops](/category/it-ops/)
*   [Cloud](/category/cloud/)
*   [DevOps](/category/devops/)
*   [Home Ops](/category/home-ops/)
*   [Information Security](/category/infosec/)
*   [Software Development](/category/software-development/)

## Site

*   [Home](/)
*   [Tutorials](/tutorials/)
*   [Instructors](/author/)
*   [Advertising](/advertising/)
*   [Recommended Resources](/resources/)
*   [About Adam](/about-adam/)

Copyright 2026© ATA Learning | [Privacy Policy](/privacy/)
