Параллельный запуск для этого конкретного сценария powershell

#powershell

#powershell

Вопрос:

Я нахожусь в процессе переписывания сценария ниже, чтобы иметь возможность работать параллельно, как видно из кода, скрипту передается массив серверов, а затем он загружает его в хеш-таблицу, перебирает каждый сервер за раз для выполнения развертывания,для каждого сервера существуют файлы для выполнения в определенном порядке (см. Массив файлов). Глядя на структуру, я чувствую, что workspace — это правильный путь, но я могу ошибаться.

Где, на мой взгляд, можно увидеть прирост производительности или наличие кода, позволяющего запускать несколько серверов одновременно, а не ждать завершения работы каждого сервера и перехода к следующему. для каждого параллельного

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

Ниже приведен код, с которым я тестирую.

 Function Check-Instance-Connection{
    param
    (
        [Parameter(Mandatory=$true,
                    ValueFromPipelineByPropertyName=$true,
                    Position=0)]
                    $sql_server,                    

                    [Parameter(Mandatory=$true,
                    ValueFromPipelineByPropertyName=$true,
                    Position=1)]
                    $db_name         
    )

    try
    {
        #Return extra useful info by using custom objects
        $check_outcome = "" | Select-Object -Property log_date, stage, status, error_message             
        $check_outcome.log_date = (Get-Date)
        $check_outcome.stage = 'Ping SQL instance for $sql_server'

        #test connection for a sql instance
        $connectionstring = "Data Source=$sql_server;Integrated Security =true;Initial Catalog=$db_name;Connect Timeout=5;"
        $sqllconnection = New-Object System.Data.SqlClient.SqlConnection $connectionstring
        $sqllconnection.Open();
        $check_outcome.status = $true
        $check_outcome.error_message = ''

        return $check_outcome

    }
    Catch
    {   
        $check_outcome.status = $false
        $check_outcome.error_message = $_.Exception.Message
        return $check_outcome

    }

    finally{
        $sqllconnection.Close();              

    }
}







$file_list = @("deployment_1.sql","deployment_2.sql","deployment_3.sql","deployment_4.sql","deployment_5.sql")

$x = (1,"Server1",3,1),(4,"Server2",6,2),(3,"Server3",4,3)
$k = 'serverid','servername','locationid','appid'    # key names correspond to data positions in each array in $x
$h = @{}
  
  
For($i=0;$i -lt $x[0].length; $i  ){
    $x |
        ForEach-Object{
            [array]$h.($k[$i])  = [string]$_[$i]
        }
           
           
} 

$folder = "F:Files"
$database_name = "Test"


foreach ($server_id in $all_server_ids)
{
    $severid = $h["serverid"][$all_server_ids.indexof($server_id)]
    $servername =  $h["servername"][$all_server_ids.indexof($server_id)]
    $locationid =  $h["locationid"][$all_server_ids.indexof($server_id)]

    $message = 'ServerID {0} has a servername of  {1} and a location id of {2}'  -f $server_id, $h["servername"][$all_server_ids.indexof($server_id)],$h["locationid"][$all_server_ids.indexof($server_id)]
    Write-Output $message
    Write-Output "This $severid and this $servername and this $locationid"
    
    foreach ($file in $file_list)
    {
    
        $is_instance_ok = Check-Instance-Connection $servername $database_name
        if ($is_instance_ok.check_outcome -eq $true){
            invoke-sqlcmd -ServerInstance "$servername" -inputfile $folder$file  -Database  "$database_name" -Querytimeout 60 -OutputSqlErrors $true -ConnectionTimeout 10 -ErrorAction Continue -Errorvariable generated_error | Out-Null
        }
    }
    
}
 

Комментарии:

1. В PowerShell v5 вы можете использовать Workflow и / или Jobs для выполнения параллельной обработки. Это описано в файлах справки PowerShell. В PowerShell Core v7 можно использовать новую опцию ForEach -parallel .

Ответ №1:

Спасибо, я провел гораздо больше исследований и рассмотрел множество примеров того, как работают рабочие процессы. Это то, что я придумал.

 Workflow RunExecution
    { 



Function Check-Instance-Connection{
    param
    (
        [Parameter(Mandatory=$true,
                    ValueFromPipelineByPropertyName=$true,
                    Position=0)]
                    $sql_server,                    

                    [Parameter(Mandatory=$true,
                    ValueFromPipelineByPropertyName=$true,
                    Position=1)]
                    $db_name         
    )

    try
    {
        #Return extra useful info by using custom objects
        $check_outcome = "" | Select-Object -Property log_date, stage, status, error_message             
        $check_outcome.log_date = (Get-Date)
        $check_outcome.stage = 'Ping SQL instance for $sql_server'

        #test connection for a sql instance
        $connectionstring = "Data Source=$sql_server;Integrated Security =true;Initial Catalog=$db_name;Connect Timeout=5;"
        $sqllconnection = New-Object System.Data.SqlClient.SqlConnection $connectionstring
        $sqllconnection.Open();
        $check_outcome.status = $true
        $check_outcome.error_message = ''

        return $check_outcome

    }
    Catch
    {   
        $check_outcome.status = $false
        $check_outcome.error_message = $_.Exception.Message
        return $check_outcome

    }

    finally{
        $sqllconnection.Close();              

    }
}



$file_list = @("deployment_1.sql","deployment_2.sql","deployment_3.sql","deployment_4.sql","deployment_5.sql")

$x = (1,"server1DEV3",3,1),(4,"serer1DEV2",6,2),(3,"serer2DEV1",4,3)
$k = 'serverid','servername','locationid','appid'     
$h = @{}
  
  
For($i=0;$i -lt $x[0].length; $i  ){
    $x |
        ForEach-Object{
            [array]$h.($k[$i])  = [string]$_[$i]
        }
           
           
} 

$folder = "C:Temp"
$database_name = "Test"
$all_server_ids = $h['serverid']


    foreach -parallel ($server_id in $all_server_ids)
    {
        $severid = $h["serverid"][$all_server_ids.indexof($server_id)]
        $servername =  $h["servername"][$all_server_ids.indexof($server_id)]
        $locationid =  $h["locationid"][$all_server_ids.indexof($server_id)]

        foreach ($file in $file_list)
        {
        


            # $check_fine = $is_instance_ok.check_outcome 
            # if ($check_fine = $true){
                invoke-sqlcmd -ServerInstance "$servername" -inputfile $folder$file  -Database  "$database_name" -Querytimeout 60 -OutputSqlErrors $true -ConnectionTimeout 10 -ErrorAction Continue 
                write-output  "invoke-sqlcmd -ServerInstance $servername -inputfile $folder$file  -Database  $database_name -Querytimeout 60 -OutputSqlErrors $true -ConnectionTimeout 10 -ErrorAction Continue "
 
#            }
        }
        
    }
}

RunExecution
 

Комментарии:

1. Я понял, что не могу запустить это в рамках рабочего процесса if ($check_fine = $true) . Интересно, есть ли здесь обходной путь. Могу ли я преобразовать выходные данные пользовательского объекта в строку вместо bool и использовать вместо этого -eq ?

2. -eq работает с любым типом объекта, а не только со строкой. Предполагая $is_instance_ok , что содержит вывод из Check-Internet-Connection , ваше if условие должно быть if ($is_instance_ok.status){...}