Как вызвать внешнюю определенную функцию в блоке сценария пространства выполнения

У меня есть сложная функция PowerShell, которую я хотел бы запустить в других потоках.

Однако, если я прав, функция не может быть доступна в блоке сценариев. Я хочу избежать копирования каждой связанной функции рядом с ней.

Есть ли способ или метод вызвать функцию в блоке сценария?

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 
    }
}

person tomas    schedule 13.08.2018    source источник
comment
Вы можете передать сам complex_function в свой блок скриптов. Вы можете попробовать: stackoverflow.com /вопросы/22129621/   -  person Clijsters    schedule 13.08.2018
comment
Как я могу передать его с помощью функции AddArgument? У него также есть некоторые аргументы.   -  person tomas    schedule 13.08.2018
comment
Я думаю, вы можете использовать что-то вроде этого Invoke-Command -ScriptBlock ${Function:Complex_Function} -ArgumentList 'arg1','arg2'. Я нашел блог об этом здесь   -  person Theo    schedule 13.08.2018


Ответы (1)


Я думаю, что код, найденный в эта запись в блоге, вероятно, то, что вы ищете:

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 и (я думаю) любой другой функцией, которая вам нужна, и они должны использоваться вашими пространствами выполнения.

edit Вы спрашивали в комментариях, как собрать все функции. Путь 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)
}
person veefu    schedule 13.08.2018
comment
Спасибо, это работает! Вы знаете, как я могу загрузить все в сеанс? У меня много зацикленных функций, и импорт всего может занять много времени. - person tomas; 13.08.2018
comment
@tomas Я обновил ответ чем-то, с чем вы можете поэкспериментировать. Я не уверен, что есть простой способ получить все. - person veefu; 13.08.2018
comment
Спасибо еще раз. Я также начал писать очень похожий код, но, к сожалению, чего-то не хватает (функция или модуль), и процесс немедленно завершается. Однако я обнаружил, что есть функция $pool.InitialSessionState.ImportPSModule, которую можно использовать для импорта другого модуля (даже текущего) в пространство выполнения. Может быть, это может быть решением. - person tomas; 13.08.2018