Change from single target to last used cell in column - excel

I am sure this is a common question. I am trying to just paste instead of to the target cell in the paste range, to go to the last used cell in the column + 1, so it just appends the target spread sheet. What do I need to change here?
I have tried some of the suggestions on here but keep getting errors, probably because I am using $lastRow = $ExcelWorkSheet.UsedRange.rows.count + 1 in the wrong place (haven't been using powershell that long).
If anyone can show easiest way to do this would be great. Thanks!
$Excel = New-Object -ComObject "Excel.Application"
$Excel.Visible=$true
$Workbook = $Excel.Workbooks.Open($pathxlsx)
$TempWorkbook = $Excel.Workbooks.Opentext($pathcsv)
$temp = $excel.Workbooks.Item(2)
$temp = $temp.Worksheets.Item(1)
$CopyRange = $temp.Range("C15")
$CopyRange.Copy()
$workbooksheet = $Workbook.Worksheets.Item(1)
$Workbooksheet.activate()
$PasteRange = $workbooksheet.Range("C10")
$workbooksheet.Paste($PasteRange)
EDIT - Ok, got it to do something different, but still not what I want.
$Excel = New-Object -ComObject "Excel.Application"
$Excel.Visible=$true
$Workbook = $Excel.Workbooks.Open($pathxlsx)
$TempWorkbook = $Excel.Workbooks.Opentext($pathcsv)
$temp = $excel.Workbooks.Item(2)
$temp = $temp.Worksheets.Item(1)
$CopyRange = $temp.Range("C15")
$CopyRange.Copy()
$workbooksheet = $Workbook.Worksheets.Item(1)
$ExcelWorkSheet.UsedRange.rows.count
$lastRow = $workbooksheet.UsedRange.rows.count + 1
$Workbooksheet.activate()
$PasteRange = $workbooksheet.Range("C" + $lastrow)
$workbooksheet.Paste($PasteRange)

I ended up just creating an excel template with a power query for this issue. This plus a formula to transpose the data allowed for a clean copy and paste with the data I needed in the form i needed it.

Related

Split Excelfile .xlxs with Powershell based on column values

I need to split and save an excel file based on the values of the first column via a powershell script. Here is how the excel file is build up (app 30.000 rows)
´´´Column1 # Column2 # Column3´´´
´´´AA # data # data # data´´´
´´´AA # data # data # data´´´
´´´AB # data # data # data´´´
´´´AC # data # data # data´´´
´´´AC # data # data # data´´´
The result should be multiple files with filenames AA.xlxs, AB.xlxs, AC.xlxs and of course the according rows data.
What I have so far is the following code:
$objexcel = New-Object -ComObject Excel.Application
$wb = $objexcel.WorkBooks.Open("C:\Test.xlsx")
$objexcel.Visible = $true
$objexcel.DisplayAlerts = $False
$ws = $wb.Worksheets.Item(1)
$doc = $ws.Range("A:A")
foreach ($doc in $docs) {
$newfile,$objexcel = $objexcel.where({$doc -eq $doc})
$newfile | Export-Excel "C:\$doc.xlxs"
}
It just opens the file, but nothing happens.
It would be great if some coder could have a look at the code or provide a working one.
Thanks in advance.
Following is a working code that will iterate through unique elements in column one and make a copy of it in a new spreadsheet and save it.
Function Create-Excel-Spreadsheet {
Param($NameOfSpreadsheet)
# open excel
$excel = New-Object -ComObject excel.application
$excel.visible = $true
# add a worksheet
$workbook = $excel.Workbooks.Add()
$xl_wksht= $workbook.Worksheets.Item(1)
$xl_wksht.Name = $NameOfSpreadsheet
return $workbook
}
$objexcel = New-Object -ComObject Excel.Application
$wb = $objexcel.WorkBooks.Open("C:\Temp\Test.xlsx") # Changing path for test.xlsx file.
$objexcel.Visible = $true
$objexcel.DisplayAlerts = $False
$ws = $wb.Worksheets.Item(1)
$usedRange = $ws.UsedRange
$usedRange.AutoFilter()
$totalRows = $usedRange.Rows.Count
$rangeForUnique = $usedRange.Offset(1, 0).Resize($UsedRange.Rows.Count-1)
[string[]]$UniqueListOfRowValues = $rangeForUnique.Columns.Item(1).Value2 | sort -Unique
for ($i = 0; $i -lt $UniqueListOfRowValues.Count; $i++) {
$newRange = $usedRange.AutoFilter(1, $UniqueListOfRowValues[$i])
$workbook = Create-Excel-Spreadsheet $UniqueListOfRowValues[$i]
$wksheet = $workbook.Worksheets.Item(1)
$range = $ws.UsedRange.Cells
$range.Copy()
$wksheet.Paste($wksheet.Range("A1"))
$workbook.SaveAs("C:\temp\" + $UniqueListOfRowValues[$i], $xlFixedFormat)
$workbook.Close()
}
Reason nothing is happening is because you are iterating over $docs which does not contain any elements. It is currently null.
When you make a reference to look up the data, you are using $objexcel, but thats your excel application.. not the worksheet that you want to iterate over. Use $as for accessing the worksheet.
You need to iterate over Cells of your $ws and take the data when cells.Item(x, 0) and create a new file based on that with values in other two columns.
Link to example on SO -> Create and Update excel file

Copying graph from Excel to Word with Powershell

I am trying to copy a graph from excel to word. The source file in excel has two sheets, 'data' & 'graph' on the 'graph' sheet there are 4 graphs, arranged 2x2.
The Word document is empty.
I am fairly new to powershell, but i want to automate a weekly report i have to make. This might seem a little steep, but i like a challenge. Plus, the report eats my time.
This is my code:
$xl = new-object -comobject excel.application
$xl.Visible = $true
$wb = $xl.workbooks.open("H:\Reporting\ULTRAgraphTest.xlsx")
$ws = $wb.worksheets.item(1)
$charts = $ws.ChartObjects()
$chart = $charts.Item(1)
$a = $chart.copy
$wd = new-object -comobject Word.application
$wd.visible = $true
$path = "H:\Reporting\insertest.docx"
$doc = $wd.documents.open($path)
$wd.selection.Paste()
When i run this, the files get opened, but it pastes the clipboard content in the word document. It doesn't seem to copy the graph. What am i not seeing here?
Forgot the partheses
$a = $chart.copy
Should be
$a = $chart.copy()

powershell excel get first row(header) column count

I'm trying to count the cell number of the first row (A1-D1) which is known as header and get that count as the counter.
As all the while find most of them using Usedrange to count the columns:
$headercolcount=($worksheet.UsedRange.Columns).count
But UsedRange will capture maximum count in the whole activesheet, which resulting not identical to the column count in first row if there is extra content data below the header.
I only wish to grab just the first row:
[]
Update:
For clearer view, here is an example.
As 1F & 1G there are no value present, so the answer should be 5 as 1A-1E as it contains data. So how should I grab the 5 correctly?
[]
Get-Process excel | Stop-Process -Force
# Specify the path to the Excel file and the WorkSheet Name
$FilePath = "C:\temp\A_A.xlsx"
$SheetName = "Blad1" # In english this is probably Sheet1
# Create an Object Excel.Application using Com interface
$objExcel = New-Object -ComObject Excel.Application
# Disable the 'visible' property so the document won't open in excel
$objExcel.Visible = $false
$objExcel.DisplayAlerts = $false
# Open Excel file and in $WorkBook
$WorkBook = $objExcel.Workbooks.Open($FilePath)
# Load WorkSheet 'Blad 1' in variable Worksheet
$WorkSheet = $WorkBook.sheets.item($SheetName)
$xlup = -4162
$lastRow = $WorkSheet.cells.Range("A1048576").End($xlup).row
# get the highest amount of columns
$colMax = ($WorkSheet.UsedRange.Columns).count
# initiatie a counter
$count = $null
# set the column you'd like to count
$row = 1
for ($i = 0; $i -le $colMax; $i++){
if($worksheet.rows.Item("$row").columns.Item($i+1).text){
$count++
}
}
$count
This should work. It takes the highest amount of columns. It then loops until it reaches that amount. During the loop it checks if the cell on that row is filled or not, if it is, it adds to the counter.
If you have millions of lines, this might not be the best way but this works for me.
I've testes it with an excel file:
With
$row = 1 this will give : 5
$row = 2 this will give : 6
$row = 3 this will give : 7
$row = 4 this will give : 8
# Specify the path to the Excel file and the WorkSheet Name
$FilePath = "C:\temp\A_A.xlsx"
$SheetName = "Blad1" # In english this is probably Sheet1
# Create an Object Excel.Application using Com interface
$objExcel = New-Object -ComObject Excel.Application
# Disable the 'visible' property so the document won't open in excel
$objExcel.Visible = $false
$objExcel.DisplayAlerts = $false
# Open Excel file and in $WorkBook
$WorkBook = $objExcel.Workbooks.Open($FilePath)
# Load WorkSheet 'Blad 1' in variable Worksheet
$WorkSheet = $WorkBook.sheets.item($SheetName)
$xlup = -4162
$lastRow = $WorkSheet.cells.Range("A1048576").End($xlup).row
$amountofcolumns = $worksheet.UsedRange.Rows(1).Columns.Count
#OUTPUT
write-host "Last Used row:" $lastRow
Write-host "Amount of columns" $amountofcolumns
#show all columnnames
for($i = 1 ; $i -le $amountofcolumns; $i++){
$worksheet.Cells.Item(1,$i).text
}
This will show you how many rows you have AND will show you all values in the first row , ergo your titles.

Paste into Excel from Powershell

I have tried lots of options to paste information copied from other Excel workbook into my new workbook but not success do that (the range is huge - more them 3000 lines).
Please see sample of my script:
$objExcel = New-Object -ComObject Excel.Application
$objExcel.Visible = $false
$objExcel.displayAlerts = $false
$Src = [Environment]::GetFolderPath('Desktop')+'\New.xlsx'
$Files = [Environment]::GetFolderPath('Desktop')+'\Org.xlsx'
$wb1 = $objExcel.workbooks.open($Files)
$Worksheetwb1 = $wb1.WorkSheets.item('Org')
$Worksheetwb1.activate()
$Range = $Worksheetwb1.Range('A1:I1').EntireColumn
$Range.Copy() | Out-Null
$wb3 = $objExcel.workbooks.open($Src)
$Worksheetwb3 = $wb3.WorkSheets.item('Dest')
$Worksheetwb3.activate()
$Worksheetwb3.Columns.item('A:I').clear()
$Range3 = $Worksheetwb3.Range('A1:I1').EntireColumn
$Worksheetwb3.Paste($Range.Value2)
$wb3.close($true)
$wb1.close($true)
$objExcel.Quit()
You're pasting into a wrong range. Worksheet.Paste() has parameters of destination and link, your code uses destination only, which should be a Range belonging to that worksheet. Therefore, the proper line should be this:
$Worksheetwb3.Paste($Range3)
Alternatively to Vesper's solution:
$Worksheetwb3.Range("A1").Paste() | Out-Null
# Paste special (as values)
$Worksheetwb3.Range("A1").PasteSpecial(-4163) | Out-Null
I have found the answer by changing the order of commands the Copy and then immediate after it the paste solved it for me.

Copy CSV Rows to an Existing Excel Sheet

This should be pretty simple. I'm looking to take the information from my previous question(s), which is a CSV, and place them in an existing Excel document.
Here's the existing data (in a CSV):
SO | Status | ElapsedHrs
PMTT12345678 Hit on Debra 2.5
PMTS23456789 Get rejected 4.25
PMTT87654321 Send some faxes 1.0
So I have an existing Excel sheet, where all of the SO category needs to go to column K starting at cell 6, Status goes to L starting at 6 and ElapsedHrs goes to column O starting at cell 6.
Using this and a few others as examples, but I can't figure out the syntax. Any help is appreciated, again.
Edit
So far I have this:
$Excel = New-Object -ComObject excel.application
$Excel.visible = $false
$WorkBook = $objExcel.Workbooks.Open($ExportCsv)
$WorkBook2 = $excel.Workbooks.open($Template)
$Worksheet = $Workbook.WorkSheets.item(“$ExpCsvShort”)
$ExportCsv is the name of the CSV with the full path. $ExpCsvShort' is just the filename (the name changes based on the hour and date). $Template` is the template .xslx file to which the data would be written.
$range = $WorkSheet.Range(“A2”).EntireColumn
$range.Copy() | out-null
Not sure what this should be, as I want column A (minus the header) to go to K on $Template starting at 6. Then I want C to start at L6 and D to start at O6, but I don't know the syntax.
Once I have that:
$Worksheet2 = $Workbook2.Worksheets.item(“Worklog”)
$worksheet2.activate()
$range2 = $Worksheet2.Range(“K6:K6”)
$Worksheet2.Paste($range2)
$workbook2.SaveAs($WorkLogSave)
$workbook.close($false)
$Excel.Quit()
[gc]::collect()
[gc]::WaitForPendingFinalizers()
But again, I don't know the syntax for the range here, either.
Edit 2
Here's what I ended up doing.
$Excel = New-Object -ComObject excel.application
$Excel.visible = $true
$WorkBook = $excel.Workbooks.Open($ExportCsv)
$WorkBook2 = $excel.Workbooks.open($Template)
$Worksheet = $Workbook.WorkSheets.item($ExpCsvShort)
$Worksheet.activate()
#A Range Copy
$rangeAc = $WorkSheet.Range(“A2:A26”)
$rangeAc.Copy() | out-null
#Select sheet 2
$Worksheet2 = $Workbook2.Worksheets.item(“Worklog”)
$worksheet2.activate()
#A Range Paste
$rangeAp = $Worksheet2.Range(“K6:K30”)
$Worksheet2.Paste($rangeAp)
#C Range Copy
$rangeCc = $WorkSheet.Range(“C2:C26”)
$rangeCc.Copy() | out-null
#C Range Paste
$rangeCp = $Worksheet2.Range(“O6:O30”)
$Worksheet2.Paste($rangeCp)
#D Range Copy
$rangeDc = $WorkSheet.Range(“D2:D26”)
$rangeDc.Copy() | out-null
#D Range Paste
$rangeDp = $Worksheet2.Range(“L6:L30”)
$Worksheet2.Paste($rangeDp)
$workbook2.SaveAs($WorkLogSave)
$workbook2.close($true)
$workbook.close($true)
$Excel.Quit()
[gc]::collect()
[gc]::WaitForPendingFinalizers()
Probably a pretty crappy way to do it, but it works. Also, I still have EXCEL.EXE running after everything is closed. I've read about 5 ways to kill the process, but I'm worried if I do I'll mess someone up who has another document open, so maybe I can -passthru and capture the .id and kill that instead, but I'll worry about that later I guess.
Thanks for helping, all.
And I'd love to use that gravity, but I'm not sure I understand how. Thanks!

Resources