Import-Csv 添加一列然后 Export-Csv

Import-Csv add a column then Export-Csv

我经常收到一份 CSV 文件并要求我向其中添加信息。对于一个简化的示例,我可能会收到以下 CSV 并要求为每个用户获取 lastlogontimestamp

为了实现这一点,我做了以下工作

$csv = import-csv users.csv
$report = "User Audit_{0:dd-MM-yyyy_HHmm}.csv" -f (Get-Date)
$csv | ForEach-Object {
    $user = ""
    $user = get-aduser $_.user -Properties lastlogontimestamp | Select-Object @{ N = 'LastLogonTimestamp'; E = { [DateTime]::FromFileTime($_.LastLogonTimestamp) } }
    [pscustomobject]@{
        User = $_.User
        'First Name' = $_.'First Name'
        'Last Name' = $_.'Last Name'
        'LastLogonTimestamp (AD)' = $user.lastlogontimestamp
    } | Export-Csv $report -NoTypeInformation -Append
} 

这非常有效,但创建它对于包含大量列的电子表格来说可能很耗时,并且在 pscustomobject 构建过程中容易出现人为错误。所以我的问题是 - 除了手动构建 pscustomobject 之外,还有没有一种方法可以对其进行编码(使用列标题填充每个键和值),然后我可以附加新添加的内容?

它是 time-consuming 的部分原因是您要为每个用户附加结果。您可以通过简单地将所有结果分配给一个变量然后在最后将这些结果导出到 CSV 来减少花费的时间,如下所示:

$csv = import-csv users.csv
$report = "User Audit_{0:dd-MM-yyyy_HHmm}.csv" -f (Get-Date)
$results = $csv | ForEach-Object {
    $user = ""
    $user = get-aduser $_.user -Properties lastlogontimestamp | Select-Object @{ N = 'LastLogonTimestamp'; E = { [DateTime]::FromFileTime($_.LastLogonTimestamp) } }
    [pscustomobject]@{
        User = $_.User
        'First Name' = $_.'First Name'
        'Last Name' = $_.'Last Name'
        'LastLogonTimestamp (AD)' = $user.lastlogontimestamp
    } 
} 
$results | Export-Csv $report -NoTypeInformation

您也可以忽略所有变量并将结果直接通过管道传输到 Export-Csv

$csv = import-csv users.csv
$report = "User Audit_{0:dd-MM-yyyy_HHmm}.csv" -f (Get-Date)
$csv | ForEach-Object {
        $user = ""
        $user = get-aduser $_.user -Properties lastlogontimestamp | Select-Object @{ N = 'LastLogonTimestamp'; E = { [DateTime]::FromFileTime($_.LastLogonTimestamp) } }
        [pscustomobject]@{
            User = $_.User
            'First Name' = $_.'First Name'
            'Last Name' = $_.'Last Name'
            'LastLogonTimestamp (AD)' = $user.lastlogontimestamp
        } 
    } | Export-Csv $report -NoTypeInformation

在人为错误方面。我不确定您的代码中“容易出现人为错误”的具体内容是什么,所以我无法在那里提出建议。

更新 - 这应该能满足您的需求

$csv | ForEach-Object {
Get-AdUser $_.user -Properties lastlogontimestamp | Select-Object UserPrincipalName, SamAccountName, GivenName, SurName, @{ N = 'LastLogonTimestamp'; E = { [DateTime]::FromFileTime($_.LastLogonTimestamp) } }       
} | Export-Csv $report -NoTypeInformation

您可以使用 Select-Object* 复制所有现有列并使用 calculated properties 添加新列:

$report = "User Audit_{0:dd-MM-yyyy_HHmm}.csv" -f (Get-Date)

import-csv users.csv | ForEach-Object {

    $user = get-aduser $_.user -Properties lastlogontimestamp
 
    $_ | Select-Object *, 
        @{ N = 'LastLogonTimestamp (AD)'; E = { [DateTime]::FromFileTime($user.LastLogonTimestamp) } }

} | Export-Csv $report -NoTypeInformation

另外,按照 Mathias R. Jessen 的建议,将 Export-Csv 移动到管道的末尾并删除 -Append 以提高性能。否则文件会为每一行打开和关闭,这非常慢。

我还冒昧地稍微重构了代码以删除不再需要的第一个 Select-Object 语句。您也可以将 Import-Csv 直接通过管道传输到 ForEach-Object,而无需使用临时变量。