Powershell:将数据从一个Excel工作簿复制到另一个
本文关键字:Excel 一个 工作簿 复制 另一个 数据 Powershell | 更新日期: 2023-09-27 18:13:06
大家好!
我有一个Powershell
脚本,我正在努力做以下事情:
- 选择一个Excel
xlsx
文件与现有的工作表只有标题 - 选择文本文件
- 从文本文件创建一个临时CSV文件,并添加标题以匹配Excel文件
- 将CSV文件中的信息复制到Excel文件 中的工作表中
- 保存/退出
我已经得到了使用Excel对象的范围方面所需的一切。当尝试从实例化为COM对象的CSV文件复制数据,然后激活xlsx文件时,我得到一个错误,说明
异常调用"粘贴",参数为"1":"粘贴方法工作表类失败" At line:1 char:1
- 脚本:美元ExcelWorkSheet.Paste ($ tempRange)
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- CategoryInfo: NotSpecified: (:) [], MethodInvocationException
- fulllyqualifiederrid: 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#代码更容易完成这样的任务,我将洗耳恭听!
在花费了大量时间之后,我终于找到了一个可行的解决方案。对于将来可能通过搜索引擎遇到这种情况的任何人,我希望下面的代码能有所帮助!
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
{
}