【问题标题】:How to call outside defined function in runspace scriptblock如何在运行空间脚本块中调用外部定义的函数
【发布时间】:2019-01-19 23:07:43
【问题描述】:

我有一个复杂的 PowerShell 函数,我想运行另一个线程。

但是,如果我是对的,则无法在脚本块中访问该函数。我想避免复制它旁边的每个相关函数。

有什么方法或者方法可以调用scriptblock中的函数吗?

function Function1 {
    Param()
    Process {
        $param1 = "something"
        $pool = [RunspaceFactory]::CreateRunspacePool(1, [int]$env:NUMBER_OF_PROCESSORS + 1)
        $pool.ApartmentState = "MTA"
        $pool.Open()
        $runspaces = @()

        $scriptblock = {
            Param (
                [Object] [Parameter(Mandatory = $true)] $param1
            )
            Complex_Function -param1 $param1
        }

        1..10 | ForEach-Object {
            $runspace = [PowerShell]::Create()
            $null = $runspace.AddScript($scriptblock)
            $null = $runspace.AddArgument($param1)
            $runspace.RunspacePool = $pool
            $runspaces += [PSCustomObject]@{ Pipe = $runspace; Status = $runspace.BeginInvoke() }
        }

        while ($runspaces.Status -ne $null) {
            $completed = $runspaces | Where-Object { $_.Status.IsCompleted -eq $true }
            foreach ($runspace in $completed) {
                $runspace.Pipe.EndInvoke($runspace.Status)
                $runspace.Status = $null
            }
        }

        $pool.Close()
        $pool.Dispose()
    }
}

function Complex_Function {
    Param(
        [Object] [Parameter(Mandatory = $true)] $param1
    )
    Process {
        #several function calls 
    }
}

【问题讨论】:

  • 您可以将complex_function 本身传递给您的脚本块。你可以试试看:stackoverflow.com/questions/22129621/…
  • 如何使用 AddArgument 函数传递它?它也有一些论据。
  • 我认为你可以使用类似 Invoke-Command -ScriptBlock ${Function:Complex_Function} -ArgumentList 'arg1','arg2' 的东西。我发现了一个关于这个的博客here

标签: multithreading powershell runspace scriptblock


【解决方案1】:

我认为在this blog post 中找到的代码可能就是您要查找的内容:

Function ConvertTo-Hex {
    Param([int]$Number)
    '0x{0:x}' -f $Number
}

#Get body of function
$Definition = Get-Content Function:\ConvertTo-Hex -ErrorAction Stop

#Create a sessionstate function entry
$SessionStateFunction = New-Object System.Management.Automation.Runspaces.SessionStateFunctionEntry 
    -ArgumentList 'ConvertTo-Hex', $Definition

#Create a SessionStateFunction

$InitialSessionState.Commands.Add($SessionStateFunction)

 #Create the runspacepool by adding the sessionstate with the custom function

$RunspacePool = [runspacefactory]::CreateRunspacePool(1,5,$InitialSessionState,$Host)

对您的 Complex_Function 和(我猜)您需要的所有其他功能执行类似的操作,并且它们应该可供您的运行空间使用。

编辑 您在 cmets 中询问如何收集所有功能。路径function:/ 可以像目录一样被遍历和搜索,所以get-chiditem function:/ 获取所有当前定义的函数。

在对此进行试验时,似乎在当前脚本中或从点源脚本中定义的函数有一个空的Source 属性。玩这个。它应该导致你想要的。

$InitialSessionState = [initialsessionstate]::Create()

Get-ChildItem function:/ | Where-Object Source -like "" | ForEach-Object {
    $functionDefinition = Get-Content "Function:\$($_.Name)"
    $sessionStateFunction = New-Object System.Management.Automation.Runspaces.SessionStateFunctionEntry `
        -ArgumentList $_.Name, $functionDefinition 
    $InitialSessionState.Commands.Add($sessionStateFunction)
}

【讨论】:

  • 谢谢,它正在工作!您知道如何将所有内容加载到会话中吗?我有很多循环函数,导入所有内容可能需要很长时间。
  • @tomas 我用你可以试验的东西更新了答案。我不确定是否有一种简单的方法可以获取一切
  • 再次感谢。我也开始编写类似这样的代码,但不幸的是缺少某些东西(函数或模块)并且进程立即退出。但是我发现有一个$pool.InitialSessionState.ImportPSModule 函数可以用来将另一个模块(甚至是当前模块)导入运行空间。也许它可以成为解决方案。
猜你喜欢
  • 2018-02-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-02
  • 1970-01-01
  • 2016-06-07
  • 1970-01-01
相关资源
最近更新 更多