如何向PowerShell中的现有CSV行添加列?
我正试图在我的脚本中编写一个简单的用法记录器,它将存储有关用户打开脚本、完成使用脚本和用户名的时间的信息 我收集前两个数据的记录器的第一部分工作正常,并向CSV文件添加了两个必要的列和值。但是,当我运行记录器的第二部分时,它不会向现有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
#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]
将哈希表转换为自定义对象,也会得到可预测的枚举,如上所示
如果要附加到现有文件中,可以使用以下命令,但请注意:
- 这种方法不能很好地扩展,因为每次都会将整个日志文件读入内存(并转换为对象),不过将条目限制为一个月的值应该可以
- 没有并发管理,因此假设每次只运行脚本的一个实例
假设您只想记录最近一次跑步[如果要记录多次跑步,请参见底部](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
- 为了确保在您尝试用