使用一个文件中的 CSV header 名称创建具有不同 header 名称的新文件

Using CSV header names from one file to create new file with different headers name

大家好!

我完全不熟悉 Powershell 脚本。我的经理指派我为我们将要使用的新系统编写集成脚本。我想利用我们每晚生成的 HR 集成文件中的 headers,并将这些值输入到具有不同 headers 的 CSV 文件中。新系统需要这些特定的 headers.The 搭载原因,是因为我们在 AD 中没有为 UserStatus 定义的属性。该列中的值对新系统至关重要。它将确定是否从系统中添加或删除用户。

这是我当前的脚本:

$dateString = Get-Date -Format yyyyMMdd

$users = Import-Csv -Path "c:\scripts\XXXXXX\ActiveDirectory_$dateString.csv" -Header `
'PreferredName,Last,EmployeeID,Email,UserStatus'

$OutFile = "C:\Scripts\XXXXXX\Test\DeltaFeed_$dateString.csv"

$Outheader =  "Funds,Firstname,Lastname,Employeenumber,Email,Action"

Add-Content -Path $OutFile -Value $Outheader

$userFunds = "XXXX"

$action = if ($_.UserStatus -eq 'A')
{'A'}
elseif ($_.UserStatus -eq 'T')
{'D'}

ForEach ($user in $users)
{
$outstring = $userFunds + "," + $_.PreferredName + "," + $_.Last + "," + $_.EmployeeID + "," + $_.Email + "," + $action
Add-Content -Path $OutFile -Value $outstring
}

我 运行 遇到的问题是输出文件有 headers,但每一列中都没有值。我不太确定我在这里做错了什么。我不习惯这种语法。

您的直接问题是您传递的是 单个字符串 ,而不是 header 的 数组(列名称)到 Import-Csv -Header.

也就是说,而不是:

# WRONG: Single string.
#        If you do this, the objects returned will have a SINGLE property
#        literally named 'PreferredName,Last,EmployeeID,Email,UserStatus'
-Header 'PreferredName,Last,EmployeeID,Email,UserStatus'

你必须使用:

# OK: ARRAY of names.
-Header PreferredName, Last, EmployeeID, Email, UserStatus

请注意,在 argument 解析模式中(将 argument 传递给 command) ,没有空格的简单数组元素不需要引号;在 expression-parsing 模式下,需要引用,例如当您分配给 变量 ($array = 'PreferredName', 'Last', ...) 时;有关 PowerShell 的两种解析模式的更多信息,请参阅 this answer


但是:

  • 这听起来像是将 -HeaderImport-Csv 一起使用实际上并不是您所需要的,因为您不能仅使用 select 列的子集 。相反,-Header 用于为 缺少 header 行 的输入数据指定列名。 Import-Csv 导入 all columns[1],你可以限制自己只访问那些感兴趣的属性(列) .

  • 正如 Lee_Dailey 所建议的那样,您通常应该使用 objects,使用 Import-CsvSelect-Object / [pscustomobject] 个实例和 Export-Csv,这大大简化了您的任务。 Plain-text 仅当 object-oriented 处理的性能不足时才需要处理。

在您的情况下,您可以组合 Select-Object with calculated properties,它可用于 重命名 输入 objects 的属性并提供 动态值:

# Determine in- and output files.
$dateString = Get-Date -Format yyyyMMdd
$inFile = "C:\scripts\XXXXXX\ActiveDirectory_$dateString.csv"
$outFile = "C:\Scripts\XXXXXX\Test\DeltaFeed_$dateString.csv"

# Import, rename properties and add additional ones, then export.
#  * -NoTypeInformation is only needed in Windows PowerShell.
#  * Adjust the -Encoding argument as needed; Windows PowerShell defaults
#    to ASCII(!), PowerShell [Core] v6+ to BOM-less UTF-8.
Import-Csv -Path $inputFile | 
  Select-Object @{ n='Funds'; e={ 'XXXX' } },
                @{ n='Firstname'; e='PreferredName' },
                @{ n='Lastname'; e='Last' },
                @{ n='Employeenumber'; e='EmployeeID' },
                Email, # no renaming required
                @{ n='Action'; e = { @{ A='A'; T='D' }[$_.UserStatus] } } |
    Export-Csv $outFile -NoTypeInformation -Encoding utf8

[1]如果你使用-Header并且指定的列名数比数据列数,那么你可以技术上 return 列的子集,但 (a) 仅 从第一列开始 ,并且 (b) 如前所述,仅当输入数据 具有没有 header 行.

我采取了一些不同的做法。我看到的直接问题是将单个变量传递给 csv。其次,当您真的想使用 Excel 时,我不喜欢使用 CSV。我重写了你的原作来完成你所说的。

 #Variable assignation
 $dateString = (Get-Date -Format yyyyMMdd)
 $userFunds = "XXXX"

 $original = “c:\scripts\XXXXXX\ActiveDirectory_$dateString.csv”
 $path = “c:\scripts\XXXXXX\Test\DeltaFeed_$dateString.xlsx”
 
 $users = Import-Csv -Path $original
 $Excel = New-Object -ComObject excel.application
 $Excel.visible = $false #True if you want it to popup before saving.
 $workbook = $Excel.workbooks.add()
 $excel.cells.item(1,1) = “Funds”
 $excel.cells.item(1,2) = “FirstName”
 $excel.cells.item(1,3) = “LastName”
 $excel.cells.item(1,4) = “Employee Number”
 $excel.cells.item(1,5) = “Email”
 $excel.cells.item(1,5) = “Action”
 $i=2
 foreach($user in $users)
 {
   $action = if ($user.UserStatus -eq 'A')
   {'A'}
   elseif ($user.UserStatus -eq 'T')
   {'D'} 
 
 $excel.cells.item($i,1) = $userFunds
 $excel.cells.item($i,2) = $user.PreferredName
 $excel.cells.item($i,3) = $user.Last
 $excel.cells.item($i,4) = $user.EmployeeID
 $excel.cells.item($i,5) = $user.Email
 $excel.cells.item($i,6) = $user.UserStatus
 $excel.cells.item($i,6) = $action
 $i++
 } #end foreach user
 $workbook.saveas($path)
 $Excel.Quit()
 Remove-Variable -Name excel
 [gc]::collect()
 [gc]::WaitForPendingFinalizers()

我的解决方案:

$dateString = Get-Date -Format yyyyMMdd

import-csv "C:\scripts\XXXXXX\ActiveDirectory_$dateString.csv" -Header Firstname,Lastname,Employeenumber,Email,Action | %{

if ($_.Action -eq 'T') {$_.Action='D'}

Add-Member -InputObject $_ -NotePropertyName "Funds" -NotePropertyValue "XXXX" -PassThru

} |  export-csv "C:\Scripts\XXXXXX\Test\DeltaFeed_$dateString.csv" -NoType