powershell - 将数据导出到CSV-每个返回值或首先将数据收集到哈希表?

标签 powershell

我创建了一些Powershell脚本,它们专注于数据收集。我编写了一些函数,这些函数大部分都这样工作:

  • 连接到机器
  • 获取我需要的任何数据
  • 将数据追加到现有的csv文件

  • 现在,export-csv直接在函数中使用。因此,本身没有返回值。
    由于我仍在学习Powershell,因此我偶然发现了散列表,并想知道是否值得更改我的函数以将数据收集到散列表中,而不是直接导出所有填充有数据的变量。

    我不知道什么是最佳实践。性能不是问题,但是我认为遍历数百台计算机,打开一个csv,对其进行写入,然后将其关闭可能并不是I / O的最佳选择。

    或者,我可以想象在将所有收集到的数据输出之前将它们存储到一个哈希表(或多个哈希表)中可能会很困难。

    你能帮我吗?最好的方法是什么?

    最佳答案

    对于这种情况,有两种常见的方法:

  • 使用foreach循环并将数据收集在变量中,然后将该变量导出到CSV。
    $data = foreach ($server in (Get-Content 'input.txt')) {
         # do stuff here, then build a custom object from the results
         New-Object -Type PSObject -Property @{
             'ComputerName' = $server
             ...
         }
    }
    
    $data | Export-Csv 'output.csv' -NoType
    
  • 使用ForEach-Object循环,在该循环中,您从管道读取输入,并通过管道将输出传递给Export-Csv
    Get-Content 'input.txt' | ForEach-Object {
        # do stuff here, then build a custom object from the results
        New-Object -Type PSObject -Property @{
            'ComputerName' = $_
            ...
        }
    } | Export-Csv 'output.csv' -NoType
    

  • 前一种方法提供了更好的性能,但缺点是所有数据都被读入内存(foreach循环无法写入管道)。如果您有大量数据,可能会导致内存耗尽。

    后一种方法可以抵抗内存耗尽,因为管道通常一次只能处理一个对象。但是,整体处理比foreach循环慢。

    在给定的情况下,这两种方法中哪种最好,取决于您正在处理的实际数据。

    我不建议将Export-Csv放入您的处理函数中,至少在没有使其成为可选函数的情况下如此。一方面,从性能的 Angular 来看,这不是好习惯。在循环中调用函数时,必须重复打开文件。最好只打开一次,然后在写入所有数据后将其关闭。此外,您还可以通过将处理与输出分开来获得灵活性。让您的函数返回“原始”数据,您可以根据需要进行处理(写入CSV,显示给用户,传递给另一个应用程序,...)。

    让您的函数接受管道输入,例如像这样:
    function Invoke-Foo {
        [CmdletBinding()]
        Param(
            [Parameter(
                Position=0,
                Mandatory=$true,
                ValueFromPipeline=$true,
                ValueFromPipelineByPropertyName=$true
            )]
            $InputObject,
            ...
        )
    
        Begin {
            # initialize stuff here
        }
    
        Process {
            $InputObject | ForEach-Object {
                # do stuff here, then build a custom object from the results
                New-Object -Type PSObject -Property @{
                    ...
                }
            }
        }
    
        End {
            # cleanup goes here
        }
    }
    

    你可以在foreach循环中使用它
    $data = foreach ($server in (Get-Content 'input.txt')) {
        Invoke-Foo $server
    }
    
    $data | Export-Csv 'output.csv' -NoType
    

    以及管道:
    Get-Content 'input.txt' | Invoke-Foo | Export-Csv 'output.csv' -NoType
    

    如果由于某种原因您必须具有从函数内部将数据写入文件的能力,我可能会这样修改函数:
    function Invoke-Foo {
        [CmdletBinding()]
        Param(
            ...
            [Parameter(Mandatory=$false)]
            [string]$Path,
            [Parameter(Mandatory=$false)]
            [switch]$Append,
            ...
        )
    
        ...
        Process {
            $InputObject | ForEach-Object {
                # do stuff here, then build a custom object from the results
                $obj = New-Object -Type PSObject -Property @{
                    ...
                }
                if ($PSBoundParameters.ContainsKey('Path')) {
                    $obj | Export-Csv $Path -NoType -Append:$Append.IsPresent
                } else {
                    $obj
                }
            }
        }
        ...
    }
    

    关于powershell - 将数据导出到CSV-每个返回值或首先将数据收集到哈希表?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50815998/

    相关文章:

    Powershell 查找创建文件的机器

    azure - 通过 PowerShell 从本地 SQL Server 2016 将 dacpac 发布到 Azure SQL 托管实例失败 "cannot publish to SQL Server 2014"

    powershell - 如何使用 PowerShell checkout TFS 中的文件?

    html - 在 Powershell 中查找 html 标签之间的字符串

    vb.net - 如何在VB .NET中将包含 “”的字符串追加到现有字符串?

    powershell - PowerShell 中 "| foreach { "$ _"}"的别名

    azure - 使用 Powershell 获取应用服务计划的值(value)

    azure - Powershell Get-AzureADAuditSignInLogs 未返回预期数量的日志

    windows - RunOnce 在重新启动时使用随机名称重命名计算机名

    c# - 电源外壳 : Import-Module