Get-Walkthru.ps1
function Get-Walkthru { <# .Synopsis Gets information from a file as a walkthru .Description Parses walkthru steps from a walkthru file. Walkthru files contain step-by-step examples for using PowerShell. .Link Write-WalkthruHTML .Example Get-Walkthru -Text { # Walkthrus are just scripts with comments that start at column 0. # Step 1: Get-Process #Step 2: Get-Command } #> [CmdletBinding(DefaultParameterSetName="File")] [OutputType([PSObject])] param( # The command used to generate walkthrus [Parameter(Mandatory=$true, ParameterSetName="Command", ValueFromPipeline=$true)] [Management.Automation.CommandInfo] $Command, # The module containing walkthrus [Parameter(Mandatory=$true, ParameterSetName="Module", ValueFromPipeline=$true)] [Management.Automation.PSModuleInfo] $Module, # The file used to generate walkthrus [Parameter(Mandatory=$true, ParameterSetName="File", ValueFromPipelineByPropertyName=$true)] [Alias('Fullname')] [string]$File, # The text used to generate walkthrus [Parameter(Mandatory=$true, ParameterSetName="Text")] [String]$Text, # The script block used to generate a walkthru [Parameter(Mandatory=$true, ParameterSetName="ScriptBlock")] [ScriptBlock]$ScriptBlock ) begin { $err = $null #region Create walkthru type if it doesn't exist 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 Link = String.Empty;',' public string Screenshot = String.Empty;',' public string[] Hint;',' public ScriptBlock Script; public ScriptBlock Silent;',' public DateTime LastWriteTime; ' } #endregion Create walkthru type if it doesn't exist } process { if ($psCmdlet.ParameterSetName -eq "File") { # If the walkthru's in a file, open it and send it to Get-Walthru -Text $realItem = Get-Item $file -ErrorAction SilentlyContinue if (-not $realItem) { return } $text = [IO.File]::ReadAllText($realItem.FullName) $Result = Get-Walkthru -Text $text if ($result) { # If there was in fact walkthru information, add on the file name and the last write time. foreach ($r in $result) { $r.Sourcefile = $realItem.Fullname $r.LastWriteTime = $realItem.LastWriteTime $r } } return } elseif ($psCmdlet.ParameterSetName -eq "Command") { # If they want to see a command's examples a a walkthru, then pass each example to Get-Walkthru -Text $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 } elseif ($psCmdlet.ParameterSetName -eq 'Module') { # For modules, enumerate all files for the current culture, then pass them down to Get-Walkthru -File $moduleRoot = Split-Path $module.Path Get-ChildItem -Path (Join-Path $moduleRoot "$(Get-Culture)") -Filter *.walkthru.help.txt | Get-Walkthru return } if ($psCmdlet.ParameterSetName -eq 'ScriptBlock') { $text = "$ScriptBlock" } # Tokenize the script $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 $paragraphs = @() $lastResult $null = $paragraphs $lastToken = $null $lastResult = New-Object PSWalkthru.WalkthruData $isInContent = $false } } if ($isInContent) { if ($token.Type -eq 'Comment' -and $token.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 $paragraphs = @() $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") # Handle specialized return data foreach ($_ in $lines) { if ($_ -like ".Audio *" ) { $lastResult.AudioFile = ($_ -ireplace "\.Audio","").Trim() } elseif ($_ -like ".Video *" ) { $lastResult.VideoFile = ($_ -ireplace "\.Video","").Trim() } elseif ($_ -like ".Question *"){ $lastResult.Question = ($_ -ireplace "\.Question","").Trim() } elseif ($_ -like ".Answer *" ) { $lastResult.Answer = ($_ -ireplace "\.Answer","").Trim() } elseif ($_ -like ".Hint *") { $lastResult.Hint = $_.Substring(".Hint ".Length) -split ',' } elseif ($_ -like ".Link *") { $lastResult.Link = ($_ -ireplace "\.link","").Trim() } elseif ($_ -like ".Screenshot *") { $lastResult.Screenshot = ($_ -ireplace "\.Screenshot","").Trim() } elseif ($_ -like "*.Silent *") { $lastResult.Silent = [ScriptBlock]::Create(($_ -ireplace "\.Silent","").Trim()) } else { if ($_.TrimEnd().EndsWith(".")) { $lastResult.Explanation += ($_ + [Environment]::NewLine + [Environment]::NewLine + [Environment]::NewLine ) } else { $lastResult.Explanation += ($_ + [Environment]::NewLine) } } } } } if ($lastToken -and $lastResult) { $chunk = $text.Substring($lastToken.Start) $lastResult.Script = [ScriptBlock]::Create($chunk) $lastResult } elseif ($lastResult) { $lastResult } } } |