注-この回答が役に立った場合は、jonZの回答に賛成してください。彼の有益な回答がなかった場合、私はこれを思い付くことができなかったでしょう。
この関数抽出関数は、リンク先のスクリプト@jonZに基づいて作成しました。これは[System.Management.Automation.PsParser]::Tokenize
、入力スクリプト内のすべてのトークンをトラバースするために使用し、関数を関数情報オブジェクトに解析して、すべての関数情報オブジェクトを配列として返します。各オブジェクトは次のようになります。
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"