Is it possible to include functions only without running a script?

Say I have MyScript.ps1:

[cmdletbinding()]
param ( 
    [Parameter(Mandatory=$true)]
        [string] $MyInput
)

function Show-Input {
    param ([string] $Incoming)
    Write-Output $Incoming
}

function Save-TheWorld {
    #ToDo
}

Write-Host (Show-Input $MyInput)

Is it possible to accurately calculate the source of functions? The problem is that if the script is above the source point, it does all this ...

I prefer to use Get-Contentand analyze functions and use Invoke-Expression ...? Or is there a way to access the PowerShell parser programmatically? I see that this is possible with PSv3 using [System.Management.Automation.Language.Parser]::ParseInput, but this is not an option because it should work on PSv2.

, , , Pester PowerShell , - . :

MyScript.Tests.ps1

$here = Split-Path -Parent $MyInvocation.MyCommand.Path
$sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path).Replace(".Tests.", ".")
. "$here\$sut"

Describe "Show-Input" {

    It "Verifies input 'Hello' is equal to output 'Hello'" {
        $output = Show-Input "Hello"
        $output.should.be("Hello")
    }
}
+5
2

. , , jonZ, , .

- script @jonZ, . [System.Management.Automation.PsParser]::Tokenize script . :

Start       : 99
Stop        : 182
StartLine   : 7
Name        : Show-Input
StopLine    : 10
StartColumn : 5
StopColumn  : 1
Text        : {function Show-Input {,     param ([string] $Incoming),     Write-Output $Incoming, }}

text , Invoke-Expression.

, , : Get-Process ; function foo () {, , .

function Get-Functions {
    param (
        [Parameter(Mandatory=$true)]
        [System.IO.FileInfo] $File
    )

    try {
        $content = Get-Content $File
        $PSTokens = [System.Management.Automation.PsParser]::Tokenize($content, [ref] $null)

        $functions = @()

        #Traverse tokens.
        for ($i = 0; $i -lt $PSTokens.Count; $i++) {
            if($PSTokens[$i].Type -eq  'Keyword' -and $PSTokens[$i].Content -eq 'Function' ) {
                $fxStart = $PSTokens[$i].Start
                $fxStartLine = $PSTokens[$i].StartLine
                $fxStartCol = $PSTokens[$i].StartColumn

                #Skip to the function name.
                while (-not ($PSTokens[$i].Type -eq  'CommandArgument')) {$i++}
                $functionName = $PSTokens[$i].Content

                #Skip to the start of the function body.
                while (-not ($PSTokens[$i].Type -eq 'GroupStart') -and -not ($PSTokens[$i].Content -eq '{')) {$i++ }

                #Skip to the closing brace.
                $startCount = 1 
                while ($startCount -gt 0) { $i++ 
                    if ($PSTokens[$i].Type -eq 'GroupStart' -and $PSTokens[$i].Content -eq '{') {$startCount++}
                    if ($PSTokens[$i].Type -eq 'GroupEnd'   -and $PSTokens[$i].Content -eq '}') {$startCount--}
                }

                $fxStop = $PSTokens[$i].Start
                $fxStopLine = $PSTokens[$i].StartLine
                $fxStopCol = $PSTokens[$i].StartColumn

                #Extract function text. Handle 1 line functions.
                $fxText = $content[($fxStartLine -1)..($fxStopLine -1)]
                $origLine = $fxText[0]
                $fxText[0] = $fxText[0].Substring(($fxStartCol -1), $fxText[0].Length - ($fxStartCol -1))
                if ($fxText[0] -eq $fxText[-1]) {
                    $fxText[-1] = $fxText[-1].Substring(0, ($fxStopCol - ($origLine.Length - $fxText[0].Length)))
                } else {
                    $fxText[-1] = $fxText[-1].Substring(0, ($fxStopCol))
                }

                $fxInfo = New-Object -TypeName PsObject -Property @{
                    Name = $functionName
                    Start = $fxStart
                    StartLine = $fxStartLine
                    StartColumn = $fxStartCol
                    Stop = $fxStop
                    StopLine = $fxStopLine
                    StopColumn = $fxStopCol
                    Text = $fxText
                }
                $functions += $fxInfo
            }
        }
        return $functions
    } catch {
        throw "Failed in parse file '{0}'. The error was '{1}'." -f $File, $_
    }
}

# Dumping to file and dot sourcing:
Get-Functions -File C:\MyScript.ps1 | Select -ExpandProperty Text | Out-File C:\fxs.ps1
. C:\fxs.ps1
Show-Input "hi"

#Or import without dumping to file:

Get-Functions -File  C:\MyScript.ps1 | % { 
    $_.Text -join [Environment]::NewLine | Invoke-Expression
}
Show-Input "hi"
+2

Doug Get-Function, :

$script = get-item .\myscript.ps1
foreach ($function in (get-function $script))
{
  $startline = $function.line - 1
  $endline = $startline
  $successful = $false
  while (! $successful)
  {
    try {
      $partialfunction = ((get-content $script)[$startline..$endline]) -join [environment]::newline
      invoke-expression $partialfunction
      $successful = $true
    }
    catch [Exception] { $endline++ }
  }
}

: [System.Management.Automation.IncompleteParseException] [] Powershell V2.

+3

All Articles