winforms 如何在不同的PowerShell运行空间中重用本地函数?

bpsygsoo  于 2022-11-17  发布在  Shell
关注(0)|答案(1)|浏览(120)

我一直在学习运行空间和Winforms,我想知道如何为我创建的每个不同的运行空间重用一个函数。我可以通过在每个脚本块中包含函数的完整脚本来使它工作,但我希望只写一次函数,并在创建新的运行空间时引用它。
以下是我目前拥有的:

$hash = [hashtable]::Synchronized(@{})
$Script:Jobs = [system.collections.arraylist]::Synchronized((New-Object System.Collections.ArrayList))
# Our main GUI Form object
$hash.Form = New-Object System.Windows.Forms.Form

# Results that come back from the query get saved here
$script:hash.ServerResults = $null

# Buttons
$hash.QueryServerButton = New-Object System.Windows.Forms.Button

# Button properties
$hash.QueryServerButton.Location = New-Object System.Drawing.Point(40,300)
$hash.QueryServerButton.Size = New-Object System.Drawing.Size (105,40)
$hash.QueryServerButton.Text = "Get Servers"
$hash.QueryServerButton.Add_Click({
    PerformRunspaceAction($QueryServer)
})
$hash.ServerTab.Controls.Add($hash.QueryServerButton)

$QueryServer = {
    $connectionString = "Server=xxx\xxx;Database=xxxx;Trusted_Connection=True;"
    $sql = @"
    SELECT * FROM DB_DB;
    "@

    do {
        Start-Sleep -Seconds 30  
        $script:hash.ServerResults = sqlExecuteRead $connectionString $sql $pars
    } while ($true)
}

Function PerformRunspaceAction {
            param($scriptRun)
    
            $newRunspace = [runspacefactory]::CreateRunspace()
            $newRunspace.ApartmentState = "STA"
            $newRunspace.ThreadOptions = "ReuseThread"
            $newRunspace.Open()
            $newRunspace.SessionStateProxy.SetVariable("hash", $hash)
    
            $Powershell = [powershell]::Create().AddScript($scriptRun)
            $Powershell.Runspace = $newRunspace
            [void]$Script:Jobs.Add((
                [PSCustomObject]@{
                    PowerShell = $PowerShell
                    Runspace = $PowerShell.BeginInvoke()
                }
            ))
    }

function sqlExecuteRead($connectionString, $sqlCommand, $pars) {

    $connection = new-object system.data.SqlClient.SQLConnection($connectionString)
    $connection.Open()
    $command = new-object system.data.sqlclient.sqlcommand($sqlCommand, $connection)

    if ($pars -and $pars.Keys) {
       foreach($key in $pars.keys) {
        # avoid injection in varchar parameters
            $par = $command.Parameters.Add("@$key", [system.data.SqlDbType]::VarChar, 512);
            $par.Value = $pars[$key];
        }
    }

    $adapter = New-Object System.Data.sqlclient.sqlDataAdapter $command
    $dataset = New-Object System.Data.DataSet
    $adapter.Fill($dataset) | Out-Null
    $connection.Close()
    return $dataset.tables[0].rows
}

它的布局不起作用,但是如果我把sqlExecuteRead函数移到$QueryServer中,它就可以正常工作。问题是我想在许多其他运行空间中也使用这个函数,希望不要到处复制粘贴它。如果代码看起来缺少片段/用例没有意义,我不得不剪下相当多的部分,请道歉。:)
任何帮助都是感激不尽的!

twh00eeo

twh00eeo1#

这里有一种方法可以初始化运行空间,包括本地会话中预定义的functions。在本例中,我们将使用一个Default2会话状态,因为这是一个较简单的版本。已定义的InitialSessionState示例,其中包含函数。

using namespace System.Management.Automation.Runspaces

function Say-Hello1 {param($i) "Hello from function 1 - Runspace $i" }
function Say-Hello2 {param($i) "Hello from function 2 - Runspace $i" }

[SessionStateFunctionEntry[]] $funcs = Get-Command Say-Hello* | ForEach-Object {
    [SessionStateFunctionEntry]::new($_.Name, $_.Definition)
}

$iss    = [initialsessionstate]::CreateDefault2()
$iss.Commands.Add($funcs)
$rspool = [runspacefactory]::CreateRunspacePool(1, 10, $iss, $Host)
$rspool.Open()

$runspaces = 1..10 | ForEach-Object {
    $ps = [powershell]::Create().AddScript({
        param($i)

        Start-Sleep 2

        Say-Hello1 $i
        Say-Hello2 $i

    }).AddParameters(@{ i = $_ })

    $ps.RunspacePool = $rspool

    @{
        Instance    = $ps
        AsyncResult = $ps.BeginInvoke()
    }
}

foreach($runspace in $runspaces) {
    $runspace.Instance.EndInvoke($runspace.AsyncResult)
    $runspace.Instance.Dispose()
}

$rspool.Dispose()

在上面的示例中,您会注意到我们可以使用Get-Command来定位将使用运行空间初始化的所需函数,此cmdlet允许使用通配符和多个函数名称。假设您有函数Get-ThisSet-ThatAdd-SomethingElse,您还可以使用确切的函数名称创建SessionStateFunctionEntry可枚举函数:

[SessionStateFunctionEntry[]] $funcs = Get-Command Get-This, Set-That, Add-SomethingElse | ForEach-Object {
    [SessionStateFunctionEntry]::new($_.Name, $_.Definition)
}

相关问题