powershell 从脚本获取函数列表

pbpqsu0x  于 2023-03-08  发布在  Shell
关注(0)|答案(5)|浏览(397)

如果我有一个.ps1文件,其中包含以下函数

function SomeFunction {}

function AnotherFunction {}

我怎样才能得到所有这些函数的列表并调用它们呢?
我想这样做:

$functionsFromFile = Get-ListOfFunctions -Path 'C:\someScript.ps1'
foreach($function in $functionsFromFile)
{
   $function.Run() #SomeFunction and AnotherFunction execute
}
i7uaboj4

i7uaboj41#

您可以使用Get-ChildItem检索所有函数并将其存储到变量中。然后将脚本加载到运行空间并再次检索所有函数,并使用Where-Object cmdlet通过排除所有以前检索的函数来筛选所有新函数。最后,迭代所有新函数并调用它们:

$currentFunctions = Get-ChildItem function:
# dot source your script to load it to the current runspace
. "C:\someScript.ps1"
$scriptFunctions = Get-ChildItem function: | Where-Object { $currentFunctions -notcontains $_ }

$scriptFunctions | ForEach-Object {
      & $_.ScriptBlock
}
xjreopfe

xjreopfe2#

  • ·解决方案1.*

如果需要使用其他脚本文件中的函数,可以使用**Import-Module**cmdlet导入该函数

    • Functions.ps1**包含全部函数。此脚本需要由主脚本导入。
function Write-TextColor
{
    Param(
        [parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
        [ValidateNotNullOrEmpty()]
        [Object]
        $Info,

        [parameter(Position=1, ValueFromPipeline=$true)]
        [ValidateNotNullOrEmpty()]
        [System.ConsoleColor]
        $ForegroundColor =  [System.ConsoleColor]::White,

        [parameter(Position=2, ValueFromPipeline=$true)]
        [ValidateNotNullOrEmpty()]
        [Switch]
        $NoNewLine
        )

        Process{
            foreach ($value in $Info)
            {
                if($NoNewLine)
                {
                    Write-Host $value -ForegroundColor $ForegroundColor -NoNewline
                }
                else {
                    Write-Host $value -ForegroundColor $ForegroundColor
                }
            }            
        }
}
function Write-InfoBlue 
{
    Param(
        [parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
        [ValidateNotNullOrEmpty()]
        [Object]
        $Information,

        [parameter(Position=1, ValueFromPipeline=$true)]
        [Switch]
        $NoNewLine
        )

    Process{
        Write-TextColor $Information Blue $NoNewLine
    }
}
    • 主电源1**
Import-Module -Name "$($PSCommandPath | Split-Path)/Functions.ps1" -Force
Write-InfoBlue "Printed from imported function."
    • 控制台输出**
  • ·溶液2。*

    • Functions.ps1**包含完整函数。此脚本需要由主脚本导入。与Solution1的脚本相同。
    • 主电源1**

此脚本包含3个函数。
1.* * Get-ScriptFunctionNames**.返回一个String数组,每个元素为函数名。
2.* * Get-ScriptFunctionDefinitions**.返回一个String数组,每个元素都是完整的函数。
3.* * Get-AmalgamatedScriptFunctionDefinitions**。它只返回一个字符串,即联接函数Get-ScriptFunctionDefinitions返回的所有元素的结果。所有3个字符串都需要相同的参数,即Powershell脚本文件的路径。
我们将在此文件上测试3个函数。
此脚本不使用Import-Module cmdlet。

function Get-ScriptFunctionNames {
    param (
        [parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
        [AllowEmptyString()]
        [AllowNull()]
        [System.String]
        $Path
    )
    Process{
        [System.Collections.Generic.List[String]]$FX_NAMES = New-Object System.Collections.Generic.List[String]

        if(!([System.String]::IsNullOrWhiteSpace($Path)))
        { 
            Select-String -Path "$Path" -Pattern "function" | 
            ForEach-Object {
                [System.Text.RegularExpressions.Regex] $regexp = New-Object Regex("(function)( +)([\w-]+)")
                [System.Text.RegularExpressions.Match] $match = $regexp.Match("$_")
                if($match.Success)
                {
                    $FX_NAMES.Add("$($match.Groups[3])")
                }   
            }    
        }
        return ,$FX_NAMES.ToArray()
    }
}
function Get-ScriptFunctionDefinitions {

    param (
        [parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
        [AllowEmptyString()]
        [AllowNull()]
        [System.String]
        $Path
    )
    Process{
        [System.Collections.Generic.List[String]]$FX_DEFS = New-Object System.Collections.Generic.List[String]
        if(!([System.String]::IsNullOrWhiteSpace($Path)))
        {
            Import-Module -Name "$Path" -Force 
        }
        $names = Get-ScriptFunctionNames -Path $Path
        Get-ChildItem "function:" | Where-Object { $_ -in $names } | ForEach-Object{
            $FX_DEFS.Add("function $($_.Name) { $($_.Definition) };")
        }
        return ,$FX_DEFS.ToArray()
    }
}

function Get-AmalgamatedScriptFunctionDefinitions {

    param (
        [parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
        [AllowEmptyString()]
        [AllowNull()]
        [System.String]
        $Path
    )
    Process{
        [System.String]$FX_DEFS = ""
        Get-ScriptFunctionDefinitions -Path $Path | 
        ForEach-Object {
            $FX_DEFS += "$_$([System.Environment]::NewLine)$([System.Environment]::NewLine)"
        }
        return $FX_DEFS
    }
}
Write-Host
[System.String[]]$FX_NAMES = Get-ScriptFunctionNames -Path "$($PSCommandPath | Split-Path)/Functions.ps1"
[System.String[]]$FX_DEFS = Get-ScriptFunctionDefinitions -Path "$($PSCommandPath | Split-Path)/Functions.ps1"
[System.String] $FX_ALL_DEFS = Get-AmalgamatedScriptFunctionDefinitions -Path "$($PSCommandPath | Split-Path)/Functions.ps1"

. ([System.Management.Automation.ScriptBlock]::Create($FX_ALL_DEFS)) #The functions in Functions.ps1 are created in the current script.
Write-InfoBlue "Printed from imported function."

检查:点源操作员。
Dot Source
ScriptBlock

    • 控制台输出**

将以下内容添加到Main.ps1,我们可以测试3个功能。

Write-Host "• TEST 1" -ForegroundColor Magenta
$FX_NAMES | 
ForEach-Object {
    Write-Host $_
}
Write-Host

Write-Host "• TEST 2" -ForegroundColor Magenta
foreach($value in $FX_DEFS)
{
    Write-Host $value
    Write-Host "███" -ForegroundColor DarkGray
}
Write-Host

Write-Host "• TEST 3" -ForegroundColor Magenta
Write-Host $FX_ALL_DEFS

控制台输出**

    • 3.额外解决方案-特殊情况**当获得函数的定义时,使用它们来调用不包含本地函数定义的远程计算机上的命令可能是有用的,我们简单地获得定义并如下通过参数传递它们。

如果您需要在远程计算机上运行powershell命令,请在远程计算机上安装Powershell Core

    • 本地文件**
    • 打印颜色函数. ps1**

内容与解决方案1的脚本相同。

    • 本地文件****Main.ps1**
$FX_ALL_DEFS = Get-AmalgamatedScriptFunctionDefinitions -Path "$($PSCommandPath | Split-Path)/Functions.ps1"
$R_HOST = "192.168.211.1" 
$R_USERNAME = "root" 
$R_PORT = "2222" 
$R_SESSION = New-PSSession -HostName $R_USERNAME@$($R_HOST):$R_PORT #//Connected by OpenSSL, private key added to OpenSSH Session Agent. If you need login by password, remove the private key from OpenSSH Session Agent and write as follows user:pass@host:port $($R_USERNAME):$R_PASS@$($R_HOST):$R_PORT
Invoke-Command -ArgumentList $FX_ALL_DEFS,"Joma" -Session $R_SESSION -ScriptBlock{ #// -ArgumentList function definitions and a name.
    Param($fxs, $name) #// Param received by remote context.
    . ([System.Management.Automation.ScriptBlock]::Create($fxs)) #//Creating function definitions in remote script context.

    Clear-Host
    Write-Host "Running commands in my remote Linux Server" -ForegroundColor Green #//Powershell Core cmdlet
    #//We can use Write-InfoBlue on this script context.
    Write-InfoBlue ($(Get-Content /etc/*-release | Select-String -Pattern "^PRETTY_NAME=.*" ).ToString().Split("=")[1]) #//Created function + cmdlets combo
    Write-InfoBlue $(uname -a) #//Created function + Native remote command
    Write-InfoBlue $(whoami) #//Cmdlet + Native remote command
    printf "Hello! $name" #//Native remote command
    Write-InfoBlue "Local function executed in remote context"
}
Remove-PSSession -Session $R_SESSION
    • 控制台输出**
ckocjqey

ckocjqey3#

我需要从一个多功能脚本中得到函数的名称。这是我想到的。基于此,也许有人可以提供一个更短的版本。

# Get text lines from file that contain 'function' 
$functionList = Select-String -Path $scriptName -Pattern "function"

# Iterate through all of the returned lines
foreach ($functionDef in $functionList)
{
    # Get index into string where function definition is and skip the space
    $funcIndex = ([string]$functionDef).LastIndexOf(" ") + 1

    # Get the function name from the end of the string
    $FunctionExport = ([string]$functionDef).Substring($funcIndex)

    Write-Output $FunctionExport
}

我想出了一个较短的版本来查找和列出脚本列表中的函数。它并不完美,会有一个问题,因为模式只是单词“Function”,如果这个方法将假设它在任何找到关键字的地方都找到了函数。
为了迭代文件并获得列表,我使用了“Get-ChildItem”函数,并使用递归选项传递了路径和文件过滤器规范。
它通过管道传递到“Select-String”中,并查找“Function”关键字。它不区分大小写,将接受“Function”或“function”。如果需要,可以通过添加“-CaseSensitive”来提供区分大小写的选项。
然后迭代输出以获得实际的函数名。“Line”成员是一个字符串类型,我使用了从位置9开始的“Substring”选项,这是刚刚传递给“function”标识符的长度。

$scriptPath = "c:\\Project"
$scriptFilter = "*.ps1"

( Get-ChildItem -Path $scriptPath -Filter $scriptFilter -Recurse | Select-String -Pattern "function" ) | %{ $_.Line.Substring(9) }
ivqmmu1c

ivqmmu1c4#

事实上,Powershell已经有了方法,为什么还要重新发明轮子呢?我们可以简单地把它做成一个模块:

cp .\scriptFile.ps1 .\scriptfile.psm1

然后导入模块

import-module .\scriptfile.psm1

现在,获取所有函数

get-command -module scriptfile

function SomeFunction
function AnotherFunction
5ssjco0h

5ssjco0h5#

这是一个一行程序的解决方案,如果有人还在寻找它

Get-Content "C:\Path\To\File.ps1" | Select-String -Pattern "function\s+([^\s{]+)" | Foreach-Object { $_.Matches.Groups[1].Value }

说明:

  • Get-Content "C:\Path\To\File.ps1"读取指定文件的内容,并将内容作为字符串数组输出。
  • Select-String -Pattern "function\s+([^\s{]+)"在输入文本中搜索与指定正则表达式模式的匹配项。此模式与关键字function匹配,关键字function后跟一个或多个空白字符,关键字function后跟一个或多个非空白字符,直到左大括号符号,并捕获组中匹配的非空白字符。
  • Foreach-Object { $_.Matches.Groups[1].Value }循环遍历Select-String找到的每个匹配项,并使用$_变量提取第一个捕获组的值(函数名),该变量表示管道中的当前对象。然后将提取的函数名输出到控制台。

相关问题