PowerShell Export-CSV - 缺少列

Ori*_*ami 1 powershell export-csv

这是 PowerShell 的后续问题| EVTX | 将消息与数组进行比较(例如)

\n

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

\n
$7045 = Get-WinEvent -FilterHashtable @{ Path="1system.evtx"; Id = 7045 } | select \n@{N=\xe2\x80\x99Timestamp\xe2\x80\x99; E={$_.TimeCreated.ToUniversalTime().ToString(\'yyyy-MM-ddTHH:mm:ssZ\')}},\nId, \n@{N=\xe2\x80\x99Machine Name\xe2\x80\x99; E={$_.MachineName}},\n@{N=\xe2\x80\x99Service Name\xe2\x80\x99; E={$_.Properties[0].Value}},@{N=\xe2\x80\x99Image Path\xe2\x80\x99;E=$_.Properties[1].Value}},\n@{N=\xe2\x80\x99RunAsUser\xe2\x80\x99; E={$_.Properties[4].Value}},@{N=\xe2\x80\x99Installed By\xe2\x80\x99; E={$_.UserId}}\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n
foreach ($Evt in $7045)\n{\nif ($Evt.\'Image Path\' -match $sus)\n    {\n\n    $Evt | Add-Member -MemberType NoteProperty -Name \'Suspicious\' -Value \'Yes\'\n\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n
$7045 | Format-Table\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n
$7045 | select * | Export-Csv -Path test.csv -NoTypeInformation\n$7045 | Export-Csv -Path test.csv -NoTypeInformation\n$7045 | Select-Object Timestamp, Id, \'Machine Name\', \'Service Name\', \'Image Path\', \'RunAsUser\', \'Installed By\', Suspicious | Export-Csv -Path test.csv -NoTypeInformation\n
Run Code Online (Sandbox Code Playgroud)\n

我阅读了 MS 上的 Export-CSV 文档。在 StackOverFlow 中搜索了一些提示,我认为这与 PS 检查第一行然后比较第二行的属性是否存在有关,依此类推。\n谢谢

\n

San*_*zon 6

您遇到的问题部分是由于对象如何显示到控制台,第一个对象的属性决定了所有对象的显示属性(列) 。

但更大的问题是,Export-Csv不会导出那些与第一个对象的属性不匹配的属性,除非将它们显式添加到其余对象或重建对象,实现此目的的一种简单方法是使用Select-Object您所指出的在问题中。

给出以下示例:

$test = @(
    [pscustomobject]@{
        A = 'ValA'
    }
    [pscustomobject]@{
        A = 'ValA'
        B = 'ValB'
    }
    [pscustomobject]@{
        C = 'ValC'
        D = 'ValD'
        E = 'ValE'
    }
)
Run Code Online (Sandbox Code Playgroud)
$test | Format-Table

A
-
ValA
ValA
Run Code Online (Sandbox Code Playgroud)
  • Format-List可以正确显示对象,这是因为每个属性及其对应的值在显示中都有自己的控制台行:
PS /> $test | Format-List

A : ValA

A : ValA
B : ValB

C : ValC
D : ValD
E : ValE
Run Code Online (Sandbox Code Playgroud)
$test | ConvertTo-Csv

"A"
"ValA"
"ValA"
Run Code Online (Sandbox Code Playgroud)

您可以选择不同的解决方法来解决此问题,您可以将该Suspicious属性添加到所有对象,对于那些不可疑的事件,您可以添加$nullValue

另一种解决方法是使用Select-Object显式调用该Suspicious属性(这是有效的,因为您知道该属性在那里并且您知道它的Name)。

如果您不知道对象有多少属性,解决此问题的动态方法是使用PSObject内部成员发现它们的属性。

using namespace System.Collections.Generic

function ConvertTo-NormalizedObject {
    [CmdletBinding()]
    param(
        [Parameter(ValueFromPipeline, Mandatory)]
        [object[]] $InputObject
    )

    begin {
        $list  = [List[object]]::new()
        $props = [HashSet[string]]::new([StringComparer]::InvariantCultureIgnoreCase)
    }
    process {
        foreach($object in $InputObject) {
            $list.Add($object)
            foreach($property in $object.PSObject.Properties) {
                $null = $props.Add($property.Name)
            }
        }
    }
    end {
        $out = [ordered]@{}
        foreach ($object in $list) {
            foreach ($prop in $props) {
                $out[$prop] = $object.$prop
            }

            [pscustomobject] $out
            $out.Clear()
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

# From Pipeline
$test | ConvertTo-NormalizedObject | Format-Table
# From Positional / Named parameter binding
ConvertTo-NormalizedObject $test | Format-Table
Run Code Online (Sandbox Code Playgroud)
$prop = $test.ForEach{ $_.PSObject.Properties.Name } | Select-Object -Unique
$test | Select-Object $prop
Run Code Online (Sandbox Code Playgroud)

使用$test此示例,结果将变为:

A    B    C    D    E
-    -    -    -    -
ValA
ValA ValB
          ValC ValD ValE
Run Code Online (Sandbox Code Playgroud)