0

My script does the following:

  1. Run a process for packet capture (using windump) for 1 hour, data are saved textFile1
  2. Dump data into database after 1 hour
  3. Delete text file
  4. Run another windump and save data to textfile2 (Then Repeat process. while alternating between textfiles).

The problem is it takes a long time to dump the data to the database. Therefore, the packet capture process will only run again after a few hours. I am unable to make multithreading work because Start-Job won't accept a function as ScriptBlock. The idea is packet capture process should run continuously. (and maybe have the dumping to database in the bacground, that is why we are alternating between two text files)

I have already tried to put the whole ParseDumpDB into $Scriptblock and it is still not working.

Script (some parts removed):

   #====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
    } 
} 
AlexPawlak
  • 779
  • 1
  • 10
  • 22
lulala
  • 637
  • 4
  • 12
  • 21

1 Answers1

0

You need to define the function inside the script block and pass variables as arguments to it:

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

  ParseDumpDB $args[0]
} 

Start-Job -ScriptBlock $ScriptBlock -ArgumentList $LogFile2

As a side note: running batch scripts from a PowerShell script makes your script pretty convoluted. You're probably better off incorporating the content of the batch scripts in the PowerShell script and run them as background jobs, e.g. like this:

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 (...)
Ansgar Wiechers
  • 193,178
  • 25
  • 254
  • 328
  • How do yuou force start-job to only run one instancce? Like set a max thread? – lulala Jun 18 '14 at 02:23
  • @lulala You could implement a [job queue](http://stackoverflow.com/a/18193195/1630171) (note that you'll have at least 2 parallel jobs: `WinDump` and the database import), but you'll need to handle situations where the database import runs longer than 1 hour, i.e. the import is not finished when the next import is supposed to start. – Ansgar Wiechers Jun 18 '14 at 07:48