This week, I’ll continue where I left off in my previous blog article “PowerShell Script Module Design Philosophy“.
Moving forward, the development versions of my PowerShell script modules will use a non-monolithic design where each function is dot-sourced from the PSM1 file. When I move them to production, I’ll convert them to using a monolithic design where all functions reside in the PSM1 file. In development, each PS1 file uses a Requires statement which specifies the requirements from a PowerShell version and required modules standpoint. This is so the requirements are known if someone grabs individual functions instead the entire module from the development version on GitHub. This information needs to be consolidated and placed in the module manifest (PSD1 file) when transitioning to production. The Requires statement should be excluded when retrieving the content of the function itself before placing it in the PSM1 file.
Since I didn’t want to resort to writing regular expressions and parsing text, I decided to use the Abstract Syntax Tree (AST) to extract the content from the functions that I needed. Beginning with PowerShell version 3.0, script blocks have an AST property.
First, I’ll store the content of one of my functions in a variable.
$GetVmHost = Get-Content -Path U:\GitHub\Hyper-V\MrHyperV\public\Get-MrVmHost.ps1 -Raw
Converting it to a script block and piping it to Get-Member shows that it does indeed have an AST property.
Get-Member is used to perform recon (exploration) on commands in PowerShell. Any command that produces object based output can be piped to Get-Member.
I just kept piping to Get-Member to see what kind of information could be retrieved.
The ScriptRequirements property returns the information needed about which PowerShell version is required. It also returns the required modules if any were required, which none are for this particular function.
I kept working with the properties and drilling down into each of them until I determined that the Ast.EndBlock.Extent.Text property returns the content of the function without the Requires statement.
That was easy enough, but who really wants to cast everything as a script block just to view the AST for it? If you do, I’ve created a function named ConvertTo-MrScriptBlock that’s part of my ModuleBuildTools repository on GitHub. Otherwise, I’ll be showing you an easier way to accomplish the same task in a future blog article.