Powershell 为什么详细重定向会在导出的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

我有以下代码导入两个csv文件并将它们合并在一起。作为合并的一部分,我删除了使用的两个文件,并导出一个主CSV文件

$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
    对象
  • 在这里,PowerShell将使用第一个
    对象[]
    数组对象来构建
    导出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
    }