是否有方法可以加快此命令并使其更有效地使用资源?
如果不必提取文件并且可以通过evtx文件格式解析,我愿意转换为python 3.5。
我有一个运行cmdlet的脚本,调用并行脚本块。 $ files是我根据用户名和事件ID过滤的10000个evtx文件的列表。
我试图调用powershell.exe的新实例并从scriptblock运行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"
答案 0 :(得分:1)
您可以考虑设置Runspaces and RunspacePools。它们设置起来有点棘手,但它们的工作方式非常酷且效率很高。池允许您设置各种节流。 RunspaceFactory将作业加载到x个槽中的1个槽中,然后一旦完成,它就会在该槽中抛出另一个槽。 其中一个重大优势是开销 - 或者缺乏开销。 Runspaces不需要另一个PowerShell实例,而Job则需要。
因此,如果您有一个宽度为50的RunspacePool和1000个要处理的作业,那么其中50个作业将在任何时间运行。超酷。
Check out this example from mjolinor。 当然,这是一个非常复杂的例子。他经历了很多麻烦,无法访问各种数据流。这样就可以监控池中的进程。
答案 1 :(得分:1)
以下是在我的主安全审计事件日志文件(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
}