【问题标题】:PowerShell - paste data into ExcelPowerShell - 将数据粘贴到 Excel
【发布时间】:2011-04-28 14:11:49
【问题描述】:

今天我刚刚整理了这个 PowerShell 脚本

  • 采用制表符分隔的文本文件,

  • 将其读入内存,

  • 根据特定列的不同值进行可变数量的过滤查询

  • 创建一个新的空 Excel 工作簿

  • 将过滤数据的每个子集添加到 一个新的 Excel 工作表

最后一步是我卡住的地方。目前,我的代码以展开/转置的“键:值”条目的形式将几行数据放入工作表的一个范围内,从而形成水平数据布局。始终覆盖相同范围的数据。

我想要垂直布局形式的数据,即列中的数据,就像使用 MS Excel 的导入文件向导导入 CSV 文件一样。

有没有比下面更简单的方法?

我承认,某些 PowerShell 功能以一种货物崇拜的编程模式粘贴到这里。请注意,我没有任何 PowerShell 经验。几年前我做了一些批处理文件,VBScriptVBA 编码。因此,也欢迎其他批评。

PARAM (
    [Parameter(ValueFromPipeline = $true)]
    $infile = ".\04-2011\110404-13.txt"
)

PROCESS {
    echo " $infile"
    Write-Host "Num Args:" $args.Length;

    $xl = New-Object -comobject Excel.Application;
    $xl.Visible = $true;

    $Workbook = $xl.Workbooks.Add();

    $content = Import-Csv -delimiter "`t" $infile;
    $ports = $content | Select-Object Port# | Sort-Object Port# -Unique -Descending;
    $ports | ForEach-Object {
        $p = $_;
        Write-Host $p.{Port#};

        $Worksheet = $Workbook.Worksheets.Add();
        $workSheet.Name = [string]::Format("{0} {1}", "PortNo", $p.{Port#});
        $filtered = $content | Where-Object {$_.{Port#} -eq $p.{Port#} };
        $filtered | ForEach-Object {
            Write-Host $_.{ObsDateTime}, $_.{Port#}
        }
        $filtered | clip.exe;
        $range = $Workbook.ActiveSheet.Range("a2", "a$($filtered.count)");
        $Workbook.ActiveSheet.Paste($range, $false);
    }
    $xl.Quit()
}

数据输出示例

错误

Port#       : 1
Obs#        : 1
Exp_Flux    : 0,99
IV Cdry     : 406.96
IV Tcham    : 16.19
IV Pressure : 100.7
IV H2O      : 9.748
IV V3       : 11.395
IV V4       : 0.759
IV RH       : 53.12

Port#    Obs#    Exp_Flux    IV Cdry    IV Tcham    IV Pressure    IV H2O    IV V3    IV V4    IV RH
1      1    0,99    406.96    16.19    100.7    9.748    11.395    0.759    53.12

【问题讨论】:

    标签: excel powershell


    【解决方案1】:

    试试Export-Xls,它看起来很不错。从来没有机会使用它,但是(实际上)知道它的工作人员,我相信你会很高兴使用它。如果您愿意,请在此处提供反馈,我们将不胜感激。


    Export-Xls 中无序属性的可能解决方法

    可以更改函数Add-Array2Clipboard,使其接受新的输入参数:提供按要求排序的属性名称的数组。

    然后您可以更改使用get-member 的部分。愚蠢的例子:

    "z", "a", "c" | %{ 获取成员 -name $_ -inputobject $thecurrentobject }

    这只是一个示例,说明如何从get-member 获得有序属性。

    【讨论】:

    • 谢谢,我将首先从 Export-Xls 中选择一些东西来改进我的代码。关键部分似乎在第 138 行及以下。
    • 您真的需要为端口创建工作表吗?否则,您可以直接在您的 select-object 数据上使用 Export-Xls。我的意思是您将能够直接在excel上通过端口执行数据过滤。
    • 起初不想这样做,因为预期 powershell 令人困惑的代码签名和安全功能。尽管如此,我还是按照您的建议直接使用了它。成功!缩短了我的代码。是有点慢。 Export-XLS 会在每次迭代后错误地关闭新创建的文件,在“文档恢复”对话框中创建 n 个条目。不过没什么大不了的。
    • 还有一点令人烦恼的是,Export-XLS 会重新排列列,将日期时间值放在 excel 文件的最右边一列。时间序列数据不可行。
    • 你确定吗?它应该遵循您的select-object 的顺序。
    【解决方案2】:

    我使用了$Workbook.ActiveSheet.Cells.Item($row, $col).Value2 函数,以便在导出到 Excel 时更准确地确定数据的放置位置。

    类似

    $row = 1
    Get-Content $file | Foreach-Object {
       $cols = $_.split("`t")
       for ($i = 0; $i < $cols.count; $i++)
       {
          $Workbook.ActiveSheet.Cells.Item($row, $i+1).Value2 = $cols[$i]
       }
       $row++
    }
    

    警告:干编码!您可能还需要一些 try..catch

    【讨论】:

    • 谢谢,我会按照提示进行的。显然,来自kentfinkle.com/PowershellAndExcel.aspx:如何更改活动单元格的值? $a.ActiveCell.Value2 = "x";如何更改指定单元格的值? $a.ActiveSheet.Range("B1").Value2 = "y"; $ws.Cells.Item($row,1) = $_;
    【解决方案3】:

    我使用了修改后的Export-Xls 函数,与用户 empo 建议的有点不同。 这是我的呼唤

    Export-Xls  $filtered -Path $outfile -WorksheetName "$wn" -SheetPosition "end"  | Out-Null #  -SheetPosition "end";
    

    但是,当前版本的 Export-Xls 对 csv-text 文件的内存表示形式的列进行了重新排序。我希望文本文件的数据列按原始顺序排列,因此我不得不修改并简化原始代码,如下所示:

        function Add-Array2Clipboard {
            param (
                [PSObject[]]$ConvertObject,
                [switch]$Header
            )
            process{
                $array = @();
                $line =""
                if ($Header) {
    
                    $line = @()
                    $row = $ConvertObject | Select -First 1
                    $row.psobject.properties | Foreach {$line += "$($_.Name)" }
                    $array += [String]::Join("`t", $line)
    
    
                }
                else {
                    foreach($row in $ConvertObject){
                        $line =""
                        $vals = @()
                        $row.psobject.properties | Foreach {$vals +=  $_.Value}                      
                        $array += [String]::Join("`t", $vals)
    
                    }
    
                }
                $array | clip.exe; 
            }
    
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-20
      • 1970-01-01
      • 1970-01-01
      • 2010-11-08
      相关资源
      最近更新 更多