PipeScript.types.ps1xml

<!-- Generated with EZOut 2.0.4: Install-Module EZOut or https://github.com/StartAutomating/EZOut -->
<Types>
  <Type>
    <Name>System.Management.Automation.AliasInfo</Name>
    <Members>
      <AliasProperty>
        <Name>Namespace</Name>
        <ReferencedMemberName>CommandNamespace</ReferencedMemberName>
      </AliasProperty>
    </Members>
  </Type>
  <Type>
    <Name>System.Management.Automation.ApplicationInfo</Name>
    <Members>
      <AliasProperty>
        <Name>Namespace</Name>
        <ReferencedMemberName>CommandNamespace</ReferencedMemberName>
      </AliasProperty>
      <ScriptProperty>
        <Name>Root</Name>
        <GetScriptBlock>
                        if ($this.'.Root') {
    return $this.'.Root'
}

$nextRoot = $this.Source | Split-Path
:findingRoot do {
    
    $lastRoot = $nextRoot
    $lastRootName = $lastRoot | Split-Path -Leaf

    if ($lastRootName -as [Version]) {
        $lastRootName = $lastRoot | Split-Path | Split-Path -Leaf
    }

    foreach ($fileNameThatIndicatesRoot in 'LICENSE', 'LICENSE.txt',
        "$LastRootName.psd1", "$LastRootName.psm1", ".git") {
        $lookingForPath = Join-Path $lastRoot $fileNameThatIndicatesRoot
        if (Test-Path $lookingForPath) {
            break findingRoot
        }
    }

    $nextRoot = $nextRoot | Split-Path
} while ($nextRoot)

$this | Add-Member NoteProperty '.Root' "$lastRoot" -Force
$this.'.Root'
                    </GetScriptBlock>
        <SetScriptBlock>
                        $this | Add-Member NoteProperty ".Root" $args -Force

                    </SetScriptBlock>
      </ScriptProperty>
    </Members>
  </Type>
  <Type>
    <Name>System.Management.Automation.Language.Ast</Name>
    <Members>
      <ScriptMethod>
        <Name>ConvertFromAST</Name>
        <Script>
                        param()

return $this

                    </Script>
      </ScriptMethod>
      <ScriptMethod>
        <Name>FirstElements</Name>
        <Script>
                        &lt;#
.SYNOPSIS
    Gets the First N elements in an AST
.DESCRIPTION
    Gets the First N elements within an AST, excluding this element.
#&gt;
param(
# The number of elements to get. By default, one.
[int]
$NumberOfElements = 1
)


$foundElementCount = 0
foreach ($foundElement in $this.FindAll({$true}, $true)) {
    if (-not $foundElementCount) {
        $foundElementCount++
        continue
    }
    # We want to skip named blocks in this case, as we're really after the first "real" element.
    if ($foundElement -is [Management.Automation.Language.NamedBlockAst]) {
        continue
    }
    if ($foundElementCount -le $NumberOfElements) {
        $foundElementCount++
        $foundElement
    } else {
        break
    }
}

                    </Script>
      </ScriptMethod>
      <ScriptMethod>
        <Name>GetLineage</Name>
        <Script>
                        &lt;#
.SYNOPSIS
    Gets AST Lineage
.DESCRIPTION
    Gets the Lineage of an Abstract Syntax Tree element.
    
    The Lineage is all of the Abstract Syntax Tree's parents.
#&gt;
$thisParent = $this.Parent
while ($thisParent) {
    $thisParent
    $thisParent = $thisParent.Parent
}

                    </Script>
      </ScriptMethod>
      <ScriptMethod>
        <Name>IsEquivalentTo</Name>
        <Script>
                        &lt;#
.SYNOPSIS
    Attempts to Determine Ast Equivalence
.DESCRIPTION
    Attempts to Determine if `$this` Ast element is the same as some `$Other` object.

    If `$Other is a `[string]`, it will be converted into a `[ScriptBlock]`
    If `$Other is a `[ScriptBlock]`, it will become the `[ScriptBlock]`s AST

    If the types differ, `$other is not equivalent to `$this.

    If the content is the same with all whitespace removed, it will be considered equivalent.
.NOTES
    Due to the detection mechanism, IsEquivalentTo will consider strings with whitespace changes equivalent.
#&gt;
param(
# The other item.
$Other
)

if (-not $other) { return $false }

if ($other -is [string]) {
    $other = [ScriptBlock]::Create($other).Ast
}

if ($other -is [scriptblock]) {
    $other = $Other.Ast
}

if ($other -isnot [Management.Automation.Language.Ast]) {
    return $false
}

if ($other.GetType() -ne $this.GetType()) { return $false }

# We're going to start off very easy, and slightly incorrect:
($this -replace '[\s\r\n]') -eq ($other -replace '[\s\r\n]')

# (There are many cases where, say, variable renames would be innocuous, but that's a rabbit hole of variable detection. The same is true of commands.)

# However, in 98% of cases, two scriptblocks without whitespace that are the same are equivalent. The exception to the rule: whitespace within strings.
                    </Script>
      </ScriptMethod>
      <ScriptMethod>
        <Name>Transpile</Name>
        <Script>
                        [ScriptBlock]::Create(
    "$this"
) | .&gt;PipeScript

                    </Script>
      </ScriptMethod>
      <ScriptProperty>
        <Name>ByType</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Gets PowerShell AST Nodes by type
.DESCRIPTION
    Gets a dictionary of all nodes in a PowerShell AST beneath this point, grouped by type.
.EXAMPLE
    {"hello world"}.Ast.ByType
#&gt;
if (-not $this.'.ByType') {
    $ByType = [Collections.Generic.Dictionary[Type,Collections.Generic.List[PSObject]]]::new()
    foreach ($node in $this.FindAll({$true}, $true)) {
        $nodeType = $node.GetType()

        if (-not $ByType[$nodeType]) {
            $ByType[$nodeType] = [Collections.Generic.List[PSObject]]::new()
        }
        $ByType[$nodeType].Add($node)
    }
    Add-Member -InputObject $this -MemberType NoteProperty -Name '.ByType' -Value $ByType -Force
}

$this.'.ByType'

                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>Commands</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Gets all Commands within an AST
.DESCRIPTION
    Gets all Command references within a PowerShell Abstract Syntax Tree
.EXAMPLE
    {Get-Process}.Ast.Commands
#&gt;

,@(foreach ($node in $this.ByType[[Management.Automation.Language.CommandAST]]) {
    $node
})

                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>Defines</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Gets all Definitions within an AST
.DESCRIPTION
    Gets all Function and Type Definitions and Parameters within a PowerShell Abstract Syntax Tree
.EXAMPLE
    {function foo() { "foo"} class bar { $bar = "none"} }.Ast.Defines
#&gt;

, @(
    foreach ($node in $this.ByType[@(
        [Management.Automation.Language.FunctionDefinitionAst]
        [Management.Automation.Language.TypeDefinitionAst]
        [Management.Automation.Language.ParameterAst]
    )]) {
        $node
    }
)

                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>First</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Gets the first nested AST
.DESCRIPTION
    Gets the first nested element of this AST
.EXAMPLE
    {
        do { } while ($false)
    }.First
#&gt;
param()
$this.FirstElements(1)

                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>IsEmpty</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Determines if a PowerShell AST is empty
.DESCRIPTION
    Determines if a PowerShell Abstract Syntax Tree is empty.

    It will be considered empty if is a ScriptBlockExpression with no parameters or statements in any blocks.
#&gt;
param()
$ast = $this
if ($ast.Body) {
    $ast = $ast.Body
}

if ($ast -isnot [Management.Automation.Language.ScriptBlockExpressionAST]) {
    return $false
}

foreach ($property in $ast.psobject.Properties) {
    if ($property.Name -notmatch 'Block$') { continue }
    if ($property.Value.Statements.Count) { return $false }
    if ($property.Value.Parameters.Count) { return $false }
}

return $true

                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>Tokens</Name>
        <GetScriptBlock>
                        $text = $this.Extent.ToString()
    
$previousToken = $null
$tokenCount = 0
@(foreach ($token in [Management.Automation.PSParser]::Tokenize($text, [ref]$null)) {
    Add-Member NoteProperty Text $text -Force -InputObject $token
    Add-Member NoteProperty PreviousToken $previousToken -Force -InputObject $token
    if ($token.Type -in 'Variable', 'String') {
        $realContent = $text.Substring($token.Start, $token.Length)
        Add-Member NoteProperty Content $realContent -Force -InputObject $token
    }
    $previousToken = $token
    $tokenCount++
    $token
})
                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>Transpilers</Name>
        <GetScriptBlock>
                        $scriptText = $this.Extent.ToString()

# If the ScriptBlock had attributes, we'll add them to a special list of things that will be transpiled first.
    
# Find all AST elements within the script block.
$astList = @($this.FindAll({$true}, $false))

# At various points within transpilation, we will be skipping processing until a known end pointer. For now, set this to null.
$skipUntil = 0
# Keep track of the offset from a starting position as well, for the same reason.
$myOffset = 0

# Walk over each item in the abstract syntax tree.
:NextAstItem foreach ($item in $astList) {
    # If skipUntil was set,
    if ($skipUntil) {
        # find the space between now and the last known offset.
        try {
            $newOffset = $scriptText.IndexOf($item.Extent.Text, $myOffset)
            if ($newOffset -eq -1) { continue }
            $myOffset = $newOffset
        } catch {
            $ex =$_
            $null = $null
        }
        if ($myOffset -lt $skipUntil) { # If this is before our skipUntil point
            continue # ignore this AST element.
        }
        $skipUntil = $null # If we have reached our skipUntil point, let's stop skipping.
    }
    # otherwise, find if any pipescripts match this AST

    $foundTranspilers = Get-Transpiler -CouldPipe $item -ValidateInput $item

    if ($foundTranspilers) {
        foreach ($transpiler in $foundTranspilers) {
            [PSCustomObject][Ordered]@{
                PSTypeName = 'PipeScript.Transpiler.Location'
                Transpiler =
                    if ($Transpiler.ExtensionInputObject.ResolvedCommand) {
                        @($Transpiler.ExtensionInputObject.ResolvedCommand) -ne $null
                    } else {
                        $Transpiler.ExtensionCommand
                    }
                AST = $item
            }
        }
        
        $start = $scriptText.IndexOf($item.Extent.Text, $myOffset) # determine the end of this AST element
        $end = $start + $item.Extent.Text.Length
        $skipUntil = $end # set SkipUntil
    }
}
                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>Types</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Gets all Types within an AST
.DESCRIPTION
    Gets all Types referenced within a PowerShell Abstract Syntax Tree
.EXAMPLE
    {[int];[psobject];[xml]}.Ast.Types
#&gt;

,@(foreach ($node in $this.ByType[[Management.Automation.Language.TypeExpressionAst]]) {
    $node
})

                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>Unique</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Gets unique AST elements
.DESCRIPTION
    Gets unique AST elements. Uniqueness is defined by being literally the same text.
#&gt;
$uniqueElements = [Ordered]@{}
foreach ($foundElement in @($this.FindAll({$true},$true))) {
    if ($uniqueElements["$foundElement"]) {
        continue
    }
    $uniqueElements["$foundElement"] = $foundElement
}

@($uniqueElements.Values)

                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>Variables</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Gets all Variables within an AST
.DESCRIPTION
    Gets all Variable references within a PowerShell Abstract Syntax Tree
.EXAMPLE
    {$x, $y, $z}.Ast.Variables
#&gt;

, @(foreach ($node in $this.ByType[[Management.Automation.Language.VariableExpressionAst]]) {
    $node
})

                    </GetScriptBlock>
      </ScriptProperty>
    </Members>
  </Type>
  <Type>
    <Name>System.Management.Automation.Language.AttributeAst</Name>
    <Members>
      <AliasProperty>
        <Name>Args</Name>
        <ReferencedMemberName>ArgumentList</ReferencedMemberName>
      </AliasProperty>
      <AliasProperty>
        <Name>Arguments</Name>
        <ReferencedMemberName>ArgumentList</ReferencedMemberName>
      </AliasProperty>
      <AliasProperty>
        <Name>Parameters</Name>
        <ReferencedMemberName>Parameter</ReferencedMemberName>
      </AliasProperty>
      <ScriptProperty>
        <Name>ArgumentList</Name>
        <GetScriptBlock>
                        $Parameter = [Ordered]@{}
$ArgumentList = @()
# Collect all of the arguments of the attribute, in the order they were specified.
$argsInOrder = @(
    @($this.PositionalArguments) + @($this.NamedArguments) |
    Sort-Object { $_.Extent.StartOffset}
)


# Now we need to map each of those arguments into either named or positional arguments.
foreach ($attributeArg in $argsInOrder) {
    # Named arguments are fairly straightforward:
    if ($attributeArg -is [Management.Automation.Language.NamedAttributeArgumentAst]) {
        $argName = $attributeArg.ArgumentName
        $argAst = $attributeArg.Argument
        $parameter[$argName] =
            if ($argName -eq $argAst) { # If the argument is the name,
                $true # treat it as a [switch] parameter.
            }
            # If the argument value was an ScriptBlockExpression
            else {
                $argAst
            }
    } else {
        # If we are a positional parameter, for the moment:
        if ($parameter.Count) {
            # add it to the last named parameter.
            $parameter[@($parameter.Keys)[-1]] =
                @() + $parameter[@($parameter.Keys)[-1]] + $argAst
        } else {
            # Or add it to the list of string arguments.
            $ArgumentList +=
                $attributeArg.ConvertFromAst()
        }
    }
}

return $ArgumentList

                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>Parameter</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Gets the parameters of an attribute
.DESCRIPTION
    Gets the named parameters of an attribute.
.EXAMPLE
    {
        [AnAttribute(Parameter='Value')]$null
    }.Ast.EndBlock.Statements[0].PipelineElements[0].Expression.Attribute.Parameters
#&gt;
$Parameter = [Ordered]@{}
# Collect all of the arguments of the attribute, in the order they were specified.
$argsInOrder = @(
    @($this.PositionalArguments) + @($this.NamedArguments) |
    Sort-Object { $_.Extent.StartOffset}
)

# Now we need to map each of those arguments into either named or positional arguments.
foreach ($attributeArg in $argsInOrder) {
    # Named arguments are fairly straightforward:
    if ($attributeArg -is [Management.Automation.Language.NamedAttributeArgumentAst]) {
        $argName = $attributeArg.ArgumentName
        $argAst = $attributeArg.Argument
        $parameter[$argName] =
            if ($argName -eq $argAst) { # If the argument is the name,
                $true # treat it as a [switch] parameter.
            }
            # If the argument value was an ScriptBlockExpression
            else {
                $argAst.ConvertFromAst()
            }
    } else {
        # If we are a positional parameter, for the moment:
        if ($parameter.Count) {
            # add it to the last named parameter.
            $parameter[@($parameter.Keys)[-1]] =
                @() + $parameter[@($parameter.Keys)[-1]] + $attributeArg.ConvertFromAst()
        }
    }
}

return $Parameter
                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>ResolvedCommand</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Resolves an Attribute to a CommandInfo
.DESCRIPTION
    Resolves an Attribute to one or more CommandInfo.
.EXAMPLE
    {
        [InvokePipeScript()]$null
    }.Ast.EndBlock.Statements[0].PipelineElements[0].Expression.Attribute.ResolvedCommand
.EXAMPLE
    {
        [Microsoft.PowerShell.Core.GetCommand()]$null
    }.Ast.EndBlock.Statements[0].PipelineElements[0].Expression.Attribute.ResolvedCommand
.EXAMPLE
    {
        [Get_Command()]$null
    }.Ast.EndBlock.Statements[0].PipelineElements[0].Expression.Attribute.ResolvedCommand
.EXAMPLE
    {
        [GetCommand()]$null
    }.Ast.EndBlock.Statements[0].PipelineElements[0].Expression.Attribute.ResolvedCommand
.EXAMPLE
    {
        [cmd()]$null
    }.EndBlock.Statements[0].PipelineElements[0].Expression.Attribute.ResolvedCommand
#&gt;
# Get the name of the transpiler.
$transpilerStepName =
    if ($this.TypeName.IsGeneric) {
        $this.TypeName.TypeName.Name
    } else {
        $this.TypeName.Name
    }
$decamelCase = [Regex]::new('(?&lt;=[a-z])(?=[A-Z])')
@(
    # If a Transpiler exists by that name, it will be returned first.
    Get-Transpiler -TranspilerName $transpilerStepName
    # Then, any periods in the attribute name will be converted to slashes,
    $fullCommandName = $transpilerStepName -replace '\.','\' -replace
        '_','-' # and any underscores to dashes.

    # Then, the first CamelCased code will have a - injected in between the CamelCase.
    $fullCommandName = $decamelCase.Replace($fullCommandName, '-', 1)
    # Now we will try to find the command.
    $ExecutionContext.SessionState.InvokeCommand.GetCommand($fullCommandName, 'All')
)
                    </GetScriptBlock>
      </ScriptProperty>
    </Members>
  </Type>
  <Type>
    <Name>AutomaticVariable.Command</Name>
    <Members>
      <ScriptProperty>
        <Name>VariableName</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Gets the automatic variable name
.DESCRIPTION
    Gets the name of an automatic variable that is defined in an Automatic?Variable* command.
#&gt;
$this -replace '(?&gt;Magic|Automatic)\p{P}Variable\p{P}' -replace
    '^(?&gt;PowerShell|PipeScript)' -replace
    '^\p{P}' -replace '\p{P}$'

                    </GetScriptBlock>
      </ScriptProperty>
    </Members>
  </Type>
  <Type>
    <Name>BuildScript.Command</Name>
    <Members>
      <ScriptProperty>
        <Name>Template</Name>
        <GetScriptBlock>
                        $potentialTemplatePaths =
    @(
        $this.Source -replace '\.ps1$', '.ps.ps1'
        $this.Source -replace '\.ps1$', '.ps1.ps1'
    )

foreach ($potentialTemplatePath in $potentialTemplatePaths ) {
    if (Test-Path $potentialTemplatePath) {
        return (Get-PipeScript -PipeScriptPath $potentialTemplatePath)
    }
}


                    </GetScriptBlock>
      </ScriptProperty>
    </Members>
  </Type>
  <Type>
    <Name>System.Management.Automation.Language.CommandAst</Name>
    <Members>
      <AliasProperty>
        <Name>Args</Name>
        <ReferencedMemberName>ArgumentList</ReferencedMemberName>
      </AliasProperty>
      <AliasProperty>
        <Name>Arguments</Name>
        <ReferencedMemberName>ArgumentList</ReferencedMemberName>
      </AliasProperty>
      <AliasProperty>
        <Name>Parameters</Name>
        <ReferencedMemberName>Parameter</ReferencedMemberName>
      </AliasProperty>
      <ScriptMethod>
        <Name>AsSentence</Name>
        <Script>
                        &lt;#
.SYNOPSIS
    Maps Natural Language Syntax to PowerShell Parameters
.DESCRIPTION
    Maps a statement in natural language syntax to a set of PowerShell parameters.

    All parameters will be collected.
    
    For the purposes of natural language processing ValueFromPipeline will be ignored.
    
    The order the parameters is declared takes precedence over Position attributes.
.NOTES
    Each potential command can be thought of as a simple sentence with (mostly) natural syntax
    
    command &lt;parametername&gt; ...&lt;parameterargument&gt; (etc)
        
    either more natural or PowerShell syntax should be allowed, for example:

    ~~~PowerShell
    all functions can Quack {
        "quack"
    }
    ~~~

    would map to the command all and the parameters -Function and -Can (with the arguments Quack and {"quack"})

    Assuming -Functions was a `[switch]` or an alias to a `[switch]`, it will match that `[switch]` and only that switch.

    If -Functions was not a `[switch]`, it will match values from that point.

    If the parameter type is not a list or PSObject, only the next parameter will be matched.

    If the parameter type *is* a list or an PSObject,
    or ValueFromRemainingArguments is present and no named parameters were found,
    then all remaining arguments will be matched until the next named parameter is found.
    
    _Aliasing is important_ when working with a given parameter.
    The alias, _not_ the parameter name, will be what is mapped in .Parameters.
#&gt;
param()

# Because we want to have flexible open-ended arguments here, we do not hard-code any arguments:
# we parse them.

# We're trying to determine:
# Was it right to left?
$IsRightToLeft = $false
# Are there specific commands it might be?
$SpecificCommands = @()
# If so, what are their names?
$specificCommandNames = @()

# We want to start after the first element by default
$startingElementIndex = 1

for ($argIndex =0 ; $argIndex -lt $args.Count; $argIndex++) {
    $arg = $args[$argIndex]
    # If the argument was an int and greater than one
    if ($arg -is [int] -and $arg -gt 1) {
        $startingElementIndex = $arg # start parsing that many words in (#479).
        continue
    }
    
    $commandInfos = $arg -as [Management.Automation.CommandInfo[]]
    if ($commandInfos) {
        foreach ($cmdInfo in $commandInfos) {
            $SpecificCommands += $cmdInfo
            $specificCommandNames += $cmdInfo.Name
        }
        continue
    }
    if ($arg -match '^[-/]{0,2}(?:Is)?RightToLeft$') {
        # If -RightToLeft was passed
        $IsRightToLeft = $true
        continue
    }

    $argCommands = @(
        $foundTranspiler = Get-Transpiler -TranspilerName $arg
        if ($foundTranspiler) {
            foreach ($transpiler in $foundTranspiler) {
                if ($transpiler.Validate($arg)) {
                    $transpiler
                }
            }
        } else {
            $ExecutionContext.SessionState.InvokeCommand.GetCommands($arg, 'All', $true)
        }
    )

    if ($argCommands) {
        $SpecificCommands += $argCommands
        continue
    }
}


$mappedParameters = [Ordered]@{}
$sentence = [Ordered]@{
    PSTypeName='PipeScript.Sentence'
    Command = $null
}


$commandAst = $this
$commandElements = @($commandAst.CommandElements)
# If we are going right to left, reverse the command elements


if ($IsRightToLeft) {
    [Array]::Reverse($commandElements)
}


$commandElements = # Walk thru each command element
    @(foreach ($element in $commandElements) {
        # If the element is an array literal, expand it
        if ($element -is [Management.Automation.Language.ArrayLiteralAst]) {
            $element.Elements
        } else {
            # otherwise, include it as is.
            $element
        }
    })

# Now we have all of the words in a sentence.
# We can still determine if an item in a list was in a list by inspecting it's parent.

$sentences = @()
if ($SpecificCommands) {
    $potentialCommands = $SpecificCommands
    $potentialCommandNames = @($SpecificCommands | Select-Object -ExpandProperty Name)
} else {

    # The first command element should be the name of the command.
    $firstCommandElement = $commandElements[0]
    $commandName = ''
    $potentialCommandNames = @()
    $potentialCommands =
        @(
        if ($firstCommandElement.Value -and $firstCommandElement.StringConstantType -eq 'BareWord') {
            $commandName = $firstCommandElement.Value
            $foundTranspiler = Get-Transpiler -TranspilerName $commandName
            if ($foundTranspiler) {
                foreach ($transpiler in $foundTranspiler) {
                    if ($transpiler.Validate($commandAst)) {
                        $potentialCommandNames += $commandName
                        $transpiler
                    }
                }
            } else {
                foreach ($foundCmd in $ExecutionContext.SessionState.InvokeCommand.GetCommands($commandName, 'All', $true)) {
                    $foundCmd
                    $potentialCommandNames += $commandName
                }
            }
        })

    if (-not $potentialCommands) {
        [PSCustomObject][Ordered]@{
            PSTypeName = 'PipeScript.Sentence'
            Keyword = ''
            Command = $null
            Arguments = $commandElements[0..$commandElements.Length]
        }
    }
}

$mappedParameters = [Ordered]@{}

if (-not $Script:SentenceWordCache) {
    $Script:SentenceWordCache = @{}
}

$potentialCommandIndex = -1

:nextPotentialCommand foreach ($potentialCommand in $potentialCommands) {
    $potentialCommandIndex++
    $commandName = $potentialCommandName = $potentialCommandNames[$potentialCommandIndex]

    # To save time, generate a map of all potential bareword aliases for this command.
    $potentialCommandBarewordMap = [Ordered]@{}
    foreach ($parameterInfo in $potentialCommand.Parameters.Values) {
        $potentialCommandBarewordMap[$parameterInfo.Name] = $parameterInfo
        if ($parameterInfo.Aliases) {
            foreach ($aliasName in $parameterInfo.Aliases) {
                $potentialCommandBarewordMap[$aliasName] = $parameterInfo
            }
        }
    }

    # Cache the potential parameters
    $potentialParameters = $potentialCommand.Parameters

    # Assume the current parameter is empty,
    $currentParameter = ''
    # the current parameter metadata is null,
    $currentParameterMetadata = $null
    # there is no current clause,
    $currentClause = @()
    # and there are no unbound parameters.
    $unboundParameters = @()
    $clauses = @()

    # Walk over each command element in a for loop (we may adjust the index when we match)
    for ($commandElementIndex = $startingElementIndex ;$commandElementIndex -lt $commandElements.Count; $commandElementIndex++) {
        $commandElement = $CommandElements[$commandElementIndex]
        # by default, we assume we haven't found a parameter.
        $parameterFound = $false
        
        $barewordSequenece =
            @(for ($cei = $commandElementIndex; $cei -lt $commandElements.Count; $cei++) {
                if (
                    $commandElements[$cei] -isnot [Management.Automation.Language.StringConstantExpressionAst] -or
                    $commandElements[$cei].StringConstantType -ne 'Bareword'
                ) { break }
                $commandElements[$cei].Value
            })

        # That assumption is quickly challenged if the AST type was CommandParameter
        if ($commandElement -is [Management.Automation.Language.CommandParameterAst]) {
            # If there were already clauses, finalize them before we start this clause
            if ($currentClause) {
                $clauses += [PSCustomObject][Ordered]@{
                    PSTypeName = 'PipeScript.Sentence.Clause'
                    Name = if ($currentParameter) { $currentParameter} else { '' }
                    ParameterName = if ($currentParameterMetadata) { $currentParameterMetadata.Name } else { '' }
                    Words = $currentClause
                }
            }

            $commandParameter = $commandElement
            # In that case, we know the name they want to use for the parameter
            $currentParameter = $commandParameter.ParameterName
            
            $currentClause = @($currentParameter)
            $currentClauseValues = @()
            # We need to get the parameter metadata as well.
            $currentParameterMetadata =
                # If it was the real name of a parameter, this is easy
                if ($potentialCommand.Parameters[$currentParameter]) {
                    $potentialCommand.Parameters[$currentParameter]
                    $parameterFound = $true
                }
                else {
                    # Otherwise, we need to search each parameter for aliases.
                    foreach ($cmdParam in $potentialCommand.Parameters.Values) {
                        if ($cmdParam.Aliases -contains $currentParameter) {
                            $parameterFound = $true
                            $cmdParam
                            break
                        }
                    }
                }
            
            # If the parameter had an argument
            if ($commandParameter.Argument) {
                # Use that argument
                if ($mappedParameters[$currentParameter]) {
                    $mappedParameters[$currentParameter] = @($mappedParameters[$currentParameter]) + @(
                        $commandParameter.Argument
                    )
                } else {
                    $mappedParameters[$currentParameter] = $commandParameter.Argument
                }
                # and move onto the next element.
                $clauses += [PSCustomObject][Ordered]@{
                    PSTypeName = 'PipeScript.Sentence.Clause'
                    Name = if ($currentParameter) { $currentParameter} else { '' }
                    ParameterName = if ($currentParameterMetadata) { $currentParameterMetadata.Name } else { '' }
                    Words = $currentClause
                    ParameterValues = @($commandParameter.Argument)
                }
                $currentParameter = ''
                $currentParameterMetadata = $null
                
                $currentClause = @()
                $currentClauseValues = @()
                continue
            }
            # Since we have found a parameter, we advance the index.
            $commandElementIndex++
        }
        
        # If the command element was a bareword, it could also be the name of a parameter
        elseif ($barewordSequenece) {
            # We need to know the name of the parameter as it was written.
            # However, we also want to allow --parameters and /parameters,
            $potentialParameterName = $barewordSequenece[0]
            # therefore, we will compare against the potential name without leading dashes or slashes.
            $parameterFound = $false

            :MappedBareword for (
                $barewordSequenceIndex = $barewordSequenece.Length - 1;
                $barewordSequenceIndex -ge 0;
                $barewordSequenceIndex--
            ) {
                $combinedBareword = $barewordSequenece[0..$barewordSequenceIndex] -replace '^[-/]{0,}' -join ' '
                if (-not $potentialCommandBarewordMap[$combinedBareword]) {
                    continue
                }

                # If we are already in a clause
                if ($currentClause) {
                    # output the existing clause
                    $clauses += [PSCustomObject][Ordered]@{
                        PSTypeName = 'PipeScript.Sentence.Clause'
                        Name = if ($currentParameter) { $currentParameter} else { '' }
                        ParameterName = if ($currentParameterMetadata) { $currentParameterMetadata.Name } else { '' }
                        Words = $currentClause
                        ParameterValues = $currentClauseValues
                    }
                }

                # keep track of of it and advance the index.
                $currentParameter = $combinedBareword
                $currentParameterMetadata = $potentialCommandBarewordMap[$combinedBareword]
                
                
                $currentClause = @($commandElements[$commandElementIndex..($commandElementIndex + $barewordSequenceIndex)])
                $currentClauseValues = @()
                $commandElementIndex = $commandElementIndex +$barewordSequenceIndex + 1

                $parameterFound = $true
                break MappedBareword
            }

            
            
            
            if (-not $parameterFound) {
                foreach ($potentialParameter in $potentialCommand.Parameters.Values) {
                    # If we did not, check the parameter for .ValueFromRemainingArguments
                    foreach ($attr in $potentialParameter.Attributes) {
                        if ($attr.ValueFromRemainingArguments) {
                            $valueFromRemainingArgumentsParameter = $potentialParameter
                            break
                        }
                    }
                }
            }
            
        }

        # If we have our current parameter, but it is a switch,
        if ($currentParameter -and $currentParameterMetadata.ParameterType -eq [switch]) {
            $mappedParameters[$currentParameter] = $true # set it.
            if ($currentClause) {
                $clauses += [PSCustomObject][Ordered]@{
                    PSTypeName = 'PipeScript.Sentence.Clause'
                    Name = if ($currentParameter) { $currentParameter} else { '' }
                    ParameterName = if ($currentParameterMetadata) { $currentParameterMetadata.Name } else { '' }
                    Words = $currentClause
                    ParameterValues = $currentClauseValues
                }
            }
            $currentParameter = '' # and clear the current parameter.
            $currentClause = @()
            $commandElementIndex--
            continue
        }
        elseif ($currentParameter) {
            if ($mappedParameters.Contains($currentParameter) -and
                $currentParameterMetadata.ParameterType -ne [Collections.IList] -and
                $currentParameterMetadata.ParameterType -ne [PSObject] -and
                $currentParameterMetadata.ParameterType -ne [Object]
            ) {
                $clauses += [PSCustomObject][Ordered]@{
                    PSTypeName = 'PipeScript.Sentence.Clause'
                    Name = if ($currentParameter) { $currentParameter} else { '' }
                    ParameterName = if ($currentParameterMetadata) { $currentParameterMetadata.Name } else { '' }
                    Words = $currentClause
                    ParameterValues = $currentClauseValues
                }
                $currentParameter = $null
                $currentParameterMetadata = $null
                $currentClause = @()
                $commandElementIndex--
                continue
            }
        }

        # Refersh our $commandElement, as the index may have changed.
        $commandElement = $CommandElements[$commandElementIndex]

        # If we have a ValueFromRemainingArguments but no current parameter mapped
        if ($valueFromRemainingArgumentsParameter -and -not $currentParameter) {
            # assume the ValueFromRemainingArguments parameter is the current parameter.
            $currentParameter = $valueFromRemainingArgumentsParameter.Name
            $currentParameterMetadata = $valueFromRemainingArgumentsParameter
            $currentClause = @()
            $currentClauseValues = @()
        }

        $commandElementValue =
            if ($commandElement.Value -and
                $commandElement -isnot [Management.Automation.Language.ExpandableStringExpressionAst]) {
                $commandElement.Value
            }
            elseif ($commandElement -is [Management.Automation.Language.ScriptBlockExpressionAst]) {
                [ScriptBlock]::Create($commandElement.Extent.ToString() -replace '^\{' -replace '\}$')
            }
            else {
                $commandElement
            }

        # If we have a current parameter
        if ($currentParameter) {
            
            # Map the current element to this parameter.
            $mappedParameters[$currentParameter] =
                if ($mappedParameters[$currentParameter]) {
                    @($mappedParameters[$currentParameter]) + $commandElementValue
                } else {
                    $commandElementValue
                }
            $currentClause += $commandElement
            $currentClauseValues = @(@($currentClauseValues) -ne $null) + $commandElementValue
        } else {
            # otherwise add the command element to our unbound parameters.
            $unboundParameters += $commandElementValue
            $currentClause += $commandElement
            $currentClauseValues = @(@($currentClauseValues) -ne $null) + $commandElementValue
        }
    }

    if ($currentClause) {
        $clauses += [PSCustomObject][Ordered]@{
            PSTypeName = 'PipeScript.Sentence.Clause'
            Name = if ($currentParameter) { $currentParameter} else { '' }
            ParameterName = if ($currentParameterMetadata) { $currentParameterMetadata.Name } else { '' }
            Words = $currentClause
            ParameterValues = $currentClauseValues
        }
    }

    if ($potentialCommand -isnot [Management.Automation.ApplicationInfo] -and
        @($mappedParameters.Keys) -match '^[-/]') {
        $keyIndex = -1
        :nextParameter foreach ($mappedParamName in @($mappedParameters.Keys)) {
            $keyIndex++
            $dashAndSlashlessName = $mappedParamName -replace '^[-/]{0,}'
            if ($potentialCommand.Parameters[$mappedParamName]) {
                continue
            } else {
                foreach ($potentialParameter in $potentialCommand.Parameters) {
                    if ($potentialParameter.Aliases -contains $mappedParamName) {
                        continue nextParameter
                    }
                }
                $mappedParameters.Insert($keyIndex, $dashAndSlashlessName, $mappedParameters[$mappedParamName])
                $mappedParameters.Remove($mappedParamName)
            }

        }
    }

    $sentence =
        [PSCustomObject]@{
            PSTypeName = 'PipeScript.Sentence'
            Keyword = $potentialCommandName
            Command = $potentialCommand
            Clauses = $clauses
            Parameters = $mappedParameters
            Arguments = $unboundParameters
        }
    $sentences+= $sentence
    $sentence
}
                    </Script>
      </ScriptMethod>
      <ScriptProperty>
        <Name>ArgumentList</Name>
        <GetScriptBlock>
                        $parameterAstType = [Management.Automation.Language.CommandParameterAst]
@(
for (
    $commandElementIndex = 1
    $commandElementIndex -lt $this.CommandElements.Count
    $commandElementIndex++
)
{
    $commandElement = $this.CommandElements[$commandElementIndex]
    $nextElement = $this.CommandElements[$commandElementIndex + 1]
    if ($commandElement -is $parameterAstType) {
        if (-not $commandElement.Argument -and
            $nextElement -and
            $nextElement -isnot $parameterAstType) {
            $commandElementIndex++
        }
    } else {
        $commandElement.ConvertFromAst()
    }
}
)
                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>IsAssigned</Name>
        <GetScriptBlock>
                        $this.Parent.IsAssigned -as [bool]

                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>IsPiped</Name>
        <GetScriptBlock>
                        ($this.Parent -is [Management.Automation.Language.PipelineAst]) -and
($this.Parent.PipelineElements.Count -gt 1)

                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>IsPipedFrom</Name>
        <GetScriptBlock>
                        if ($this.Parent -isnot [Management.Automation.Language.PipelineAst]) { return $false }
$this.Parent.PipelineElements.IndexOf($this) -lt ($this.Parent.PipelineElements.Count - 1)

                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>IsPipedTo</Name>
        <GetScriptBlock>
                        if ($this.Parent -isnot [Management.Automation.Language.PipelineAst]) { return $false }
$this.Parent.PipelineElements.IndexOf($this) -gt 0

                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>Parameter</Name>
        <GetScriptBlock>
                        $commandAst = $this
$NamedParameters = [Ordered]@{}
$parameterAstType = [Management.Automation.Language.CommandParameterAst]

for (
    $commandElementIndex = 1
    $commandElementIndex -lt $commandAst.CommandElements.Count
    $commandElementIndex++
)
{
    $commandElement = $commandAst.CommandElements[$commandElementIndex]
    $nextElement = $commandAst.CommandElements[$commandElementIndex + 1]
    if ($commandElement -is $parameterAstType) {
        if ($commandElement.Argument) {
            $NamedParameters[$commandElement.ParameterName] =
                $commandElement.Argument.ConvertFromAst()
        } elseif ($nextElement -and $nextElement -isnot $parameterAstType) {
            $NamedParameters[$commandElement.ParameterName] =
                $nextElement.ConvertFromAst()
            $commandElementIndex++
        } else {
            $NamedParameters[$commandElement.ParameterName] = $true
        }
    }
}

$NamedParameters
                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>PipelineLength</Name>
        <GetScriptBlock>
                        if ($this.Parent -isnot [Management.Automation.Language.PipelineAst]) { return $null }
$this.Parent.PipelineElements.Count



                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>PipelinePosition</Name>
        <GetScriptBlock>
                        if ($this.Parent -isnot [Management.Automation.Language.PipelineAst]) { return $null }
$this.Parent.PipelineElements.IndexOf($this)


                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>ResolvedCommand</Name>
        <GetScriptBlock>
                        
$commandName = $this.CommandElements[0].ToString()
$foundTranspiler = Get-Transpiler -TranspilerName $commandName
if ($foundTranspiler) {
    foreach ($transpiler in $foundTranspiler) {
        if ($transpiler.Validate($this)) {
            $transpiler
        }
    }
} else {
    $ExecutionContext.SessionState.InvokeCommand.GetCommands($commandName, 'All', $true)
}



                    </GetScriptBlock>
      </ScriptProperty>
    </Members>
  </Type>
  <Type>
    <Name>System.Management.Automation.CommandInfo</Name>
    <Members>
      <AliasProperty>
        <Name>Categories</Name>
        <ReferencedMemberName>Category</ReferencedMemberName>
      </AliasProperty>
      <AliasProperty>
        <Name>Example</Name>
        <ReferencedMemberName>Examples</ReferencedMemberName>
      </AliasProperty>
      <AliasProperty>
        <Name>Link</Name>
        <ReferencedMemberName>Links</ReferencedMemberName>
      </AliasProperty>
      <AliasProperty>
        <Name>Order</Name>
        <ReferencedMemberName>Rank</ReferencedMemberName>
      </AliasProperty>
      <ScriptMethod>
        <Name>CouldPipe</Name>
        <Script>
                        param([PSObject]$InputObject)

$parameterSets =
    if ($this.ResolvedCommand.ParameterSets) {
        $this.ResolvedCommand.ParameterSets
    } elseif ($this.ParameterSets) {
        $this.ParameterSets
    }

:nextParameterSet foreach ($paramSet in $parameterSets) {
    if ($ParameterSetName -and $paramSet.Name -ne $ParameterSetName) { continue }
    $params = @{}
    $mappedParams = [Ordered]@{} # Create a collection of mapped parameters
    # Walk thru each parameter of this command
    :nextParameter foreach ($myParam in $paramSet.Parameters) {
        # If the parameter is ValueFromPipeline
        if ($myParam.ValueFromPipeline) {
            $potentialPSTypeNames = @($myParam.Attributes.PSTypeName) -ne ''
            if ($potentialPSTypeNames) {
                foreach ($potentialTypeName in $potentialPSTypeNames) {
                    if ($potentialTypeName -and $InputObject.pstypenames -contains $potentialTypeName) {
                        $mappedParams[$myParam.Name] = $params[$myParam.Name] = $InputObject
                        continue nextParameter
                    }
                }
            }
            # and we have an input object
            elseif ($null -ne $inputObject -and
                (
                    # of the exact type
                    $myParam.ParameterType -eq $inputObject.GetType() -or
                    # (or a subclass of that type)
                    $inputObject.GetType().IsSubClassOf($myParam.ParameterType) -or
                    # (or an inteface of that type)
                    ($myParam.ParameterType.IsInterface -and $InputObject.GetType().GetInterface($myParam.ParameterType))
                )
            ) {
                # then map the parameter.
                $mappedParams[$myParam.Name] = $params[$myParam.Name] = $InputObject
            }
        }
    }
    # Check for parameter validity.
    foreach ($mappedParamName in @($mappedParams.Keys)) {
        if (-not $this.IsParameterValid($mappedParamName, $mappedParams[$mappedParamName])) {
            $mappedParams.Remove($mappedParamName)
        }
    }
    if ($mappedParams.Count -gt 0) {
        return $mappedParams
    }
}
                    </Script>
      </ScriptMethod>
      <ScriptMethod>
        <Name>CouldPipeType</Name>
        <Script>
                        param(
[Type]
$Type
)

$parameterSets =
    if ($this.ResolvedCommand.ParameterSets) {
        $this.ResolvedCommand.ParameterSets
    } elseif ($this.ParameterSets) {
        $this.ParameterSets
    }

:nextParameterSet foreach ($paramSet in $parameterSets) {
    if ($ParameterSetName -and $paramSet.Name -ne $ParameterSetName) { continue }
    $params = @{}
    $mappedParams = [Ordered]@{} # Create a collection of mapped parameters
    # Walk thru each parameter of this command
    :nextParameter foreach ($myParam in $paramSet.Parameters) {
        # If the parameter is ValueFromPipeline
        if ($myParam.ValueFromPipeline -and
            (
        
                # of the exact type
                $myParam.ParameterType -eq $type -or
                # (or a subclass of that type)
                $type.IsSubClassOf($myParam.ParameterType) -or
                # (or an inteface of that type)
                ($myParam.ParameterType.IsInterface -and $type.GetInterface($myParam.ParameterType))
            )
        ) {
            return $true
        }
    }
}

return $false
                    </Script>
      </ScriptMethod>
      <ScriptMethod>
        <Name>CouldRun</Name>
        <Script>
                        param([Collections.IDictionary]$params, [string]$ParameterSetName)

:nextParameterSet foreach ($paramSet in $this.ParameterSets) {
    if ($ParameterSetName -and $paramSet.Name -ne $ParameterSetName) { continue }
    $mappedParams = [Ordered]@{} # Create a collection of mapped parameters
    $mandatories = # Walk thru each parameter of this command
        @(foreach ($myParam in $paramSet.Parameters) {
            if ($params.Contains($myParam.Name)) { # If this was in Params,
                $mappedParams[$myParam.Name] = $params[$myParam.Name] # then map it.
            } else {
                foreach ($paramAlias in $myParam.Aliases) { # Otherwise, check the aliases
                    if ($params.Contains($paramAlias)) { # and map it if the parameters had the alias.
                        $mappedParams[$myParam.Name] = $params[$paramAlias]
                        break
                    }
                }
            }
            if ($myParam.IsMandatory) { # If the parameter was mandatory,
                $myParam.Name # keep track of it.
            }
        })

    # Check for parameter validity.
    foreach ($mappedParamName in @($mappedParams.Keys)) {
        if (-not $this.IsParameterValid($mappedParamName, $mappedParams[$mappedParamName])) {
            $mappedParams.Remove($mappedParamName)
        }
    }
    
    foreach ($mandatoryParam in $mandatories) { # Walk thru each mandatory parameter.
        if (-not $mappedParams.Contains($mandatoryParam)) { # If it wasn't in the parameters.
            continue nextParameterSet
        }
    }
    return $mappedParams
}
return $false
                    </Script>
      </ScriptMethod>
      <ScriptMethod>
        <Name>GetHelpField</Name>
        <Script>
                        param([Parameter(Mandatory)]$Field)
$fieldNames = 'synopsis','description','link','example','inputs', 'outputs', 'parameter', 'notes'
foreach ($block in $this.BlockComments) {
    foreach ($match in [Regex]::new("
        \.(?&lt;Field&gt;$Field) # Field Start
        [\s-[\r\n]]{0,} # Optional Whitespace
        [\r\n]+ # newline
        (?&lt;Content&gt;(?:.|\s)+?(?=
        (
            [\r\n]{0,}\s{0,}\.(?&gt;$($fieldNames -join '|'))|
            \#\&gt;|
            \z
        ))) # Anything until the next .field or end of the comment block
        ", 'IgnoreCase,IgnorePatternWhitespace', [Timespan]::FromSeconds(1)).Matches(
            $block.Value
        )) {
        $match.Groups["Content"].Value -replace '[\s\r\n]+$'
    }
    break
}
                    </Script>
      </ScriptMethod>
      <ScriptMethod>
        <Name>IsParameterValid</Name>
        <Script>
                        param([Parameter(Mandatory)]$ParameterName, [PSObject]$Value)

if ($this.Parameters.Count -ge 0 -and
    $this.Parameters[$parameterName].Attributes
) {
    foreach ($attr in $this.Parameters[$parameterName].Attributes) {
        $_ = $value
        if ($attr -is [Management.Automation.ValidateScriptAttribute]) {
            $result = try { . $attr.ScriptBlock } catch { $null }
            if ($result -ne $true) {
                return $false
            }
        }
        elseif ($attr -is [Management.Automation.ValidatePatternAttribute] -and
                (-not [Regex]::new($attr.RegexPattern, $attr.Options, '00:00:05').IsMatch($value))
            ) {
                return $false
            }
        elseif ($attr -is [Management.Automation.ValidateSetAttribute] -and
                $attr.ValidValues -notcontains $value) {
                    return $false
                }
        elseif ($attr -is [Management.Automation.ValidateRangeAttribute] -and (
            ($value -gt $attr.MaxRange) -or ($value -lt $attr.MinRange)
        )) {
            return $false
        }
    }
}
return $true
                    </Script>
      </ScriptMethod>
      <ScriptMethod>
        <Name>Validate</Name>
        <Script>
                        param(
    # input being validated
    [PSObject]$ValidateInput,
    # If set, will require all [Validate] attributes to be valid.
    # If not set, any input will be valid.
    [switch]$AllValid
)

foreach ($attr in $this.ScriptBlock.Attributes) {
    if ($attr -is [Management.Automation.ValidateScriptAttribute]) {
        try {
            $_ = $this = $psItem = $ValidateInput
            $isValidInput = . $attr.ScriptBlock
            if ($isValidInput -and -not $AllValid) { return $true}
            if (-not $isValidInput -and $AllValid) {
                if ($ErrorActionPreference -eq 'ignore') {
                    return $false
                } elseif ($AllValid) {
                    throw "'$ValidateInput' is not a valid value."
                }
            }
        } catch {
            if ($AllValid) {
                if ($ErrorActionPreference -eq 'ignore') {
                    return $false
                } else {
                    throw
                }
            }
        }
    }
    elseif ($attr -is [Management.Automation.ValidateSetAttribute]) {
        if ($ValidateInput -notin $attr.ValidValues) {
            if ($AllValid) {
                if ($ErrorActionPreference -eq 'ignore') {
                    return $false
                } else {
                    throw "'$ValidateInput' is not a valid value. Valid values are '$(@($attr.ValidValues) -join "','")'"
                }
            }
        } elseif (-not $AllValid) {
            return $true
        }
    }
    elseif ($attr -is [Management.Automation.ValidatePatternAttribute]) {
        $matched = [Regex]::new($attr.RegexPattern, $attr.Options, [Timespan]::FromSeconds(1)).Match("$ValidateInput")
        if (-not $matched.Success) {
            if ($allValid) {
                if ($ErrorActionPreference -eq 'ignore') {
                    return $false
                } else {
                    throw "'$ValidateInput' is not a valid value. Valid values must match the pattern '$($attr.RegexPattern)'"
                }
            }
        } elseif (-not $AllValid) {
            return $true
        }
    }
    elseif ($attr -is [Management.Automation.ValidateRangeAttribute]) {
        if ($null -ne $attr.MinRange -and $validateInput -lt $attr.MinRange) {
            if ($AllValid) {
                if ($ErrorActionPreference -eq 'ignore') {
                    return $false
                } else {
                    throw "'$ValidateInput' is below the minimum range [ $($attr.MinRange)-$($attr.MaxRange) ]"
                }
            }
        }
        elseif ($null -ne $attr.MaxRange -and $validateInput -gt $attr.MaxRange) {
            if ($AllValid) {
                if ($ErrorActionPreference -eq 'ignore') {
                    return $false
                } else {
                    throw "'$ValidateInput' is above the maximum range [ $($attr.MinRange)-$($attr.MaxRange) ]"
                }
            }
        }
        elseif (-not $AllValid) {
            return $true
        }
    }
}

if ($AllValid) {
    return $true
} else {
    return $false
}
                    </Script>
      </ScriptMethod>
      <ScriptProperty>
        <Name>BlockComments</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Gets Block Comments
.DESCRIPTION
    Gets Block Comments declared within a script.
#&gt;
$TargetScriptBlock = $this.ScriptBlock
if (-not $TargetScriptBlock) {
    if ($this -is [Management.Automation.AliasInfo]) {
        $resolveThis = $this
        while ($resolveThis.ResolvedCommand) {
            $resolveThis = $resolveThis.ResolvedCommand
        }
        if ($resolveThis.ScriptBlock) {
            $TargetScriptBlock = $resolveThis.ScriptBlock
        } else {
            $TargetScriptBlock = ''
        }
    } else {
        $TargetScriptBlock = ''
    }
}

@([Regex]::New("
\&lt;\# # The opening tag
(?&lt;Block&gt;
    (?:.|\s)+?(?=\z|\#&gt;) # anything until the closing tag
)
\#\&gt; # the closing tag
", 'IgnoreCase,IgnorePatternWhitespace', '00:00:01').Matches($TargetScriptBlock)) -as [Text.RegularExpressions.Match[]]

                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>CacheControl</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Gets a Command's Cache Control
.DESCRIPTION
    Gets a Command's Cache Control header (if present).

    Any [Reflection.AssemblyMetaData] whose key is named `*Cache*Control*` will be counted as a cache-control value.

    All values will be joined with commas and cached.
.NOTES
    Cache Control allows any script to easily specify how long it's results should be cached.
#&gt;
if (-not $this.'.CacheControl') {
    $resolvedScriptBlock =
        if ($this -is [Management.Automation.AliasInfo]) {
            $resolveCommand = $this
            do {
                $resolveCommand = $this.ResolvedCommand
            } while ($resolveCommand -and $resolveCommand.ResolvedCommand)
            if ($resolveCommand) {
                $resolveCommand.ScriptBlock
            }
        } elseif ($this.ScriptBlock) {
            $this.ScriptBlock
        }

    if (-not $resolvedScriptBlock) { return }
    $cacheControlValues = foreach ($attr in $resolvedScriptBlock.Attributes) {
        if ($attr -isnot [Reflection.AssemblyMetadata]) {
            continue
        }

        if ($attr.Key -notmatch 'Cache.?Control') { continue }
        $attr.Value
    }
    Add-Member -InputObject $this -MemberType NoteProperty -Name '.CacheControl' -Value (
        $cacheControlValues -join ','
    ) -Force
}

$This.'.CacheControl'
                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>Category</Name>
        <GetScriptBlock>
                        @(foreach ($attr in $this.ScriptBlock.Attributes) {
    if ($attr -is [Reflection.AssemblyMetaDataAttribute] -and
        $attr.Key -eq 'Category') {
        $attr.Value
    }
    elseif ($attr -is [ComponentModel.CategoryAttribute]) {
        $attr.Category
    }
}) -as [string[]]
                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>CommandMetaData</Name>
        <GetScriptBlock>
                        if (-not $this.'.CommandMetadata') {
    $this.psobject.properties.add(
        [psnoteproperty]::new('.CommandMetadata',
            [PSObject]::new([Management.Automation.CommandMetadata]::new($this))
        ), $true
    )
}

return $this.'.CommandMetadata'

                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>Description</Name>
        <GetScriptBlock>
                        if ($this -is [Management.Automation.AliasInfo]) {
    $resolveThis = $this
    while ($resolveThis.ResolvedCommand) {
        $resolveThis = $resolveThis.ResolvedCommand
    }
    if ($resolveThis) {
        @($resolveThis.GetHelpField("Description"))[0] -replace '^\s+'
    }
} else {
    @($this.GetHelpField("Description"))[0] -replace '^\s+'
}

                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>Examples</Name>
        <GetScriptBlock>
                        $this.GetHelpField("Example")
                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>FullyQualifiedName</Name>
        <GetScriptBlock>
                        if ($this -is [Management.Automation.ExternalScriptInfo] -or
    $this -is [Management.Automation.ApplicationInfo]) {
    if ($this.Root -and
        $this.Source.StartsWith -and
        $this.Source.StartsWith($this.Root, "OrdinalIgnoreCase")) {
        $this.Source.Substring($this.Root.Length)
    } else {
        $this.Source
    }
}
elseif ($this.Module) {
    '' + $this.Module + '\' + $this.Name
}
elseif ($this -is [Management.Automation.CmdletInfo]) {
    $this.ImplementingType.Namespace + '.' + $this.Name
}
else {
    $this.Name
}
                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>HasValidation</Name>
        <GetScriptBlock>
                        foreach ($attr in $this.ScriptBlock.Attributes) {
    if ($attr -is [Management.Automation.ValidateScriptAttribute] -or
        $attr -is [Management.Automation.ValidateSetAttribute] -or
        $attr -is [Management.Automation.ValidatePatternAttribute] -or
        $attr -is [Management.Automation.ValidateRangeAttribute]) {
        return $true
    }
}

return $false
                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>IsStronglyPiped</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Determines if a command is strongly piped.
.DESCRIPTION
    Determines if a command uses strong typing on at least one ValueFromPipeline parameter.
#&gt;
$weakTypeList = [string],[object],[psobject], [string[]],[object[]],[psobject[]]
foreach ($parameterSet in $this.ParameterSets) {
    foreach ($parameterInSet in $parameterSet.Parameters) {
        if (-not $parameterInSet.ValueFromPipeline) { continue }
        if ((-not $parameterInSet.ParameterType.IsPrimitive) -and
            $parameterInSet.ParameterType -notin $weakTypeList) {
            return $true
        }
    }
}
return $false

                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>Links</Name>
        <GetScriptBlock>
                        $this.GetHelpField("Link")

                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>Metadata</Name>
        <GetScriptBlock>
                        $Metadata = [Ordered]@{}
foreach ($attr in $this.ScriptBlock.Attributes) {
    if ($attr -is [Reflection.AssemblyMetaDataAttribute]) {
        if ($Metadata[$attr.Key]) {
            $Metadata[$attr.Key] = @($Metadata[$attr.Key]) + $attr.Value
        } else {
            $Metadata[$attr.Key] = $attr.Value
        }
    }
}
return $Metadata
                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>PipeScriptType</Name>
        <GetScriptBlock>
                        
if ($this.pstypenames -like '*.Command') {
    $this.pstypenames -like '*.Command' -replace '\.Command'
}

                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>Rank</Name>
        <GetScriptBlock>
                        foreach ($attr in $this.ScriptBlock.Attributes) {
    if ($attr -is [Reflection.AssemblyMetaDataAttribute] -and
        $attr.Key -in 'Order', 'Rank') {
        return $attr.Value -as [int]
    }
}
return 0
                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>StrongPipeType</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Gets strongly piped types for a command.
.DESCRIPTION
    Gets the strong types that a given command can accept as a ValueFromPipeline parameter.
#&gt;
$weakTypeList = [string],[object],[psobject], [string[]],[object[]],[psobject[]]
, @(foreach ($parameterSet in $this.ParameterSets) {
    foreach ($parameterInSet in $parameterSet.Parameters) {
        if (-not $parameterInSet.ValueFromPipeline) { continue }
        if ((-not $parameterInSet.ParameterType.IsPrimitive) -and
            $parameterInSet.ParameterType -notin $weakTypeList) {
            $parameterInSet.ParameterType
        }
    }
})


                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>Synopsis</Name>
        <GetScriptBlock>
                        @($this.GetHelpField("Synopsis"))[0] -replace '^\s+'
                    </GetScriptBlock>
      </ScriptProperty>
    </Members>
  </Type>
  <Type>
    <Name>System.Management.Automation.Language.ConstantExpressionAst</Name>
    <Members>
      <ScriptMethod>
        <Name>ConvertFromAST</Name>
        <Script>
                        $this.Value

                    </Script>
      </ScriptMethod>
    </Members>
  </Type>
  <Type>
    <Name>System.Management.Automation.Language.ExpandableStringExpressionAst</Name>
    <Members>
      <ScriptMethod>
        <Name>Expand</Name>
        <Script>
                        &lt;#
.SYNOPSIS
    Expands a String Expression
.DESCRIPTION
    Expands a PowerShell ExpandableStringExpressionAst.

    Expanding a string allows for code injection, and should be used cautiously.

    Also, when expanding strings during compilation, variable context is likely very different than it will be during execution.
.EXAMPLE
    {"$pid"}.Ast.EndBlock.Statements[0].PipelineElements[0].Expression.Value
#&gt;
param(
# The execution context
$Context = $ExecutionContext
)

$Context.SessionState.InvokeCommand.ExpandString($this.Value)
                    </Script>
      </ScriptMethod>
    </Members>
  </Type>
  <Type>
    <Name>System.Management.Automation.ExternalScriptInfo</Name>
    <Members>
      <AliasProperty>
        <Name>Namespace</Name>
        <ReferencedMemberName>CommandNamespace</ReferencedMemberName>
      </AliasProperty>
      <ScriptProperty>
        <Name>Root</Name>
        <GetScriptBlock>
                        if ($this.'.Root') {
    return $this.'.Root'
}

$nextRoot = $this.Source | Split-Path
:findingRoot do {
    
    $lastRoot = $nextRoot
    $lastRootName = $lastRoot | Split-Path -Leaf

    if ($lastRootName -as [Version]) {
        $lastRootName = $lastRoot | Split-Path | Split-Path -Leaf
    }

    foreach ($fileNameThatIndicatesRoot in 'LICENSE', 'LICENSE.txt',
        "$LastRootName.psd1", "$LastRootName.psm1", ".git") {
        $lookingForPath = Join-Path $lastRoot $fileNameThatIndicatesRoot
        if (Test-Path $lookingForPath) {
            break findingRoot
        }
    }

    $nextRoot = $nextRoot | Split-Path
} while ($nextRoot)

$this | Add-Member NoteProperty '.Root' "$lastRoot" -Force
$this.'.Root'
                    </GetScriptBlock>
        <SetScriptBlock>
                        $this | Add-Member NoteProperty ".Root" $args -Force

                    </SetScriptBlock>
      </ScriptProperty>
    </Members>
  </Type>
  <Type>
    <Name>System.Management.Automation.FunctionInfo</Name>
    <Members>
      <AliasProperty>
        <Name>Namespace</Name>
        <ReferencedMemberName>CommandNamespace</ReferencedMemberName>
      </AliasProperty>
    </Members>
  </Type>
  <Type>
    <Name>Hashtable</Name>
    <Members>
    </Members>
  </Type>
  <Type>
    <Name>Language</Name>
    <Members>
      <AliasProperty>
        <Name>Aliases</Name>
        <ReferencedMemberName>Alias</ReferencedMemberName>
      </AliasProperty>
      <AliasProperty>
        <Name>Functions</Name>
        <ReferencedMemberName>Function</ReferencedMemberName>
      </AliasProperty>
      <AliasProperty>
        <Name>Templates</Name>
        <ReferencedMemberName>Template</ReferencedMemberName>
      </AliasProperty>
      <ScriptProperty>
        <Name>Alias</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Gets Language Functions
.DESCRIPTION
    Gets Functions related to a language.

    These are functions that either match a language's `.FilePattern` or start with a language name, followed by punctuation.
#&gt;
if (-not $global:AllFunctionsAndAliases) {
    $global:AllFunctionsAndAliases = $global:ExecutionContext.SessionState.InvokeCommand.GetCommand('*','Alias,Function',$true)
}
$FunctionsForThisLanguage = [Ordered]@{PSTypeName='Language.Functions'}
if ($this.FilePattern) {
    foreach ($FunctionForLanguage in $global:AllFunctionsAndAliases -match $this.FilePattern) {
        $FunctionsForThisLanguage["$FunctionForLanguage"] = $FunctionForLanguage
    }
}
if ($this.LanguageName) {
    foreach ($FunctionForLanguage in $global:AllFunctionsAndAliases -match "(?&lt;=(?&gt;^|[\p{P}-[\\]]))$([Regex]::Escape($this.LanguageName))[\p{P}-[\\]]") {
        $FunctionsForThisLanguage["$FunctionForLanguage"] = $FunctionForLanguage
    }
}

$FunctionsForThisLanguage = [PSCustomObject]$FunctionsForThisLanguage
$FunctionsForThisLanguage.pstypenames.insert(0,"$($this.LanguageName).Functions")
$FunctionsForThisLanguage


                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>Function</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Gets Language Functions
.DESCRIPTION
    Gets Functions related to a language.

    These are functions that either match a language's `.FilePattern` or start with a language name, followed by punctuation.
#&gt;
if (-not $global:AllFunctionsAndAliases) {
    $global:AllFunctionsAndAliases = $global:ExecutionContext.SessionState.InvokeCommand.GetCommand('*','Alias,Function',$true)
}
$FunctionsForThisLanguage = [Ordered]@{PSTypeName='Language.Functions'}
if ($this.FilePattern) {
    foreach ($FunctionForLanguage in $global:AllFunctionsAndAliases -match $this.FilePattern) {
        $FunctionsForThisLanguage["$FunctionForLanguage"] = $FunctionForLanguage
    }
}
if ($this.LanguageName) {
    foreach ($FunctionForLanguage in $global:AllFunctionsAndAliases -match "(?&lt;=(?&gt;^|[\p{P}-[\\]]))$([Regex]::Escape($this.LanguageName))[\p{P}-[\\]]") {
        $FunctionsForThisLanguage["$FunctionForLanguage"] = $FunctionForLanguage
    }
}

$FunctionsForThisLanguage = [PSCustomObject]$FunctionsForThisLanguage
$FunctionsForThisLanguage.pstypenames.insert(0,"$($this.LanguageName).Functions")
$FunctionsForThisLanguage


                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>HasInterpreter</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Does a Language Have an Interpreter?
.DESCRIPTION
    Returns true if a language defined an interpreter.
#&gt;
return ($this.Interpreter -as [bool])

                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>HasPowerShellInterpreter</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Determines if a language has a PowerShell interpreter
.DESCRIPTION
    Determines if a language's interpreter is PowerShell or an external application.
.NOTES
    Returns $true is the interpreter is a `[ScriptBlock]`, `[FunctionInfo]`, or `[CmdletInfo]`,
    or an `[AliasInfo]` that does not point to an application. Otherwise, returns $false.
#&gt;
if ($this.Interpreter -is [scriptblock]) {
    return $true
}
if ($this.Interpreter -is [Management.Automation.FunctionInfo]) {
    return $true
}
if ($this.Interpreter -is [Management.Automation.CmdletInfo]) {
    return $true
}
if ($this.Interpreter -is [Management.Automation.AliasInfo] -and
    $this.Interpreter.ResolvedCommand -isnot [Management.Automation.ApplicationInfo]) {
    return $true
}
return $false

                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>Template</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Gets Language Templates
.DESCRIPTION
    Gets Templates related to a language.
#&gt;
if (-not $global:AllFunctionsAndAliases) {
    $global:AllFunctionsAndAliases = $global:ExecutionContext.SessionState.InvokeCommand.GetCommand('*','Alias,Function',$true)
}
$templatePrefix = '^Template\p{P}'
$templateCommands = $global:AllFunctionsAndAliases -match $templatePrefix
$thisLanguagesTemplates = [Ordered]@{PSTypename='Language.Templates'}
if ($this.FilePattern) {
    foreach ($templateForThisLanguage in $templateCommands -match $this.FilePattern) {
        $thisLanguagesTemplates["$templateForThisLanguage" -replace $templatePrefix] = $templateForThisLanguage
    }
}
if ($this.LanguageName) {
    foreach ($templateForThisLanguage in $templateCommands -match "(?&lt;=(?&gt;^|[\p{P}-[\\]]))$([Regex]::Escape($this.LanguageName))[\p{P}-[\\]]") {
        $thisLanguagesTemplates["$templateForThisLanguage" -replace $templatePrefix] = $templateForThisLanguage
    }
}
$thisLanguagesTemplates = [PSCustomObject]$thisLanguagesTemplates
$thisLanguagesTemplates.pstypenames.insert(0, "$($this.LanguageName).Templates")
$thisLanguagesTemplates


                    </GetScriptBlock>
      </ScriptProperty>
    </Members>
  </Type>
  <Type>
    <Name>Language.Command</Name>
    <Members>
      <ScriptMethod>
        <Name>IsMatch</Name>
        <Script>
                        

$regexPatterns = @(foreach ($attr in $this.ScriptBlock.Attributes) {
    if ($attr -isnot [ValidatePattern]) { continue }
    [Regex]::new($attr.RegexPattern, $attr.Options, '00:00:05')
})

foreach ($arg in $args) {
    foreach ($regexPattern in $regexPatterns) {
       if ($regexPattern.IsMatch($arg)) { return $true }
    }
}

return $false
                    </Script>
      </ScriptMethod>
    </Members>
  </Type>
  <Type>
    <Name>Language.Functions</Name>
    <Members>
      <AliasProperty>
        <Name>Distinct</Name>
        <ReferencedMemberName>Unique</ReferencedMemberName>
      </AliasProperty>
      <ScriptProperty>
        <Name>All</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Gets all Language Functions
.DESCRIPTION
    Gets all functions explicitly related to a language defined in PipeScript.
#&gt;
,@(foreach ($psProperty in $this.PSObject.properties) {
    if ($psProperty -isnot [psnoteproperty]) { continue }
    if ($psProperty.Value -isnot [Management.Automation.CommandInfo]) { continue }
    $psProperty.Value
})
                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>ByInputType</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Gets Language Functions by Input Type
.DESCRIPTION
    Returns a dictionary of all unique language functions that accept a pipeline parameter.

    The key will be the type of parameter accepted.
    The value will be a list of commands that accept that parameter from the pipeline.
.NOTES
    Primitive parameter types and string types will be ignored.
#&gt;
param()
# We want the results to be ordered (both the keys and the values)
$byInputType = [Ordered]@{}
$uniqueList = @($this.Unique | Sort-Object Order)
foreach ($uniqueCommand in $uniqueList) {
    , @(foreach ($parameterSet in $uniqueCommand.ParameterSets) {
        foreach ($parameterInSet in $parameterSet.Parameters) {
            if (-not $parameterInSet.ValueFromPipeline) { continue }
            if ($parameterInSet.ParameterType.IsPrimitive) { continue }
            if ($parameterInSet.ParameterType -eq [string]) { continue }
            if (-not $byInputType[$parameterInSet.ParameterType]) {
                $byInputType[$parameterInSet.ParameterType] = [Collections.Generic.List[PSObject]]::new()
            }
            $byInputType[$parameterInSet.ParameterType].Add($uniqueCommand)
        }
    })
}
$byInputType
                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>Count</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Gets the number of language functions
.DESCRIPTION
    Gets the number of functions explicitly related to a language defined in PipeScript.
#&gt;
@(foreach ($psProperty in $this.PSObject.properties) {
    if ($psProperty -isnot [psnoteproperty]) { continue }
    if ($psProperty.Value -isnot [Management.Automation.CommandInfo]) { continue }
    $psProperty.Value
}).Length
                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>Unique</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Gets unique Language Functions
.DESCRIPTION
    Gets unique functions related to a language.
#&gt;
$distinctCommands = @{}
,@(foreach ($psProperty in $this.PSObject.properties) {
    if ($psProperty -isnot [psnoteproperty]) { continue }
    if ($psProperty.Value -isnot [Management.Automation.CommandInfo]) { continue }
    if (
        $psProperty.Value -is [Management.Automation.AliasInfo] -and
        (
            $distinctCommands[$psProperty.Value.ResolvedCommand] -or
            $this.PSObject.Properties[$psProperty.Value.ResolvedCommand.Name]
        )
    ) {
        continue
    }
    $distinctCommands[$psProperty.Value] = $psProperty.Value
    $psProperty.Value
})
                    </GetScriptBlock>
      </ScriptProperty>
    </Members>
  </Type>
  <Type>
    <Name>Language.Templates</Name>
    <Members>
      <AliasProperty>
        <Name>Distinct</Name>
        <ReferencedMemberName>Unique</ReferencedMemberName>
      </AliasProperty>
      <ScriptProperty>
        <Name>All</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Gets all Language Templates
.DESCRIPTION
    Gets all templates explicitly related to a language defined in PipeScript.
#&gt;
,@(foreach ($psProperty in $this.PSObject.properties) {
    if ($psProperty -isnot [psnoteproperty]) { continue }
    if ($psProperty.Value -isnot [Management.Automation.CommandInfo]) { continue }
    $psProperty.Value
})
                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>ByInputType</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Gets Language Templates by Input Type
.DESCRIPTION
    Returns a dictionary of all unique language templates that accept a pipeline parameter.

    The key will be the type of parameter accepted.
    The value will be a list of commands that accept that parameter from the pipeline.
.NOTES
    Primitive parameter types and string types will be ignored.
#&gt;
param()
# We want the results to be ordered (both the keys and the values)
$byInputType = [Ordered]@{}
$uniqueList = @($this.Unique | Sort-Object Order)
foreach ($uniqueCommand in $uniqueList) {
    , @(foreach ($parameterSet in $uniqueCommand.ParameterSets) {
        foreach ($parameterInSet in $parameterSet.Parameters) {
            if (-not $parameterInSet.ValueFromPipeline) { continue }
            if ($parameterInSet.ParameterType.IsPrimitive) { continue }
            if ($parameterInSet.ParameterType -eq [string]) { continue }
            if (-not $byInputType[$parameterInSet.ParameterType]) {
                $byInputType[$parameterInSet.ParameterType] = [Collections.Generic.List[PSObject]]::new()
            }
            $byInputType[$parameterInSet.ParameterType].Add($uniqueCommand)
        }
    })
}
$byInputType
                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>Count</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Gets the number of language templates
.DESCRIPTION
    Gets the number of templates explicitly related to a language defined in PipeScript.
#&gt;
@(foreach ($psProperty in $this.PSObject.properties) {
    if ($psProperty -isnot [psnoteproperty]) { continue }
    if ($psProperty.Value -isnot [Management.Automation.CommandInfo]) { continue }
    $psProperty.Value
}).Length
                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>Unique</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Gets unique Language Templates
.DESCRIPTION
    Gets unique templates related to a language.
#&gt;
$distinctCommands = @{}
$ThisPSObject = $this.PSObject
$theseProperties = @($this.PSObject.properties)
foreach ($psProperty in $theseProperties) {
    if ($psProperty -isnot [psnoteproperty]) { continue }
    if ($psProperty.Value -isnot [Management.Automation.CommandInfo]) { continue }
    if ($psProperty.Value -is [Management.Automation.AliasInfo]) {
        $aliasInfo = $psProperty.Value
        if (
            $distinctCommands[$aliasInfo.ResolvedCommand] -or
            $ThisPSObject.Properties[$aliasInfo.ResolvedCommand.Name -replace 'Template\p{P}']
        ) {
            continue
        }
    }
    $distinctCommands[$psProperty.Value] = $psProperty.Value
    $psProperty.Value
}
                    </GetScriptBlock>
      </ScriptProperty>
    </Members>
  </Type>
  <Type>
    <Name>Markdown</Name>
    <Members>
    </Members>
  </Type>
  <Type>
    <Name>System.Management.Automation.Language.ParamBlockAst</Name>
    <Members>
      <ScriptProperty>
        <Name>Header</Name>
        <GetScriptBlock>
                        # and extract the difference between the parent and the start of the block
$offsetDifference = $this.Extent.StartOffset - $this.Parent.Extent.StartOffset
# (this is where the header and help reside)
# try to strip off leading braces and whitespace
$this.Parent.Extent.ToString().Substring(0, $offsetDifference) -replace '^[\r\n\s]{0,}\{'
                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>ParameterNames</Name>
        <GetScriptBlock>
                        @(foreach ($parameter in $this.Parameters) {
    $parameter.ParameterNames
})
                    </GetScriptBlock>
      </ScriptProperty>
    </Members>
  </Type>
  <Type>
    <Name>System.Management.Automation.Language.ParameterAST</Name>
    <Members>
      <AliasProperty>
        <Name>Aliases</Name>
        <ReferencedMemberName>ParameterNames</ReferencedMemberName>
      </AliasProperty>
      <AliasProperty>
        <Name>FriendlyName</Name>
        <ReferencedMemberName>DisplayName</ReferencedMemberName>
      </AliasProperty>
      <AliasProperty>
        <Name>ValueByName</Name>
        <ReferencedMemberName>ByPropertyName</ReferencedMemberName>
      </AliasProperty>
      <AliasProperty>
        <Name>ValueFromPipeline</Name>
        <ReferencedMemberName>FromPipeline</ReferencedMemberName>
      </AliasProperty>
      <AliasProperty>
        <Name>ValueFromPipelineByPropertyName</Name>
        <ReferencedMemberName>ByPropertyName</ReferencedMemberName>
      </AliasProperty>
      <AliasProperty>
        <Name>ValueFromRemaining</Name>
        <ReferencedMemberName>FromUnbound</ReferencedMemberName>
      </AliasProperty>
      <AliasProperty>
        <Name>ValueFromRemainingArguments</Name>
        <ReferencedMemberName>FromUnbound</ReferencedMemberName>
      </AliasProperty>
      <AliasProperty>
        <Name>VBN</Name>
        <ReferencedMemberName>ByPropertyName</ReferencedMemberName>
      </AliasProperty>
      <AliasProperty>
        <Name>VFP</Name>
        <ReferencedMemberName>FromPipeline</ReferencedMemberName>
      </AliasProperty>
      <AliasProperty>
        <Name>VFPBN</Name>
        <ReferencedMemberName>ByPropertyName</ReferencedMemberName>
      </AliasProperty>
      <ScriptProperty>
        <Name>Binding</Name>
        <GetScriptBlock>
                        $isBindable = $false
foreach ($attr in $this.Attributes) {
    $reflectedType = $attr.TypeName.GetReflectionType()
    if ((-not $reflectedType) -or
        $reflectedType -notin [ComponentModel.DefaultBindingPropertyAttribute],
        [ComponentModel.BindableAttribute],
        [ComponentModel.ComplexBindingPropertiesAttribute]) {
        continue
    }
    
    $positionalArguments = @(
        foreach ($positionalParameter in $attr.PositionalArguments) {
            $positionalParameter.Value
        }
    )
    $realAttribute =
        if ($positionalArguments) {
            $reflectedType::new($positionalArguments)
        } else {
            $reflectedType::new()
        }
    
    
    foreach ($namedArgument in $attr.NamedArguments) {
        if ($namedArgument.ArgumentName -eq 'Name') {
            $realAttribute.$($namedArgument.ArgumentName) = $namedArgument.Argument.Value
        }
    }
    $realAttribute
}

                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>ByPropertyName</Name>
        <GetScriptBlock>
                        foreach ($attr in $this.Attributes) {
    $reflectedType = $attr.TypeName.GetReflectionType()
    if ($reflectedType -ne [Management.Automation.ParameterAttribute]) {
        continue
    }
    foreach ($namedArgument in $attr.NamedArguments) {
        if ($namedArgument.ArgumentName -ne 'ValueFromPipelineByPropertyName') {
            continue
        }
        if ($namedArgument.Argument -and $namedArgument.Argument.Value) {
            return $true
        } elseif (-not $namedArgument.Argument) {
            return $true
        }
    }
}

return $false
                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>DefaultBindingProperty</Name>
        <GetScriptBlock>
                        $isBindable = $false
foreach ($attr in $this.Attributes) {
    $reflectedType = $attr.TypeName.GetReflectionType()
    if ($reflectedType -ne [ComponentModel.DefaultBindingPropertyAttribute]) {
        if ($reflectedType -eq [ComponentModel.BindableAttribute]) {
            if ($attr.PositionalArguments.Value -eq $false) {
                return ''
            } else {
                $isBindable = $true
            }
        }
        continue
    }
    
    foreach ($positionalParameter in $attr.PositionalArguments) {
        return $positionalParameter.Value
    }

    foreach ($namedArgument in $attr.NamedArguments) {
        if ($namedArgument.ArgumentName -eq 'Name') {
            return $namedArgument.Argument.Value
        }
    }
}


if ($isBindable) {
    return $this.Name.VariablePath.ToString()
} else {
    return ''
}
                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>DisplayName</Name>
        <GetScriptBlock>
                        foreach ($attr in $this.Attributes) {
    $reflectedType = $attr.TypeName.GetReflectionType()
    if ($reflectedType -ne [ComponentModel.DisplayNameAttribute]) {
        continue
    }
    
    foreach ($positionalParameter in $attr.PositionalArguments) {
        return $positionalParameter.Value
    }

    foreach ($namedArgument in $attr.NamedArguments) {
        if ($namedArgument.ArgumentName -eq 'DisplayName') {
            return $namedArgument.Argument.Value
        }
    }
}

return $this.Name.VariablePath.ToString()
                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>FromPipeline</Name>
        <GetScriptBlock>
                        foreach ($attr in $this.Attributes) {
    $reflectedType = $attr.TypeName.GetReflectionType()
    if ($reflectedType -ne [Management.Automation.ParameterAttribute]) {
        continue
    }
    foreach ($namedArgument in $attr.NamedArguments) {
        if ($namedArgument.ArgumentName -ne 'ValueFromPipeline') {
            continue
        }
        if ($namedArgument.Argument -and $namedArgument.Argument.Value) {
            return $true
        } elseif (-not $namedArgument.Argument) {
            return $true
        }
    }
}

return $false
                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>FromUnbound</Name>
        <GetScriptBlock>
                        foreach ($attr in $this.Attributes) {
    $reflectedType = $attr.TypeName.GetReflectionType()
    if ($reflectedType -ne [Management.Automation.ParameterAttribute]) {
        continue
    }
    foreach ($namedArgument in $attr.NamedArguments) {
        if ($namedArgument.ArgumentName -ne 'ValueFromRemainingArguments') {
            continue
        }
        if ($namedArgument.Argument -and $namedArgument.Argument.Value) {
            return $true
        } elseif (-not $namedArgument.Argument) {
            return $true
        }
    }
}

return $false
                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>Help</Name>
        <GetScriptBlock>
                        $parameter = $this
$parameterIndex = $parameter.Parent.Parameters.IndexOf($this)

if ($parameterIndex -eq 0) { # For the first parameter
    $parentExtent = $parameter.Parent.Extent.ToString()
    # This starts after the first parenthesis.
    $afterFirstParens = $parentExtent.IndexOf('(') + 1
    # and goes until the start of the parameter.
    $parentExtent.Substring($afterFirstParens,
        $parameter.Extent.StartOffset -
            $parameter.Parent.Extent.StartOffset -
                $afterFirstParens) -replace '^[\s\r\n]+'
    # (don't forget to trim leading whitespace)
} else {
    # for every other parameter it is the content between parameters.
    $lastParameter = $parameter.Parent.Parameters[$parameterIndex - 1]
    $relativeOffset = $lastParameter.Extent.EndOffset + 1 - $parameter.Parent.Extent.StartOffset
    $distance = $parameter.Extent.StartOffset - $lastParameter.Extent.EndOffset - 1
    # (don't forget to trim leading whitespace and commas)
    $parameter.Parent.Extent.ToString().Substring($relativeOffset,$distance) -replace '^[\,\s\r\n]+'
}
                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>Index</Name>
        <GetScriptBlock>
                        $this.Parent.Parameters.IndexOf($this)

                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>Metadata</Name>
        <GetScriptBlock>
                        $metadata = [Ordered]@{}

foreach ($attr in $this.Attributes) {
    $reflectedType = $attr.TypeName.GetReflectionType()
    if ($reflectedType -ne [Reflection.AssemblyMetadataAttribute]) {
        continue
    }
    $key, $value =
        foreach ($positionalParameter in $attr.PositionalArguments) {
            $positionalParameter.Value
        }

    foreach ($namedArgument in $attr.NamedArguments) {
        if ($namedArgument.ArgumentName -eq 'Key') {
            $key = $namedArgument.Argument.Value
        }
        elseif ($namedArgument.ArgumentName -eq 'Value') {
            $value = $namedArgument.Argument.Value
        }
    }
    if (-not $metadata[$key]) {
        $metadata[$key] = $value
    } else {
        $metadata[$key] = @($metadata[$key]) + $value
    }
}

return $metadata
                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>ParameterNames</Name>
        <GetScriptBlock>
                        @(foreach ($attr in $this.Attributes) {
    $reflectedType = $attr.TypeName.GetReflectionType()
    if ($reflectedType -ne [Alias]) {
        continue
    }
    
    foreach ($positionalParameter in $attr.PositionalArguments) {
        $positionalParameter.Value
    }

    foreach ($namedArgument in $attr.NamedArguments) {
        if ($namedArgument.ArgumentName -eq 'AliasNames') {
            $namedArgument.Argument.Value
        }
    }
}

$this.Name.VariablePath.ToString())
                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>ParameterSets</Name>
        <GetScriptBlock>
                        $parameterSetNames = @(foreach ($attr in $this.Attributes) {
    $reflectedType = $attr.TypeName.GetReflectionType()
    if ($reflectedType -ne [Management.Automation.ParameterAttribute]) {
        continue
    }
    foreach ($namedArgument in $attr.NamedArguments) {
        if ($namedArgument.ArgumentName -eq 'ParameterSetName') {
            $namedArgument.Argument.Value
        }
    }
})

if ($parameterSetNames) {
    $parameterSetNames -as [string[]]
} else {
    "__AllParameterSets" -as [string[]]
}
                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>Position</Name>
        <GetScriptBlock>
                        $positions = @(
:nextAttribute foreach ($attr in $this.Attributes) {
    $reflectedType = $attr.TypeName.GetReflectionType()
    if ($reflectedType -ne [Management.Automation.ParameterAttribute]) {
        continue
    }
    foreach ($namedArgument in $attr.NamedArguments) {
        if ($namedArgument.ArgumentName -eq 'Position') {
            $namedArgument.Argument.Value
            continue nextAttribute
        }
    }
})

if ($positions.Length -gt 1) {
    $positions -as [int[]]
} elseif ($positions) {
    $positions[0]
} else {
    $null
}
                    </GetScriptBlock>
      </ScriptProperty>
    </Members>
  </Type>
  <Type>
    <Name>System.Management.Automation.Language.PipelineAST</Name>
    <Members>
      <ScriptProperty>
        <Name>IsAssigned</Name>
        <GetScriptBlock>
                        $this.Parent -and
$this.Parent.GetType().Name -in 'AssignmentStatementAST', 'HashtableAST'

                    </GetScriptBlock>
      </ScriptProperty>
    </Members>
  </Type>
  <Type>
    <Name>PipeScript</Name>
    <Members>
      <ScriptProperty>
        <Name>PipeScriptType</Name>
        <GetScriptBlock>
                        
if ($this.pstypenames -like '*.Command') {
    $this.pstypenames -like '*.Command' -replace '\.Command'
} else {
    if ($this.Source -match '\.psx\.ps1{0,1}$') {
        "Transpiler"
    }
    elseif ($this.Source -match "\.ps1{0,1}\.(?&lt;ext&gt;[^.]+$)") {
        "Template"
    }
    elseif ($this.Source -match '(?&lt;=(?&gt;^|\.))build\.ps1$') {
        "BuildScript"
    }
    elseif (($this.Source -match '\.[^\.\\/]+\.ps1$')) {
        "ExtensionScript"
    }
    elseif ($this.Source) {
        "PipeScriptFile"
    }
    else {
        "Function"
    }
}
                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>Template</Name>
        <GetScriptBlock>
                        $potentialTemplatePaths =
    @(
        $this.Source -replace '\.ps1$', '.ps.ps1'
        $this.Source -replace '\.ps1$', '.ps1.ps1'
    )

foreach ($potentialTemplatePath in $potentialTemplatePaths ) {
    if (Test-Path $potentialTemplatePath) {
        return (Get-PipeScript -PipeScriptPath $potentialTemplatePath)
    }
}


                    </GetScriptBlock>
      </ScriptProperty>
    </Members>
  </Type>
  <Type>
    <Name>PipeScript.Interpreters</Name>
    <Members>
      <AliasProperty>
        <Name>ExcludePaths</Name>
        <ReferencedMemberName>ExcludePaths</ReferencedMemberName>
      </AliasProperty>
      <AliasProperty>
        <Name>ExcludePatterns</Name>
        <ReferencedMemberName>ExcludePatterns</ReferencedMemberName>
      </AliasProperty>
      <AliasProperty>
        <Name>Excludes</Name>
        <ReferencedMemberName>Exclude</ReferencedMemberName>
      </AliasProperty>
      <AliasProperty>
        <Name>LanguageNames</Name>
        <ReferencedMemberName>LanguageName</ReferencedMemberName>
      </AliasProperty>
      <ScriptMethod>
        <Name>ForFile</Name>
        <Script>
                        &lt;#
.SYNOPSIS
    Gets the language for a file.
.DESCRIPTION
    Gets the PipeScript language definitions for a path.
.EXAMPLE
    $PSLanguage.ForFile("a.xml")
.EXAMPLE
    $PSInterpreters.ForFile("a.js")
#&gt;
param(
# The path to the file, or the name of the command.
[string]
$FilePath
)

foreach ($excludePattern in $this.ExcludePattern) {
    if ($filePath -match $excludePattern) { return }
}

foreach ($excludePath in $this.ExcludePath) {
    if (-not $excludePath) { continue }
    if ($filePath -like $excludePath) { return }
}

foreach ($prop in $this.psobject.properties) {
    if ($prop -is [psscriptproperty]) { continue }
    if ($prop.IsInstance -and
        $prop.Value.LanguageName -and
        $prop.Value.FilePattern -and
        $filePath -match $prop.Value.FilePattern) {
        $prop.Value
    }
}


                    </Script>
      </ScriptMethod>
      <ScriptProperty>
        <Name>All</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Gets all Languages
.DESCRIPTION
    Gets all currently loaded language definitions in PipeScript.
#&gt;
,@(foreach ($psProperty in $this.PSObject.properties) {
    if ($psProperty -isnot [psnoteproperty]) { continue }
    if ($psProperty.IsInstance -and $psProperty.Value.LanguageName) {
        $psProperty.Value
    }
})
                    </GetScriptBlock>
        <SetScriptBlock>
                        &lt;#
.SYNOPSIS
    Gets all Languages
.DESCRIPTION
    Gets all currently loaded language definitions in PipeScript.
#&gt;
,@(foreach ($psProperty in $this.PSObject.properties) {
    if ($psProperty -isnot [psnoteproperty]) { continue }
    if ($psProperty.IsInstance -and $psProperty.Value.LanguageName) {
        $psProperty.Value
    }
})
                    </SetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>Count</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Gets the number of loaded languages.
.DESCRIPTION
    Gets the number of language definitions loaded by PipeScript.
.EXAMPLE
    $PSLanguage.Count
#&gt;
$count= 0
foreach ($prop in $this.psobject.properties) {
    if ($prop -is [psscriptproperty]) { continue }
    if ($prop.IsInstance -and $prop.Value.LanguageName) {
        $count++
    }
}
return $count
                    </GetScriptBlock>
        <SetScriptBlock>
                        &lt;#
.SYNOPSIS
    Gets the number of loaded languages.
.DESCRIPTION
    Gets the number of language definitions loaded by PipeScript.
.EXAMPLE
    $PSLanguage.Count
#&gt;
$count= 0
foreach ($prop in $this.psobject.properties) {
    if ($prop -is [psscriptproperty]) { continue }
    if ($prop.IsInstance -and $prop.Value.LanguageName) {
        $count++
    }
}
return $count
                    </SetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>Exclude</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Gets Languages Exclusions
.DESCRIPTION
    Gets any excluded patterns and paths for languages in PipeScript.

    If a command matches any of these patterns, it should not be interpreted.
#&gt;
param()


return @(
    $this.ExcludePattern
    $this.ExcludePath
)
                    </GetScriptBlock>
        <SetScriptBlock>
                        &lt;#
.SYNOPSIS
    Gets Languages Exclusions
.DESCRIPTION
    Gets any excluded patterns and paths for languages in PipeScript.

    If a command matches any of these patterns, it should not be interpreted.
#&gt;
param()


return @(
    $this.ExcludePattern
    $this.ExcludePath
)
                    </SetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>ExcludePath</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Gets Excluded Paths for all languages.
.DESCRIPTION
    Gets any excluded paths for interpreted languages in PipeScript.

    If a command is like any of these paths, it should not be interpreted.
#&gt;
param()

if ($null -eq $this.'.ExcludePath'.Length) {
    Add-Member -InputObject $this -Force -MemberType NoteProperty -Name '.ExcludePath' -Value @()
}

return $this.'.ExcludePath'
                    </GetScriptBlock>
        <SetScriptBlock>
                        &lt;#
.SYNOPSIS
    Gets Excluded Paths for all languages.
.DESCRIPTION
    Gets any excluded paths for interpreted languages in PipeScript.

    If a command is like any of these paths, it should not be interpreted.
#&gt;
param()

if ($null -eq $this.'.ExcludePath'.Length) {
    Add-Member -InputObject $this -Force -MemberType NoteProperty -Name '.ExcludePath' -Value @()
}

return $this.'.ExcludePath'
                    </SetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>ExcludePattern</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Gets Language Exclusion Patterns
.DESCRIPTION
    `$psLanguages.ExcludePattern` and `$psInterpreters.ExcludePattern` contain the patterns excluded from interpretation.

    If a command matches any of these patterns, it should not be interpreted.
#&gt;
param()

if (-not $this.'.ExcludePattern') {
    Add-Member -InputObject $this -Force -MemberType NoteProperty -Name '.ExcludePattern' @(
        [Regex]::new('\.ps1?\.','IgnoreCase')
        [Regex]::new('://.')
    )
}

return $this.'.ExcludePattern'
                    </GetScriptBlock>
        <SetScriptBlock>
                        &lt;#
.SYNOPSIS
    Gets Language Exclusion Patterns
.DESCRIPTION
    `$psLanguages.ExcludePattern` and `$psInterpreters.ExcludePattern` contain the patterns excluded from interpretation.

    If a command matches any of these patterns, it should not be interpreted.
#&gt;
param()

if (-not $this.'.ExcludePattern') {
    Add-Member -InputObject $this -Force -MemberType NoteProperty -Name '.ExcludePattern' @(
        [Regex]::new('\.ps1?\.','IgnoreCase')
        [Regex]::new('://.')
    )
}

return $this.'.ExcludePattern'
                    </SetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>LanguageName</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Gets the loaded language names.
.DESCRIPTION
    Gets the names of language definitions loaded by PipeScript.
.EXAMPLE
    $PSLanguage.LanguageName
#&gt;

,@(foreach ($prop in $this.psobject.properties) {
    if ($prop -is [psscriptproperty]) { continue }
    if ($prop.IsInstance -and $prop.Value.LanguageName) {
        $prop.Value.LanguageName
    }
})
                    </GetScriptBlock>
        <SetScriptBlock>
                        &lt;#
.SYNOPSIS
    Gets the loaded language names.
.DESCRIPTION
    Gets the names of language definitions loaded by PipeScript.
.EXAMPLE
    $PSLanguage.LanguageName
#&gt;

,@(foreach ($prop in $this.psobject.properties) {
    if ($prop -is [psscriptproperty]) { continue }
    if ($prop.IsInstance -and $prop.Value.LanguageName) {
        $prop.Value.LanguageName
    }
})
                    </SetScriptBlock>
      </ScriptProperty>
      <NoteProperty>
        <Name>README</Name>
        <Value>PipeScript works with a number of Languages.

A Language is defined a function named Language.NameOfLanguage.

Languages may define an .Interpreter command or script.

If they do, that language can be interpretered within PipeScript.

## Languages with Interpreters

The following languages support interpreters.

* ATOM
* Bash
* Batch
* Dart
* Go
* JavaScript
* JSON
* Lua
* Perl
* PHP
* PowerShellData
* Python
* R
* RSS
* Ruby
* SVG
* Wren
* XML
* XSD
* XSL

Note: Interpreters may require commands to be installed.
</Value>
      </NoteProperty>
    </Members>
  </Type>
  <Type>
    <Name>PipeScript.Languages</Name>
    <Members>
      <AliasProperty>
        <Name>ExcludePaths</Name>
        <ReferencedMemberName>ExcludePaths</ReferencedMemberName>
      </AliasProperty>
      <AliasProperty>
        <Name>ExcludePatterns</Name>
        <ReferencedMemberName>ExcludePatterns</ReferencedMemberName>
      </AliasProperty>
      <AliasProperty>
        <Name>Excludes</Name>
        <ReferencedMemberName>Exclude</ReferencedMemberName>
      </AliasProperty>
      <AliasProperty>
        <Name>LanguageNames</Name>
        <ReferencedMemberName>LanguageName</ReferencedMemberName>
      </AliasProperty>
      <ScriptMethod>
        <Name>ForFile</Name>
        <Script>
                        &lt;#
.SYNOPSIS
    Gets the language for a file.
.DESCRIPTION
    Gets the PipeScript language definitions for a path.
.EXAMPLE
    $PSLanguage.ForFile("a.xml")
.EXAMPLE
    $PSInterpreters.ForFile("a.js")
#&gt;
param(
# The path to the file, or the name of the command.
[string]
$FilePath
)

foreach ($excludePattern in $this.ExcludePattern) {
    if ($filePath -match $excludePattern) { return }
}

foreach ($excludePath in $this.ExcludePath) {
    if (-not $excludePath) { continue }
    if ($filePath -like $excludePath) { return }
}

foreach ($prop in $this.psobject.properties) {
    if ($prop -is [psscriptproperty]) { continue }
    if ($prop.IsInstance -and
        $prop.Value.LanguageName -and
        $prop.Value.FilePattern -and
        $filePath -match $prop.Value.FilePattern) {
        $prop.Value
    }
}


                    </Script>
      </ScriptMethod>
      <ScriptProperty>
        <Name>All</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Gets all Languages
.DESCRIPTION
    Gets all currently loaded language definitions in PipeScript.
#&gt;
,@(foreach ($psProperty in $this.PSObject.properties) {
    if ($psProperty -isnot [psnoteproperty]) { continue }
    if ($psProperty.IsInstance -and $psProperty.Value.LanguageName) {
        $psProperty.Value
    }
})
                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>Count</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Gets the number of loaded languages.
.DESCRIPTION
    Gets the number of language definitions loaded by PipeScript.
.EXAMPLE
    $PSLanguage.Count
#&gt;
$count= 0
foreach ($prop in $this.psobject.properties) {
    if ($prop -is [psscriptproperty]) { continue }
    if ($prop.IsInstance -and $prop.Value.LanguageName) {
        $count++
    }
}
return $count
                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>Exclude</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Gets Languages Exclusions
.DESCRIPTION
    Gets any excluded patterns and paths for languages in PipeScript.

    If a command matches any of these patterns, it should not be interpreted.
#&gt;
param()


return @(
    $this.ExcludePattern
    $this.ExcludePath
)
                    </GetScriptBlock>
        <SetScriptBlock>
                        &lt;#
.SYNOPSIS
    Sets language exclusions
.DESCRIPTION
    Gets any excluded patterns and paths for languages in PipeScript.
.NOTES
    If you provide a `[regex]`, it will set `.ExcludePattern`.
    Otherwise, this will set `.ExcludePath`.
#&gt;
$unrolledArgs = $args | . { process { $_ } }
$patterns = @()
$paths = @(
foreach ($arg in $unrolledArgs) {
    if ($arg -is [Regex]) {
        $patterns += $arg
    } else {
        "$arg"
    }
})

if ($patterns) {
    $this.ExcludePattern = $patterns
}
if ($paths) {
    $this.ExcludePath = $paths
}

                    </SetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>ExcludePath</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Gets Excluded Paths for all languages.
.DESCRIPTION
    Gets any excluded paths for interpreted languages in PipeScript.

    If a command is like any of these paths, it should not be interpreted.
#&gt;
param()

if ($null -eq $this.'.ExcludePath'.Length) {
    Add-Member -InputObject $this -Force -MemberType NoteProperty -Name '.ExcludePath' -Value @()
}

return $this.'.ExcludePath'
                    </GetScriptBlock>
        <SetScriptBlock>
                        &lt;#
.SYNOPSIS
    Changes the Exclusion Paths
.DESCRIPTION
    Sets any excluded paths for interpreted languages in PipeScript.

    If a command matches any of these patterns, it should not be interpreted.
.NOTES
    Excluded paths will be processed as wildcards.
#&gt;
$paths = @(foreach ($arg in $args | . { process { $_ }}) {
    "$arg"
})

Add-Member -InputObject $this -Force -MemberType NoteProperty -Name '.ExcludePath' -Value $paths

                    </SetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>ExcludePattern</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Gets Language Exclusion Patterns
.DESCRIPTION
    `$psLanguages.ExcludePattern` and `$psInterpreters.ExcludePattern` contain the patterns excluded from interpretation.

    If a command matches any of these patterns, it should not be interpreted.
#&gt;
param()

if (-not $this.'.ExcludePattern') {
    Add-Member -InputObject $this -Force -MemberType NoteProperty -Name '.ExcludePattern' @(
        [Regex]::new('\.ps1?\.','IgnoreCase')
        [Regex]::new('://.')
    )
}

return $this.'.ExcludePattern'
                    </GetScriptBlock>
        <SetScriptBlock>
                        &lt;#
.SYNOPSIS
    Changes the Exclusion Patterns
.DESCRIPTION
    Sets any excluded patterns for interpreted languages in PipeScript.

    If a command matches any of these patterns, it should not be interpreted.
.NOTES
    Under most circumstances, this should not be set.
    
    Setting this may cause Templates and Protocols to stop working (for interpretable languages)
#&gt;
$patterns = @(foreach ($arg in $args | . { process { $_ }}) {
    [Regex]::new("$arg","IgnoreCase,IgnorePatternWhitespace","00:00:00.1")
})

Add-Member -InputObject $this -Force -MemberType NoteProperty -Name '.ExcludePattern' -Value $patterns

                    </SetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>LanguageName</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Gets the loaded language names.
.DESCRIPTION
    Gets the names of language definitions loaded by PipeScript.
.EXAMPLE
    $PSLanguage.LanguageName
#&gt;

,@(foreach ($prop in $this.psobject.properties) {
    if ($prop -is [psscriptproperty]) { continue }
    if ($prop.IsInstance -and $prop.Value.LanguageName) {
        $prop.Value.LanguageName
    }
})
                    </GetScriptBlock>
      </ScriptProperty>
      <NoteProperty>
        <Name>README</Name>
        <Value>PipeScript works with a number of Languages.

A Language is defined a function named Language.NameOfLanguage.

PipeScript presently ships with 68 languages:

* ADA
* Arduino
* ATOM
* Bash
* BASIC
* Batch
* Bicep
* BrightScript
* C
* C3
* Conf
* CPlusPlus
* Crystal
* CSharp
* CSS
* Dart
* Docker
* Eiffel
* FSharp
* GCode
* GLSL
* Go
* Haxe
* HCL
* HLSL
* HTML
* Java
* JavaScript
* JSON
* Kotlin
* Kusto
* LaTeX
* Liquid
* Lua
* Markdown
* ObjectiveC
* OpenSCAD
* Perl
* PHP
* PipeScript
* PowerShell
* PowerShellData
* PowerShellXML
* Python
* R
* Racket
* Razor
* RSS
* Ruby
* Rust
* Scala
* SQL
* SVG
* TCL
* TOML
* TypeScript
* Vue
* WebAssembly
* Wren
* XAML
* XML
* XSD
* XSL
* YAML

</Value>
      </NoteProperty>
    </Members>
  </Type>
  <Type>
    <Name>PipeScript.net</Name>
    <Members>
      <NoteProperty>
        <Name>PSNodeJob.cs</Name>
        <Value>namespace PipeScript.Net
{
    using System;
    using System.ComponentModel;
    using System.Collections;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.IO;
    using System.Text;
    using System.Text.RegularExpressions;
    using System.Timers;
    using System.Threading;
    using System.Management.Automation;
    using System.Management.Automation.Runspaces;
    using System.Net;
    #if Windows
    using Microsoft.Win32;
    using System.Security.Principal;
    #endif
    using System.Web;
    
    
    public class PSNodeJob : Job
    {
        static RunspacePool runspacePool;
        PowerShell powerShellCommand;
        int bufferSize = 262144;
        uint poolSize = 3;
        TimeSpan sessionTimeout = TimeSpan.FromMinutes(15);
        Dictionary&lt;string, string&gt; MimeTypes = new Dictionary&lt;string, string&gt;();
        RunspacePool _PSNodePool;
        ScriptBlock _PSNodeAction;
        ScriptBlock _FullPSNodeAction;
        PSNodeJob parentJob = null;
        AuthenticationSchemes authenticationType = AuthenticationSchemes.Anonymous;
        private string PSNodeScriptPreface = @"
&lt;#ScriptPreface#&gt;
";
                       
        static PSNodeJob()
        {
            InitialSessionState iss = InitialSessionState.CreateDefault();
            //#StartWindowsOnly
            iss.ThreadOptions = PSThreadOptions.UseNewThread;
            iss.ApartmentState = ApartmentState.STA;
            //#EndWindowsOnly
            runspacePool = RunspaceFactory.CreateRunspacePool(iss);
            runspacePool.Open();
            AppDomain.CurrentDomain.ProcessExit += PooledJob_Exiting;
        }

        RunspacePool PSNodePool
        {
            get
            {
                if (_PSNodePool == null || _PSNodePool.RunspacePoolStateInfo.State != RunspacePoolState.Opened)
                {
                    InitialSessionState iss = InitialSessionState.CreateDefault();
                    if (this.ImportModule != null) {
                        iss.ImportPSModule(this.ImportModule);
                    }
                    if (this.DeclareFunction != null) {
                        foreach (FunctionInfo df in this.DeclareFunction) {
                            iss.Commands.Add(new SessionStateFunctionEntry(df.Name, df.Definition));
                        }
                    }
                    if (this.DeclareAlias != null) {
                        foreach (AliasInfo af in this.DeclareAlias) {
                            iss.Commands.Add(new SessionStateAliasEntry(af.Name, af.Definition));
                        }
                    }

                    if (this.ImportTypeFile != null) {
                        foreach (string typeFile in this.ImportTypeFile) {
                            iss.Types.Add(new SessionStateTypeEntry(typeFile));
                        }
                    }

                    if (this.ImportFormatFile != null) {
                        foreach (string formatFile in this.ImportFormatFile) {
                            iss.Formats.Add(new SessionStateFormatEntry(formatFile));
                        }
                    }

                    _PSNodePool = RunspaceFactory.CreateRunspacePool(iss);
                    //#StartWindowsOnly
                    _PSNodePool.ThreadOptions = PSThreadOptions.UseNewThread;
                    _PSNodePool.ApartmentState = System.Threading.ApartmentState.STA;
                    //#EndWindowsOnly
                    _PSNodePool.SetMaxRunspaces((int)PoolSize);
                    _PSNodePool.Open();
                }
                return _PSNodePool;
            }
        }

        public HttpListener Listener { get; set; }
        public bool AllowBrowseDirectory { get; set; }
        public bool AllowScriptExecution { get; set; }
        public string CORS { get; set;}
        public AuthenticationSchemes AuthenticationType {
            get {
                return authenticationType;
            }
            
            set {
                authenticationType = value;
            }
        }
        public FunctionInfo[] DeclareFunction { get; set; }
        public AliasInfo[] DeclareAlias { get; set; }
        public string[] ImportTypeFile { get; set; }
        public string[] ImportFormatFile { get; set; }
        public string[] FileBlacklist { get; set; }
        public int BufferSize {
            get { return bufferSize; }
            set { bufferSize = value; }
        }
        public string[] ImportModule { get; set; }
        public string[] ListenerLocation { get; set; }
        public uint PoolSize {
            get {
                return poolSize;
            } set {
                poolSize = value;
            }
        }
        public string RootPath { get; set; }
        public TimeSpan SessionTimeout { get { return sessionTimeout; } set { sessionTimeout = value; } }
        public ScriptBlock PSNodeAction {
            get {
                return _PSNodeAction;
            }
            
            set {
                _PSNodeAction = value;
                _FullPSNodeAction = ScriptBlock.Create(this.PSNodeScriptPreface + _PSNodeAction.ToString());
            }
        }

        public AsyncCallback Callback {
            get {
                return new AsyncCallback(this.ListenerCallback);
            }
        }

        

        static void PooledJob_Exiting(object sender, EventArgs e) {
            runspacePool.Close();
            runspacePool.Dispose();
            runspacePool = null;
        }

        public PSNodeJob(string name, string command, ScriptBlock scriptBlock)
            : base(command, name)
        {}

        private PSNodeJob(ScriptBlock scriptBlock)
        {}
        
        
        public PSNodeJob(string name, string command, ScriptBlock scriptBlock, Hashtable parameters)
            : base(command, name)
        {}

        public PSNodeJob(string name, string command, ScriptBlock scriptBlock, Hashtable parameters, PSObject[] argumentList)
            : base(command, name)
        {}

        private PSNodeJob(string name, string command, ScriptBlock scriptBlock, Hashtable parameters, PSObject[] argumentList, bool isChildJob)
            : base(command, name)
        {
            if (! isChildJob) {
                PSNodeJob childJob = new PSNodeJob(name, command, scriptBlock, parameters, argumentList, true);
                childJob.StateChanged += new EventHandler&lt;JobStateEventArgs&gt;(childJob_StateChanged);
                this.ChildJobs.Add(childJob);
            }
        }


        void childJob_StateChanged(object sender, JobStateEventArgs e)
        {
            this.SetJobState(e.JobStateInfo.State);
        }

        /// &lt;summary&gt;
        /// Synchronizes Job State with Background Runspace
        /// &lt;/summary&gt;
        /// &lt;param name="sender"&gt;&lt;/param&gt;
        /// &lt;param name="e"&gt;&lt;/param&gt;
        void powerShellCommand_InvocationStateChanged(object sender, PSInvocationStateChangedEventArgs e)
        {
            try
            {
                if (e.InvocationStateInfo.State == PSInvocationState.Failed)
                {
                    ErrorRecord err = new ErrorRecord(e.InvocationStateInfo.Reason, "JobFailed", ErrorCategory.OperationStopped, this);
                    Error.Add(err);
                }
                JobState js = (JobState)Enum.Parse(typeof(JobState), e.InvocationStateInfo.State.ToString(), true);
                this.SetJobState(js);
            }
            catch (Exception ex) {
                this.Error.Add(new ErrorRecord(ex, "PSNode.Unknown.Error", ErrorCategory.NotSpecified, this));
            }
        }

        public void ServeFile(string fullPath, HttpListenerRequest request, HttpListenerResponse response) {
            if (File.Exists(fullPath)) {
                FileInfo fileInfo = new FileInfo(fullPath);
                if (FileBlacklist != null ){
                    foreach (string f in FileBlacklist) {
                        WildcardPattern wp = new WildcardPattern(f, WildcardOptions.IgnoreCase);
                        if (wp.IsMatch(fileInfo.FullName)) {
                            return;
                        }
                    }
                }
                if (MimeTypes.ContainsKey(fileInfo.Extension.ToLower())) {
                    response.ContentType = MimeTypes[fileInfo.Extension.ToLower()];
                }
                int read = 0;
                if (request.HttpMethod.ToUpper() == "HEAD") {
                    response.ContentLength64 = fileInfo.Length;
                    response.OutputStream.Close();
                    return;
                }
                response.Headers["Accept-Ranges"] = "bytes";
                long start = 0;
                long end = fileInfo.Length;
                if (!String.IsNullOrEmpty(request.Headers["Range"])) {
                    
                    var RangeMatch = Regex.Match(request.Headers["Range"], "bytes=(?&lt;Start&gt;\\d{1,})(-(?&lt;End&gt;\\d{1,})){0,1}");
                    if (RangeMatch != null &amp;&amp;
                        RangeMatch.Groups["Start"].Success &amp;&amp;
                        RangeMatch.Groups["End"].Success) {
                        start = long.Parse(RangeMatch.Groups["Start"].ToString());
                        end = long.Parse(RangeMatch.Groups["End"].ToString());
                    }
                }

                
                using ( var fs = File.OpenRead(fullPath)) {
                    if (start &gt; 0 &amp;&amp; end &gt; 0) {
                        byte[] buffer = new byte[this.BufferSize];
                        fs.Seek(start, SeekOrigin.Begin);
                        read = fs.Read(buffer, 0, this.BufferSize);
                        string contentRange = start.ToString() + "-" + (start + read - 1).ToString() +
                            "/" + fs.Length.ToString();
                        response.StatusCode = 206;
                        response.ContentLength64 = read;
                        response.Headers.Add("Content-Range", contentRange);
                        response.OutputStream.Write(buffer, 0, read);
                        response.OutputStream.Close();
                    } else {
                        response.ContentLength64 = fs.Length;
                        fs.CopyTo(response.OutputStream);
                        response.OutputStream.Close();
                    }
                    
                }

                response.Close();
                return;
            }
        }

        Dictionary&lt;string, PSObject&gt; UserSessions = new Dictionary&lt;string, PSObject&gt;();

        Dictionary&lt;string, string&gt; ContentTypeCommands = new Dictionary&lt;string, string&gt;(StringComparer.OrdinalIgnoreCase);
        
        System.Timers.Timer SessionTimer = null;
        Dictionary&lt;string, Object&gt; Application = new Dictionary&lt;string, Object&gt;();

        public Cookie NewSessionCookie() {
            string sessionGuid = Guid.NewGuid().ToString();
            Cookie sessionKey = new Cookie("SessionKey", sessionGuid);
            sessionKey.Expires = DateTime.UtcNow.AddMinutes(15);
            UserSessions[sessionGuid] = new PSObject();
            UserSessions[sessionGuid].Properties.Add(new PSNoteProperty("Expires", sessionKey.Expires), true);
            UserSessions[sessionGuid].Properties.Add(new PSNoteProperty("SessionKey", sessionKey.Value), true);
            return sessionKey;
        }

        public void ServeScript(string powerShellScript, HttpListenerContext context) {
            HttpListenerRequest request = context.Request;
            HttpListenerResponse response = context.Response;

            PSObject session = null;
            
            // If we're serving a script, we'll want a SessionKey, so we can have _some_ sense of Web Session State.
            if (request.Cookies["SessionKey"] == null) {
                Cookie sessionCookie = NewSessionCookie();
                response.AppendCookie(sessionCookie);
                session = UserSessions[sessionCookie.Value];
            } else {
                string sessionKey = request.Cookies["SessionKey"].Value.ToString();
                if (UserSessions.ContainsKey(sessionKey)) {
                    session = UserSessions[sessionKey];
                    ((PSNoteProperty)UserSessions[sessionKey].Properties["Expires"]).Value = DateTime.UtcNow;
                } else {
                    Cookie sessionCookie = NewSessionCookie();
                    response.AppendCookie(sessionCookie);
                    session = UserSessions[sessionCookie.Value];
                }
            }
            
            string contentType = request.ContentType;
            if (contentType != null) {
                contentType = contentType.ToLower();
            }
           
            using (
                PowerShell command = PowerShell.Create()
                    .AddScript(powerShellScript, false)
                    .AddArgument(request)
                    .AddArgument(response)
                    .AddArgument(context)
                    //#StartWindowsOnly
                    .AddArgument(context.User)
                    //#EndWindowsOnly
                    .AddArgument(session)
                    .AddArgument(this.Application)
                    .AddArgument(this))
            {
                if (String.IsNullOrEmpty(contentType) || contentType.ToLower() == "text/html") {
                    command.AddCommand("Out-Html");
                } else if (request.ContentType != null &amp;&amp; (contentType == "application/json" || contentType == "text/json")) {
                    command.AddCommand("ConvertTo-Json").AddParameter("Compress", true);
                } else if (request.ContentType != null &amp;&amp; contentType == "text/plain") {
                    command.AddCommand("Out-String");
                } else if (request.ContentType != null &amp;&amp; contentType == "application/clixml") {
                    command.AddScript("process { [Management.Automation.PSSerializer]::Serialize($_) }");
                }
                
                command.RunspacePool = PSNodePool;
                if (! string.IsNullOrEmpty(this.CORS)) {
                    response.Headers["Access-Control-Allow-Origin"] = this.CORS;
                }
                
                int offset = 0;

                try
                {
                    foreach (PSObject psObject in command.Invoke&lt;PSObject&gt;())
                    {
                        if (psObject.BaseObject == null) { continue; }
                        byte[] buffer = null;
                        string stringified = psObject.ToString();
                        buffer = System.Text.Encoding.UTF8.GetBytes(stringified);
                        if (response.OutputStream.CanWrite) {
                            response.OutputStream.Write(buffer, 0, buffer.Length);
                        }
                        offset += buffer.Length;
                        buffer = null;
                    }
                    
                    foreach (ErrorRecord err in command.Streams.Error) {
                        string errorString = err.Exception.ToString() + ' ' + err.InvocationInfo.PositionMessage;
                        byte[] buffer = System.Text.Encoding.UTF8.GetBytes(errorString);
                        if (response.OutputStream.CanWrite) {
                            response.OutputStream.Write(buffer, 0, buffer.Length);
                        }
                        offset += buffer.Length;
                        buffer = null;
                    }
                }
                catch (Exception ex)
                {
                    byte[] buffer = System.Text.Encoding.UTF8.GetBytes(ex.Message);
                    response.StatusCode = 500;
                    if (response.OutputStream.CanWrite) {
                        response.OutputStream.Write(buffer, 0, buffer.Length);
                    }
                    offset += buffer.Length;
                    buffer = null;
                }
                finally
                {
                    try {
                        response.Close();
                    } catch (Exception ex) {
                        this.Error.Add(new ErrorRecord(ex, "PSNode.Unknown.Error", ErrorCategory.NotSpecified, this));
                    }
                }
            }
        }

        public void ListenerCallback(IAsyncResult result)
        {
            try
            {
                HttpListener listener = (HttpListener)result.AsyncState;

                // Call EndGetContext to complete the asynchronous operation.
                HttpListenerContext context = listener.EndGetContext(result);
                HttpListenerRequest request = context.Request;
                // Obtain a response object.
                HttpListenerResponse response = context.Response;
                
                if (request.Url.Segments.Length &gt; 2 &amp;&amp; request.Url.Segments[1].ToLower() == "favicon.ico") {
                    response.StatusCode = 200;
                    response.Close();
                    return;
                }

                if (! String.IsNullOrEmpty(this.RootPath)) {
                    string url = request.RawUrl.ToString();
                    url = url.Replace('/', System.IO.Path.DirectorySeparatorChar);
                    url = HttpUtility.UrlDecode(url, Encoding.UTF8);
                    url = url.Substring(1);
                    string fullPath = string.IsNullOrEmpty(url) ? this.RootPath : Path.Combine(this.RootPath, url);
                    
                    if (Directory.Exists(fullPath) &amp;&amp; AllowBrowseDirectory &amp;&amp; fullPath != this.RootPath) {
                        context.Response.ContentType = "text/html";
                        context.Response.ContentEncoding = Encoding.UTF8;
                        using (var sw = new StreamWriter(context.Response.OutputStream)) {
                            sw.WriteLine("&lt;html&gt;");
                            sw.WriteLine("&lt;head&gt;&lt;meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"&gt;&lt;/head&gt;");
                            sw.WriteLine("&lt;body&gt;&lt;ul&gt;");
                            foreach (string d in Directory.GetDirectories(fullPath)) {
                                string link = d.Replace(this.RootPath, "").Replace(System.IO.Path.DirectorySeparatorChar, '/');
                                sw.WriteLine("&lt;li&gt;&amp;lt;DIR&amp;gt; &lt;a href=\"" + link + "\"&gt;" + Path.GetFileName(d) + "&lt;/a&gt;&lt;/li&gt;");
                            }
                            foreach (string f in Directory.GetFiles(fullPath)) {
                                string link = f.Replace(this.RootPath, "").Replace(System.IO.Path.DirectorySeparatorChar, '/');
                                sw.WriteLine("&lt;li&gt;&lt;a href=\"" + link + "\"&gt;" + Path.GetFileName(f) + "&lt;/a&gt;&lt;/li&gt;");
                            }
                            sw.WriteLine("&lt;/ul&gt;&lt;/body&gt;&lt;/html&gt;");
                        }
                        context.Response.OutputStream.Close();
                        return;
                    }
    
                    if (request.Url.Segments[request.Url.Segments.Length - 1].Contains(".")) {
                        if (File.Exists(fullPath)) {
                            FileInfo fileInfo = new FileInfo(fullPath);
                            if (this.AllowScriptExecution &amp;&amp; fileInfo.Extension.ToLower() == ".ps1") {
                                this.ServeScript(File.ReadAllText(fullPath), context);
                            } else {
                                this.ServeFile(fullPath, request, response);
                            }
                            
                            return;
                        }
                    }
                                        
                }

                this.ServeScript(_FullPSNodeAction.ToString(), context);
            }
            catch (Exception e)
            {
                this.Error.Add(new ErrorRecord(e, e.Message, ErrorCategory.NotSpecified, e));
            }
        }
        
        public void WriteOutput(PSObject item) {
            this.Output.Add(item);
        }

        private ElapsedEventHandler elapsedEventHandler = null;
        
        public void Start()
        {
            #if Windows
            WindowsIdentity current = System.Security.Principal.WindowsIdentity.GetCurrent();
            WindowsPrincipal principal = new WindowsPrincipal(current);
            if (!principal.IsInRole(WindowsBuiltInRole.Administrator))
            {
                throw new UnauthorizedAccessException();
            }
            #endif
            if (SessionTimer != null) {
                SessionTimer.Stop();
                SessionTimer.Elapsed -= elapsedEventHandler;
            }
            SessionTimer = new System.Timers.Timer();
            SessionTimer.Interval = 5119;
            elapsedEventHandler = new ElapsedEventHandler(SessionTimerElapsed);
            SessionTimer.Elapsed += elapsedEventHandler;
            SessionTimer.Start();
            
            if (! String.IsNullOrEmpty(this.RootPath)) {
                #if Windows
                RegistryKey hkcr = Microsoft.Win32.Registry.ClassesRoot;
                RegistryKey ctKey = hkcr.OpenSubKey("MIME\\Database\\Content Type");
                foreach (string ctName in ctKey.GetSubKeyNames()) {
                    object extension = ctKey.OpenSubKey(ctName).GetValue("Extension");
                    if (extension != null) {
                        MimeTypes[extension.ToString().ToLower()]= ctName;
                    }
                }
                #endif
                if (! MimeTypes.ContainsKey(".js")) {
                    MimeTypes[".css"] = "text/javascript";
                }
                if (! MimeTypes.ContainsKey(".css")) {
                    MimeTypes[".css"] = "text/css";
                }
            }

            Listener = new HttpListener();

            //this.ListenerLocation = listenerLocation;
            //this.PSNodeAction = scriptblock;
            //this.AuthenticationType = authenticationType;
                

            int max = runspacePool.GetMaxRunspaces();
            runspacePool.SetMaxRunspaces(max + 1);
            powerShellCommand = PowerShell.Create();
            powerShellCommand.RunspacePool = runspacePool;

            powerShellCommand.Streams.Error = this.Error;
            powerShellCommand.Streams.Warning = this.Warning;
            powerShellCommand.Streams.Verbose = this.Verbose;
            powerShellCommand.Streams.Debug = this.Debug;
            //powerShellCommand.Streams.Progress = this.Progress;
            //this.Progress.DataAdded += new EventHandler&lt;DataAddedEventArgs&gt;(Progress_DataAdded);
            PSNodeJob nodeJob = this;
            if (this.parentJob != null) {
                nodeJob = this.parentJob;
            }
            powerShellCommand.AddScript(@"
param($PSNodeJob, $listener)
:ResetPSNode while (1) {
    $AuthenticationType = $PSNodeJob.AuthenticationType
    $ListenerLocation = $PSNodeJob.ListenerLocation
    if ($AuthenticationType) {
        $listener.AuthenticationSchemes =$AuthenticationType
    }
    foreach ($ll in $ListenerLocation) {
        $listener.Prefixes.Add($ListenerLocation);
    }

    # Start the listener to begin listening for requests.
    $listener.IgnoreWriteExceptions = $true;

    try {
        $listener.Start();
    } catch {
        Write-Error -ErrorRecord $_
        return
    }
    
    :NodeIsRunning while (1) {
        $result = $listener.BeginGetContext($PSNodeJob.Callback, $listener);
        if (-not $result) { return }
        $null = $result.AsyncWaitHandle.WaitOne(1kb);
        if (""$($PSNodeJob.ListenerLocation)"" -ne ""$ListenerLocation"" -or
            $PSNodeJob.AuthenticationType -ne $AuthenticationType) {

            if ($listener) {
                $listener.Stop()
                $listener.Close();
                $listener.Prefixes.Clear();
                [GC]::Collect()
            }
            continue ResetPSNode
        }
    }

    $listener.Stop()
    $listener.Close()
    [GC]::Collect()
}", false).AddArgument(nodeJob).AddArgument(this.Listener);
                        
            powerShellCommand.InvocationStateChanged += new EventHandler&lt;PSInvocationStateChangedEventArgs&gt;(powerShellCommand_InvocationStateChanged);
            powerShellCommand.BeginInvoke&lt;Object, PSObject&gt;(null, this.Output);
        }

        
        void SessionTimerElapsed(object sender, ElapsedEventArgs e) {
            try {
                List&lt;string&gt; toRemove = new List&lt;string&gt;();
                foreach (PSObject sessionObject in UserSessions.Values) {
                    try {
                        DateTime sessionExpiresAt = (DateTime)sessionObject.Properties["Expires"].Value;
                        if (sessionExpiresAt != null &amp;&amp; sessionExpiresAt &gt;= DateTime.UtcNow ) {
                            string sessionKey = sessionObject.Properties["SessionKey"].Value as string;
                            toRemove.Add(sessionKey);
                        }
                    }
                    catch (Exception ex) {
                        this.Error.Add(new ErrorRecord(ex, "PSNode.Unknown.Error", ErrorCategory.NotSpecified, this));
                    }
                }

                foreach (string tr in toRemove) {
                    UserSessions.Remove(tr);
                }
            } catch (Exception ex) {
                this.Error.Add(new ErrorRecord(ex, "PSNode.Unknown.Error", ErrorCategory.NotSpecified, this));
            }
        }
        

        /// &lt;summary&gt;
        /// If the comamnd is running, the job indicates it has more data
        /// &lt;/summary&gt;
        public override bool HasMoreData
        {
            get
            {
                if (powerShellCommand.InvocationStateInfo.State == PSInvocationState.Running)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
        }

        public override string Location
        {
            get
            {
                if (this.JobStateInfo.State == JobState.Running)
                {
                    if (this.ListenerLocation == null) {
                        return " ";
                    } else {
                        return this.ListenerLocation[0];
                    }
                }
                else
                {
                    return " ";
                }
            }
        }


        public override string StatusMessage
        {
            get { return string.Empty; }
        }

        public override void StopJob()
        {
            try {
                powerShellCommand.BeginStop(null, null);
                if (Listener != null) {
                    Listener.Stop();
                    Listener.Close();
                }

            } catch (Exception ex) {
                this.Error.Add(new ErrorRecord(ex, "PSNode.StopJob.Error", ErrorCategory.CloseError, this));
            }
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                powerShellCommand.Dispose();
                runspacePool.Close();
                runspacePool.Dispose();
            }
            base.Dispose(disposing);
        }
    }
}</Value>
      </NoteProperty>
      <NoteProperty>
        <Name>PSTransform.cs</Name>
        <Value>namespace PipeScript.Net
{
    using System;
    using System.ComponentModel;
    using System.Collections;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Management.Automation;
    /// &lt;summary&gt;
    /// Transforms objects with PowerShell.
    /// &lt;/summary&gt;
    public class PSTransformAttribute : ArgumentTransformationAttribute
    {
        /// &lt;summary&gt;
        /// Creates a Argument Transform from an expression.
        /// &lt;/summary&gt;
        /// &lt;param name="transformExpression"&gt;
        /// An expression to use for the transform.
        /// This will be converted into a ScriptBlock.&lt;/param&gt;
        public PSTransformAttribute(string transformExpression) {
            this.TransformScript = ScriptBlock.Create(transformExpression);
        }

        /// &lt;summary&gt;
        /// Creates a Argument Transform from a ScriptBlock
        /// &lt;/summary&gt;
        /// &lt;param name="transformScript"&gt;A ScriptBlock to transform the value&lt;/param&gt;
        public PSTransformAttribute(ScriptBlock transformScript) {
            this.TransformScript = transformScript;
        }

        /// &lt;summary&gt;
        /// A ScriptBlock to transform the value.
        /// The output of this script block will become the argument.
        /// &lt;/summary&gt;
        public ScriptBlock TransformScript {
            get;
            set;
        }

        /// &lt;summary&gt;
        /// If a transform is disabled, nothing will happen.
        /// &lt;/summary&gt;
        public bool Disabled {
            get;
            set;
        }

        /// &lt;summary&gt;
        /// The name of the transform.
        /// This is not required. It is present in order to disambiguate multiple transforms.
        /// &lt;/summary&gt;
        public string TransformName {
            get;
            set;
        }

        /// &lt;summary&gt;
        /// Determines if the script uses a new scope to execute.
        /// &lt;/summary&gt;
        public bool UseNewScope {
            get;
            set;
        }

        /// &lt;summary&gt;
        /// Transforms arguments.
        /// If the attribute is disabled, no transformation will take place.
        /// If the attribute has a .TransformScript, this argument will be transformed by invoking the script.
        /// &lt;/summary&gt;
        /// &lt;param name="engineIntrinsics"&gt;&lt;/param&gt;
        /// &lt;param name="inputData"&gt;&lt;/param&gt;
        /// &lt;returns&gt;&lt;/returns&gt;
        public override object Transform(EngineIntrinsics engineIntrinsics, object inputData) {
            // If disabled, do nothing
            if (this.Disabled) { return inputData; }
            // If there is no transform script, return the input data.
            if (this.TransformScript == null) { return inputData; }

            // By getting the value of InvocationInfo now, we know what command is trying to perform the transform.
            InvocationInfo myInvocation = engineIntrinsics.SessionState.PSVariable.Get("MyInvocation").Value as InvocationInfo;

            engineIntrinsics.SessionState.PSVariable.Set("thisTransform", this);
            engineIntrinsics.SessionState.PSVariable.Set("_", inputData);

            // The transform script will be passed the following arguments:
            // The input data, invocation info, command, and this attribute.
            object[] arguments = new object[] { inputData, myInvocation, myInvocation.MyCommand, this };
            object[] transformInput = new object[] inputData;

            // Invoke it in place.
            // ($_ will be the current transformed value)
            Collection&lt;PSObject&gt; invokeResults = engineIntrinsics.SessionState.InvokeCommand.InvokeScript(this.UseNewScope, this.TransformScript, transformInput, arguments);
            
            if (invokeResults != null &amp;&amp; invokeResults.Count == 1) {
                return invokeResults[0];
            } else if (invokeResults != null) {
                return invokeResults;
            } else {
                return inputData;
            }
        }
    }
}</Value>
      </NoteProperty>
    </Members>
  </Type>
  <Type>
    <Name>PipeScript.Parsers</Name>
    <Members>
      <ScriptMethod>
        <Name>ForCommand</Name>
        <Script>
                        &lt;#
.SYNOPSIS
    Gets the parser for a command.
.DESCRIPTION
    Gets the parser for a given command.
#&gt;
param(
# The command line to examine for a match.
[Alias('InvocationName','CommandName')]
[string]
$CommandLine
)


foreach ($parserCommand in $this.All) {
    if ($parserCommand -is [Management.Automation.AliasInfo]) {
        $resolvedParserCommand = $parserCommand
        while ($resolvedParserCommand.ResolvedCommand) {
            $resolvedParserCommand = $resolvedParserCommand.ResolvedCommand
        }
        if ($resolvedParserCommand.ScriptBlock) {
            $parserCommand = $resolvedParserCommand
        }
    }
    if (-not $parserCommand.ScriptBlock) { continue }
    foreach ($parserAttribute in $parserCommand.ScriptBlock.Attributes) {
        if ($parserAttribute -isnot [ValidatePattern]) { continue }
        
        $pattern = [Regex]::new($parserAttribute.RegexPattern, $parserAttribute.Options, '00:00:01')
        if ($pattern.IsMatch($CommandLine)) {
            $parserCommand
            break
        }
    }
}
                    </Script>
      </ScriptMethod>
      <ScriptProperty>
        <Name>All</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Gets all Parsers
.DESCRIPTION
    Gets all parsers loaded in PipeScript.
#&gt;
,@(foreach ($psProperty in $this.PSObject.properties) {
    if ($psProperty -isnot [psnoteproperty]) { continue }
    if ($psProperty.Value -isnot [Management.Automation.CommandInfo]) { continue }
    $psProperty.Value
})
                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>Count</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Gets the number of loaded parsers.
.DESCRIPTION
    Gets the number of parsers loaded by PipeScript.
.EXAMPLE
    $PSParser.Count
#&gt;
$count= 0
foreach ($prop in $this.psobject.properties) {
    if ($prop -is [psscriptproperty]) { continue }
    if ($prop.Value -is [Management.Automation.CommandInfo]) {
        $count++
    }
}
return $count
                    </GetScriptBlock>
      </ScriptProperty>
    </Members>
  </Type>
  <Type>
    <Name>PipeScript.Sentence</Name>
    <Members>
      <AliasProperty>
        <Name>Argument</Name>
        <ReferencedMemberName>Arguments</ReferencedMemberName>
      </AliasProperty>
      <AliasProperty>
        <Name>ArgumentList</Name>
        <ReferencedMemberName>Arguments</ReferencedMemberName>
      </AliasProperty>
      <AliasProperty>
        <Name>Parameter</Name>
        <ReferencedMemberName>Parameters</ReferencedMemberName>
      </AliasProperty>
      <ScriptMethod>
        <Name>GetParameterAlias</Name>
        <Script>
                        &lt;#
.SYNOPSIS
    Gets a parameter's alias
.DESCRIPTION
    Gets the alias used to call a parameter in a sentence.

    This can be useful for inferring subtle differences based off of word choice, as in

    `all functions matching Sentence` # Returns all functions that match Sentence

    Compared to:

    `all functions where Sentence` # Returns all functions that are Sentences
.EXAMPLE
    {* pid $pid}.Ast.EndBlock.Statements[0].PipelineElements[0].AsSentence((Get-Command Get-Process)).GetParameterAlias('id')
#&gt;
param(
# The name of one or more parameters.
[string[]]
$Parameter
)

$parameterWildcards = $Parameter -match '[\*\?]'

@(:nextClause foreach ($sentenceClause in $this.Clauses) {
    if (-not $sentenceClause.ParameterName) { continue }
    
    if ($parameter -contains $sentenceClause.ParameterName) {
        $sentenceClause.Name
    }
    elseif ($parameterWildcards) {
        foreach ($wildcard in $parameterWildcards) {
            if ($sentenceClause.ParameterName -like $wildcard) {
                $sentenceClause.Name
                continue nextClause
            }
        }
    }
})
                    </Script>
      </ScriptMethod>
      <ScriptMethod>
        <Name>Run</Name>
        <Script>
                        if (-not $this.Keyword) {
    throw "Sentence lacks a keyword"
}

if (-not $this.Command) {
    throw "Sentence has no command"
}

$parameters = $this.Parameters
$arguments = $this.Arguments

if (-not $parameters -and -not $arguments) {
    &amp; $this.Command
}
elseif (-not $arguments) {
    &amp; $this.Command @parameters
}
elseif (-not $parameters) {
    &amp; $this.Command @arguments
}
else {
    &amp; $this.Command @arguments @parameters
}



                    </Script>
      </ScriptMethod>
    </Members>
  </Type>
  <Type>
    <Name>PipeScript.Template</Name>
    <Members>
    </Members>
  </Type>
  <Type>
    <Name>PipeScript.Transpiler</Name>
    <Members>
    </Members>
  </Type>
  <Type>
    <Name>Protocol.Command</Name>
    <Members>
      <ScriptProperty>
        <Name>CommandParameter</Name>
        <GetScriptBlock>
                        foreach ($param in $this.Parameters.GetEnumerator()) {
    if ($param.Value.ParameterType -eq [Management.Automation.Language.CommandAST]) {
        return $param.Value
    }
}
                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>CommandParameterName</Name>
        <GetScriptBlock>
                        foreach ($param in $this.Parameters.GetEnumerator()) {
    if ($param.Value.ParameterType -eq [Management.Automation.Language.CommandAST]) {
        return $param.Value.Name
    }
}
                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>URLParameter</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Gets a Protocol's URL parameter
.DESCRIPTION
    Gets a Protocol Command's URL parameter.
#&gt;
foreach ($param in $this.Parameters.GetEnumerator()) {
    if ($param.Value.ParameterType -eq [uri]) {
        return $param.Value
    }
}
                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>URLParameterName</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Gets a Protocol's URL parameter
.DESCRIPTION
    Gets a Protocol Command's URL parameter.
#&gt;
foreach ($param in $this.Parameters.GetEnumerator()) {
    if ($param.Value.ParameterType -eq [uri]) {
        return $param.Value.Name
    }
}
                    </GetScriptBlock>
      </ScriptProperty>
    </Members>
  </Type>
  <Type>
    <Name>System.Management.Automation.PSMemberSet</Name>
    <Members>
      <ScriptMethod>
        <Name>hasOwnProperty</Name>
        <Script>
                        &lt;#
.SYNOPSIS
    Determines if an object has define a property
.DESCRIPTION
    Determines if an object has define a property (as opposed to inheriting it)
.NOTES
    This makes .PSObject more similar to a JavaScript prototype.
#&gt;
param(
# The property name.
[string]
$PropertyName
)

if ($PropertyName) {
    if (-not $this.Properties[$PropertyName]) {
        return $false
    }
    return $this.Properties[$PropertyName].IsInstance
}








                    </Script>
      </ScriptMethod>
      <ScriptMethod>
        <Name>propertyIsEnumerable</Name>
        <Script>
                        &lt;#
.SYNOPSIS
    Determines if a property is enumerable
.DESCRIPTION
    Determines if a property or object is enumerable.

    If no PropertyName is provided, this method will determine if the .ImmediateBaseObject is enumerable.
.NOTES
    This makes .PSObject more similar to a JavaScript prototype.
#&gt;
param(
# The property name.
# If this is not provided, this method will determine if the .ImmediateBaseObject is enumerable.
[string]
$PropertyName
)

if ($PropertyName) {
    if (-not $this.Properties[$PropertyName]) {
        return $false
    }
    return $this.Properties[$PropertyName].Value -is [Collections.IEnumerable]
} else {
    $this.ImmediateBaseObject -is [Collections.IEnumerable]
}








                    </Script>
      </ScriptMethod>
      <ScriptMethod>
        <Name>valueOf</Name>
        <Script>
                        &lt;#
.SYNOPSIS
    Returns the Value Of an object
.DESCRIPTION
    valueOf allows you to override the returned value (in _some_ circumstances).

    Defining a member named `valueOf` will make .PSObject.valueOf return that member's value or result.

    Otherwise, `.valueOf()` will return the .ImmediateBaseObject.
.NOTES
    This makes .PSObject more similar to a JavaScript prototype.
#&gt;
param()
$myName = 'valueOf'
if ($this.Members[$myName]) {
    if ($this.Properties[$myName]) {
        $this.Properties[$myName].Value
    }
    elseif ($this.Methods[$myName]) {
        $this.Methods[$myName].Invoke($args)
    }
}
else {
    $this.ImmediateBaseObject
}
                    </Script>
      </ScriptMethod>
    </Members>
  </Type>
  <Type>
    <Name>System.Management.Automation.PSModuleInfo</Name>
    <Members>
      <AliasProperty>
        <Name>Assets</Name>
        <ReferencedMemberName>Asset</ReferencedMemberName>
      </AliasProperty>
      <AliasProperty>
        <Name>Directories</Name>
        <ReferencedMemberName>Folders</ReferencedMemberName>
      </AliasProperty>
      <AliasProperty>
        <Name>Directory</Name>
        <ReferencedMemberName>Folder</ReferencedMemberName>
      </AliasProperty>
      <AliasProperty>
        <Name>Domain</Name>
        <ReferencedMemberName>Server</ReferencedMemberName>
      </AliasProperty>
      <AliasProperty>
        <Name>Domains</Name>
        <ReferencedMemberName>Server</ReferencedMemberName>
      </AliasProperty>
      <AliasProperty>
        <Name>Exports</Name>
        <ReferencedMemberName>Export</ReferencedMemberName>
      </AliasProperty>
      <AliasProperty>
        <Name>ExtendedCommand</Name>
        <ReferencedMemberName>Extension</ReferencedMemberName>
      </AliasProperty>
      <AliasProperty>
        <Name>ExtendedCommands</Name>
        <ReferencedMemberName>Extension</ReferencedMemberName>
      </AliasProperty>
      <AliasProperty>
        <Name>Extensions</Name>
        <ReferencedMemberName>Extension</ReferencedMemberName>
      </AliasProperty>
      <AliasProperty>
        <Name>Router</Name>
        <ReferencedMemberName>Route</ReferencedMemberName>
      </AliasProperty>
      <AliasProperty>
        <Name>Routers</Name>
        <ReferencedMemberName>Route</ReferencedMemberName>
      </AliasProperty>
      <AliasProperty>
        <Name>Routes</Name>
        <ReferencedMemberName>Route</ReferencedMemberName>
      </AliasProperty>
      <AliasProperty>
        <Name>Servers</Name>
        <ReferencedMemberName>Server</ReferencedMemberName>
      </AliasProperty>
      <ScriptMethod>
        <Name>ExtensionsForName</Name>
        <Script>
                        &lt;#
.SYNOPSIS
    Gets Extensions for a name.
.DESCRIPTION
    Gets Extensions for an invocation name.
.EXAMPLE
    (Get-Module PipeScript).ExtensionsForName(".cs")
#&gt;
param(
[string]
$InvocationName
)

@(:nextExtension foreach ($extension in $this.Extension) {
    foreach ($attr in $extension.ScriptBlock.Attributes) {
        if ($attr -isnot [ValidatePattern]) { continue }
        $validatePattern = [regex]::new(
            $attr.RegexPattern,
            $attr.Options,
            [Timespan]'00:00:00.1'
        )
        if ($validatePattern.IsMatch($InvocationName)) {
            $extension
            continue nextExtension
        }
    }
})
                    </Script>
      </ScriptMethod>
      <ScriptMethod>
        <Name>File</Name>
        <Script>
                        &lt;#
.SYNOPSIS
    Gets a file in a module
.DESCRIPTION
    Gets a file located within a module.
    
    Hidden files are ignored.
.EXAMPLE
    (Get-Module PipeScript).File(".\PipeScript.psd1")
#&gt;
param()
foreach ($arg in $args) {
    $shouldRecurse = ($arg -match "^\.\\") -as [bool]
    $this | Split-Path | Get-ChildItem -File -Recurse -Path $arg -Recurse:$shouldRecurse
}
                    </Script>
      </ScriptMethod>
      <ScriptMethod>
        <Name>FindExtensions</Name>
        <Script>
                        &lt;#
.SYNOPSIS
    Finds extensions for a module
.DESCRIPTION
    Finds extended commands for a module.
.EXAMPLE
    (Get-Module PipeScript).FindExtensions((Get-Module PipeScript | Split-Path))
#&gt;
param()

$targetModules = @()
$targetPaths = @()
$loadedModules = Get-Module
foreach ($arg in $args) {
    if ($arg -is [Management.Automation.PSModuleInfo]) {
        $targetModules += $arg
    }
    elseif ($arg -is [IO.FileInfo] -or $arg -is [IO.DirectoryInfo]) {
        $targetPaths += $arg
    }
    elseif ($arg -is [Management.Automation.PathInfo]) {
        $targetPaths += "$arg"
    }
    elseif ($arg -is [string]) {
        $argIsModule =
            foreach ($module in $loadedModules) { if ($module.Name -like $arg) { $module}}
        if ($argIsModule) {
            $targetModules += $argIsModule
        } elseif (Test-Path $arg) {
            $targetPaths += $arg
        }
        
    }
}

if (-not $targetModules) { $targetModules = $this}
$Splat = @{}
if ($targetPaths) {
    $Splat.FilePath = $targetPaths
}
foreach ($module in $targetModules) {
    # Aspect.ModuleExtendedCommand
    &amp; {
    
        &lt;#
        .SYNOPSIS
            Returns a module's extended commands
        .DESCRIPTION
            Returns the commands or scripts in a module that match the module command pattern.
    
            Each returned script will be decorated with the typename(s) that match,
            so that the extended commands can be augmented by the extended types system.
        .LINK
            Aspect.ModuleExtensionPattern
        .EXAMPLE
            Aspect.ModuleExtensionCommand -Module PipeScript # Should -BeOfType ([Management.Automation.CommandInfo])
        #&gt;
        [Alias('Aspect.ModuleExtendedCommand')]
        param(
        # The name of a module, or a module info object.
        [Parameter(Mandatory,ValueFromPipelineByPropertyName)]
        [ValidateScript({
        $validTypeList = [System.String],[System.Management.Automation.PSModuleInfo]
        
        $thisType = $_.GetType()
        $IsTypeOk =
            $(@( foreach ($validType in $validTypeList) {
                if ($_ -as $validType) {
                    $true;break
                }
            }))
        
        if (-not $isTypeOk) {
            throw "Unexpected type '$(@($thisType)[0])'. Must be 'string','psmoduleinfo'."
        }
        return $true
        })]
        
        $Module,
        
        # A list of commands.
        # If this is provided, each command that is a valid extension will be returned.
        [Parameter(ValueFromPipelineByPropertyName)]
        [Management.Automation.CommandInfo[]]
        $Commands,
    
        # The suffix to apply to each named capture.
        # Defaults to '_Command'
        [Parameter(ValueFromPipelineByPropertyName)]
        [string]
        $Suffix = '_Command',
    
        # The prefix to apply to each named capture.
        [Parameter(ValueFromPipelineByPropertyName)]
        [string]
        $Prefix,
    
        # The file path(s). If provided, will look for commands within these paths.
        [Parameter(ValueFromPipelineByPropertyName)]
        [Alias('Fullname')]
        $FilePath,
    
        # The PowerShell command type. If this is provided, will only get commands of this type.
        [Parameter(ValueFromPipelineByPropertyName)]
        [Management.Automation.CommandTypes]
        $CommandType,
    
        # The base PSTypeName(s).
        # If provided, any commands that match the pattern will apply these typenames, too.
        [string[]]
        $PSTypeName
        )
    
        process {
            if ($Module -is [string]) {
                $Module = Get-Module $Module
            }
            $ModuleInfo = $module
    
            if (-not $ModuleInfo) { return }
            
            $ModuleCommandPattern = # Aspect.ModuleExtensionPattern
                                    &amp; {
                                    
                                        &lt;#
                                        .SYNOPSIS
                                            Outputs a module's extension pattern
                                        .DESCRIPTION
                                            Outputs a regular expression that will match any possible pattern.
                                        .EXAMPLE
                                            Aspect.ModuleCommandPattern -Module PipeScript # Should -BeOfType ([Regex])
                                        #&gt;
                                        [Alias('Aspect.ModuleCommandPattern')]
                                        param(
                                        # The name of a module, or a module info object.
                                        [Parameter(Mandatory,ValueFromPipelineByPropertyName)]
                                        [ValidateScript({
                                        $validTypeList = [System.String],[System.Management.Automation.PSModuleInfo]
                                        
                                        $thisType = $_.GetType()
                                        $IsTypeOk =
                                            $(@( foreach ($validType in $validTypeList) {
                                                if ($_ -as $validType) {
                                                    $true;break
                                                }
                                            }))
                                        
                                        if (-not $isTypeOk) {
                                            throw "Unexpected type '$(@($thisType)[0])'. Must be 'string','psmoduleinfo'."
                                        }
                                        return $true
                                        })]
                                        
                                        $Module,
                                    
                                        # The suffix to apply to each named capture.
                                        # Defaults to '_Command'
                                        [Parameter(ValueFromPipelineByPropertyName)]
                                        [string]
                                        $Suffix = '_Command',
                                    
                                        # The prefix to apply to each named capture.
                                        [Parameter(ValueFromPipelineByPropertyName)]
                                        [string]
                                        $Prefix
                                        )
                                    
                                        process {
                                            if ($Module -is [string]) {
                                                $Module = Get-Module $Module
                                            }
                                            $ModuleInfo = $module
                                    
                                    
                                            #region Search for Module Extension Types
                                            if (-not $ModuleInfo) { return }
                                            $ModuleExtensionTypes = # Aspect.ModuleExtensionTypes
                                                                    &amp; {
                                                                    
                                                                        &lt;#
                                                                        .SYNOPSIS
                                                                            Outputs a module's extension types
                                                                        .DESCRIPTION
                                                                            Outputs the extension types defined in a module's manifest.
                                                                        .EXAMPLE
                                                                            # Outputs a PSObject with information about extension command types.
                                                                            
                                                                            # The two primary pieces of information are the `.Name` and `.Pattern`.
                                                                            Aspect.ModuleExtensionType -Module PipeScript # Should -BeOfType ([PSObject])
                                                                        #&gt;
                                                                        [Alias('Aspect.ModuleCommandTypes','Aspect.ModuleCommandType','Aspect.ModuleExtensionTypes')]
                                                                        param(
                                                                        # The name of a module, or a module info object.
                                                                        [Parameter(Mandatory,ValueFromPipelineByPropertyName)]
                                                                        [ValidateScript({
                                                                        $validTypeList = [System.String],[System.Management.Automation.PSModuleInfo]
                                                                        
                                                                        $thisType = $_.GetType()
                                                                        $IsTypeOk =
                                                                            $(@( foreach ($validType in $validTypeList) {
                                                                                if ($_ -as $validType) {
                                                                                    $true;break
                                                                                }
                                                                            }))
                                                                        
                                                                        if (-not $isTypeOk) {
                                                                            throw "Unexpected type '$(@($thisType)[0])'. Must be 'string','psmoduleinfo'."
                                                                        }
                                                                        return $true
                                                                        })]
                                                                        
                                                                        $Module
                                                                        )
                                                                    
                                                                        begin {
                                                                            $ExtensionCollectionNames =
                                                                                "Extension", "Command", "Cmdlet", "Function", "Alias", "Script", "Application", "File","Configuration"
                                                                            $ExtensionCollectionNames = @($ExtensionCollectionNames -replace '.+$','${0}Type') + @($ExtensionCollectionNames -replace '.+$','${0}Types')
                                                                        }
                                                                    
                                                                        process {
                                                                            #region Resolve Module Info
                                                                            if ($Module -is [string]) {
                                                                                $Module = Get-Module $Module
                                                                            }
                                                                            $ModuleInfo = $module
                                                                            if (-not $ModuleInfo) { return }
                                                                            #endregion Resolve Module Info
                                                                    
                                                                            #region Check Cache and Hopefully Return
                                                                            if (-not $script:ModuleExtensionTypeCache) {
                                                                                $script:ModuleExtensionTypeCache = @{}
                                                                            }
                                                                            
                                                                            if ($script:ModuleExtensionTypeCache[$ModuleInfo]) {
                                                                                return $script:ModuleExtensionTypeCache[$ModuleInfo]
                                                                            }
                                                                            #endregion Check Cache and Hopefully Return
                                                                    
                                                                            #region Find Extension Types
                                                                            $modulePrivateData = $ModuleInfo.PrivateData
                                                                    
                                                                            $SortedExtensionTypes = [Ordered]@{}
                                                                            foreach ($TypeOfExtensionCollection in $ExtensionCollectionNames) {
                                                                                $moduleExtensionTypes =
                                                                                    if ($modulePrivateData.$TypeOfExtensionCollection) {
                                                                                        $modulePrivateData.$TypeOfExtensionCollection
                                                                                    } elseif ($modulePrivateData.PSData.$TypeOfExtensionCollection) {
                                                                                        $modulePrivateData.PSData.$TypeOfExtensionCollection
                                                                                    } else {
                                                                                        $null
                                                                                    }
                                                                    
                                                                                if (-not $moduleExtensionTypes) { continue }
                                                                    
                                                                                foreach ($commandType in @($ModuleExtensionTypes.GetEnumerator() | Sort-Object Key)) {
                                                                                    if ($commandType.Value -is [Collections.IDictionary]) {
                                                                                        if (-not $commandType.Value.Name) {
                                                                                            $commandType.Value["Name"] = $commandType.Key
                                                                                        }
                                                                                        if (-not $commandType.Value.PSTypeName) {
                                                                                            $commandType.Value["PSTypeName"] = "$($module.Name).ExtensionCommandType"
                                                                                        }
                                                                                        $SortedExtensionTypes[$commandType.Name] = $commandType.Value
                                                                                    } else {
                                                                                        $SortedExtensionTypes[$commandType.Name] = [Ordered]@{
                                                                                            PSTypeName = "$($module.Name).ExtensionCommandType"
                                                                                            Name = $commandType.Key
                                                                                            Pattern = $commandType.Value
                                                                                        }
                                                                                    }
                                                                                    if ($TypeOfExtensionCollection -notmatch '(?&gt;Extension|Command|Cmdlet)') {
                                                                                        $SortedExtensionTypes[$commandType.Name].CommandType = $TypeOfExtensionCollection -replace 'Type(?:s)?$'
                                                                                    } elseif ($TypeOfExtensionCollection -match 'Cmdlet') {
                                                                                        $SortedExtensionTypes[$commandType.Name].CommandType = "(?&gt;Alias|Function|Filter|Cmdlet)"
                                                                                    }
                                                                                }
                                                                            }
                                                                            
                                                                            $SortedExtensionTypes.PSTypeName="$($Module.Name).ExtensionCommandTypes"
                                                                            
                                                                            $script:ModuleExtensionTypeCache[$ModuleInfo] = [PSCustomObject]$SortedExtensionTypes
                                                                            $script:ModuleExtensionTypeCache[$ModuleInfo]
                                                                            #endregion Find Extension Types
                                                                    
                                                                        }
                                                                    
                                                                     } -Module $moduleInfo
                                    
                                            
                                            if (-not $ModuleExtensionTypes) { return }
                                                
                                            # With some clever understanding of Regular expressions, we can make match any/all of our potential command types.
                                            # Essentially: Regular Expressions can look ahead (matching without changing the position), and be optional.
                                            # So we can say "any/all" by making a series of optional lookaheads.
                                            
                                            # We'll go thru each pattern in order
                                            $combinedRegex = @(foreach ($categoryExtensionTypeInfo in @($ModuleExtensionTypes.psobject.properties)) {
                                                $categoryPattern = $categoryExtensionTypeInfo.Value.Pattern
                                                # ( and skip anyone that does not have a pattern)
                                                if (-not $categoryPattern) { continue }
                                    
                                                '(?=' + # Start a lookahead
                                                    '.{0,}' + # match any or no characters
                                                    # followed by the command pattern
                                                    "(?&lt;$Prefix$($categoryExtensionTypeInfo.Name -replace '\p{P}', '_')$Suffix&gt;$categoryPattern)" +
                                                    ')?' # made optional
                                            }) -join [Environment]::NewLine
                                    
                                            # Now that we've combined the whole thing, make it a Regex and output it.
                                            [Regex]::new("$combinedRegex", 'IgnoreCase,IgnorePatternWhitespace','00:00:01')
                                        }
                                    
                                     } $ModuleInfo -Prefix $prefix -Suffix $Suffix
            $ModuleCommandTypes = # Aspect.ModuleExtensionType
                                    &amp; {
                                    
                                        &lt;#
                                        .SYNOPSIS
                                            Outputs a module's extension types
                                        .DESCRIPTION
                                            Outputs the extension types defined in a module's manifest.
                                        .EXAMPLE
                                            # Outputs a PSObject with information about extension command types.
                                            
                                            # The two primary pieces of information are the `.Name` and `.Pattern`.
                                            Aspect.ModuleExtensionType -Module PipeScript # Should -BeOfType ([PSObject])
                                        #&gt;
                                        [Alias('Aspect.ModuleCommandTypes','Aspect.ModuleCommandType','Aspect.ModuleExtensionTypes')]
                                        param(
                                        # The name of a module, or a module info object.
                                        [Parameter(Mandatory,ValueFromPipelineByPropertyName)]
                                        [ValidateScript({
                                        $validTypeList = [System.String],[System.Management.Automation.PSModuleInfo]
                                        
                                        $thisType = $_.GetType()
                                        $IsTypeOk =
                                            $(@( foreach ($validType in $validTypeList) {
                                                if ($_ -as $validType) {
                                                    $true;break
                                                }
                                            }))
                                        
                                        if (-not $isTypeOk) {
                                            throw "Unexpected type '$(@($thisType)[0])'. Must be 'string','psmoduleinfo'."
                                        }
                                        return $true
                                        })]
                                        
                                        $Module
                                        )
                                    
                                        begin {
                                            $ExtensionCollectionNames =
                                                "Extension", "Command", "Cmdlet", "Function", "Alias", "Script", "Application", "File","Configuration"
                                            $ExtensionCollectionNames = @($ExtensionCollectionNames -replace '.+$','${0}Type') + @($ExtensionCollectionNames -replace '.+$','${0}Types')
                                        }
                                    
                                        process {
                                            #region Resolve Module Info
                                            if ($Module -is [string]) {
                                                $Module = Get-Module $Module
                                            }
                                            $ModuleInfo = $module
                                            if (-not $ModuleInfo) { return }
                                            #endregion Resolve Module Info
                                    
                                            #region Check Cache and Hopefully Return
                                            if (-not $script:ModuleExtensionTypeCache) {
                                                $script:ModuleExtensionTypeCache = @{}
                                            }
                                            
                                            if ($script:ModuleExtensionTypeCache[$ModuleInfo]) {
                                                return $script:ModuleExtensionTypeCache[$ModuleInfo]
                                            }
                                            #endregion Check Cache and Hopefully Return
                                    
                                            #region Find Extension Types
                                            $modulePrivateData = $ModuleInfo.PrivateData
                                    
                                            $SortedExtensionTypes = [Ordered]@{}
                                            foreach ($TypeOfExtensionCollection in $ExtensionCollectionNames) {
                                                $moduleExtensionTypes =
                                                    if ($modulePrivateData.$TypeOfExtensionCollection) {
                                                        $modulePrivateData.$TypeOfExtensionCollection
                                                    } elseif ($modulePrivateData.PSData.$TypeOfExtensionCollection) {
                                                        $modulePrivateData.PSData.$TypeOfExtensionCollection
                                                    } else {
                                                        $null
                                                    }
                                    
                                                if (-not $moduleExtensionTypes) { continue }
                                    
                                                foreach ($commandType in @($ModuleExtensionTypes.GetEnumerator() | Sort-Object Key)) {
                                                    if ($commandType.Value -is [Collections.IDictionary]) {
                                                        if (-not $commandType.Value.Name) {
                                                            $commandType.Value["Name"] = $commandType.Key
                                                        }
                                                        if (-not $commandType.Value.PSTypeName) {
                                                            $commandType.Value["PSTypeName"] = "$($module.Name).ExtensionCommandType"
                                                        }
                                                        $SortedExtensionTypes[$commandType.Name] = $commandType.Value
                                                    } else {
                                                        $SortedExtensionTypes[$commandType.Name] = [Ordered]@{
                                                            PSTypeName = "$($module.Name).ExtensionCommandType"
                                                            Name = $commandType.Key
                                                            Pattern = $commandType.Value
                                                        }
                                                    }
                                                    if ($TypeOfExtensionCollection -notmatch '(?&gt;Extension|Command|Cmdlet)') {
                                                        $SortedExtensionTypes[$commandType.Name].CommandType = $TypeOfExtensionCollection -replace 'Type(?:s)?$'
                                                    } elseif ($TypeOfExtensionCollection -match 'Cmdlet') {
                                                        $SortedExtensionTypes[$commandType.Name].CommandType = "(?&gt;Alias|Function|Filter|Cmdlet)"
                                                    }
                                                }
                                            }
                                            
                                            $SortedExtensionTypes.PSTypeName="$($Module.Name).ExtensionCommandTypes"
                                            
                                            $script:ModuleExtensionTypeCache[$ModuleInfo] = [PSCustomObject]$SortedExtensionTypes
                                            $script:ModuleExtensionTypeCache[$ModuleInfo]
                                            #endregion Find Extension Types
                                    
                                        }
                                    
                                     } $ModuleInfo
            
            $commands =
                @(
                if ($PSBoundParameters['Commands']) {
                    $commands
                }
                elseif ($PSBoundParameters['FilePath']) {
                    if (-not $commandType) {
                        $commandType = 'Application,ExternalScript'
                    }
                    
                    $shouldRecurse = $($PSBoundParameters['FilePath'] -notmatch '^\.\\') -as [bool]
                        
                    foreach ($file in Get-ChildItem -File -Path $PSBoundParameters['FilePath'] -Recurse:$shouldRecurse ) {
                        $ExecutionContext.SessionState.InvokeCommand.GetCommand($file.FullName, $commandType)
                    }
                } else {
                    if (-not $CommandType) {
                        $commandType = 'Function,Alias,Filter,Cmdlet'
                    }
                    $ExecutionContext.SessionState.InvokeCommand.GetCommands('*', $commandType, $true)
                })
    
            :nextCommand foreach ($cmd in $commands) {
                $matched = $ModuleCommandPattern.Match("$cmd")
                if (-not $matched.Success) { continue }
                $NamedGroupMatch = $false
                :nextCommandType foreach ($group in $matched.Groups) {
                    if (-not $group.Success) { continue }
                    if ($null -ne ($group.Name -as [int])) { continue }
                    $CommandTypeName = $group.Name.Replace('_','.')
                    $ThisCommandsType = $ModuleCommandTypes.($group.Name -replace "^$prefix" -replace "$suffix$")
                    if ($ThisCommandsType) {
                        $ThisTypeFilter = @($ThisCommandsType.CommandType,$ThisCommandsType.CommandTypes -ne $null)[0]
                        if ($ThisTypeFilter -and ($cmd.CommandType -notmatch $ThisTypeFilter)) {
                            continue nextCommandType
                        }
                        $ThisExcludeFilter = @($ThisCommandsType.ExcludeCommandType,$ThisCommandsType.ExcludeCommandTypes -ne $null)[0]
                        if ($ThisExcludeFilter -and ($cmd.CommandType -match $ThisExcludeFilter)) {
                            continue nextCommandType
                        }
                    }
                    $NamedGroupMatch = $true
                    if ($PSTypeName) {
                        foreach ($psuedoType in $PSTypeName) {
                            if ($cmd.pstypenames -notcontains $psuedoType) {
                                $cmd.pstypenames.insert(0, $psuedoType)
                            }
                        }
                    }
                    if ($cmd.pstypenames -notcontains $CommandTypeName) {
                        $cmd.pstypenames.insert(0, $CommandTypeName)
                    }
                }
                if ($NamedGroupMatch) {
                    $cmd
                }
            }
        }
    
     } -Module $module @Splat
}

                    </Script>
      </ScriptMethod>
      <ScriptMethod>
        <Name>Folder</Name>
        <Script>
                        &lt;#
.SYNOPSIS
    Gets a folder in a module
.DESCRIPTION
    Gets a folder located within a module.
    
    Hidden folders are ignored.
.EXAMPLE
    (Get-Module PipeScript).Folder(".\Build")
#&gt;
param()

foreach ($arg in $args) {
    $shouldRecurse = ($arg -match "^\.\\") -as [bool]
    $this | Split-Path | Get-ChildItem -Directory -Recurse -Path $arg -Recurse:$shouldRecurse
}
                    </Script>
      </ScriptMethod>
      <ScriptMethod>
        <Name>GetDynamicParameters</Name>
        <Script>
                        &lt;#
.SYNOPSIS
    Gets dynamic parameters
.DESCRIPTION
    Gets dynamic parameters for a command
#&gt;
param()

$unrolledArgs = $args | . { process{ $_ } }
$DynamicParameterSplat = [Ordered]@{}
$dynamicParametersFrom =@(foreach ($arg in $unrolledArgs) {
    if ($arg -is [Management.Automation.CommandInfo] -or $arg -is [ScriptBlock]) {
        $arg
    }
    if ($arg -is [Collections.IDictionary]) {
        foreach ($keyValuePair in $arg.GetEnumerator()) {
            $DynamicParameterSplat[$keyValuePair.Key] = $keyValuePair.Value
        }
    }
})

if (-not $dynamicParametersFrom) { return }

$dynamicParametersFrom |
    # Aspect.DynamicParameter
    &amp; {
    
        &lt;#
        .SYNOPSIS
            Dynamic Parameter Aspect
        .DESCRIPTION
            The Dynamic Parameter Aspect is used to add dynamic parameters, well, dynamically.
    
            It can create dynamic parameters from one or more input objects or scripts.
        .EXAMPLE
            Get-Command Get-Command |
                Aspect.DynamicParameter
        .EXAMPLE
            Get-Command Get-Process |
                Aspect.DynamicParameter -IncludeParameter Name # Select -Expand Keys # Should -Be Name
        .EXAMPLE
            Get-Command Get-Command, Get-Help |
                Aspect.DynamicParameter
        #&gt;
        [Alias('Aspect.DynamicParameters')]
        param(
        # The InputObject.
        # This can be anything, but will be ignored unless it is a `[ScriptBlock]` or `[Management.Automation.CommandInfo]`.
        [Parameter(ValueFromPipeline)]
        [PSObject]
        $InputObject,
    
        # The name of the parameter set the dynamic parameters will be placed into.
        [string]
        $ParameterSetName,
    
        # The positional offset. If this is provided, all positional parameters will be shifted by this number.
        # For example, if -PositionOffset is 1, the first parameter would become the second parameter (and so on)
        [int]
        $PositionOffset,
    
        # If set, will make all dynamic parameters non-mandatory.
        [switch]
        $NoMandatory,
    
        # If provided, will check that dynamic parameters are valid for a given command.
        # If the [Management.Automation.CmdletAttribute]
        [string[]]
        $commandList,
    
        # If provided, will include only these parameters from the input.
        [string[]]
        $IncludeParameter,
    
        # If provided, will exclude these parameters from the input.
        [string[]]
        $ExcludeParameter,
    
        # If provided, will make a blank parameter for every -PositionOffset.
        # This is so, presumably, whatever has already been provided in these positions will bind correctly.
        # The name of this parameter, by default, will be "ArgumentN" (for example, Argument1)
        [switch]
        $BlankParameter,
    
        # The name of the blank parameter.
        # If there is a -PositionOffset, this will make a blank parameter by this name for the position.
        [string[]]
        $BlankParameterName = "Argument"
        )
    
        begin {
            # We're going to accumulate all input into a queue, so we'll need to make a queue in begin.
            $inputQueue = [Collections.Queue]::new()
        }
        process {
            $inputQueue.Enqueue($InputObject) # In process, we just need to enqueue the input.
        }
    
        end {
            # The dynamic parameters are created at the end of the pipeline.
            $DynamicParameters = [Management.Automation.RuntimeDefinedParameterDictionary]::new()
            
            # We're going to want to track what aliases are assigned (to avoid conflicts)
            $PendingAliasMap = [Ordered]@{}
    
            # Before any dynamic parameters are bound, we need to create any blank requested parameters
            if ($PositionOffset -and # (if we're offsetting position
                ($BlankParameter -or $PSBoundParameters['BlankParameterName']) # and we have a -BlankParameter)
            ) {
    
                for ($pos =0; $pos -lt $PositionOffset; $pos++) {
                    # If we have a name, use that
                    $paramName = $BlankParameterName[$pos]
                    if (-not $paramName) {
                        # Otherwise, just use the last name and give it a number.
                        $paramName = "$($BlankParameterName[-1])$pos"
                    }
                    # construct a minimal dynamic parameter
                    $DynamicParameters.Add($paramName,
                        [Management.Automation.RuntimeDefinedParameter]::new(
                            $paramName,
                            [PSObject],
                            @(
                                $paramAttr = [Management.Automation.ParameterAttribute]::new()
                                $paramAttr.Position = $pos
                                $paramAttr
                            )
                        )
                    )
    
                    $PendingAliasMap[$paramName] = $DynamicParameters[$paramName]
                }
            }
    
            # After we've blank parameters, we move onto the input queue.
            while ($inputQueue.Count) {
                # and work our way thru it until it is empty.
                $InputObject = $inputQueue.Dequeue()
    
                # First up, we turn our input into [CommandMetaData]
                $inputCmdMetaData =
                    if ($inputObject -is [Management.Automation.CommandInfo]) {
                        # this is a snap if it's a command already
                        [Management.Automation.CommandMetaData]$InputObject
                    }
                    elseif ($inputObject -is [scriptblock]) {
                        # but scriptblocks need to be put into a temporary function.
                        $function:TempFunction = $InputObject
                        [Management.Automation.CommandMetaData]$ExecutionContext.SessionState.InvokeCommand.GetCommand('TempFunction','Function')
                    }
    
                # If for any reason we couldn't get command metadata, continue.
                if (-not $inputCmdMetaData) { continue }
                                                       
                :nextDynamicParameter foreach ($paramName in $inputCmdMetaData.Parameters.Keys) {
                    if ($ExcludeParameter) {
                        foreach ($exclude in $ExcludeParameter) {
                            if ($paramName -like $exclude) { continue nextDynamicParameter}
                        }
                    }
                    if ($IncludeParameter) {
                        $shouldInclude =
                            foreach ($include in $IncludeParameter) {
                                if ($paramName -like $include) { $true;break}
                            }
                        if (-not $shouldInclude) { continue nextDynamicParameter }
                    }
    
                    $attrList = [Collections.Generic.List[Attribute]]::new()
                    $validCommandNames = @()
                    foreach ($attr in $inputCmdMetaData.Parameters[$paramName].attributes) {
                        if (
                            $attr -isnot [Management.Automation.ParameterAttribute] -and
                            $attr -isnot [Management.Automation.AliasAttribute]
                        ) {
                            # we can passthru any non-parameter attributes
                            $attrList.Add($attr)
                            # (`[Management.Automation.CmdletAttribute]` is special, as it indicates if the parameter applies to a command)
                            if ($attr -is [Management.Automation.CmdletAttribute] -and $commandList) {
                                $validCommandNames += (
                                    ($attr.VerbName -replace '\s') + '-' + ($attr.NounName -replace '\s')
                                ) -replace '^\-' -replace '\-$'
                            }
                        }
                        elseif ($attr -is [Management.Automation.AliasAttribute]) {
                            # If it is an alias attribute, we need to ensure that it will not conflict with existing aliases
                            $unmappedAliases = @(foreach ($a in $attr.Aliases) {
                                if (($a -in $pendingAliasMap.Keys)) { continue }
                                $a
                            })
                            if ($unmappedAliases) {
                                $attrList.Add([Management.Automation.AliasAttribute]::new($unmappedAliases))
                                foreach ($nowMappedAlias in $unmappedAliases) {
                                    $PendingAliasMap[$nowMappedAlias] = $DynamicParameters[$paramName]
                                }
                            }
                        }
                        else {
                            # but parameter attributes need to copied.
                            $attrCopy = [Management.Automation.ParameterAttribute]::new()
                            # (Side note: without a .Clone, copying is tedious.)
                            foreach ($prop in $attrCopy.GetType().GetProperties('Instance,Public')) {
                                if (-not $prop.CanWrite) { continue }
                                if ($null -ne $attr.($prop.Name)) {
                                    $attrCopy.($prop.Name) = $attr.($prop.Name)
                                }
                            }
    
                            $attrCopy.ParameterSetName =
                                if ($ParameterSetName) {
                                    $ParameterSetName
                                }
                                else {
                                    $defaultParamSetName = $inputCmdMetaData.DefaultParameterSetName
                                    if ($attrCopy.ParameterSetName -ne '__AllParameterSets') {
                                        $attrCopy.ParameterSetName
                                    }
                                    elseif ($defaultParamSetName) {
                                        $defaultParamSetName
                                    }
                                    elseif ($this -is [Management.Automation.FunctionInfo]) {
                                        $this.Name
                                    } elseif ($this -is [Management.Automation.ExternalScriptInfo]) {
                                        $this.Source
                                    }
                                }
    
                            if ($NoMandatory -and $attrCopy.Mandatory) {
                                $attrCopy.Mandatory = $false
                            }
    
                            if ($PositionOffset -and $attr.Position -ge 0) {
                                $attrCopy.Position += $PositionOffset
                            }
                            $attrList.Add($attrCopy)
                        }
                    }
    
                    if ($commandList -and $validCommandNames) {
                        :CheckCommandValidity do {
                            foreach ($vc in $validCommandNames) {
                                if ($commandList -match $vc) { break CheckCommandValidity }
                            }
                            continue nextDynamicParameter
                        } while ($false)
                    }
                    
                    if ($DynamicParameters.ContainsKey($paramName)) {
                        $DynamicParameters[$paramName].ParameterType = [PSObject]
                        foreach ($attr in $attrList) {
                            $DynamicParameters[$paramName].Attributes.Add($attr)
                        }
                    } else {
                        $DynamicParameters.Add($paramName, [Management.Automation.RuntimeDefinedParameter]::new(
                            $inputCmdMetaData.Parameters[$paramName].Name,
                            $inputCmdMetaData.Parameters[$paramName].ParameterType,
                            $attrList
                        ))
                    }
                }
            }
            $DynamicParameters
        }
    
     } @DynamicParameterSplat

                    </Script>
      </ScriptMethod>
      <ScriptProperty>
        <Name>Asset</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Gets module assets
.DESCRIPTION
    Gets and caches module assets.

    Assets can be found beneath `/Asset(s)` subdirectories of the module or within `.PrivateData.Asset(s)` or `.PrivateData.PSData.Asset(s)`
#&gt;
param()

if (-not $this.'.Assets') {

    filter ToAssetFile {
        $potentialAssetPath = $_
        if (Test-Path $potentialAssetPath) {
            foreach ($assetItem in Get-Item $potentialAssetPath) {
                $assetItem.pstypenames.add("$this.Asset")
                $assetItem.pstypenames.add('PipeScript.Module.Asset')
                $assetItem
            }
        }
    }
    
    $this | Add-Member NoteProperty '.Assets' @(foreach ($place in $this.PrivateData, $this.PrivateData.PSData) {
        foreach ($potentialName in 'Asset', 'Assets') {
            $potentialAssets = $place.$potentialName
            if (-not $potentialAssets) { continue }
    
            foreach ($potentialAsset in $potentialAssets) {
    
                    if ($potentialAsset -is [hashtable]) {
                        $AssetObject = [Ordered]@{}
                        foreach ($sortedKeyValue in $place.$potentialName.GetEnumerator() | Sort-Object Key) {
                            $AssetObject[$sortedKeyValue.Key]= $sortedKeyValue.Value
                        }
                        $AssetObject = [PSCustomObject]$AssetObject
                        $AssetObject.pstypenames.clear()
                        $AssetObject.pstypenames.add("$this.Asset")
                        $AssetObject.pstypenames.add('PipeScript.Module.Asset')
                        $AssetObject
                    } elseif ($potentialAsset) {
                        Join-Path ($this.Path | Split-Path) $potentialAsset | ToAssetFile
                    }
            }
        }
    }) -Force
    
    $this |
        Split-Path |
        Get-ChildItem -Directory |
        Where-Object Name -in 'Asset', 'Assets' |
        Get-ChildItem -Recurse -File |
        ToAssetFile
}

$this.'.Assets'


                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>CommandType</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Gets Module Command Types
.DESCRIPTION
    Gets Command Types defined within a Module
.EXAMPLE
    (Get-Module PipeScript).CommandType
#&gt;
param()

if (-not $this.'.CommandTypes') {
    Add-Member -InputObject $this -MemberType NoteProperty -Force -Name '.CommandTypes' (
        # Aspect.ModuleCommandType
        &amp; {
        
            &lt;#
            .SYNOPSIS
                Outputs a module's extension types
            .DESCRIPTION
                Outputs the extension types defined in a module's manifest.
            .EXAMPLE
                # Outputs a PSObject with information about extension command types.
                
                # The two primary pieces of information are the `.Name` and `.Pattern`.
                Aspect.ModuleExtensionType -Module PipeScript # Should -BeOfType ([PSObject])
            #&gt;
            [Alias('Aspect.ModuleCommandTypes','Aspect.ModuleCommandType','Aspect.ModuleExtensionTypes')]
            param(
            # The name of a module, or a module info object.
            [Parameter(Mandatory,ValueFromPipelineByPropertyName)]
            [ValidateScript({
            $validTypeList = [System.String],[System.Management.Automation.PSModuleInfo]
            
            $thisType = $_.GetType()
            $IsTypeOk =
                $(@( foreach ($validType in $validTypeList) {
                    if ($_ -as $validType) {
                        $true;break
                    }
                }))
            
            if (-not $isTypeOk) {
                throw "Unexpected type '$(@($thisType)[0])'. Must be 'string','psmoduleinfo'."
            }
            return $true
            })]
            
            $Module
            )
        
            begin {
                $ExtensionCollectionNames =
                    "Extension", "Command", "Cmdlet", "Function", "Alias", "Script", "Application", "File","Configuration"
                $ExtensionCollectionNames = @($ExtensionCollectionNames -replace '.+$','${0}Type') + @($ExtensionCollectionNames -replace '.+$','${0}Types')
            }
        
            process {
                #region Resolve Module Info
                if ($Module -is [string]) {
                    $Module = Get-Module $Module
                }
                $ModuleInfo = $module
                if (-not $ModuleInfo) { return }
                #endregion Resolve Module Info
        
                #region Check Cache and Hopefully Return
                if (-not $script:ModuleExtensionTypeCache) {
                    $script:ModuleExtensionTypeCache = @{}
                }
                
                if ($script:ModuleExtensionTypeCache[$ModuleInfo]) {
                    return $script:ModuleExtensionTypeCache[$ModuleInfo]
                }
                #endregion Check Cache and Hopefully Return
        
                #region Find Extension Types
                $modulePrivateData = $ModuleInfo.PrivateData
        
                $SortedExtensionTypes = [Ordered]@{}
                foreach ($TypeOfExtensionCollection in $ExtensionCollectionNames) {
                    $moduleExtensionTypes =
                        if ($modulePrivateData.$TypeOfExtensionCollection) {
                            $modulePrivateData.$TypeOfExtensionCollection
                        } elseif ($modulePrivateData.PSData.$TypeOfExtensionCollection) {
                            $modulePrivateData.PSData.$TypeOfExtensionCollection
                        } else {
                            $null
                        }
        
                    if (-not $moduleExtensionTypes) { continue }
        
                    foreach ($commandType in @($ModuleExtensionTypes.GetEnumerator() | Sort-Object Key)) {
                        if ($commandType.Value -is [Collections.IDictionary]) {
                            if (-not $commandType.Value.Name) {
                                $commandType.Value["Name"] = $commandType.Key
                            }
                            if (-not $commandType.Value.PSTypeName) {
                                $commandType.Value["PSTypeName"] = "$($module.Name).ExtensionCommandType"
                            }
                            $SortedExtensionTypes[$commandType.Name] = $commandType.Value
                        } else {
                            $SortedExtensionTypes[$commandType.Name] = [Ordered]@{
                                PSTypeName = "$($module.Name).ExtensionCommandType"
                                Name = $commandType.Key
                                Pattern = $commandType.Value
                            }
                        }
                        if ($TypeOfExtensionCollection -notmatch '(?&gt;Extension|Command|Cmdlet)') {
                            $SortedExtensionTypes[$commandType.Name].CommandType = $TypeOfExtensionCollection -replace 'Type(?:s)?$'
                        } elseif ($TypeOfExtensionCollection -match 'Cmdlet') {
                            $SortedExtensionTypes[$commandType.Name].CommandType = "(?&gt;Alias|Function|Filter|Cmdlet)"
                        }
                    }
                }
                
                $SortedExtensionTypes.PSTypeName="$($Module.Name).ExtensionCommandTypes"
                
                $script:ModuleExtensionTypeCache[$ModuleInfo] = [PSCustomObject]$SortedExtensionTypes
                $script:ModuleExtensionTypeCache[$ModuleInfo]
                #endregion Find Extension Types
        
            }
        
         } -Module $this
    )
}
$this.'.CommandTypes'


                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>Export</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Gets a module's exports
.DESCRIPTION
    Gets everything a module exports or intends to export.

    This combines the various `.Exported*` properties already present on a module.
    
    It also adds anything found in a manifest's `.PrivateData.Export(s)` properties,
    as well as anything in a manifest's `.PrivateData.PSData.Export(s)`.
.NOTES
    This property serves two major purposes:

    1. Interacting with all of the exports from any module in a consistent way
    2. Facilitating exporting additional content from modules, such as classes.
#&gt;
param()
$(
    if ($this.ExportedCommands.Count) {
        $this.ExportedCommands.Values
    } elseif (-not $this.ExportedVariables.Count) {
        foreach ($loadedCommand in $ExecutionContext.SessionState.InvokeCommand.GetCommands("*","Alias,Function,Cmdlet",$true)) {
            if ($loadedCommand.Module -eq $this) {
                $loadedCommand
            }
        }
    }
),
$this.ExportedDSCResources.Values,
$this.ExportedTypeFiles,
$this.ExportedFormatFiles,
$this.ExportedVariables,
$this.PrivateData.Export,
$this.PrivateData.Exports,
$this.PrivateData.PSData.Export,
$this.PrivateData.PSData.Exports -ne $null |
    &amp; { process { if ($_) { $_ } } }
                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>Extension</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Gets Extended Commands
.DESCRIPTION
    Gets Extended Commands for this module
.EXAMPLE
    (Get-Module PipeScript).Extensions
#&gt;
if (-not $this.'.ExtendedCommands') {
    Add-Member -InputObject $this -MemberType NoteProperty -Name '.ExtendedCommands' -Value @(
        $this.FindExtensions()
        $this.FindExtensions(($This | Split-Path))
    ) -Force
}
$this.'.ExtendedCommands'

                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>Files</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Gets all files in a module
.DESCRIPTION
    Gets all of the files located within a module.
    
    Hidden files are ignored.
.EXAMPLE
    (Get-Module PipeScript).Files
#&gt;
param()
$this | Split-Path | Get-ChildItem -File -Recurse

                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>Folders</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Gets all folders in a module
.DESCRIPTION
    Gets all of the file folders located within a module.
    
    Hidden folders are ignored.
.EXAMPLE
    (Get-Module PipeScript).Folders
#&gt;
param()
$this | Split-Path | Get-ChildItem -Directory -Recurse

                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>Route</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Gets module routes
.DESCRIPTION
    Gets information about potential module routes
#&gt;
param()

foreach ($place in $this.PrivateData, $this.PrivateData.PSData) {
    foreach ($potentialName in 'Route', 'Routes','Router','Routers') {
        $potentialRoutes = $place.$potentialName
        if (-not $potentialRoutes) { continue }

        foreach ($potentialRoute in $potentialRoutes) {
            $potentialRoute =
                if ($potentialRoute -is [hashtable]) {
                    $RouteObject = [Ordered]@{}
                    foreach ($sortedKeyValue in $place.$potentialName.GetEnumerator() | Sort-Object Key) {
                        $RouteObject[$sortedKeyValue.Key]= $sortedKeyValue.Value
                    }
                    $RouteObject = [PSCustomObject]$RouteObject
                } elseif ($potentialRoute) {
                    [PSObject]::new($potentialRoute)
                }
            $potentialRoute.pstypenames.clear()
            $potentialRoute.pstypenames.add("$this.Route")
            $potentialRoute.pstypenames.add('PipeScript.Module.Route')
            $potentialRoute
        }
    }
}
                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>Server</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Gets Module Servers
.DESCRIPTION
    Gets any servers associated with a module.

    Servers can be defined within a module's `.PrivateData` or `.PrivateData.PSData`

    Servers are defined within the `.Server','.Servers','.Domain','.Domains','.HostHeader','.HostHeaders' sections of the manifest.
#&gt;
param()

, @(foreach ($place in $this.PrivateData, $this.PrivateData.PSData) {
    foreach ($potentialName in 'Server', 'Servers','Domain','Domains','HostHeader','HostHeaders') {
        $potentialServers = $place.$potentialName
        if (-not $potentialServers) { continue }

        foreach ($potentialServer in $potentialServers) {
            $potentialServer =
                if ($potentialServer -is [hashtable]) {
                    $serverObject = [Ordered]@{}
                    foreach ($sortedKeyValue in $place.$potentialName.GetEnumerator() | Sort-Object Key) {
                        $serverObject[$sortedKeyValue.Key]= $sortedKeyValue.Value
                    }
                    $serverObject = [PSCustomObject]$serverObject
                } elseif ($potentialServer) {
                    [PSObject]::new($potentialServer)
                }
            $potentialServer.pstypenames.clear()
            $potentialServer.pstypenames.add("$this.Server")
            $potentialServer.pstypenames.add('PipeScript.Module.Server')
            $potentialServer
        }
    }
})
                    </GetScriptBlock>
      </ScriptProperty>
    </Members>
  </Type>
  <Type>
    <Name>Route.Command</Name>
    <Members>
      <ScriptMethod>
        <Name>Validate</Name>
        <Script>
                        &lt;#
.SYNOPSIS
    Determines if a given route is valid
.DESCRIPTION
    Determines if a given route is valid and could be used.
.EXAMPLE

#&gt;
param()

$unrolledArgs = $args | . { process { $_ }}

$psRoute = $this
$routeScriptBlock =
if ((-not $psRoute.ScriptBlock) -and $psRoute.ResolvedCommand.ScriptBlock) {
    $psRoute.ResolvedCommand.ScriptBlock
} elseif ($psRoute.ScriptBlock) {
    $psRoute.ScriptBlock
}

if (-not $routeScriptBlock) { return $false }

$validationAttributes = foreach ($attr in $routeScriptBlock.Attributes) {
    if (-not $attr.Validate) { continue }
    if ($attr.ErrorMessage -notmatch '^\$request') {
        Write-Verbose "Skipping Validation for routing because '$($attr.ErrorMessage)' does not start with '`$Request'"
        continue
    }
    $attr
}

if (-not $validationAttributes) { return $false }

foreach ($validationAttribute in $validationAttributes) {
    if (-not $validationAttribute.Validate($unrolledArgs)) {
        return $false
    }
}

return $true
                    </Script>
      </ScriptMethod>
    </Members>
  </Type>
  <Type>
    <Name>System.Management.Automation.ScriptBlock</Name>
    <Members>
      <AliasProperty>
        <Name>AllValidMatches</Name>
        <ReferencedMemberName>AllValidMatch</ReferencedMemberName>
      </AliasProperty>
      <AliasProperty>
        <Name>AllValidObjects</Name>
        <ReferencedMemberName>AllValidObject</ReferencedMemberName>
      </AliasProperty>
      <AliasProperty>
        <Name>AnyValidMatches</Name>
        <ReferencedMemberName>AnyValidMatch</ReferencedMemberName>
      </AliasProperty>
      <AliasProperty>
        <Name>AnyValidObjects</Name>
        <ReferencedMemberName>AnyValidObject</ReferencedMemberName>
      </AliasProperty>
      <ScriptMethod>
        <Name>AllValid</Name>
        <Script>
                        
&lt;#
.SYNOPSIS
    Determines if any validation passes, given an object.
.DESCRIPTION
    Determines if all of the `[ValidateScript]` or `[ValidatePattern]` attributes on a `[ScriptBlock]` pass, given one or more inputs.

    Any input considered valid by all `[ValidateScript]` or `[ValidatePattern]` will be returned.

    If there is no validation present, no objects will be returned.
.EXAMPLE
    {
        [ValidatePattern("a")]
        [ValidatePattern("c$")]
        param()
    }.AllValid("c","b","a","abc")
.EXAMPLE
    {
        [ValidateScript({$_ % 2})]
        [ValidateScript({-not ($_ % 3)})]
        param()
    }.AllValid(1..10)
#&gt;
param()

$allArgs = $args | &amp; { process { $_ }}

, @(
:nextArg foreach ($arg in $allArgs) {
    $validatedArg = $false
    foreach ($attr in $this.Attributes) {
        if (-not $attr.Validate) { continue }
        if (-not $attr.Validate($arg)) { continue nextArg}
        else { $validatedArg = $true }
    }
    if ($validatedArg) {
        $arg
    }
}
)
                    </Script>
      </ScriptMethod>
      <ScriptMethod>
        <Name>AllValidMatch</Name>
        <Script>
                        
&lt;#
.SYNOPSIS
    Determines if all validation matches, given an object.
.DESCRIPTION
    Determines if all of the `[ValidatePattern]` attributes on a `[ScriptBlock]` pass, given one or more inputs.

    Any input considered valid by all `[ValidatePattern]` will be returned.

    If there is no validation present, no objects will be returned.
.EXAMPLE
    {
        [ValidatePattern("a")]
        [ValidatePattern("c$")]
        param()
    }.AllValidMatches("c","b","a","abc")
.EXAMPLE
    {
        [ValidatePattern("a")]
        [ValidatePattern("c$")]
        param()
    }.AllValidMatch("c","b","a","abc")
#&gt;
param()

$allArgs = $args | &amp; { process { $_ }}

, @(
:nextArg foreach ($arg in $allArgs) {
    $validatedArg = $false
    foreach ($attr in $this.Attributes) {
        if (-not $attr.Validate) { continue }
        if ($attr -isnot [ValidatePattern]) { continue }
        if (-not $attr.Validate($arg)) { continue nextArg}
        else { $validatedArg = $true}
    }
    if ($validatedArg) {
        $arg
    }
}
)
                    </Script>
      </ScriptMethod>
      <ScriptMethod>
        <Name>AllValidObject</Name>
        <Script>
                        
&lt;#
.SYNOPSIS
    Determines if all validation matches, given an object.
.DESCRIPTION
    Determines if all of the `[ValidateScript]` attributes on a `[ScriptBlock]` pass, given one or more inputs.

    Any input considered valid by all `[ValidateScript]` will be returned.

    If there is no validation present, no objects will be returned.
.EXAMPLE
    {
        [ValidateScript({$_ % 2})]
        [ValidateScript({-not ($_ % 3)})]
        param()
    }.AllValidObject(1..10)
.EXAMPLE
#&gt;
param()

$allArgs = $args | &amp; { process { $_ }}

, @(
:nextArg foreach ($arg in $allArgs) {
    $validatedArg = $false
    foreach ($attr in $this.Attributes) {
        if (-not $attr.Validate) { continue }
        if ($attr -isnot [ValidateScript]) { continue }
        if (-not $attr.Validate($arg)) { continue nextArg}
        else { $validatedArg = $true}
    }
    if ($validatedArg) {
        $arg
    }
}
)
                    </Script>
      </ScriptMethod>
      <ScriptMethod>
        <Name>AnyValid</Name>
        <Script>
                        
&lt;#
.SYNOPSIS
    Determines if any validation passes, given an object.
.DESCRIPTION
    Determines if any of the `[ValidateScript]` or `[ValidatePattern]` attributes on a `[ScriptBlock]` passes, given an input.

    Any input considered valid by a `[ValidateScript]` or `[ValidatePattern]` will be returned.
.EXAMPLE
    {
        [ValidatePattern("a")]
        [ValidatePattern("b")]
        param()
    }.AnyValid("c","b","a")
.EXAMPLE
    {
        [ValidateScript({$_ % 2})]
        [ValidateScript({-not ($_ % 3)})]
        param()
    }.AnyValid(1..10)
    
#&gt;
param()

$allArgs = $args | &amp; { process { $_ }}

, @(foreach ($attr in $this.Attributes) {
    if (-not $attr.Validate) { continue }
    foreach ($arg in $allArgs) {
        if ($attr.Validate($arg)) {
            $arg
        }
    }
})
                    </Script>
      </ScriptMethod>
      <ScriptMethod>
        <Name>AnyValidMatch</Name>
        <Script>
                        
&lt;#
.SYNOPSIS
    Determines if any validation passes, given an object.
.DESCRIPTION
    Determines if any of the `[ValidateScript]` or `[ValidatePattern]` attributes on a `[ScriptBlock]` passes, given an input.

    Any input considered valid by a `[ValidateScript]` or `[ValidatePattern]` will be returned.
.EXAMPLE
    {
        [ValidatePattern("a")]
        [ValidatePattern("b")]
        param()
    }.AnyValidMatch("c","b","a")
#&gt;
param()

$allArgs = $args | &amp; { process { $_ }}

, @(foreach ($attr in $this.Attributes) {
    if (-not $attr.Validate) { continue }
    if ($attr.Validate -isnot [ValidatePattern]) { continue }
    foreach ($arg in $allArgs) {
        if ($attr.Validate($arg)) {
            $arg
        }
    }
})
                    </Script>
      </ScriptMethod>
      <ScriptMethod>
        <Name>AnyValidObject</Name>
        <Script>
                        
&lt;#
.SYNOPSIS
    Determines if any validation passes, given an object.
.DESCRIPTION
    Determines if any of the `[ValidateScript]` attributes on a `[ScriptBlock]` passes, given an input.

    Any input considered valid by a `[ValidateScript]` will be returned.
.EXAMPLE
    {
        [ValidateScript({$_ -like "a*" })]
        param()
    }.AnyValidObject("a")
#&gt;
param()

$allArgs = $args | &amp; { process { $_ }}

, @(foreach ($attr in $this.Attributes) {
    if (-not $attr.Validate) { continue }
    if ($attr.Validate -isnot [ValidateScript]) { continue }
    foreach ($arg in $allArgs) {
        if ($attr.Validate($arg)) {
            $arg
        }
    }
})
                    </Script>
      </ScriptMethod>
      <ScriptMethod>
        <Name>IsEquivalentTo</Name>
        <Script>
                        &lt;#
.SYNOPSIS
    Attempts to Determine Ast Equivalence
.DESCRIPTION
    Attempts to Determine if `$this` Ast element is the same as some `$Other` object.

    If `$Other is a `[string]`, it will be converted into a `[ScriptBlock]`
    If `$Other is a `[ScriptBlock]`, it will become the `[ScriptBlock]`s AST

    If the types differ, `$other is not equivalent to `$this.

    If the content is the same with all whitespace removed, it will be considered equivalent.
.NOTES
    Due to the detection mechanism, IsEquivalentTo will consider strings with whitespace changes equivalent.
#&gt;
param(
# The other item.
$Other
)

$this.Ast.IsEquivalentTo($other)
                    </Script>
      </ScriptMethod>
      <ScriptMethod>
        <Name>Transpile</Name>
        <Script>
                        $TranspilerErrors = @()
$TranspilerWarnings = @()

$ErrorsAndWarnings = @{ErrorVariable='TranspilerErrors';WarningVariable='TranspilerWarnings'}
$this | .&gt;PipeScript @ErrorsAndWarnings

if ($TranspilerErrors) {
    $failedMessage = (@(
        "$($TranspilerErrors.Count) error(s)"
        if ($transpilerWarnings) {
            "$($TranspilerWarnings.Count) warning(s)"
        }
    ) -join ',') + (@(
        foreach ($transpilerError in $TranspilerErrors) {
            "$($transpilerError | Out-String)"
        }
    ) -join [Environment]::Newline)
    throw $failedMessage
}
elseif ($TranspilerWarnings) {
    foreach ($TranspilerWarning in $TranspilerWarnings) {
        Write-Warning "$TranspilerWarning "
    }
}

                    </Script>
      </ScriptMethod>
      <ScriptProperty>
        <Name>HasValidation</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Determines if a ScriptBlock has validation
.DESCRIPTION
    Determines if a ScriptBlock has either a `[ValidatePattern]` or a `[ValidateScript]` attribute defined.
.EXAMPLE
    {}.HasValidation
.EXAMPLE
    {[ValidateScript({$true})]param()}.HasValidation
#&gt;
param()
foreach ($attr in $this.Attributes) {
    if ($attr -is [ValidatePattern]) { return $true }
    if ($attr -is [ValidateScript]) { return $true }
}
return $false
                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>IsEmpty</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Determines if a ScriptBlock is empty
.DESCRIPTION
    Determines if a ScriptBlock is empty.

    A ScriptBlock is considered empty if it's Abstract Syntax Tree contains no statements or parameters.
#&gt;
$ast = $this.Ast
if ($ast.Body) {
    $ast = $ast.Body
}
foreach ($property in $ast.psobject.Properties) {
    if ($property.Name -notmatch 'Block$') { continue }
    if ($property.Value.Statements.Count) { return $false }
    if ($property.Value.Parameters.Count) { return $false }
}

return $true

                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>Transpilers</Name>
        <GetScriptBlock>
                        $this.Ast.Transpilers

                    </GetScriptBlock>
      </ScriptProperty>
    </Members>
  </Type>
  <Type>
    <Name>System.Management.Automation.Language.ScriptBlockExpressionAst</Name>
    <Members>
      <ScriptMethod>
        <Name>AsScriptBlock</Name>
        <Script>
                        [ScriptBlock]::create($this -replace '^\{' -replace '\}$')

                    </Script>
      </ScriptMethod>
      <ScriptMethod>
        <Name>ConvertFromAST</Name>
        <Script>
                        $this.AsScriptBlock()

                    </Script>
      </ScriptMethod>
      <ScriptProperty>
        <Name>IsEmpty</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Determines if a ScriptBlock AST is empty
.DESCRIPTION
    Determines if a ScriptBlock AST is empty.

    A ScriptBlock is considered empty if it's Abstract Syntax Tree contains no statements or parameters.
#&gt;
$ast = $this
if ($ast.Body) {
    $ast = $ast.Body
}
foreach ($property in $ast.psobject.Properties) {
    if ($property.Name -notmatch 'Block$') { continue }
    if ($property.Value.Statements.Count) { return $false }
    if ($property.Value.Parameters.Count) { return $false }
}

return $true

                    </GetScriptBlock>
      </ScriptProperty>
    </Members>
  </Type>
  <Type>
    <Name>System.Management.Automation.Language.ScriptBlockAst</Name>
    <Members>
      <ScriptMethod>
        <Name>AsScriptBlock</Name>
        <Script>
                        [ScriptBlock]::create($this -replace '^\{' -replace '\}$')

                    </Script>
      </ScriptMethod>
      <ScriptMethod>
        <Name>ConvertFromAST</Name>
        <Script>
                        $this.AsScriptBlock()

                    </Script>
      </ScriptMethod>
      <ScriptProperty>
        <Name>IsEmpty</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Determines if a ScriptBlock AST is empty
.DESCRIPTION
    Determines if a ScriptBlock AST is empty.

    A ScriptBlock is considered empty if it's Abstract Syntax Tree contains no statements or parameters.
#&gt;
$ast = $this
if ($ast.Body) {
    $ast = $ast.Body
}
foreach ($property in $ast.psobject.Properties) {
    if ($property.Name -notmatch 'Block$') { continue }
    if ($property.Value.Statements.Count) { return $false }
    if ($property.Value.Parameters.Count) { return $false }
}

return $true

                    </GetScriptBlock>
      </ScriptProperty>
    </Members>
  </Type>
  <Type>
    <Name>System.Management.Automation.Language.ScriptRequirements</Name>
    <Members>
      <ScriptMethod>
        <Name>ToString</Name>
        <Script>
                        $this.Script.ToString()

                    </Script>
      </ScriptMethod>
      <ScriptProperty>
        <Name>Script</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Gets the script that represents a requires statement
.DESCRIPTION
    Gets the a PowerShell `[ScriptBlock]` that #requires the exact same list of script requirements.

    This script method exists because it provides a way to check the requirements without actually running a full script.
.EXAMPLE
    [ScriptBlock]::Create('#requires -Module PipeScript').Ast.ScriptRequirements.Script
#&gt;
$requirement = $this
[ScriptBlock]::create(
    @(if ($requirement.RequirementPSVersion) {
        "#requires -Version $($requirement.RequirementPSVersion)"
    }
    if ($requirement.IsElevationRequired) {
        "#requires -RunAsAdministrator"
    }
    if ($requirement.RequiredModules) {
        "#requires -Module $(@(foreach ($reqModule in $requirement.RequiredModules) {
            if ($reqModule.Version -or $req.RequiredVersion -or $req.MaximumVersion) {
                '@{' + $(@(foreach ($prop in $reqModule.PSObject.Properties) {
                    if (-not $prop.Value) { continue }
                    if ($prop.Name -in 'Name', 'Version') {
                        "Module$($prop.Name)='$($prop.Value.ToString().Replace("'","''"))'"
                    } elseif ($prop.Name -eq 'RequiredVersion') {
                        "MinimumVersion='$($prop.Value)'"
                    } else {
                        "$($prop.Name)='$($prop.Value)'"
                    }
                }) -join ';') + '}'
            } else {
                $reqModule.Name
            }
        }) -join ',')"
    }
    if ($requirement.RequiredAssemblies) {
        "#requires -Assembly $($requirement.RequiredAssemblies -join ',')"
    }) -join [Environment]::NewLine
)
                    </GetScriptBlock>
      </ScriptProperty>
    </Members>
  </Type>
  <Type>
    <Name>Search.PipeScript.Result</Name>
    <Members>
    </Members>
  </Type>
  <Type>
    <Name>Microsoft.CodeAnalysis.SyntaxNode</Name>
    <Members>
      <ScriptMethod>
        <Name>Find</Name>
        <Script>
                        &lt;#
.SYNOPSIS
    Finds a CSharp Node
.DESCRIPTION
    Finds a single CSharp Syntax Node that meets any one of a number of criteria
.EXAMPLE
    (Parse-CSharp 'Console.WriteLine("Hello World");').Find("*hello*")
#&gt;
param()

$Conditions = @(
foreach ($argument in $args) {
    if ($argument -is [scriptblock]) {
        [ScriptBlock]::Create($argument)
    }
    elseif ($argument -is [string]) {
        [ScriptBlock]::Create("`$_ -like '$argument'")
    }
    elseif ($argument -is [type] -and $argument.IsPublic) {
        [ScriptBlock]::Create("`$_ -as [$($argument.Fullname)]")
    }
}
)

foreach ($node in $this.DescendantNodes($null, $true)) {
    foreach ($condition in $Conditions) {
        $_ = $ast = $node
        $conditionResult = . $condition
        if ($conditionResult) {
            return $node
        }
    }
}




                    </Script>
      </ScriptMethod>
      <ScriptMethod>
        <Name>FindAll</Name>
        <Script>
                        &lt;#
.SYNOPSIS
    Finds all CSharp Nodes
.DESCRIPTION
    Finds all CSharp Syntax Nodes that meet any one of a number of criteria
.EXAMPLE
    (Parse-CSharp 'Console.WriteLine("Hello World");').FindAll("*hello*")
#&gt;
param()

$Conditions = @(
foreach ($argument in $args) {
    if ($argument -is [scriptblock]) {
        [ScriptBlock]::Create($argument)
    }
    elseif ($argument -is [string]) {
        [ScriptBlock]::Create("$_ -like $argument")
    }
}
)

foreach ($node in $this.DescendantNodes($null, $true)) {
    foreach ($condition in $Conditions) {
        $_ = $ast = $node
        $conditionResult = . $condition
        if ($conditionResult) {
            $node
        }
    }
}




                    </Script>
      </ScriptMethod>
      <ScriptProperty>
        <Name>ByType</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Gets CSharp AST Nodes by type
.DESCRIPTION
    Gets a dictionary of all nodes in a CSharp AST beneath this point, grouped by type.
.EXAMPLE
    (Parse-CSharp '"Hello World";').ByType
#&gt;

if (-not $this.'.ByType') {
    $ByType = [Collections.Generic.Dictionary[Type,Collections.Generic.List[PSObject]]]::new()
    foreach ($node in $this.FindAll({$true}, $true)) {
        $nodeType = $node.GetType()

        if (-not $ByType[$nodeType]) {
            $ByType[$nodeType] = [Collections.Generic.List[PSObject]]::new()
        }
        $ByType[$nodeType].Add($node)
    }
    Add-Member -InputObject $this -MemberType NoteProperty -Name '.ByType' -Value $ByType -Force
}

$this.'.ByType'

                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>Defines</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Gets all Definitions within an AST
.DESCRIPTION
    Gets all Class and Type Definitions within a CSharp Abstract Syntax Tree
.EXAMPLE
    Parse-CSharp ('
        public class MyClass {
            public void MyMethod();
        }
    ').Defines
#&gt;

, @(
    foreach ($node in $this.ByType[@(
        [Microsoft.CodeAnalysis.CSharp.Syntax.ClassDeclarationSyntax]
        [Microsoft.CodeAnalysis.CSharp.Syntax.ClassOrStructConstraintSyntax]
        [Microsoft.CodeAnalysis.CSharp.Syntax.MemberDeclarationSyntax]
        [Microsoft.CodeAnalysis.CSharp.Syntax.EnumDeclarationSyntax]
    )]) {
        $node
    }
)

                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>Id</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Gets the Identifier of a Syntax Node.
.DESCRIPTION
    Gets a [string] Identifier of a CSharp syntax node
#&gt;
if ($this.Identifier) {
    "$($this.Identifier)"
}
                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>Text</Name>
        <GetScriptBlock>
                        if (-not $this.'.Text') {
    $this | Add-Member NoteProperty '.Text' $this.GetText() -Force
}

$this.'.Text'

                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>Variables</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Gets all Variables within an AST
.DESCRIPTION
    Gets all Variable and Field Definitions within a CSharp Abstract Syntax Tree
.EXAMPLE
    Parse-CSharp ('
        public class MyClass {
            public void MyMethod() {
                string bar = "bar";
            }
            public int foo = 1;
        }
    ').Variables
#&gt;
@(

foreach ($node in $this.ByType[
    @(
        [Microsoft.CodeAnalysis.CSharp.Syntax.FieldDeclarationSyntax]
        [Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeclarationSyntax]
    )
]) {
    $node
}

)
                    </GetScriptBlock>
      </ScriptProperty>
    </Members>
  </Type>
  <Type>
    <Name>Microsoft.CodeAnalysis.SyntaxTree</Name>
    <Members>
      <ScriptMethod>
        <Name>Find</Name>
        <Script>
                        &lt;#
.SYNOPSIS
    Finds a CSharp Node
.DESCRIPTION
    Finds a single CSharp Syntax Node that meets any one of a number of criteria
.EXAMPLE
    (Parse-CSharp 'Console.WriteLine("Hello World");').Find("*hello*")
#&gt;
$this.Root.Find.Invoke($args)

                    </Script>
      </ScriptMethod>
      <ScriptMethod>
        <Name>FindAll</Name>
        <Script>
                        &lt;#
.SYNOPSIS
    Finds all CSharp Nodes
.DESCRIPTION
    Finds all CSharp Syntax Nodes that meet any one of a number of criteria
.EXAMPLE
    (Parse-CSharp 'Console.WriteLine("Hello World");').FindAll("*hello*")
#&gt;
$this.Root.FindAll.Invoke($args)

                    </Script>
      </ScriptMethod>
      <ScriptProperty>
        <Name>ByType</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Gets CSharp AST Nodes by type
.DESCRIPTION
    Gets a dictionary of all nodes in a CSharp AST beneath this point, grouped by type.
.EXAMPLE
    (Parse-CSharp '"Hello World";').ByType
#&gt;


$this.Root.ByType

                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>Defines</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Gets all Definitions within an AST
.DESCRIPTION
    Gets all Class and Type Definitions within a CSharp Abstract Syntax Tree
.EXAMPLE
    Parse-CSharp ('
        public class MyClass {
            public void MyMethod();
        }
    ').Defines
#&gt;

return $this.Root.Defines

                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>Root</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Gets the root of a Syntax Tree
.DESCRIPTION
    Gets the root of a CSharp Abstract Syntax Tree
.EXAMPLE
    (Parse-CSharp 'Console.WriteLine("Hello world");').Root
#&gt;
if (-not $this.'.Root') {
    $rootObject = $this.GetRoot()
    $rootObject | Add-Member NoteProperty '.Tree' $this -Force
    $this | Add-Member NoteProperty '.Root' $rootObject -Force
}

$this.'.Root'


                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>Text</Name>
        <GetScriptBlock>
                        if (-not $this.'.Text') {
    $this | Add-Member NoteProperty '.Text' $this.GetText([Threading.CancellationToken]::None) -Force
}

$this.'.Text'

                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>Variables</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Gets all Variables within an AST
.DESCRIPTION
    Gets all Variable and Field Definitions within a CSharp Abstract Syntax Tree
.EXAMPLE
    Parse-CSharp ('
        public class MyClass {
            public void MyMethod() {
                string bar = "bar";
            }
            public int foo = 1;
        }
    ').Variables
#&gt;
@(

foreach ($node in $this.ByType[
    @(
        [Microsoft.CodeAnalysis.CSharp.Syntax.FieldDeclarationSyntax]
        [Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeclarationSyntax]
    )
]) {
    $node
}

)
                    </GetScriptBlock>
      </ScriptProperty>
    </Members>
  </Type>
  <Type>
    <Name>System.Management.Automation.Language.TypeConstraintAst</Name>
    <Members>
      <AliasProperty>
        <Name>Args</Name>
        <ReferencedMemberName>ArgumentList</ReferencedMemberName>
      </AliasProperty>
      <AliasProperty>
        <Name>Arguments</Name>
        <ReferencedMemberName>ArgumentList</ReferencedMemberName>
      </AliasProperty>
      <AliasProperty>
        <Name>Parameters</Name>
        <ReferencedMemberName>Parameter</ReferencedMemberName>
      </AliasProperty>
      <ScriptProperty>
        <Name>ArgumentList</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Gets arguments of a type constraint
.DESCRIPTION
    Gets the arguments from a type constraint.

    This will treat any generic type specifiers as potential parameters, and other type specifiers as arguments.
.EXAMPLE
    {
        [a[b[c],c]]'d'
    }.Ast.EndBlock.Statements[0].PipelineElements[0].Expression.Type.ArgumentList
#&gt;
if (-not $this.TypeName.IsGeneric) { return @() }
@(foreach ($typeName in $this.TypeName.GenericArguments ) {
    if ($TypeName.IsGeneric) { continue }
    if (-not $TypeName.IsArray) {
        $TypeName.Name
    }
})

                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>Parameter</Name>
        <GetScriptBlock>
                        
&lt;#
.SYNOPSIS
    Gets parameters to a type constraint
.DESCRIPTION
    Gets the parameters from a type constraint.

    This will treat any generic type specifiers as potential parameters, and other type specifiers as arguments.
.EXAMPLE
    {
        [a[b[c],c]]'d'
    }.Ast.EndBlock.Statements[0].PipelineElements[0].Expression.Type.Parameters
#&gt;
function TypeConstraintToArguments (
    [Parameter(ValueFromPipeline)]
    $TypeName
) {
    begin {
        $TypeNameArgs = @()
        $TypeNameParams = [Ordered]@{}
        
    }
    process {

        if ($TypeName.IsGeneric) {
            $TypeNameParams[$typeName.TypeName.Name] =
                $typeName.GenericArguments |
                    TypeConstraintToArguments
        } elseif (-not $TypeName.IsArray) {
            $TypeNameArgs += $TypeName.Name
        }
    }
    end {
        if ($TypeNameParams.Count) {
            $TypeNameParams
        } elseif ($TypeNameArgs) {
            $TypeNameArgs
        }
    }
}

if (-not $this.TypeName.IsGeneric) { return @{} }
foreach ($arg in @($this.TypeName.GenericArguments | TypeConstraintToArguments)) {
    if ($arg -is [Collections.IDictionary]) {
        $arg
    }
}

                    </GetScriptBlock>
      </ScriptProperty>
      <ScriptProperty>
        <Name>ResolvedCommand</Name>
        <GetScriptBlock>
                        &lt;#
.SYNOPSIS
    Resolves an TypeConstraintAST to a CommandInfo
.DESCRIPTION
    Resolves an TypeConstraintAST to one or more CommandInfo Objects.
.EXAMPLE
    {
        [InvokePipeScript[a]]$null
    }.Ast.EndBlock.Statements[0].PipelineElements[0].Expression.Attribute.ResolvedCommand
.EXAMPLE
    {
        [Microsoft.PowerShell.Core.GetCommand]$null
    }.Ast.EndBlock.Statements[0].PipelineElements[0].Expression.Attribute.ResolvedCommand
.EXAMPLE
    {
        [Get_Command]$null
    }.Ast.EndBlock.Statements[0].PipelineElements[0].Expression.Attribute.ResolvedCommand
.EXAMPLE
    {
        [GetCommand]$null
    }.Ast.EndBlock.Statements[0].PipelineElements[0].Expression.Attribute.ResolvedCommand
.EXAMPLE
    {
        [cmd]$null
    }.EndBlock.Statements[0].PipelineElements[0].Expression.Attribute.ResolvedCommand
#&gt;
# Get the name of the transpiler.
$transpilerStepName =
    if ($this.TypeName.IsGeneric) {
        $this.TypeName.TypeName.Name
    } else {
        $this.TypeName.Name
    }
$decamelCase = [Regex]::new('(?&lt;=[a-z])(?=[A-Z])')
@(
    # If a Transpiler exists by that name, it will be returned first.
    Get-Transpiler -TranspilerName $transpilerStepName
    # Then, any periods in the attribute name will be converted to slashes,
    $fullCommandName = $transpilerStepName -replace '\.','\' -replace
        '_','-' # and any underscores to dashes.

    # Then, the first CamelCased code will have a - injected in between the CamelCase.
    $fullCommandName = $decamelCase.Replace($fullCommandName, '-', 1)
    # Now we will try to find the command.
    $ExecutionContext.SessionState.InvokeCommand.GetCommand($fullCommandName, 'All')
)
                    </GetScriptBlock>
      </ScriptProperty>
    </Members>
  </Type>
  <Type>
    <Name>System.Management.Automation.ValidatePatternAttribute</Name>
    <Members>
      <ScriptMethod>
        <Name>Validate</Name>
        <Script>
                        &lt;#
.SYNOPSIS
    Validates an Object against a Pattern
.DESCRIPTION
    Validates one or more objects against the .RegexPattern of this attribute.
.EXAMPLE
    [ValidatePattern]::new("a").Validate("a") # Should -Be $true
.EXAMPLE
    [ValidatePattern]::new("a").Validate("b") # Should -Be $false
#&gt;
param()

$allArguments = @($args | &amp; { process { $_ } })

$ThisPattern = [Regex]::new(
    $this.RegexPattern,
    $this.Options,
    [timespan]::FromMilliseconds(50)
)


# Validating a Pattern is simple
foreach ($argument in $allArguments) {
    if (-not $ThisPattern.IsMatch("$argument")) {
        return $false
    }
}
return $true


                    </Script>
      </ScriptMethod>
    </Members>
  </Type>
  <Type>
    <Name>System.Management.Automation.ValidateScriptAttribute</Name>
    <Members>
      <ScriptMethod>
        <Name>Validate</Name>
        <Script>
                        &lt;#
.SYNOPSIS
    Validates an Object with a Script
.DESCRIPTION
    Validates one or more objects against the .ScriptBlock of this attribute.

    If the .ScriptBlock does not return "falsey" value (`$false, 0`), the validation will pass.

    If there are no arguments passed, this's ErrorMessage starts with `$`, then the values produced by that expression will be validated.
.EXAMPLE
    [ValidateScript]::new({$_ % 2}).Validate(1) # Should -Be $true
.EXAMPLE
    [ValidateScript]::new({$_ % 2}).Validate(0) # Should -Be $false
#&gt;
param()

$allArguments = @($args | &amp; { process { $_ } })

if ((-not $allArguments.Length) -and
    ($this.ErrorMessage -notmatch '^\$')
) { return }
elseif (-not $allArguments.Length) {
    $allArguments = @(
        $ExecutionContext.SessionState.InvokeCommand.InvokeScript($this.ErrorMessage) | &amp; { process { $_ } }
    )
}


# Validating a Script is mostly simple, except for one fairly large gotcha.
# In PowerShell, two wrongs ($false, $false) will be interpretered as $true
# So, we want want to correct for this "two wrongs make a right".
@(
    @(
        # Run the validate script for every argument
        foreach ($argument in $allArguments) {
            $_ = $psItem = $argument
            try {
                . $this.ScriptBlock $argument |
                . { process {
                    $_ -as [bool] # and quickly determine if each item is truthy
                } }
            } catch {
                Write-Error -ErrorRecord $_
                $false
            }
        }
    ) -as # and force the whole thing into a list, which we see if we can make into
    [bool[]] -eq # an array of booleans.
    $false # Then, PowerShell equality comparison will only return the $false items in the list
).Length -eq 0 # and if nothing is false, we're quite sure that two wrongs didn't make a right, and that our validation passed.






                    </Script>
      </ScriptMethod>
    </Members>
  </Type>
  <Type>
    <Name>System.Management.Automation.Language.VariableExpressionAst</Name>
    <Members>
      <ScriptMethod>
        <Name>ConvertFromAST</Name>
        <Script>
                        &lt;#
.SYNOPSIS
    Converts a VariablExpressionAST to an object
.DESCRIPTION
    Converts a VariablExpressionAST to an object, if possible.

    Most variables we will not know the value of until we have run.

    The current exceptions to the rule are: $true, $false, and $null
#&gt;
if ($this.variablePath.userPath -in 'true', 'false', 'null') {
    $ExecutionContext.SessionState.PSVariable.Get($this.variablePath).Value
} else {
    $this
}

                    </Script>
      </ScriptMethod>
      <ScriptMethod>
        <Name>GetAssignments</Name>
        <Script>
                        &lt;#
.SYNOPSIS
    Gets assignments of a variable
.DESCRIPTION
    Searches the abstract syntax tree for assignments of the variable.
.EXAMPLE
    {
        $x = 1
        $y = 2
        $x * $y
    }.Ast.EndBlock.Statements[-1].PipelineElements[0].Expression.Left.GetAssignments()
.EXAMPLE
    {
        [int]$x, [int]$y = 1, 2
        $x * $y
    }.Ast.EndBlock.Statements[-1].PipelineElements[0].Expression.Left.GetAssignments()
.EXAMPLE
    {
        param($x, $y)
        $x * $y
    }.Ast.EndBlock.Statements[-1].PipelineElements[0].Expression.Left.GetAssignments()
#&gt;
param()

$astVariableName = "$this"
$variableFoundAt = @{}
foreach ($parent in $this.GetLineage()) {
    $parent.FindAll({
        param($ast)
        $IsAssignment =
            (
                $ast -is [Management.Automation.Language.AssignmentStatementAst] -and
                $ast.Left.Find({
                    param($leftAst)
                    $leftAst -is [Management.Automation.Language.VariableExpressionAST] -and
                    "$leftAst" -eq $astVariableName
                }, $false)
            ) -or (
                $ast -is [Management.Automation.Language.ParameterAst] -and
                "$($ast.Name)" -eq $astVariableName
            )

        if ($IsAssignment -and -not $variableFoundAt[$ast.Extent.StartOffset]) {
            $variableFoundAt[$ast.Extent.StartOffset] = $ast
            $ast
        }
    }, $false)
}

                    </Script>
      </ScriptMethod>
      <ScriptMethod>
        <Name>GetVariableType</Name>
        <Script>
                        &lt;#
.SYNOPSIS
    Gets a Variable's Likely Type
.DESCRIPTION
    Determines the type of a variable.

    This looks for the closest assignment statement and uses this to determine what type the variable is likely to be.
.NOTES
    Subject to revision and improvement. While this covers many potential scenarios, it does not always
.EXAMPLE
    {
        [int]$x = 1
        $y = 2
        $x + $y
    }.Ast.EndBlock.Statements[-1].PipelineElements[0].Expression.Left.GetVariableType()
    # Should -Be ([int])
.EXAMPLE
    {
        $x = Get-Process
        $x + $y
    }.Ast.EndBlock.Statements[-1].PipelineElements[0].Expression.Left.GetVariableType()
    # Should -Be ([Diagnostics.Process])
.EXAMPLE
    {
        $x = [type].name
        $x
    }.Ast.EndBlock.Statements[-1].PipelineElements[0].Expression.GetVariableType()

#&gt;
if ($this.VariablePath.userPath -eq 'psBoundParmeters') {
    return [Management.Automation.PSBoundParametersDictionary]
}
$assignments = $this.GetAssignments()
$closestAssignment = $assignments[0]

# Our easiest scenario is that the variable is assigned in a parameter
if ($closestAssignment -is [Management.Automation.Language.ParameterAst]) {
    # If so, the .StaticType will give us our variable type.
    return $closestAssignment.StaticType
}

# Our next simple scenario is that the closest assignment is declaring a hashtable
if ($closestAssignment.Right.Expression -is [Management.Automation.Language.HashtableAst]) {
    return [hashtable]
}

# The left can be a convert expression.
if ($closestAssignment.Left -is [Management.Automation.Language.ConvertExpressionAst]) {
    # If the left was [ordered]
    if ($closestAssignment.Left.Type.Tostring() -eq '[ordered]') {
        return [Collections.specialized.OrderedDictionary] # return an OrderedDictionary
    } else {
        # If the left side's type can be reflected
        $reflectedType = $closestAssignment.Left.Type.TypeName.GetReflectionType()
        if ($reflectedType) {
            return $reflectedType # return it.
        }
        else {
            # otherwise, return the left's static type.
            return $closestAssignment.Left.StaticType
        }
    }
}

# Determine if the left side is multiple assignment
$isMultiAssignment =$closestAssignment.Left -is [Management.Automation.Language.ArrayLiteralAst]

# If the left side is not multiple assignment, but the right side is an array
if (-not $isMultiAssignment -and
    $closestAssignment.Right.Expression -is [Management.Automation.Language.ArrayExpressionAst]) {
    # then the object is an array.
    return [Object[]]
}

# Next, if the right as a convert expression
if ($closestAssignment.Right.Expression -is [Management.Automation.Language.ConvertExpressionAst]) {
    # If it was '[ordered]'
    if ($closestAssignment.Right.Expression.Type.Tostring() -eq '[ordered]') {
        # return an ordered dictionary
        return [Collections.specialized.OrderedDictionary]
    } else {
        # Otherwise, see if we have a reflected type.
        $reflectedType = $closestAssignment.Right.Expression.Type.TypeName.GetReflectionType()
        if ($reflectedType) {
            return $reflectedType # If we do, return it.
        }
        else {
            # If we don't, return the static type of the expression
            return $closestAssignment.Right.Expression.StaticType
        }
    }
}

if ($closestAssignment.Right.Expression -is [Management.Automation.Language.MemberExpressionAst]) {
    $invokeMemberExpr = $closestAssignment.Right.Expression
    $memberName = $invokeMemberExpr.Member.ToString()
    if ($invokeMemberExpr.Expression.TypeName) {
        $invokeType = $invokeMemberExpr.Expression.TypeName.GetReflectionType()
        if ($invokeType) {
            $potentialTypes = @(
            foreach ($invokeableMember in $invokeType.GetMember($memberName, "Public, IgnoreCase,$(if ($invokeMemberExpr.Static) { 'Static'} else { 'Instance'})")) {
                if ($invokeableMember.PropertyType) {
                    $invokeableMember.PropertyType
                } elseif ($invokeableMember.ReturnType) {
                    $invokeableMember.ReturnType
                }
            })
            return $potentialTypes | Select-Object -Unique
        }
    }
}


# The right side could be a pipeline
if ($closestAssignment.Right -is [Management.Automation.Language.PipelineAst]) {
    # If so, walk backwards thru the pipeline
    for ($pipelineElementIndex = $closestAssignment.Right.PipelineElements.Count - 1;
        $pipelineElementIndex -ge 0;
        $pipelineElementIndex--) {
        $commandInfo = $closestAssignment.Right.PipelineElements[$pipelineElementIndex].ResolvedCommand
        # If the command had an output type, return it.
        if ($commandInfo.OutputType) {
            return $commandInfo.OutputType.Type
        }
    }
}

# If we don't know, return nothing
return
                    </Script>
      </ScriptMethod>
    </Members>
  </Type>
  <Type>
    <Name>YAML</Name>
    <Members>
    </Members>
  </Type>
</Types>