簡體   English   中英

並行腳本塊的效率和速度提高

[英]efficiency and speed increase of invoke-parallel -scriptblock

是否有一種方法可以加快此命令的速度並使其更有效地使用資源?

如果文件不必提取且可以通過evtx文件格式解析,我願意轉換為python 3.5。

我有一個腳本,我正在使用帶有腳本塊的cmdlet invoke-parallel運行。 $ files是我根據用戶名和事件ID過濾的10000個evtx文件的列表。

我試圖調用powershell.exe的新實例並從腳本塊運行get-winevent cmdlet,但這會實例化到許多進程而不會關閉。 我沒有嘗試過工作,但是不確定在這種情況下該在哪里進行。

$files | Invoke-Parallel -ImportModules -ScriptBlock{ 
Get-WinEvent -FilterHashtable @{Path=$_;id=4624;data="ANONYMOUS LOGON","user.name1", "user.name2" } | 
    Select-Object  -Property MachineName,RecordId, TimeCreated,Id,
    @{Name="SubjectUserSid"; Expression={$_.Properties[0].Value}},
    @{Name="SubjectUserName";Expression={$_.Properties[1].Value}},
    @{Name="SubjectDomainName";Expression={$_.Properties[2].Value}},
    @{Name="SubjectLogonId";Expression={$_.Properties[3].Value}},
    @{Name="TargetUserSid";Expression={$_.Properties[4].Value}},
    @{Name="TargetUserName"; Expression={$_.Properties[5].Value}},
    @{Name="TargetDomainName";Expression={$_.Properties[6].Value}},
    @{Name="TargetLogonId";Expression={$_.Properties[7].Value}},
    @{Name="LogonType";Expression={$_.Properties[8].Value}},
    @{Name="LogonProcessName";Expression={$_.Properties[9].Value}},
    @{Name="AuthenticationPackageName";Expression={$_.Properties[10].Value}},
    @{Name="WorkstationName";Expression={$_.Properties[11].Value}},
    @{Name="LogonGuid";Expression={$_.Properties[12].Value}},
    @{Name="TransmittedServices";Expression={$_.Properties[13].Value}},
    @{Name="LmPackageName";Expression={$_.Properties[14].Value}},
    @{Name="KeyLength";Expression={$_.Properties[15].Value}},
    @{Name="ProcessId";Expression={$_.Properties[16].Value}},
    @{Name="ProcessName";Expression={$_.Properties[17].Value}},
    @{Name="IP"; Expression={$_.Properties[18].Value}},
    @{Name="IpPort";Expression={$_.Properties[19].Value}}} -throttle 100 |
     Export-Csv -path "C:\users\username\Desktop\folder\full.csv"   

您可能會考慮設置Runspaces和RunspacePools 設置起來有些棘手,但是它們的工作方式非常酷而且非常有效。 池允許您設置各種限制。 RunspaceFactory將作業加載到x個插槽中的1個中,然后一旦完成將其扔入該插槽中的另一個。 這樣做的最大優點之一是開銷-或缺少開銷。 運行空間不需要PowerShell的另一個實例,而Jobs則需要。

因此,如果您要運行一個寬度為50的RunspacePool,並且要處理1000個作業,那么其中50個作業將隨時運行。 超酷。

從mjolinor查看此示例 當然,這是一個非常復雜的示例。 他在訪問各種數據流時遇到了很多麻煩。 這樣就可以監視池中的進程。

以下是根據我的主要安全審核事件日志文件(20MB)測得的單項作業速度提高了約50倍。

您的代碼問題是由標准的PowerShell東西引起的,在大量數據的情況下,效率極低。

  • 具有20個計算屬性的Select-Object為每個記錄創建20個ScriptBlock上下文。 與內部的實際簡單代碼相比,在PS中創建上下文需要花費大量時間。

  • Get-WinEvent為每個事件創建自定義對象,其中包含20多個NoteProperty對象,
    每個創建都需要時間。

  • 除了使用慢速PS管道外,Export-CSV還需要訪問每個NoteProperty。

  • | 流水作業比foreach(不是cmdlet)之類的流控制語句慢。

讓我們開始工作,使用.NET 3.5+和PS3 +手動完成所有工作:

$CollectLogonsInCsv = {
param(
    [ValidateScript({ Test-Path -literal $_ })]
    [string]$eventLogPath,

    [Parameter(Mandatory)]
    [string[]]$users,

    [ValidateScript({ Test-Path -IsValid -literal $_ })]
    [string]$outputPath = ($eventLogPath -replace '[^.]+$', 'csv')
)
    $query = '*[System/EventID=4624 and EventData[' +
        ($users -replace '^.+', 'Data[@Name="TargetUserName"]="$&"' -join ' or ') + ']]'
    $reader = [Diagnostics.Eventing.Reader.EventLogReader]::new(
        [Diagnostics.Eventing.Reader.EventLogQuery]::new($eventLogPath,
            [Diagnostics.Eventing.Reader.PathType]::FilePath, $query)
    )
    $writer = [IO.StreamWriter]::new($outputPath, $false, [Text.Encoding]::UTF8, 16MB)
    $writer.WriteLine('MachineName, RecordId, TimeCreated, Id,' +
        'SubjectUserSid, SubjectUserName, SubjectDomainName, SubjectLogonId, ' +
        'TargetUserSid, TargetUserName, TargetDomainName, TargetLogonId, ' +
        'LogonType, LogonProcessName, AuthenticationPackageName, WorkstationName, ' +
        'LogonGuid, TransmittedServices, LmPackageName, KeyLength, ' +
        'ProcessId, ProcessName, IP, IpPort')
    while ($e = $reader.ReadEvent()) {
        $p = $e.properties
        $writer.WriteLine('"' +
            [string]::Join("`0",
                $($e.MachineName, $e.RecordId, $e.TimeCreated, $e.Id; $p[0..19].value)
            ).replace('"', '""').replace("`0", '","') + '"'
        )
    }
    $writer.close()
    [GC]::Collect()
}

現在,使用RunSpaces並行調用它以進行進一步改進:

$outputDir = 'C:\Users\Administrator\Desktop\folder\4768'

Get-Content C:\users\Administrator\Desktop\fullfiles.csv |
    Invoke-Parallel -throttle 100 -ImportModules -ImportVariables -ScriptBlock {
        $outputCsv = Join-Path $outputDir ((Get-Item -literal $_).BaseName + '.csv')
        & $CollectLogonsInCsv $_ @(
            'user.name.1'
            'user.name.2'
            'user.name.3'
            'user.name.4'
        ) $outputCsv
    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM