PowerShell导出-CSV-缺少列[重复]

ecbunoof  于 2023-01-20  发布在  Shell
关注(0)|答案(2)|浏览(219)
    • 此问题在此处已有答案**:

Not all properties displayed(1个答案)
1年前关闭。
这是PowerShell | EVTX | Compare Message with Array (Like)的后续问题
我稍微改变了策略,现在我收集所有安装的服务,

$7045 = 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}}

现在我匹配每个对象的任何可疑特征,如果发现,我添加一列'可疑'与值'是'.这是因为我想留给分析师的决定,并非常肯定的是,坏人可能会使用一些我们以前没有见过.

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

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

    }
}

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

$7045 | Format-Table

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

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

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

e3bfsja2

e3bfsja21#

您遇到的问题部分是由于对象在控制台上的显示方式,第一个对象的属性决定了在控制台上显示的属性(列)
更大的问题是,Export-Csv不会导出那些与第一个对象的属性**不匹配的属性,除非它们被显式地添加到剩余的对象中,或者对象被重构,对于这一点,一个简单的方法是使用Select-Object,正如您在问题中指出的那样。

    • 给出以下示例:**
$test = @(
    [pscustomobject]@{
        A = 'ValA'
    }
    [pscustomobject]@{
        A = 'ValA'
        B = 'ValB'
    }
    [pscustomobject]@{
        C = 'ValC'
        D = 'ValD'
        E = 'ValE'
    }
)
$test | Format-Table

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

A : ValA

A : ValA
B : ValB

C : ValC
D : ValD
E : ValE
$test | ConvertTo-Csv

"A"
"ValA"
"ValA"

您有不同的解决方案,您可以将Suspicious属性添加到所有对象,对于那些不可疑的事件,您可以将$null添加为 * Value *。
另一种解决方法是使用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 {
        $list | Select-Object ([object[]] $props)
    }
}

用法:

# From Pipeline
$test | ConvertTo-NormalizedObject | Format-Table
# From Positional / Named parameter binding
ConvertTo-NormalizedObject $test | Format-Table
  • 最后,有了Select-Object -Unique,这是一种非常简单的方法:
$prop = $test.ForEach{ $_.PSObject.Properties.Name } | Select-Object -Unique
$test | Select-Object $prop

在本例中使用$test,结果将变为:

A    B    C    D    E
-    -    -    -    -
ValA
ValA ValB
          ValC ValD ValE
z6psavjg

z6psavjg2#

从我的previous answer继续,如果去掉Where-Object筛选器,只需将另一个计算属性添加到Select-Object cmdlet中,就可以直接添加列Suspicious

# 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 '|'

$7045 = 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'} 
                      }}

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

因为您有许多列,所以如果您执行$7045 | Format-Table,这将不再适合控制台宽度,但是CSV文件将包含您想要的所有列。
我将开关-UseCulture添加到Export-Csv cmdlet中,这样可以确保您只需双击csv文件就可以在Excel中正确打开它。
如旁注:请不要在代码中使用那些 curl 的所谓“智能引号”,因为它们可能会导致不可预见的错误。请将这些的东西拉直,并使用普通的双引号或单引号("'

相关问题