【问题标题】:Powershell: Copying data from one Excel workbook to anotherPowershell:将数据从一个 Excel 工作簿复制到另一个
【发布时间】:2015-12-12 10:53:50
【问题描述】:

你好 stackoverflow 朋友!

我正在处理一个Powershell 脚本,我正在尝试执行以下操作:

  • 选择一个 Excel xlsx 文件,其中现有的工作表只有标题
  • 选择一个文本文件
  • 从文本文件创建一个临时 CSV 文件并添加标题以匹配 Excel 文件
  • 将 CSV 文件中的信息复制到 Excel 文件中的工作表中
  • 保存/退出

我已经准备好使用 Excel 对象的 Range 方面所需的一切。当尝试从实例化为 COM 对象的 CSV 文件中复制数据,然后激活 xlsx 文件时,我收到一条错误消息

使用“1”参数调用“粘贴”的异常:“粘贴方法 工作表类失败”在 line:1 char:1

  • $Script:ExcelWorkSheet.Paste($tempRange)
  • ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    • CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    • FullyQualifiedErrorId : ComMethodTargetInvocation

以下是我到目前为止的代码。任何帮助将不胜感激,因为我不知所措:

BEGIN
{
    Function Set-ScriptVars()
    {
        Add-Type -AssemblyName System.Windows.Forms
    }

    Function Select-File($FileType)
    {
        ## Select file via selection dialog

        do {
            if($FileType -eq "xlsx")
            {
                Write-Host "`nPlease select the Excel file to import in the dialog"
            }
            elseif($FileType -eq "txt")
            {
                Write-Host "`nPlease select the Prescan or Postscan text file to import in the dialog"
            }

            Start-Sleep -Seconds 1
            $FileBrowser = New-Object System.Windows.Forms.OpenFileDialog -Property @{InitialDirectory = [Environment]::GetFolderPath('Desktop')}

            [void]$FileBrowser.ShowDialog()

            Write-Host "`nFile selected: " -NoNewline  
            Write-Host $FileBrowser.FileNames -ForegroundColor Yellow 

            $FileName = $FileBrowser.FileName
            if ($FileName.EndsWith(".$FileType"))
            {
                $selectionValid = $True
            }
            else
            {
                Write-Host "The file selected is not a .$FileType file."
                Write-Host "Restarting file selection loop."
                $selectionValid = $False
            }
        } until ($selectionValid -eq $True)

        if($FileType -eq "txt")
        {
            $Script:TextFile = $FileName
            $Script:TextParentPath = (Get-Item $FileName).Directory.FullName
        }
        elseif($FileType -eq "xlsx")
        {
            $Script:ExcelFile = $FileName
            $Script:ExcelParentPath = (Get-Item $FileName).Directory.FullName
        }
    }

    Function Open-Excel($Sheet)
    {
        $ActiveSheet = $Sheet

        $ExcelPath = $Script:ExcelFile
        $Script:Excel = New-Object -ComObject Excel.Application
        $Script:Excel.Visible = $True
        $Script:Excel.UserControl = $False
        $Script:Excel.Interactive = $False
        $Script:Excel.DisplayAlerts = $False

        $Script:ExcelWorkBook = $Script:Excel.Workbooks.Open($ExcelPath)
        $Script:ExcelWorkSheet = $Script:Excel.WorkSheets.item($ActiveSheet)
        $Script:ExcelWorkSheet.Activate()
    }

    Function Get-TextContent()
    {
        $Script:TextContent = Get-Content $Script:TextFile 
    }

    Function Copy-TextData()
    {
        # create a random file name

        $randomInt = @(0001..9999) | Get-Random
        $tempCSV = Import-CSV $Script:TextFile -Header "Server","Role","Type","Object","Path" 
        $tempCSV | Export-CSV -Path $ENV:USERPROFILE\Desktop\tempCSV_$randomInt.csv -NoTypeInformation
        $tempCSVPath = "$ENV:USERPROFILE\Desktop\tempCSV_$randomInt.csv"
        $tempCSVName = "tempCSV_$randomInt"

        # create a temporary file to copy from

        $TempExcel = New-Object -ComObject Excel.Application
        $TempExcel.Visible = $True
        $TempWorkBook = $TempExcel.WorkBooks.Open($tempCSVPath)
        $TempWorkSheet = $TempWorkBook.WorkSheets.Item($tempCSVName)

        $tempRange = $TempWorkSheet.Range("A2:E2").UsedRange
        $tempRange.Copy() | Out-Null

        $Script:ExcelWorkSheet.Activate()
        $Script:ExcelWorkSheet.Range("A2:E2").EntireColumn
        $Script:ExcelWorkSheet.Paste($tempRange)
        $Script:ExcelWorkBook.Save()
        $Script:Excel.Quit()

        [gc]::Collect()
        [gc]::WaitForPendingFinalizers()

        Write-Host "Break"
    }
}

PROCESS
{
    Set-ScriptVars
    Select-File -FileType "xlsx"
    Select-File -FileType "txt"
    if($Script:TextFile -match "Prescan")
    {
        Open-Excel -Sheet "Prescan"
    }
    elseif($Script:TextFile -match "Postscan")
    {
        Open-Excel -Sheet "Postscan"
    }

    Get-TextContent
    Copy-TextData
}

END
{

}

在这种情况下,不能使用 VB 宏。 如果这样的任务更容易通过利用 .NET 程序集或以 @' '@ 格式放入 C# 代码来完成,我会全力以赴!

【问题讨论】:

    标签: c# powershell scripting powershell-4.0


    【解决方案1】:

    花了很多时间后,我终于找到了一个可行的解决方案。 对于将来可能通过搜索引擎遇到此问题的任何人,我希望下面的代码有所帮助!

    BEGIN
    {
        Function Set-ScriptVars()
        {
            Add-Type -AssemblyName System.Windows.Forms
        }
    
        Function Select-File($FileType)
        {
            ## Select file via selection dialog
    
            do {
                if($FileType -eq "xlsx")
                {
                    Write-Host "`nPlease select the Excel file to import in the dialog"
                }
                elseif($FileType -eq "txt")
                {
                    Write-Host "`nPlease select the Prescan or Postscan text file to import in the dialog"
                }
    
                Start-Sleep -Seconds 1
                $FileBrowser = New-Object System.Windows.Forms.OpenFileDialog -Property @{InitialDirectory = [Environment]::GetFolderPath('Desktop')}
    
                [void]$FileBrowser.ShowDialog()
    
                Write-Host "`nFile selected: " -NoNewline  
                Write-Host $FileBrowser.FileNames -ForegroundColor Yellow 
    
                $FileName = $FileBrowser.FileName
                if ($FileName.EndsWith(".$FileType"))
                {
                    $selectionValid = $True
                }
                else
                {
                    Write-Host "The file selected is not a .$FileType file."
                    Write-Host "Restarting file selection loop."
                    $selectionValid = $False
                }
            } until ($selectionValid -eq $True)
    
            if($FileType -eq "txt")
            {
                $Script:TextFile = $FileName
                $Script:TextParentPath = (Get-Item $FileName).Directory.FullName
            }
            elseif($FileType -eq "xlsx")
            {
                $Script:ExcelFile = $FileName
                $Script:ExcelParentPath = (Get-Item $FileName).Directory.FullName
            }
        }
    
        Function Open-Excel($Sheet)
        {
            $ExcelPath = $Script:ExcelFile
            $Script:Excel = New-Object -ComObject Excel.Application
            $Script:Excel.Visible = $False
            $Script:Excel.UserControl = $False
            $Script:Excel.Interactive = $True
            $Script:Excel.DisplayAlerts = $False
    
            $Script:ExcelWorkBook = $Script:Excel.Workbooks.Open($ExcelPath)
            $Script:ExcelWorkSheet = $Script:Excel.WorkSheets.item($Sheet)
            $Script:ExcelWorkSheet.Activate()
        }
    
        Function Get-TextContent()
        {
            $Script:TextContent = Get-Content $Script:TextFile 
        }
    
    function Release-Ref ($ref) { 
        ([System.Runtime.InteropServices.Marshal]::ReleaseComObject( 
        [System.__ComObject]$ref) -gt 0) | Out-Null
        [System.GC]::Collect() 
        [System.GC]::WaitForPendingFinalizers() 
    } 
        Function Copy-TextData()
        {       
            # create a CSV from the scan data
    
            $Script:TextContent = Get-Content $Script:TextFile
    
            $data = @()
            $row = New-Object PSObject
    
            foreach($line in $Script:TextContent)
            {
                if($line -eq "CSV was validated without errors." -or $line -eq "")
                {
                    Out-Null
                }
                else
                {
                    $i = 0
                    $values = $line -split ","
                    $result = [PSCustomObject]@{Server=$values[0];`
                                                Role=$values[1];`
                                                Object=$values[2];`
                                                Type=$values[3];`
                                                Path=$values[4]
                                               }
    
                    [Array]$results = $results + $result
                }
            }
            $csvName = "scanData_" + "$(@(000..999) | Get-Random)"
            $results | Export-CSV -Path "$ENV:USERPROFILE\Desktop\$csvName.csv" -NoTypeInformation
            $csvPath = $(Get-Item $ENV:USERPROFILE\Desktop\$csvName.csv).VersionInfo.FileName
    
            # Remove header generated by hashtable
            # and skip the next two lines
    
            $tempContent = Get-Content $csvPath
            $replacementContent = $tempContent | Select -Skip 3
            Set-Content $csvPath -Value $replacementContent
    
            # create temporary workbook and save as xlsx
            $tempXL = New-Object -ComObject Excel.Application
            $tempXL.Visible = $False
            $tempXL.UserControl = $False
            $tempXL.Interactive = $True
            $tempXL.DisplayAlerts = $False
    
            $tempWB = $tempXL.WorkBooks.Open("$csvPath")
            $tempWS = $tempWB.WorkSheets
    
            $convertedName = $csvPath.Replace(".csv",".xlsx")
            $tempWB.SaveAs($convertedName,1)
            $tempWB.Saved = $True
    
            $tempRange = $tempWB.Worksheets.Item(1).UsedRange
            $tempRange.Copy()
    
            if($Script:logSelection -eq "Prescan")
            {
                $permRange = $Script:ExcelWorkBook.Worksheets.Item(2)
            }
            else
            {
                $permRange = $Script:ExcelWorkBook.Worksheets.Item(3)
            }
    
            $subRange = $permRange.Range("A2","E2")
            $permRange.Paste($subRange)
            $permRange.Columns.AutoFit()
    
            $Script:ExcelWorkBook.Save()
            $Script:ExcelWorkBook.Saved = $True
            $Script:Excel.Quit()
    
            $tempWB.Save()
            $tempWB.Saved = $True
            $tempXL.Quit()
    
            Release-Ref($Script:ExcelWorkSheet)
            Release-Ref($tempWS)
    
            Release-Ref($Script:ExcelWorkBook)
            Release-Ref($tempWB)
    
            Release-Ref($Script:Excel)
            Release-Ref($tempXL)
    
            Remove-Item $csvPath -Force
            Get-Item $convertedName | Remove-Item -Force
        }
    
        Function Prompt-ReRun
        {
            do
            {
                $openChoice = Read-Host "`nRun again? (y/n)"
                $openChoice = $openChoice.ToLower()
            } until($openChoice -eq "y" -or $openChoice -eq "n")
    
            if($openChoice -ne "y" -and $openChoice -ne "n")
            {
                Write-Host "Invalid entry"
            }
            elseif($openChoice -eq "y")
            {
                Run-Selection
            }
            else
            {
                Out-Null
            }
        }
    
        Function Run-Selection
        {
            Select-File -FileType "xlsx"
            Select-File -FileType "txt"
            if($Script:TextFile -match "Prescan")
            {
                Open-Excel -Sheet "Prescan"
                $Script:logSelection = "Prescan"
            }
            elseif($Script:TextFile -match "Postscan")
            {
                Open-Excel -Sheet "Postscan"
                $Script:logSelection = "Postscan"
            }
    
            Get-TextContent
            Copy-TextData
            Prompt-ReRun
        }
    }
    
    PROCESS
    {
        Set-ScriptVars
        Run-Selection
    }
    
    END
    {
    
    }
    

    【讨论】:

      猜你喜欢
      • 2014-07-07
      • 2017-02-26
      • 2011-03-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-09
      • 1970-01-01
      • 2018-02-10
      相关资源
      最近更新 更多