Get-LanguageKeywords: Using ConvertFrom-String on About Topics
- Details
- Written by June Blender
- Last Updated: 09 October 2019
- Created: 01 December 2014
- Hits: 13329
There have been some great blog posts about the new ConvertFrom-String cmdlet in the Windows PowerShell 5.0 preview. My favorite learning tool is an excellent talk by Windows PowerShell MVP Tobias Weltner about the full range of text parsing options available in Windows PowerShell 3.0 – 5.0. While learning, I had some fun converting my electric bill and phone bill to PowerShell objects so that I could track them, but I really wasn’t using it for work.
Until today.
I wanted to find out whether the new enum keyword in the Windows PowerShell 5.0 preview had been added to the about_language_keywords help topic. I ran Update-Help and then used the Select-String cmdlet to search for enum keyword. I used the Quiet parameter of Select-String, because I wanted a $True/$False response.
Get-Help about_language_keywords | Out-String -Stream | Select-String "enum" –Quiet
You can use the same Select-String command on the help topic file.
dir $pshome\en-us\about_language_keywords.help.txt | Select-String “enum” -Quiet
Both of the commands returned $False, but that’s to be expected, since Windows PowerShell 5.0 is still in preview.
But, I’d really like to be able to manage those keywords in the same way that I manage type accelerators.
[PSObject].Assembly.GetType(“System.Management.Automation.TypeAccelerators”)::get
Or, check for approved verbs:
Get-Verb
In short, I wanted to create a keyword object that I could use in Windows PowerShell. There’s a table in the about_language_keywords help file, but I couldn’t find the contents of that table anywhere else. The About topics are just text files and the table is just a series of text strings, so I looked in my handy toolkit and pulled out ConvertFrom-String.
Isolate the Keyword Table
The brand-new ConvertFrom-String cmdlet takes text strings and returns custom objects (PSCustomObject) in which the text strings are values of object properties.
I tried to create a custom object for each row of the Keyword-Reference table. But when I ran ConvertFrom-String on the entire help topic, I got a very pleasant error message saying that it was too complex and offering to help me with it. In the meantime, I set about isolating the Keyword-Reference table in the help topic.
I saved the entire about_language_keywords help topic content in the $help variable.
$help = Get-Content $pshome\en-us\about_language_keywords.help.txt
My first task was to find the line number of the first table entry (Begin…) in the Keyword-Reference table. I could have counted the number of lines from the top of the file or searched for “Begin”, but wanted to make the technique durable – not dependent on the current version of the file. I decided to search for the Keyword-Reference header.
I used the Select-String cmdlet and a regular expression to find the Keyword-Reference table header. To get its line number, I used the LineNumber property of the MatchInfo object that Select-String returns. The first table entry is two lines after the header, so I added 2 and saved the line number of the first table entry in the $start variable.
$start = (($help | Select-String -Pattern 'Keyword\s{7,}Reference').LineNumber) + 2
Next, I needed the line number of the last table entry, so I looked for the first blank line after the table. (The ^\s*$ is the regular expression for a blank line.) The last table entry is just before the blank line, so I subtracted 1 from the line number, then added the result to the $start value to get the line number of the last table entry from the beginning of the file.
$end = $start + (($help[($start - 1) .. 999] | Select-string -Pattern '^\s*$').LineNumber | Select-Object -First 1) - 1
With the $start and $end values, I’ve captured the table in the $table variable. (Remember to subtract 1 to convert each line number to an array index.)
$table = $help[($start – 1)..($end – 1)]
Now, the fun begins.
Create a template
The ConvertFrom-String cmdlet takes text strings and returns custom objects (PSCustomObject) in which the text strings are values of object properties. I wanted each custom object to have Keyword and Reference properties. The values of those properties are the keyword and reference strings in the table.
(Remember that Keyword and Reference are just names that I chose. You can use any names for the properties.)
Keyword Reference ----------- ------------------------------------------- Begin about_Functions, about_Functions_Advanced Break about_Break, about_Trap Catch about_Try_Catch_Finally Continue about_Continue, about_Trap Data about_Data_Sections Do about_Do, about_While |
The $help variables contains text strings, so I needed to tell ConvertFrom-String which parts of each text string go with the Name property, which parts go with the Reference property, and which parts to ignore. To do that, you use a template, which is a model for the custom objects that you create. The template consists of series of labeled examples that say, in essence, I want it my objects to look like this.
Let’s begin with the first row of the table.
- To map the Begin string to the Keyword property, surround the string with curly braces and prepend the property name (Keyword) and a colon (:).
{Keyword:Begin} about_Functions, about_Functions_Advanced |
- To indicate that Keyword is the first property of each new object, append an asterisk (*) to the property name.
{Keyword*:Begin} about_Functions, about_Functions_Advanced |
- Use the same process to map the Reference property to the reference string. (You don’t need the asterisk here.)
{Keyword*:Begin} {Reference:about_Functions, about_Functions_Advanced} |
- Don’t label the spaces between the keyword and reference strings, because we want ConvertFrom-String to ignore them. ConvertFrom-String excludes unlabeled characters from the custom object.
{Keyword*:Begin} {Reference:about_Functions, about_Functions_Advanced} Break about_Break, about_Trap Catch about_Try_Catch_Finally Continue about_Continue, about_Trap Data about_Data_Sections Do about_Do, about_While |
Because the template is a series of examples, you don’t need to label every line of the table. Label only the lines that are parsed differently from the labeled line. ConvertFrom-String generates parsing rules, so use your labeling to help it generate accurate rules. (To see the rules that it generates, use the Verbose parameter.)
[Tip: You must label at least two lines, even when all lines are identical. Otherwise the parsing fails.]
For example, the reference text in the Begin row includes two phrases separated by a comma. The reference text in the Catch row has just one about phrase, so I labeled it.
{Keyword*:Begin} {Reference:about_Functions, about_Functions_Advanced} Break about_Break, about_Trap {Keyword*:Catch} {Reference:about_Try_Catch_Finally} Continue about_Continue, about_Trap Data about_Data_Sections Do about_Do, about_While |
I also labeled Exit, because its reference didn’t begin with “about” and it ends with a period. And, I labeled Workflow, because it was the last row. (Because its rules for ending a line rely on the characters that begin the next line , ConvertFrom-String tends to miss the last line.)
Then, I deleted all of the unlabeled items from the template, placed the template in a here-string, and saved it in a $template variable. You can also save a template in a text file, but using a variable in the script guarantees that the template is available to anyone who uses the script.
$template = @" {Keyword*:Begin} {Reference:about_Functions, about_Functions_Advanced} {Keyword*:Catch} {Reference:about_Try_Catch_Finally} {Keyword*:Exit} {Reference:Described in this topic.} {Keyword*:Workflow} {Reference:about_Workflows} "@ |
Run ConvertFrom-String
The syntax of a ConvertFrom-String command is pretty simple. Pipe the content to be parsed to the cmdlet. Use the TemplateContent or TemplateFile parameters to identify the template.
PS C:\>$table | ConvertFrom-String -TemplateContent $template PS C:\>$table ExtentText Keyword Reference ---------- ------- --------- Begin about_Functions, about_Functions_Advan.. . Begin about_Functions, about_Functions_Advanced Break about_Break, about_Trap.. . Break about_Break, about_Trap Catch about_Try_Catch_Finally.. . Catch about_Try_Catch_Finally Continue about_Continue, about_Trap.. . Continue about_Continue, about_Trap ...
In addition to the Keyword and Reference properties, the output object includes an ExtentText property that contains all of the labeled text strings. ExtentText is very useful for debugging ConvertFrom-String output, but I don’t want it in my custom object. To exclude it, I use Select-Object to create a custom object with only the Keyword and Reference properties.
PS C:\>$table | ConvertFrom-String -TemplateContent $template | Select-Object -Property Keyword, Reference Keyword Reference ------- --------- Begin about_Functions, about_Functions_Advanced Break about_Break, about_Trap Catch about_Try_Catch_Finally Continue about_Continue, about_Trap ...
Done!
Examine the Custom Objects
Let’s examine at the custom objects that ConvertFrom-String returned. They have the Keyword and Reference properties that I defined.
PS C:\> $k = $table | ConvertFrom-String -TemplateContent $template | Select-Object -Property Keyword, Reference PS C:\> $k | Get-Member TypeName: Selected.System.Management.Automation.PSCustomObject Name MemberType Definition ---- ---------- ---------- Equals Method bool Equals(System.Object obj) GetHashCode Method int GetHashCode() GetType Method type GetType() ToString Method string ToString() Keyword NoteProperty System.String Keyword=Begin Reference NoteProperty System.String Reference=about_Functions, about_Functions_Advanced
And, I can use them to explore the keywords in Windows PowerShell.
PS C:\> $k.Keyword.Contains("Catch") True PS C:\> $k | where Keyword -eq "Catch" Keyword Reference ------- --------- Catch about_Try_Catch_Finally PS C:> Get-Help ($k | where Keyword -eq "Catch").Reference about_Try_Catch_Finally PS C:\> Get-Help (($k | where Keyword -eq "Catch").Reference) TOPIC about_Try_Catch_Finally SHORT DESCRIPTION Describes how to use the Try, Catch, and Finally blocks to handle terminating errors. LONG DESCRIPTION Use Try, Catch, and Finally blocks to respond to or handle terminating errors in scripts. The Trap statement can also be used to handle ...
Summary
Here’s a review of the process that I used. I wanted to grab the table from the middle of the about_language_keywords help topic and convert each line of the table into an object.
- I started with the content of the about_language_keywords topic.
$help = Get-Content $pshome\en-us\about_language_keywords.help.txt
- To isolate the table in the topic, I used the Select-String cmdlet and the LineNumber property of the MatchInfo (Microsoft.PowerShell.Commands.MatchInfo) object that Select-String returns. When indexing into the help, I just subtracted 1 from the line numbers.
$start = (($help | Select-String -Pattern 'Keyword\s{7,}Reference').LineNumber) + 2 $end = $start + (($help[($start - 1) .. 999] | Select-string -Pattern '^\s*$').LineNumber | Select-Object -First 1) – 1 $table = $help[($start - 1)..($end - 1)]
- I created a template of labeled strings with Keyword and Reference properties. The labels indicate which text strings go with each property. ConvertFrom-String uses the examples in the template to generate rules for parsing the text strings.
$template = @" {Keyword*:Begin} {Reference:about_Functions, about_Functions_Advanced} {Keyword*:Catch} {Reference:about_Try_Catch_Finally} {Keyword*:Exit} {Reference:Described in this topic.} {Keyword*:Workflow} {Reference:about_Workflows} "@
- I ran the ConvertFrom-String cmdlet with the template.
$table | ConvertFrom-String -TemplateContent $template | Select-Object -Property Keyword, Reference
Finally, I dropped the commands into a script as saved it. Now, I can use it repeatedly. And when the enum keywords shows up in help, I’ll have it, too.
June Blender is a technology evangelist at SAPIEN Technologies, Inc. You can reach her at This email address is being protected from spambots. You need JavaScript enabled to view it. or follow her on Twitter at @juneb_get_help.
Get-LanguageKeywords.ps1
You can copy the script code here or download a ZIP file from the SAPIEN Downloads site.
To download, sign in, in the left nav, click Sample Scripts, click Get-LanguageKeywords.ps1.zip, and in the top right corner, click Download.
<# .NOTES =========================================================================== Created with: SAPIEN Technologies, Inc., PowerShell Studio 2014 v4.1.74 Created on: 11/25/2014 4:10 PM Organization: SAPIEN Technologies, Inc. Contact: June Blender, This email address is being protected from spambots. You need JavaScript enabled to view it., @juneb_get_help Filename: Get-LanguageKeywords.ps1 =========================================================================== .SYNOPSIS Creates custom objects from the Keyword-Reference table in the about_Language_Keywords help topic. .DESCRIPTION The Get-Language keywords script gets the Keyword-Reference table from the about_Language_Keywords help topic. It uses the ConvertFrom-String cmdlet to convert each row of the table to a custom object, and returns the custom objects. It takes no parameters, but it requires the about_Language_Keyword help topic and Windows PowerShell version 5.0. .INPUTS None .OUTPUTS System.Management.Automation.PSCustomObject .EXAMPLE $keywords = .\Get-LanguageKeyword.ps1 $keywords.Keyword.Contains("While") True $keywords.Keyword.Contains("Grapefruit") False $keywords | where Name -eq "Finally"| Format-Table -Autosize Keyword Reference ---- --------- Finally about_Try_Catch_Finally Get-Help ($keywords | where Name -eq "Finally").Reference #> #Requires -Version 5 $template = @" {Keyword*:Begin} {Reference:about_Functions, about_Functions_Advanced} {Keyword*:Catch} {Reference:about_Try_Catch_Finally} {Keyword*:Exit} {Reference:Described in this topic.} {Keyword*:Workflow} {Reference:about_Workflows} "@ if (!($help = dir $pshome\en-us\about_language_keywords.help.txt)) { throw "Can't find the about_language_keywords help topic. Run Update-Help and try again." } #Get the line number of the Keyword-Reference table header #Add 2 to get the line number of the first entry in the table $start = (($help | Select-String -Pattern 'Keyword\s{7,}Reference').LineNumber) + 2 #Get the line number of the first blank line after the table #Subtract one to get the line number of the last table entry $end = $start + (($help[($start - 1) .. 999] | Select-string -Pattern '^\s*$').LineNumber | Select-Object -First 1) - 1 #Get only the Keyword-Reference table #Subtract 1 from each line number to get the indexes $table = $help[($start - 1) .. ($end - 1)] #Create a custom object from the Keyword-Reference table $table | ConvertFrom-String -TemplateContent $template | Select-Object -Property Keyword, Reference
For licensed customers, use the forum associated with your product in our Product Support Forums for Registered Customers.
For users of trial versions, please post in our Former and Future Customers - Questions forum.