PowerShell Export-CSV - 缺少列

PowerShell Export-CSV - Missing Columns

这是

的后续问题

我稍微改变了策略,现在我正在收集所有安装的服务,

45 = Get-WinEvent -FilterHashtable @{ Path="1system.evtx"; Id = 7045 } | select 
@{N=’Timestamp’; E={$_.TimeCreated.ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ')}},
Id, 
@{N=’Machine Name’; E={$_.MachineName}},
@{N=’Service Name’; E={$_.Properties[0].Value}},@{N=’Image Path’;E=$_.Properties[1].Value}},
@{N=’RunAsUser’; E={$_.Properties[4].Value}},@{N=’Installed By’; E={$_.UserId}}

现在我匹配每个对象的任何可疑特征,如果找到,我添加一个值为 'Yes' 的列 'Suspicious'。这是因为我想将决定权留给分析师,并且很确定坏人可能会使用我们以前从未见过的东西。

foreach ($Evt in 45)
{
if ($Evt.'Image Path' -match $sus)
    {

    $Evt | Add-Member -MemberType NoteProperty -Name 'Suspicious' -Value 'Yes'

    }
}

现在,我无法让 PowerShell 显示所有列,除非我特别 Select 它们

45 | Format-Table

CSV 导出也是如此。前两个不包括 Suspicious 列,但第三个包括但那是因为我明确要求它。

45 | select * | Export-Csv -Path test.csv -NoTypeInformation
45 | Export-Csv -Path test.csv -NoTypeInformation
45 | Select-Object Timestamp, Id, 'Machine Name', 'Service Name', 'Image Path', 'RunAsUser', 'Installed By', Suspicious | Export-Csv -Path test.csv -NoTypeInformation

我阅读了 MS 上的 Export-CSV 文档。在 Whosebug 上搜索了一些提示,我认为它与 PS 检查第一行然后比较第二行是否存在 属性 等有关。 谢谢

您遇到的问题部分是因为对象在控制台上的显示方式,第一个对象的属性将决定控制台上显示的属性(列)。但是,更大的问题是 Export-Csv 不会导出那些不属于管道上第一个对象的属性,除非您明确使用 Select-Object 正如您在问题中指出的那样。

示例:

$test = @(
    [pscustomobject]@{
        Col = 'Val'
    }
    [pscustomobject]@{
        Col = 'Val'
        Col2 = 'Val2'
    }
    [pscustomobject]@{
        Col3 = 'Val3'
        Col4 = 'Val4'
        Col5 = 'Val4'
    }
)
  • Format-Table 不会显示 Col2Col5:
PS /> $test | Format-Table

Col
---
Val
Val
  • Format-List 将按原样显示对象:
PS /> $test | Format-List

Col : Val

Col  : Val
Col2 : Val2

Col3 : Val3
Col4 : Val4
Col5 : Val4
  • Export-CsvConvertTo-Csv 也会错过 Col2Col5:
PS /> $test | ConvertTo-Csv

"Col"
"Val"
"Val"

您有不同的解决方法,您可以将 Suspicious 属性 添加到 所有对象 以及那些不是怀疑你可以添加 $null 作为 Value。另一种解决方法是使用 Select-Object 显式调用 Suspicious 属性(之所以有效,是因为您知道 属性 在那里并且您知道它是 姓名)。如果您不知道对象有多少属性,另一种解决方法是循环遍历它们并使用 .PSObject.Properties.Name:

发现它们的属性
$test | ForEach-Object -Begin {
    $props = [System.Collections.Generic.HashSet[string]]::new(
        [System.StringComparer]::InvariantCultureIgnoreCase
    )
} -Process {
    foreach($i in $_.PSObject.Properties.Name)
    {
        $null = $props.Add($i)
    }
} -End {
    $test | Select-Object ([object[]]$props) | Format-Table
}

继续我的 ,如果您取出 Where-Object 过滤器并简单地将另一个计算的 属性 添加到 Select-Object 命令:

# create a regex for the suspicious executables:
$sus = '(powershell|cmd|psexesvc)\.exe'
# alternatively you can join the array items like this:
# $sus = ('powershell.exe','cmd.exe','psexesvc.exe' | ForEach-Object {[regex]::Escape($_)}) -join '|'

45 = Get-WinEvent -FilterHashtable @{ LogName = 'System';Id = 7045 } | 
        Select-Object Id, 
                      @{N='Timestamp';E={$_.TimeCreated.ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ')}}, 
                      @{N='Machine Name';E={$_.MachineName}},
                      @{N='Service Name'; E={$_.Properties[0].Value}},
                      @{N='Image Path'; E={$_.Properties[1].Value}},
                      @{N='RunAsUser'; E={$_.Properties[4].Value}},
                      @{N='Installed By'; E={$_.UserId}},
                      @{N='Suspicious'; E={
                        if ($_.Properties[1].Value -match $sus) { 'Yes' } else {'No'} 
                      }}

45 | Export-Csv -Path 'X:\Services.csv' -UseCulture -NoTypeInformation

因为你有很多列,如果你这样做,这将不再适合控制台宽度 45 | Format-Table,但 CSV 文件将包含你想要的所有列。
我在 Export-Csv cmdlet 中添加了开关 -UseCulture,确保您只需双击 csv 文件即可在 Excel.

中正确打开它

作为旁注:请不要在代码中使用那些卷曲的所谓 'smart-quotes',因为它们可能会导致无法预料的错误。拉直这些 东西并使用正常的双引号或单引号("'