Powershell 为什么详细重定向会在导出的CSV文件中的数据之间创建一行?
我有以下代码导入两个csv文件并将它们合并在一起。作为合并的一部分,我删除了使用的两个文件,并导出一个主CSV文件Powershell 为什么详细重定向会在导出的CSV文件中的数据之间创建一行?,powershell,export-to-csv,Powershell,Export To Csv,我有以下代码导入两个csv文件并将它们合并在一起。作为合并的一部分,我删除了使用的两个文件,并导出一个主CSV文件 $csvfiles | ForEach-Object { Import-Csv "$csvLocation\$_"; Remove-Item "$csvLocation\$_" -Verbose 4>&1 | tee .\log.txt -Append } | Export-Csv -NoTypeInformation "$csvLocation\$D
$csvfiles | ForEach-Object {
Import-Csv "$csvLocation\$_";
Remove-Item "$csvLocation\$_" -Verbose 4>&1 | tee .\log.txt -Append
} | Export-Csv -NoTypeInformation "$csvLocation\$DBName.csv" -Force
使用4>&1
详细重定向生成的CSV如下所示:
请注意server1和server2之间的行中有多余的空
我期望的CSV应该是这样的(中间没有额外的行):
导出的CSV看起来不错。但是,我希望将详细消息打印到控制台和文件中(使用4>&1 | tee.\log.txt-Append
似乎只能打印到文件中)
详细:正在执行删除
它唯一的工作方式就是使用4>&1
我尝试重定向到一个变量。我试了很多东西,但都没有用
更新:关于下面提供的第二个解决方案
$csvfiles | ForEach-Object {
Import-Csv "$csvLocation\$_" | Export-Csv -Append -NoTypeInformation "$csvLocation\$DBName.csv" -Force;
Remove-Item "$csvLocation\$_" -Verbose 4>&1 | tee .\log.txt -Append
}
我通常在控制台上看到的输出只有-verbose
,如下所示:
VERBOSE: Performing the operation "Remove File" on target
"D:\MyFiles\Scripts\Migration\CSVFiles\Database1_RolesMembers_server1.domain.com.c
sv".
VERBOSE: Performing the operation "Remove File" on target
"D:\MyFiles\Scripts\Migration\CSVFiles\Database1_RolesMembers_server2.domain.com.c
sv".
但是,HAL的代码会产生这种冗长的控制台输出:
VERBOSE: Performing the operation "Remove File" on target
"D:\MyFiles\Scripts\Migration\CSVFiles\Datab
VERBOSE: ase1_RolesMembers_server1.domain.com.csv".
VERBOSE: Performing the operation "Remove File" on target
"D:\MyFiles\Scripts\Migration\CSVFiles\Datab
VERBOSE: ase1_RolesMembers_server2.domain.com.csv".
当然,这并不重要,但无论如何,值得注意的是奇怪的输出风格
就生成的csv文件而言,它仍然会导致空行,但更糟的是:
好的,您可以将详细记录合并到标准流中,其中没有一个具有服务器、数据库、角色或成员属性,因此每个详细消息都会在每个csv文件的记录后生成一个空行 将合并重定向器移到外部管道-此时,
Export Csv
会将标准输出流中的所有内容写入文件,只剩下详细消息:
$csvfiles | ForEach-Object {
Import-Csv "$csvLocation\$_"
Remove-Item "$csvLocation\$_" -Verbose
} | Export-Csv -NoTypeInformation "$csvLocation\$DBName.csv" -Force 4>&1 |tee .\log.txt -Append
问题在于对象、流以及试图将两个不同的对象强制到同一个流中。我的答案说明了正在发生的事情: TLDR:基本上,您正在尝试将两个不同的对象传递到同一管道中(请参阅),而PowerShell在导出CSV时会执行“尽力而为”的解释,即“bleahh->blank”解释。它还解释了为什么不显示控制台的输出 解释管道中发生的情况的最佳方法是将其分解并分配给变量,以查看发生的情况: 展开循环时,第一个命令和类型为:
PS C:\> $csv = Import-Csv a.csv
PS C:\> $csv.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Object[] System.Array
第二个命令是:
PS C:\> $ri = Remove-Item a.csv -Verbose 4>&1 | tee .\log.txt -Append
PS C:\> $ri.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True False VerboseRecord System.Management.Automation.InformationalRecord
基本上发生的是,第一个命令:
Import-CSV ...
将对象[]
数组输出到信息(1)流
第二个命令:
Remove-Item -Verbose
输出到详细(4)流
第三个命令是重定向:
4> &1
将详细(4)流内容输出到信息(1)流
第四指挥部
... | tee .\log.txt -Append
获取信息(1)流上的Remove Item
重定向输出,并输出到信息(1)流和日志文件
当我们在ForEach对象循环中组合它们时,我们正在信息(1)流上创建一个竞争对象数组:
PS C:\> 1..2|foreach{$csv; $ri}
server Database role members
------ -------- ---- -------
server1 DB1 role1 memberx
server1 DB1 role2 membery
VERBOSE: Performing the operation "Remove File" on target "C:\a.csv".
server1 DB1 role1 memberx
server1 DB1 role2 membery
VERBOSE: Performing the operation "Remove File" on target "C:\a.csv".
这些相互竞争的对象随后通过管道传递到下一个导出Csv
命令:
1..2 | foreach{$csv,$ri} | Export-Csv .\out.csv -NoTypeInformation
这为我们提供了一个“原始”CSV:
在那里我们可以清楚地看到4个物体沿着管道传递。导出Csv
获取4个对象:
对象[]
数组VerboseRecord
对象(Remove Item-Verbose
重定向输出)对象[]
数组VerboseRecord
对象对象[]
数组对象来构建导出Csv
文件的结构。然后它将获取VerboseRecord
对象,因为它没有办法将其“放入”CSV,所以它会输出一条空记录。然后,它获取第二个对象[]
,由于它“适合”,将其输出到CSV。然后,它将获取第二个VerboseRecord
对象,而且,由于它没有办法将其“适应”到CSV中,因此它将输出一个空记录
请注意,所有4个对象都在CSV中,即使PowerShell不知道如何处理它们。这就是为什么在PowerShell控制台上看不到输出。信息(1)流内容完全被引导到管道中,由Export-Csv
cmdlet和not控制台主机使用。这就是为什么您没有“看到”控制台上的删除项
命令的-Verbose
输出,但您确实在文件中看到了它
TLDR2:第1课:如果最终有一些东西消耗了管道,不要将多个东西输出到管道中。对于管道,一次只能处理一件事情
代码可以通过两种方式修复:如果需要管道,请将这两个操作拆分为。。。好。。。防止管道损坏的两项作业:
$csvfiles | ForEach-Object {
Import-Csv "$csvLocation\$_";
} | Export-Csv -NoTypeInformation "$csvLocation\$DBName.csv" -Force
$csvfiles | ForEach-Object {
Remove-Item "$csvLocation\$_" -Verbose 4>&1 | tee .\log.txt -Append
}
或者,恕我直言,不要进入管道并期望一切正常,因为在传递之前,事情可能必须积累到内存中。消除终端管道使用者,将导出Csv
拉入ForEach对象
循环,并将内容附加到其中
编辑:别忘了先从一个空的CSV文件开始:-)
好的,您可以将详细记录合并到标准流中,其中没有一个具有
服务器
、数据库
、角色
或成员
属性,因此每一个都将导致一个空的row@MathiasR.Jessen这不会导致4行吗?我假设你有2个csv文件,所以在每一组实际的csv行之后有一个空行(你可能不会注意到Excel中的第二个/最后一个)@MathiasR.Jessen哦,我明白了,你的意思是“每个csv文件都会产生一个空行”,而不是每个属性,对吧?我的意思是“每个详细的消息记录”,很抱歉措辞混乱。发布了一个答案它没有打印到fi
1..2 | foreach{$csv,$ri} | Export-Csv .\out.csv -NoTypeInformation
"server","Database","role","members"
"server1","DB1","role1","memberx"
"server1","DB1","role2","membery"
,,,
"server1","DB1","role1","memberx"
"server1","DB1","role2","membery"
,,,
$csvfiles | ForEach-Object {
Import-Csv "$csvLocation\$_";
} | Export-Csv -NoTypeInformation "$csvLocation\$DBName.csv" -Force
$csvfiles | ForEach-Object {
Remove-Item "$csvLocation\$_" -Verbose 4>&1 | tee .\log.txt -Append
}
Remove-Item "$csvLocation\$DBName.csv" -ErrorAction SilentlyContinue
$csvfiles | ForEach-Object {
Import-Csv "$csvLocation\$_" | Export-Csv -Append -NoTypeInformation "$csvLocation\$DBName.csv" -Force;
Remove-Item "$csvLocation\$_" -Verbose 4>&1 | tee .\log.txt -Append
}