Powershell中的多线程

时间:2014-06-17 08:08:43

标签: multithreading powershell start-job start-process

我的脚本执行以下操作:

  1. 运行数据包捕获过程(使用windump)1小时,数据保存为textFile1
  2. 1小时后将数据转储到数据库中
  3. 删除文字文件
  4. 运行另一个windump并将数据保存到textfile2 (然后重复处理。在文本文件之间交替)。
  5. 问题是将数据转储到数据库需要很长时间。因此,数据包捕获过程只会在几个小时后再次运行。我无法进行多线程工作,因为Start-Job不能接受ScriptBlock的功能。这个想法是数据包捕获过程应该连续运行。 (并且可能在bacground中转储到数据库,这就是我们在两个文本文件之间交替的原因)

    我已经尝试将整个ParseDumpDB放入$ Scriptblock中,但它仍然无效。

    脚本(删除了一些部分):

       #====Global Paramters====
    $counter = 1
    $hostname = hostname 
    $Path = "D:\windump" #Update this. This should contain the windump.exe application. All results will dumped here.
    $File = "$Path\hash.txt" #for secure credential
    $FileSummary = "$Path\$hostname Summary.txt" #none yet 
    $FilePathCheck = "$Path\$hostname HCCError $(get-date -f yyyy-MM-dd).txt" #Contains all dump database errors.
    $FileBatProgram = "$Path\windumpbat.bat" #to run windump
    
    $LogFile1 = "$Path\WinDumpLog1.txt"
    $LogFile2 = "$Path\WinDumpLog2.txt"
    
    
    $SleepTimeBefore = 3600 #Run Time of windump in seconds  -  1hour or 3600 seconds
    $SleepTimeAfter = 10 #Pause before executing another windump 
    
    #====Fucntion Stop and Start WinDump====
    Function WinDumpProcessStart(){ 
        $DateTimeToday = Get-Date
        echo "$DateTimeToday" 
        echo " Waiting $SleepTimeBefore seconds"  
        Start-Sleep -Seconds $SleepTimeBefore
    
        if(Get-Process windump){
            echo " Process windump running" 
        }
    
        if(!$process.HasExited){    
            echo " Killing windump Process" 
            Stop-Process -name windump
        }
    
        echo " Waiting $SleepTimeAfter seconds" 
        Start-Sleep -Seconds $SleepTimeAfter
    }
    
    Function WinDumpProcessStop(){  
        if(Get-Process windump){
            echo " Process windump running" 
        }
    
        if(!$process.HasExited){    
            echo "Killing windump Process" 
            Stop-Process -name windump
        }
    
        echo "Waiting $SleepTimeAfter seconds" 
        Start-Sleep -Seconds $SleepTimeAfter
    }
    
    
    Function ParseDumpDB([string]$results){
        $results1 = Get-Content $results
    
        #Analyze each. Extract Time, source IP/Port, destionation IP/Port and Protocol 
        $Row = "" | select Time, SourceServer, SourcePort, DestionationServer, DestionationPort, Protocol 
    
        foreach ($line in $results1){       
            If($line -like '*bad-len*'){
                #Skip line. This is an invalid packet 
            }ElseIf($line -match "\d{1,2}\:\d{1,2}\:\d{1,2}\.\d{1,6}"){
                #echo "Match:" $line
                $Row.Time = ($line.Split(" "))[0] + " " + ($line.Split(" "))[1]    
                $time1 = (($Row.Time).Split("."))[0]
                $Row.Time = $time1 
    
                If(($line.Split(" "))[6] -match 'UDP'){
                    $Row.Protocol = (($line.Split(" "))[6]).TrimEnd(",")
                }Else{
                    $Row.Protocol = ($line.Split(" "))[6]
                }
    
                $Temp = ($line.Split(" "))[3]
                $return = ParseIP $Temp 
                $Row.SourceServer = $return[0]
                $Row.SourcePort = $return[1]
    
                $line = $line -replace ':',''
    
                $Temp = ($line.Split(" "))[5]
                $return = ParseIP $Temp 
                $Row.DestionationServer = $return[0]
                $Row.DestionationPort =  $return[1]
    
                #Get IPAddress
                try{
                    $SourceHostNameIP = [System.Net.Dns]::GetHostAddresses($Row.SourceServer)
                }catch [Exception] {}
    
                $outputstr = ''''
                $outputstr += $SourceHostNameIP 
                $outputstr += ''','''
                $outputstr += $Row.SourceServer
                $outputstr += ''','''
                $outputstr += $Row.DestionationPort
                $outputstr += ''','''
                $outputstr += $Row.Protocol 
                $outputstr += ''','''
                $outputstr += $Row.Time 
                $outputstr += ''','''
                $outputstr += "DestHost= "
                $outputstr += $Row.DestionationServer 
                $outputstr += ''''
    
                #print results || insert to DB
                #echo $Row 
    
                $SqlCmd.CommandText = $SqlQuery
                $SqlQuery = "INSERT INTO PacketCaptures VALUES ('$hostname', $outputstr)"
                #write-host $SqlQuery
                $SqlCmd.CommandText = $SqlQuery
                $SqlAdapter.SelectCommand = $SqlCmd
                $DataSet = New-Object System.Data.DataSet
                try{
                   $SqlAdapter.Fill($DataSet)
                }catch [Exception] {
                    $_.Exception.Message  | Out-File -encoding ASCII $FilePathCheck -Append
                }
    
            }ElseIf($line -like '*packets*' -and $line -ne " "){ #get summary and save to file. NOT YET WORKING, total packets captured not in file 
                $outputstr1 += " $line -"
                $outputstr1 += "`n`r"
            }Else{
                #echo "skip:" $line
                #Skip line. This is an invalid packet 
            } 
        }
    }
    
    #====One Time Configuration of Database====
    #initiate the DB connectionpart etcetc
    
    #====Start of WinDump====
    While($counter = 1){
        If ( (!(Test-Path $LogFile1)) -and (!(Test-Path $LogFile2)) ){ #First run. Both files doesn't exist yet 
            echo "`n Starting windump to LogFile1" 
            $process = Start-Process  "cmd.exe" "/c $FileBatProgram >  $LogFile1 2>&1"  -PassThru
    
            WinDumpProcessStart     
        }ElseIf( (Test-Path $LogFile1) -and (!(Test-Path $LogFile2)) ){ #Log 1 exits 
            echo "Parsing LogFile1 and dumping  to DB" 
            $ScriptBlock = { ParseDumpDB $LogFile1 } 
    
            Start-Job -ScriptBlock $ScriptBlock 
    
            While($(Get-Job -State 'Running')){
              echo "`n While parsing.. Start windump to LogFile2" 
              $process = Start-Process  "cmd.exe" "/c $FileBatProgram >  $LogFile2 2>&1"  -PassThru
            }
    
            echo "`n Once successful, stop windump process"
            WinDumpProcessStop
            echo "Delete LogFile2"
            Remove-Item $LogFile1
    
        }ElseIf( (!(Test-Path $LogFile1)) -and (Test-Path $LogFile2) ){ #Log 2 exits 
            echo "Parsing LogFile2 and dumping to DB" 
            $ScriptBlock = { ParseDumpDB $LogFile2 } 
    
            Start-Job -ScriptBlock $ScriptBlock 
    
            While($(Get-Job -State 'Running')){
                echo "`n While parsing..Starting windump to LogFile1" 
                $process = Start-Process  "cmd.exe" "/c $FileBatProgram >  $LogFile1 2>&1"  -PassThru
            }
    
            echo "`n Once successful, stop windump process2" 
            WinDumpProcessStop
            echo "Delete LogFile"
            Remove-Item $LogFile2
        }Else{
            echo "Error. Both LogFiles exists. Exiting Program.." 
            exit
        } 
    } 
    

1 个答案:

答案 0 :(得分:0)

您需要在脚本块中定义函数并将变量作为参数传递给它:

$ScriptBlock = {
  Function ParseDumpDB([string]$results){
    ...
  }

  ParseDumpDB $args[0]
} 

Start-Job -ScriptBlock $ScriptBlock -ArgumentList $LogFile2

作为旁注:从PowerShell脚本运行批处理脚本会使您的脚本变得非常复杂。您可能最好在PowerShell脚本中合并批处理脚本的内容,并将它们作为后台作业运行,例如像这样:

do {
  $job = Start-Job -ScriptBlock {
           & WinDump -i 1 -n -vv -w $args[0] ...
         } -ArgumentList $LogFile

  Start-Sleep -Seconds 3600

  Stop-Job -Id $job.Id
  Remove-Job -Id $job.Id

  Move-Item $LogFile $LogForImport
  Start-Job -ScriptBlock {
    ...
  } -ArgumentList $LogForImport
} until (...)