【问题标题】:Using CSV header names from one file to create new file with different headers name使用一个文件中的 CSV 标头名称来创建具有不同标头名称的新文件
【发布时间】:2020-11-21 05:09:57
【问题描述】:

大家好!

我完全不熟悉 powershell 脚本。我的经理要求我为我们将使用的新系统编写集成脚本。我想捎带我们每晚生成的 HR 集成文件中的标题,并将这些值输入到具有不同标题的 CSV 文件中。新系统需要这些特定的标头。捎带的原因是因为我们在 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
}

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

【问题讨论】:

  • 使用Select-Object[PSCustomObject] 构建一个新的自定义集合,将旧道具映射到新道具...然后使用Export-Csv 将内容发送到新文件。 ///// 尝试永远不要手动构建 csv 文件... [grin]

标签: powershell csv integration


【解决方案1】:

您的直接问题是您将单个字符串而不是标题(列名)的数组传递给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),没有空格的简单数组元素不需要 引用;在表达式-解析模式下,需要引用,例如当你分配给一个变量时($array = 'PreferredName', 'Last', ...);有关 PowerShell 的两种解析模式的更多信息,请参阅 this answer


但是:

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

  • 正如Lee_Dailey 的明智建议,您通常应该使用对象,使用Import-CsvSelect-Object / [pscustomobject] 实例和Export-Csv,这将大大简化您的任务。只有在面向对象处理的性能不足时才需要纯文本处理。

在您的情况下,您可以将Select-Objectcalculated properties 结合使用,它们可用于重命名输入对象的属性并提供动态值

# 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 并且指定的列名数少于 数据列数,那么从技术上讲,您可以返回列的子集,但是 ( a) 仅从第一列开始,并且 (b) 如上所述,仅当输入数据没有标题行

【讨论】:

    【解决方案2】:

    我采取了不同的做法。我看到的直接问题是将单个变量传递给 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()
    

    【讨论】:

    • 嘿,谢谢!不幸的是,我们输入文件的系统只会接收一个 CSV 文件。
    【解决方案3】:

    我的解决方案:

    $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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-11-24
      • 1970-01-01
      • 2016-06-28
      • 1970-01-01
      • 1970-01-01
      • 2019-06-10
      • 2011-03-15
      相关资源
      最近更新 更多