我正在尝试在我的脚本中编写一个简单的使用记录器,它将存储有关用户打开脚本的时间,使用脚本和用户名完成的信息。
我收集前两个数据的记录器的第一部分工作正常,并为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中明确指出Username是第一位的。
答案 0 :(得分:3)
由于您的CSV已经具有结构(即已定义的标头),因此PowerShell会在追加时遵循此规则,并且不会添加其他列。在[{1}} help:
的摘录中解释了这种情况当您向Export-CSV提交多个对象时,Export-CSV会进行组织 该文件基于您提交的第一个对象的属性。 如果剩余的对象没有指定的属性之一, 该对象的属性值为null,由两个表示 连续逗号。 如果剩余的对象有额外的 属性,这些属性值不包含在文件中 。
您可以在原始文件中包含Export-Csv
属性(即使它是空的),但最好的选择可能是在最后将输出导出到另一个CSV,也许在导入后删除原始文件然后用附加数据重新创建它。事实上,只需删除FinishDate
即可获得您想要的结果。
答案 1 :(得分:3)
假设您只想记录最近一次运行 [如果您想记录多次运行,请参见底部] (PSv3 +) :
# 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
如boxdog's helpful answer所述,-Append
与Export-Csv
一起使用不会添加其他列。
但是,由于您似乎正在尝试重写整个文件,因此无需使用
完全-Append
。
为了确保在您尝试使用Export-Csv
进行替换之前,已完全读取了旧版本的文件Import-Csv $FilePath
来电置于(...)
对于1行文件(例如在这种情况下),这不是严格必要的,但是为这种重写形成一个好习惯;请注意,这种方法通常有些脆弱,因为在重写文件时可能会出错,导致潜在的数据丢失。
@{ n='FinishDate'; e={ (Get-Date).toString("dd/MMM/yyyy HH:mm:ss") }
是附加到预先存在的列(*
)
另一个奇怪的事情是它将StartDate放在第一位,而我在$ LogArrayDetails中明确声明用户名是第一位的。
您已使用哈希表(@{ ... }
)声明输出CSV的列,但无法保证枚举哈希表条目的顺序。
在PSv3 +中,您可以使用有序哈希表([ordered] @{ ... }
)来实现可预测的枚举,如果将哈希表转换为a ,则 自定义对象通过转换为[pscustomobject]
,如上所示。
如果您确实要追加到现有文件,可以使用以下内容,但请注意:
这种方法不能很好地扩展,因为每次都会将整个日志文件读入内存(并转换为对象),但将条目限制为一个月的价值应该没问题。
如上所述,这种方法很脆弱,因为重写文件时可能会出错;考虑简单地每次执行写入 2 行,这样就可以逐行追加到文件中。
没有并发管理,所以假设一次只运行一个脚本实例。
$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