Get-Walkthru.ps1

# Some Demo Text
# Some More Demo Text
#.Audio MyAudioFile
#.Video MyVideoFile
#.Question "What Color is the Sky?"
#.Answer {$input -like "*Blue*" }
#.Hint { "Look Outside", "On a Nice Day", "Are you color blind?" }
function Get-Walkthru {
    <#
    .SynsopsiS
        Gets information from a file as a walkthru
         
    #>

    [CmdletBinding(DefaultParameterSetName="Command")]
    param(
    [Parameter(Mandatory=$true,
        ParameterSetName="Command",
        ValueFromPipeline=$true)]
    [Management.Automation.CommandInfo]
    $Command,    
    [Parameter(Mandatory=$true,
        ParameterSetName="File",
        ValueFromPipelineByPropertyName=$true)]    
    [Alias('Fullname')]
    [string]$File,
    
    [Parameter(Mandatory=$true,
        ParameterSetName="Text")]    
    [String]$Text
    )
    
    begin {
        $err = $null
        if (-not ('PSWalkthru.WalkthruData' -as [Type])) {
            Add-Type -UsingNamespace System.Management.Automation -Namespace PSWalkthru -Name WalkthruData -MemberDefinition '
public string SourceFile = String.Empty;'
,'
public string Command = String.Empty;'
,'
public string Explanation = String.Empty;'
,'
public string AudioFile = String.Empty;'
,'
public string VideoFile = String.Empty;'
,'
public string Question = String.Empty;'
,'
public string Answer = String.Empty;'
,'
public string[] Hint;'
,'
public ScriptBlock Script;'

        }
    }
    process {
        if ($psCmdlet.ParameterSetName -eq "File") {
            $realItem = Get-Item $file -ErrorAction SilentlyContinue
            if (-not $realItem) { return } 
            $text = [IO.File]::ReadAllText($realItem.FullName)                        
            $Result = Get-Walkthru -Text $text
            $result | 
                ForEach-Object {
                    $_.SourceFile = $realItem.Fullname
                    $_
                }
            return
        } elseif ($psCmdlet.ParameterSetName -eq "Command") {
            $help = $command | Get-Help 
            
            $c= 1
            $help.Examples.Example | 
                ForEach-Object {
                    $text = $_.code + ($_.remarks | Out-String)                
                    Get-Walkthru -Text $text |
                        ForEach-Object {
                            $_.Command = "$command Walkthru $c"
                            $_
                        }
                    $c++
                }
            return
        }
                                       
        $tokens = [Management.Automation.PSParser]::Tokenize($text, [ref]$err)                
        if ($err.Count) { return } 

        $lastToken = $null
        $isInContent = $false
        $lastResult = New-Object PSWalkthru.WalkthruData

        foreach ($token in $tokens) { 
            if ($token.Type -eq "Newline") { continue }
            if ($token.Type -ne "Comment" -or $token.StartColumn -gt 1) {
                $isInContent = $true
                if (-not $lastToken) { $lastToken = $token } 
            } else {
                if ($lastToken.Type -ne "Comment" -and $lastToken.StartColumn -eq 1) {
                    $chunk = $text.Substring($lastToken.Start, 
                        $token.Start - 1 - $lastToken.Start)
                    $lastResult.Script = [ScriptBlock]::Create($chunk)
                    # mutliparagraph, split up the results if multiparagraph
                    foreach ($p in $paragraphs) {
                        New-Object PSWalkthru.WalkthruData -Property @{Explanation = $p}
                    }
                    if ($lastIndex -ne -1) {
                        $lastResult.Explanation = $lastResult.Explanation.Substring($lastIndex + 1)
                    }
                    $lastResult                    

                    $null = $paragraphs
                    $lastToken = $null
                    $lastResult = New-Object PSWalkthru.WalkthruData
                    $isInContent = $false                
                }
            }
            if (-not $isInContent) {
                $lines = $token.Content.Trim("<>#")
                $lines = $lines.Split([Environment]::NewLine, 
                    [StringSplitOptions]"RemoveEmptyEntries")
                foreach ($l in $lines) {
                    switch ($l) {
                        {$_ -like ".Audio *" } {
                            $lastResult.AudioFile =
                                $l.Substring(".Audio ".Length)
                        }
                        {$_ -like ".Video *" } {
                            $lastResult.VideoFile =
                                $l.Substring(".Video ".Length)
                        }                        
                        {$_ -like ".Question *" } {
                            $lastResult.Question =
                                $l.Substring(".Question ".Length)
                        }                        
                        {$_ -like ".Answer *" } {
                            $lastResult.Answer =
                                $l.Substring(".Answer ".Length)
                        }
                        {$_ -like ".Hint *" } {
                            $lastResult.Hint =
                                $l.Substring(".Hint ".Length) -split ','
                        }                        
                        default {
                            $lastResult.Explanation += ($l + [Environment]::NewLine)                        
                        }
                    }
                }
            }            
        }
        
        if ($lastToken -and $lastResult) {
            $chunk = $text.Substring($lastToken.Start)
            $lastResult.Script = [ScriptBlock]::Create($chunk)
            $lastResult
        }
    }
}