是否有一种干净的方法可以将SEP=,
附加到由Export-CSV
创建的CSV文件的开头?
注意:这是一个XY问题;请参阅为什么这需要以获取有关我的root问题的信息。我要求SEP部分,因为这似乎是最好的修复,因为我需要继续使用UTF8 CSV并且不希望用户必须改变它们的工作方式以避免问题。
简单的选择就是这个;但是它感觉很乱(即我们释放文件上的锁然后必须返回并更新它)。
function Repair-Csv {
[CmdletBinding()]
Param (
[Parameter(Mandatory = $true, ValueFromPipeline = $true)]
[string]$Path
)
Begin {
$sep = "SEP=,`r`n"
}
Process {
$sep + (Get-Content -Path $Path -Raw) | Set-Content -Path $Path
}
}
我尝试创建代理函数(下面的代码),但发现包装的Export-CSV
命令没有将其输出附加到我调整的文件,而是读取我已编写的内容并尝试使用SEP=
作为列标题;所以我最终没有数据(除非我的导出对象的某个属性恰好被称为SEP=
。
# $MetaData = New-Object System.Management.Automation.CommandMetaData (Get-Command 'Export-CSV')
# [System.Management.Automation.ProxyCommand]::Create($MetaData)
function Export-CsvAdvanced {
[CmdletBinding(DefaultParameterSetName='Delimiter', SupportsShouldProcess=$true, ConfirmImpact='Medium', HelpUri='http://go.microsoft.com/fwlink/?LinkID=113299')]
param (
[Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
[psobject]
${InputObject}
,
[Parameter(Position=0)]
[ValidateNotNullOrEmpty()]
[string]
${Path}
,
[Alias('PSPath')]
[ValidateNotNullOrEmpty()]
[string]
${LiteralPath}
,
[switch]
${Force}
,
[Alias('NoOverwrite')]
[switch]
${NoClobber}
,
[ValidateSet('Unicode','UTF7','UTF8','ASCII','UTF32','BigEndianUnicode','Default','OEM')]
[string]
${Encoding}
,
[switch]
${Append}
,
[Parameter(ParameterSetName='Delimiter', Position=1)]
[ValidateNotNull()]
[char]
${Delimiter}
,
[Parameter(ParameterSetName='UseCulture')]
[switch]
${UseCulture}
,
[Alias('NTI')]
[switch]
${NoTypeInformation}
,
[Alias('SEP')]
[switch]
${PrefixWithSep}
)
begin {
try {
$outBuffer = $null
if ($PSBoundParameters.TryGetValue('OutBuffer', [ref]$outBuffer))
{
$PSBoundParameters['OutBuffer'] = 1
}
if ($PrefixWithSep.IsPresent) {
if (!$Delimiter) {
if ($UseCulture.IsPresent) {
$Delimiter = [System.Globalization.CultureInfo]::CurrentCulture.TextInfo.ListSeparator
} else {
$Delimiter = ','
}
}
$splat = @{}
if ($Encoding) { $splat.Add('Encoding', $Encoding) }
if ($Force) { $splat.Add('Force', $Force) }
if ($Append) { $splat.Add('Append', $Append) }
if ($NoClobber) { $splat.Add('NoClobber', $NoClobber) }
if ($PSCmdlet.ParameterSetName -eq 'PSPath') {
$splat.Add('LiteralPath', $LiteralPath)
} else {
$splat.Add('FilePath', $Path)
}
("SEP={0}`r`n" -f $Delimiter) | Out-File @splat
$PSBoundParameters.Remove('PrefixWithSep') #Export-CSV won't understand our custom parameter, so remove it (NB: if this is not the first call this will already have been removed)
$PSBoundParameters['Append'] = $true #we don't want to delete the file after adding a header
$PSBoundParameters['Force'] = $true #Don't treat `SEP=,` as a heading when appending to the file
}
$wrappedCmd = $ExecutionContext.InvokeCommand.GetCommand('Microsoft.PowerShell.Utility\Export-Csv', [System.Management.Automation.CommandTypes]::Cmdlet)
$scriptCmd = {& $wrappedCmd @PSBoundParameters }
$steppablePipeline = $scriptCmd.GetSteppablePipeline($myInvocation.CommandOrigin)
$steppablePipeline.Begin($PSCmdlet)
} catch {
throw
}
}
process {
try {
$steppablePipeline.Process($_)
} catch {
throw
}
}
end {
try {
$steppablePipeline.End()
} catch {
throw
}
}
<#
.ForwardHelpTargetName Microsoft.PowerShell.Utility\Export-Csv
.ForwardHelpCategory Cmdlet
#>
}
#test populated
Get-Process | Export-CsvAdvanced -Path 'c:\temp\processSep.csv' -NoTypeInformation -PrefixWithSep
Get-Process | Export-CsvAdvanced -Path 'c:\temp\process.csv' -NoTypeInformation
#test blank
$blankArray = @()
$blankArray | Export-CsvAdvanced -Path 'c:\temp\emptySep.csv' -NoTypeInformation -PrefixWithSep
$blankArray | Export-CsvAdvanced -Path 'c:\temp\empty.csv' -NoTypeInformation
我总是可以在ConvertTo-CSV
上创建代理功能,添加流以将结果输出到文件;但这并不舒服(例如,如果有一个例外情况,那么试图正确处理这些流会变得很复杂。)
我不严格需要SEP前缀;它会很有用;但事实是我正试图解决另一个问题(所以这是一个XY problem)。
我有一些将数据输出到CSV的功能。
在某些情况下,导出的文件是空白的(即没有结果)。在这种情况下,我仍然希望创建一个文件(即很明显代码已经运行并且没有结果,而代码根本没有运行)。
但是,我的CSV是UTF8,当它在Excel中显示为BOM时(即单元格A1包含
)。
由于我必须继续使用CSV并且理想情况下希望继续使用UTF8,所以最好的解决方案是添加一些内容; one suggestion是SEP=,
指令的前缀(与其他国家/地区的用户共享CSV时也很有用,其中使用了不同的默认分隔符。)