从对象格式化 CSV

Format CSV From Object

我想知道如何从具有适当列的 PowerShell 对象创建 .csv。我想创建一个包含三列(用户 ID、国家/地区、计数)的 .csv 文件。它还需要按用户 ID 排序,然后按国家(A 到 Z)排序。在下面的示例代码中,我希望输出如下所示:

用户 ID、国家、计数
鲍勃,中国,2
乔,加拿大,1
乔,美国,1

$path = "C:\test\test.csv"
Set-Content -Path $path -Value “UserId, Country”
Add-Content -Path $path -Value "Joe, United States", "Bob, China", "Bob, China", "Joe, Canada"
(Import-Csv -Path $path) | Group-Object -Property UserID, Country -NoElement | Select-Object * -ExcludeProperty Values, Group | Select-Object @{Name="User ID, Country";Expression={$_.Name}}, Count | Export-Csv -Path $path -NoTypeInformation -Force
Get-Content -Path $path

不幸的是,当我运行这个时,User ID和Country在同一列中,如下所示:

"User ID, Country","Count"
"Joe, United States","1"
"Bob, China","2"
"Joe, Canada","1"

我认为问题出在 Select-Object @{Name="User ID, Country";Expression={$_.Name}}。我怎样才能把它分成三列,按照上面的要求排序?顺便说一句,我不完全理解问题代码的语法。如果您能解释一下 @{Name="User ID, Country";Expression={$_.Name}} 的作用,我将不胜感激。

编辑 这是我的实际代码,以防万一这有助于解决问题。

Set-ExecutionPolicy RemoteSigned

$lastMonth = (get-date).AddMonths(-1)
$startDate = get-date -year $lastMonth.Year -month $lastMonth.Month -day 1
$endDate = ($startDate).AddMonths(1).AddSeconds(-1)
$operation = UserLoginFailed
$path = "C:\Failed Logins $($lastMonth.ToString("yyyy_MM")).csv"

Set-Content -Path $path -Value “UserId, Country”
Function Connect-EXOnline {
    $credentials = Get-Credential -Credential $credential     
    $Session = New-PSSession -ConnectionUri https://outlook.office365.com/powershell-liveid/ `
        -ConfigurationName Microsoft.Exchange -Credential $credentials `
        -Authentication Basic -AllowRedirection
    Import-PSSession $Session -AllowClobber
}
$credential = Get-Credential
Connect-EXOnline

$Logs = @()
do {
    $logs += Search-unifiedAuditLog -SessionCommand ReturnLargeSet -SessionId "UALSearch" -ResultSize 5000 -StartDate $startDate -EndDate $endDate -Operations $operation
}while ($Logs.count % 5000 -eq 0 -and $logs.count -ne 0)
 
$userIds = $logs.userIds | Sort-Object -Unique
 
foreach ($userId in $userIds) {
    $ips = @()
    $searchResult = ($logs | Where-Object {$_.userIds -contains $userId}).auditdata | ConvertFrom-Json -ErrorAction SilentlyContinue 
    $ips = $searchResult.clientip
    foreach ($ip in $ips) {
        $mergedObject = @{}
        $singleResult = $searchResult | Where-Object {$_.clientip -contains $ip} | Select-Object -First 1
        Start-sleep -m 400
        $ipresult = Invoke-restmethod -method get -uri http://ip-api.com/json/$ip
        $UserAgent = $singleResult.extendedproperties.value[0]
        $singleResultProperties = $singleResult | Get-Member -MemberType NoteProperty
        foreach ($property in $singleResultProperties) {
            if ($property.Definition -match "object") {
                $string = $singleResult.($property.Name) | ConvertTo-Json -Depth 10
                $mergedObject | Add-Member -Name $property.Name -Value $string -MemberType NoteProperty    
            }
            else {$mergedObject | Add-Member -Name $property.Name -Value $singleResult.($property.Name) -MemberType NoteProperty}          
        }
        $property = $null
        $ipProperties = $ipresult | get-member -MemberType NoteProperty
 
        foreach ($property in $ipProperties) {
            $mergedObject | Add-Member -Name $property.Name -Value $ipresult.($property.Name) -MemberType NoteProperty
        }
        $mergedObject | Select-Object UserId, Country  | Export-Csv $path -Append -NoTypeInformation
    }
}

(Import-Csv -Path $path) | Group-Object -Property UserID, Country -NoElement | Select-Object * -ExcludeProperty Values, Group | Select-Object @{Name="User ID, Country";Expression={$_.Name}}, Count | Export-Csv -Path $path -NoTypeInformation

基本上,我会有一个 .csv 文件,其中包含一堆电子邮件地址和按国家/地区分类的失败登录尝试。最后一行用于计算每个电子邮件地址从每个公司发出的失败尝试次数。这就是问题所在。

使用内置 cmdlet 的 CSV 数据实用程序,您的生活会变得更加轻松,如下所示:

$path = 'C:\test\test.csv'
$Data = @'
UserID,Country,Count
Bob,China,2
Joe,Canada,1
Joe,United States,1
'@

ConvertFrom-Csv -Delimiter ',' -InputObject $Data -OutVariable CSVData
$CSVData | Export-Csv -Path $path -NoTypeInformation -Delimiter ','

您只需完全根据需要构建数据,然后一次性转换或导出。

我已经简化了你的问题陈述,以便一次解决一个问题。
我着手解决生成您想要的输出 CSV 文件的简单问题 您声明的输入 CSV 文件。我用记事本而不是 powershell 创建了输入文件。

这是我想出的:

<# Summarizes log by user and country.   #>

Import-csv logfile.csv |
    Sort-Object  UserID, Country |
    Group-Object UserID, Country | 
    foreach { $b = $_.name -split ', '
        [PSCustomobject] @{UserID = $b[0]; Country= $b[1]; Count=$_.count}}|
    Export-Csv summary.csv

Import-Csv logfile.csv | Format-table
Import-Csv summary.csv | Format-table

最后两步仅显示输入和输出 CSV 文件。这是我 运行 时的样子。

UserID Country      
------ -------      
Joe    United States
Bob    China        
Bob    China        
Joe    Canada       



UserID Country       Count
------ -------       -----
Bob    China         2    
Joe    Canada        1    
Joe    United States 1    

如我的评论所述,您需要两个 计算属性来再次拆分名称。

(Import-Csv $path) | Group-Object 'User ID',Country -NoElement | 
    Select-Object @{n='UserID';e={($_.Name -split ', ')[0]}},
                  @{n='Country';e={($_.Name -split ', ')[1]}},
                  Count | Export-Csv $Path -NoTypeInformation

这将产生与 Walter Mitty 的解决方案相同的输出。