Powershell add 1 to excel column reference - excel

Just asked a powershell question here Finding excel cell reference and I need to add to it.
The overall code I ended up with is as follows.
$filePath = "c:\temp\test.xlsx"
if (test-path $filePath) {
$wb = $xl.Workbooks.Open($filePath)
$ws = $wb.Worksheets.Item("sheet1")
if ([bool]$ws.cells.find("German Baseload")) {write-host $ws.cells.find("German Baseload").address(0, 0, 1, 0)}
}
This returns a cell reference of F25 which is where the string is located, based on this I want to test the cell next to it in cell reference G25, my question is how do I add one column to F25?

Accessing any cell from a known cell reference is simply a matter of applying Range.Offset property to the original cell reference.
$filePath = "T:\TMP\findit.xlsx"
$xl = New-Object -ComObject Excel.Application
$xl.Visible = $true
if (test-path $filePath) {
$wb = $xl.Workbooks.Open($filePath)
$ws = $xl.WorkSheets.item("sheet1")
if ([bool]$ws.cells.find("German"))
{
$found = 1
$rc1 = $ws.cells.find("German")
$rc2 = $rc1.offset(0, 1)
write-host $found
write-host $rc1.address(0, 0, 1, 1)
write-host $rc2.address(0, 0, 1, 1)
write-host $ws.cells.find("German").offset(0, 1).address(0, 0, 1, 1)
}
}
I've reported the offset cell address back redundantly as a way of confirmation.

Related

Copy only visible worksheets via Powershell

I have a powershell script that loops through all worksheets of an excel file to copy columns from one worksheet to another worksheet with the same name in another file. It is working well, but I would like it to only loop through visible worksheets in the source file. How can I modify the script to accomplish this?
Param(
$Source = “Source.xlsm”,
$range1 = “A1:EZ1”,
$Output = “Output.xlsx”
) #end param
$Excel = New-Object -ComObject excel.application
$Excel.visible = $false
$Workbook = $excel.Workbooks.open($Source)
$WorkbookOutput = $excel.Workbooks.open($Output)
$Excel.displayAlerts = $false # don't prompt the user
$i = 1
foreach ($sheet in $workbook.Worksheets)
{
$Worksheet = $Workbook.WorkSheets.item($i)
$worksheet.activate()
$wksname = $worksheet.name
Write-Output $wksname
$range = $WorkSheet.Range($range1).EntireColumn
$range.Copy() | out-null
#$Excel.displayAlerts = $false # don't prompt the user
$WorksheetOutput = $WorkbookOutput.WorkSheets.item($wksname)
$worksheetOutput.activate()
#$Range = $Worksheet.Range($range2)
$WorksheetOutput.Range("A1:EZ1").PasteSpecial(-4163)
$i++
Write-Output $i
}
$workbook.Save()
$Excel.Quit()
Thanks for your help!
Kind Regards,
Smid
To add a bit more explanation to my comment:
An Excel WorkSheet has a .Visibility property. Usually, such a property would be a Boolean where only $true or $false apply.
In this case however .Visibility is an [Int32] value that can have three different values, taken from the XlSheetVisibility enumeration:
Name
Value
Description
xlSheetHidden
0
Hides the worksheet which the user can unhide via menu.
xlSheetVeryHidden
2
Hides the object so that the only way for you to make it visible again is by setting this property to True (the user cannot make the object visible).
xlSheetVisible
-1
Displays the sheet.
As you can see, the value for a Visible worksheet is -1
Microsofts examples on this property only show VB code and there it uses
Worksheets("Sheet1").Visible = True and Worksheets("Sheet1").Visible = False to set the visibility to either -1 or 0.
That works because in VB, the numeric value for True equals -1.
In PowerShell however, the numeric value for $true is not -1, but 1 instead:
[int]$true # --> 1
which means you should not set that property using $true as value to make the sheet visible, but -1 instead.
The same applies for testing if a sheet is visible or hidden:
Checking with if ($sheet.Visible){..} in this case does not check if a Boolean is $true or $false, but since the value is an integer, it checks for "if that property is zero or not".
If the sheet was set to xlSheetVeryHidden (value 2), that test will result in $true, making you think it is visible..
Finally, in your use case, simply change the foreach loop to read this:
foreach ($sheet in ($workbook.Worksheets | Where-Object { $_.Visible -eq -1 })) {
# the rest of your code
}
foreach ($sheet in $workbook.Worksheets) {
if ($sheet.Visible) {
...
}
}

Powershell -> find/replace in Excel -> look for a string in one cell and change the string in another cell

I would like to search for a string in a column. If it finds that string, I would like the script to replace the string in another cell - same row, different column. So my columns are like this...
screenshot
I want to search for "Hours" or "Hrs" in column "Unit Type" and when it finds it, I want to change the "Job ID" in that same row to 3289. Here's what I got so far and nothing seems to happen. Any help would be greatly appreciated. Thanks!
$excelFile = "C:\do\BEFORE.xls"
$objExcel = New-Object -ComObject Excel.Application
$WorkBook = $objExcel.Workbooks.Open($excelFile)
$worksheet = $WorkBook.sheets.item("Sheet1")
$rowCount = $worksheet.usedrange.rows.count
Select-Object "Acct", "Customer_Name", "Invoice","Inv_Date","Cost_ID","Job_ID","Description","Hours", "Quantity", "Price", "Unit_Type", "Amount"
foreach ($row in $excelFile) {
if ($row.Unit_Type -eq "Hours") {
$row.Job_ID = "3289"
}
}
$WorkBook.Save()
$WorkBook.Close()
The Select-Object command is not doing anything as you're not providing it any data. Though that doesn't matter much since you're dealing with an excel com object. You'll need to specify which column you're checking and I find it's easiest to use a for loop. We will start on row 2 since the first row is the headers. Based on your example the Unit Type column is 6 and the Job ID column is 1. You also wanted to check for either hours or hrs so a regex match would be an appropriate approach.
$excelFile = "C:\do\BEFORE.xls"
$objExcel = New-Object -ComObject Excel.Application
$WorkBook = $objExcel.Workbooks.Open($excelFile)
$worksheet = $WorkBook.sheets.item("Sheet1")
$rowCount = $worksheet.usedrange.rows.count
$unittypecolumn = 6
$jobidcolumn = 1
for($i = 2; $i -le $rowCount; $i++)
{
if($worksheet.Cells($i,$unittypecolumn).Value2 -match "hours|hrs")
{
$worksheet.Cells($i,$jobidcolumn).Value2 = "3289"
}
}
$WorkBook.Save()
$WorkBook.Close()

Reading value from Excel sheet

$filepath = "C:\Users\Desktop\New folder\Tangent.xlsx"
$sheetname = "sheet"
$objExcel = New-Object -ComObject Excel.Application
$objExcel.Visible = $false
$WorkBook = $objExcel.Workbooks.Open($filepath)
$WorkBook.sheets | Select-Object -Property Name
$WorkSheet = $WorkBook.Sheets.Item($sheetname)
$myObj = [PSCustomObject][ordered]#{
john = $WorkSheet.Range("B1").Text
Rebel = $WorkSheet.Range("B2").Text
MArk = $WorkSheet.Range("B3").Text
Susan = $WorkSheet.Range("B4").Text
Patty = $WorkSheet.Range("B5").Text
}
I have hardcoded all the names into the code which is a weird way of doing it. I want it to read from the Excel directing using command. Can anyone help me please?
Create an empty hashtable and fill it as you iterate over the rows in your Excel sheet, then create the object.
$ht = #{}
$i = 1
while ($WorkSheet.Cells.Item($i, 1).Text) {
$ht[$WorkSheet.Cells.Item($i, 1).Text] = $WorkSheet.Cells.Item($i, 2).Text
$i++
}
$obj = [PSCustomObject]$ht
Untested, as I don't have Excel at hand here.

Powershell find excel cell reference

I am using the following powershell code to search through a excel document for a string and return true or false depending on if its found.
if (test-path $filePath) {
$wb = $xl.Workbooks.Open($filePath)
if ([bool]$xl.cells.find("German")) {$found = 1}
}
I want to be able to get the cell reference of the string if its found but I cant figure it out or find an answer on google. Can you help?
While there is a method to search through an entire workbook for a value, typically a Range.Find method is performed on a worksheet. You are setting a var to the workbook but still using the application as the search. You should be getting the worksheet to search from the workbook and using that as the target of the Find operation.
Following are some suggested modifications to your PS1.
$filePath = "T:\TMP\findit.xlsx"
$xl = New-Object -ComObject Excel.Application
$xl.Visible = $true
if (test-path $filePath) {
$wb = $xl.Workbooks.Open($filePath)
$ws = $xl.WorkSheets.item("sheet1")
if ([bool]$ws.cells.find("German"))
{
$found = 1
write-host $found
write-host $ws.cells.find("German").address(0, 0, 1, 1)
}
}
To continue the search for all occurrences use the Range.FindNext method until you loop back to the original cell address.
$filePath = "T:\TMP\findit.xlsx"
$xl = New-Object -ComObject Excel.Application
$xl.Visible = $true
if (test-path $filePath) {
$wb = $xl.Workbooks.Open($filePath)
$ws = $wb.WorkSheets.item("sheet1")
$rc1 = $ws.cells.find("German")
if ($rc1)
{
$found = 1
$addr = $rc1.address(0, 0, 1, 0)
do
{
$rc1 = $ws.cells.findnext($rc1)
write-host $rc1.address(0, 0, 1, 0)
} until ($addr -eq $rc1.address(0, 0, 1, 0))
}
}
It's hard to provide much more than generalities since so much of your code is missing. I've filled in the missing information with my own test environment.

Export as CSV instead of a XLS file

I have a script that places everything nicely into a spread sheet. The problem is, I need it to export as a csv file instead. All the foreach loops are completely baffling me here as far as where to put the export csv functions in the script. If someone could could school me on how to get the fields into a csv file, It would be greatly appreciated.
$date = 0
$date = get-date -format "yyyy-MMM-dd-hhmm"
$date
#New Excel Application
$Excel = New-Object -Com Excel.Application
$Excel.visible = $False
# Create 1 worksheets
$Excel = $Excel.Workbooks.Add()
# Assign each worksheet to a variable and
# name the worksheet.
$Sheet1 = $Excel.Worksheets.Item(1)
$Sheet1.Name = "HH_SERVERS"
#Create Heading for General Sheet
$Sheet1.Cells.Item(1, 1) = "Machine_Name"
$Sheet1.Cells.Item(1, 2) = "OS"
$Sheet1.Cells.Item(1, 3) = "Software"
$Sheet1.Cells.Item(1, 4) = "Vendor"
$Sheet1.Cells.Item(1, 5) = "Version"
$colSheets = ($Sheet1)
foreach ($colorItem in $colSheets)
{
$intRow = 2
$intRowDisk = 2
$intRowSoft = 2
$intRowNet = 2
$WorkBook = $colorItem.UsedRange
$WorkBook.Interior.ColorIndex = 20
$WorkBook.Font.ColorIndex = 11
$WorkBook.Font.Bold = $True
}
#Auto Fit all sheets in the Workbook
foreach ($colorItem in $colSheets)
{
$WorkBook = $colorItem.UsedRange
$WorkBook.EntireColumn.AutoFit()
clear
}
$Servers = get-content "c:\temp\HH_Servers.txt"
foreach ($Server in $Servers)
{
$GenItems2 = gwmi Win32_OperatingSystem -Comp $Server
$Software = gwmi Win32_Product -Comp $Server
# Populate General Sheet(1) with information
foreach ($objItem in $GenItems2)
{
$Sheet1.Cells.Item($intRow, 2) = $objItem.Caption
}
#Populate Software Sheet
foreach ($objItem in $Software)
{
$Sheet1.Cells.Item($intRowSoft, 1) = $Server
$Sheet1.Cells.Item($intRowSoft, 3) = $objItem.Name
$Sheet1.Cells.Item($intRowSoft, 4) = $objItem.Vendor
$Sheet1.Cells.Item($intRowSoft, 5) = $objItem.Version
$intRowSoft = $intRowSoft + 1
}
}
$outputfile = "c:\temp\" + $date.toString() + "-HH_Server_Software"
$Excel.SaveAs($outputfile)
$Excel.Close()
Write-Host "*******************************" -ForegroundColor Green
Write-Host "The Report has been completed." -ForeGroundColor Green
Write-Host "*******************************" -ForegroundColor Green
# ========================================================================
# END of Script
# ==================
You can't save an entire workbook as CSV. You need to save the individual worksheet instead. The file format value for CSV is 6 (don't remember where I found that out though):
$xlCSV = 6
$outputfile = "c:\temp\" + $date.toString() + "-HH_Server_Software.csv"
$Sheet1.SaveAs($outputfile, $xlCSV)
(Tested on Windows 7 with Excel 2013.)
Thanks to #Matt for a comment with a link to the XLFileFormat Enumerations.

Resources