Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/powershell/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何向PowerShell中的现有CSV行添加列?_Powershell_Csv - Fatal编程技术网

如何向PowerShell中的现有CSV行添加列?

如何向PowerShell中的现有CSV行添加列?,powershell,csv,Powershell,Csv,我正试图在我的脚本中编写一个简单的用法记录器,它将存储有关用户打开脚本、完成使用脚本和用户名的时间的信息 我收集前两个数据的记录器的第一部分工作正常,并向CSV文件添加了两个必要的列和值。但是,当我运行记录器的第二部分时,它不会向现有CSV文件中添加新列 #Code I will add at the very beginning of my script $FileNameDate = Get-Date -Format "MMM_yyyy" $FilePath = "C:\Users\User

我正试图在我的脚本中编写一个简单的用法记录器,它将存储有关用户打开脚本、完成使用脚本和用户名的时间的信息

我收集前两个数据的记录器的第一部分工作正常,并向CSV文件添加了两个必要的列和值。但是,当我运行记录器的第二部分时,它不会向现有CSV文件中添加新列

#Code I will add at the very beginning of my script
$FileNameDate = Get-Date -Format "MMM_yyyy"
$FilePath = "C:\Users\Username\Desktop\Script\Logs\${FileNameDate}_MonthlyLog.csv"
$TimeStamp = (Get-Date).toString("dd/MMM/yyyy HH:mm:ss")
$UserName = [string]($env:UserName)
$LogArray = @()
$LogArrayDetails = @{
    Username = $UserName
    StartDate = $TimeStamp
}
$LogArray += New-Object PSObject -Property $LogArrayDetails | Export-Csv $FilePath -Notypeinformation -Append
#Code I will add at the very end of my script
$logArrayFinishDetails = @{FinishDate = $TimeStamp}
$LogCsv = Import-Csv $FilePath | Select Username, StartDate, @{$LogArrayFinishDetails} | Export-Csv $FilePath -NoTypeInformation -Append
关闭脚本时,CSV文件应如下所示:

Username    StartDate               FinishDate
anyplane    08/Apr/2018 23:47:55    08/Apr/2018 23:48:55
但看起来是这样的:

StartDate               Username                
08/Apr/2018 23:47:55    anyplane

另一件奇怪的事情是,它将StartDate放在第一位,而我在$LogArrayDetails中明确指出用户名放在第一位

因为您的CSV已经有了一个结构(即定义的标题),PowerShell在追加时会遵守此结构,而不会添加其他列。这段摘录自
导出Csv
,对其进行了(某种程度上)解释:

提交多个对象以导出CSV时,请导出CSV 该文件基于您提交的第一个对象的属性。 如果其余对象没有指定的属性之一, 该对象的属性值为null,由两个 连续逗号如果其余对象具有其他 属性,这些属性值不包括在文件中


您可以在原始文件中包含
FinishDate
属性(即使它是空的),但最好的选择可能是在最后将输出导出到不同的CSV,可能在导入后删除原始文件,然后使用其他数据重新创建它。事实上,只需删除
-Append
就可能得到您想要的结果。

因为您的CSV已经有了一个结构(即定义的标题),PowerShell在追加时尊重这一点,并且不添加其他列。这段摘录自
导出Csv
,对其进行了(某种程度上)解释:

提交多个对象以导出CSV时,请导出CSV 该文件基于您提交的第一个对象的属性。 如果其余对象没有指定的属性之一, 该对象的属性值为null,由两个 连续逗号如果其余对象具有其他 属性,这些属性值不包括在文件中


您可以在原始文件中包含
FinishDate
属性(即使它是空的),但最好的选择可能是在最后将输出导出到不同的CSV,可能在导入后删除原始文件,然后使用其他数据重新创建它。事实上,只要删除
-Append
就可能得到您想要的结果。

假设您只想记录最近的跑步记录[如果您想记录多次跑步,请参见底部](PSv3+):


  • 如中所述,将
    -Append
    导出Csv
    一起使用不会添加其他列

  • 但是,由于您似乎试图重写整个文件,因此无需使用
    -完全追加

    • 为了确保在您尝试用
      导出Csv
      替换该文件之前已完整读取该文件的旧版本,请确保将您的
      导入Csv$FilePath
      调用包含在
      (…)
      中。
      在这种情况下,对于一行文件来说,这并不是绝对必要的,但对于这种重写来说,这是一个良好的习惯;请注意,这种方法通常有些脆弱,因为在重写文件时可能会出错,导致潜在的数据丢失

    • @{n='FinishDate';e={(Get Date).toString(“dd/MMM/yyyy HH:mm:ss”)}
      是附加到先前存在的列(
      *
      )的示例


另一件奇怪的事情是,它将StartDate放在第一位,而我在$LogArrayDetails中明确指出用户名放在第一位

您使用了哈希表(
@{…}
)来声明输出CSV的列,但哈希表项的枚举顺序不保证

在PSv3+中,您可以使用有序哈希表(
[ordered]@{…}
)来实现可预测的枚举,如果您通过强制转换为
[pscustomobject]
将哈希表转换为自定义对象,也会得到可预测的枚举,如上所示


如果要附加到现有文件中,可以使用以下命令,但请注意:

  • 这种方法不能很好地扩展,因为每次都会将整个日志文件读入内存(并转换为对象),不过将条目限制为一个月的值应该可以

  • >P>,该方法是易碎的,因为在改写文件时可能出错,只需考虑每次执行写2行,这样就可以逐行添加到文件中。

  • 没有并发管理,因此假设每次只运行脚本的一个实例


假设您只想记录最近一次跑步[如果要记录多次跑步,请参见底部](PSv3+):


  • 如中所述,将
    -Append
    导出Csv
    一起使用不会添加其他列

  • 但是,由于您似乎试图重写整个文件,因此无需使用
    -完全追加

    • 为了确保在您尝试用
      导出Csv
      替换该文件之前已完整读取该文件的旧版本,请确保将您的
      导入Csv$FilePath
      调用包含在
      (…)
      中。
      对于像本例中这样的一行文件,这并不是绝对必要的,但对于这种重写来说,这是一个好习惯;请注意,这种方法通常有点脆弱,因为可能会出错
      # Log start of execution.
      [pscustomobject] @{ Username = $env:USERNAME; StartDate = $TimeStamp } |
        Export-Csv -Notypeinformation $FilePath
      
      # Perform script actions...
      
      # Log end of execution.
      (Import-Csv $FilePath) | 
        Select-Object *, @{ n='FinishDate'; e={ (Get-Date).toString("dd/MMM/yyyy HH:mm:ss") } } |
          Export-Csv -Notypeinformation $FilePath
      
      $FilePath = './t.csv'
      $TimeStamp = (Get-Date).toString("dd/MMM/yyyy HH:mm:ss")
      $env:USERNAME = $env:USER
      
      # Log start of execution. Note the empty 'FinishDate' property
      # to ensure all rows ultimately have the same column structure.
      [pscustomobject] @{ Username = $env:USERNAME; StartDate = $TimeStamp; FinishDate = '' } |
        Export-Csv -Notypeinformation -Append $FilePath
      
      # Perform script actions...
      
      # Log end of execution:
      # Read the entire existing file...
      $logRows = Import-Csv $FilePath
      # ... update the last row's .FinishDate property
      $logRows[-1].FinishDate = (Get-Date).toString("dd/MMM/yyyy HH:mm:ss")
      # ... and rewrite the entire file, keeping only the last 30 entries
      $logRows[-30..-1] | Export-Csv -Notypeinformation $FilePath