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.
Related
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) {
...
}
}
i have a trouble findiong a value in an excel sheet.
i want to get the cell number that contains a value with a string, but i need to use wildcars.
the cell that i am searching begins with B- and i am using this code:
$excel = New-Object -ComObject excel.application
$destinationPath = "C:\Users\john\Desktop\wb.xlsx"
$workbook = $excel.Workbooks.Open($destinationPath)
$sheet1 = $workbook.WorkSheets.item("Sheet1")
$sheet1.activate()
$range = $sheet1.Range("A:A").EntireColumn
$s = $range.find("B-")
write-host "Range found: " $s.address().tostring()
this returns me the first cell that contains B- .... but i need to know the first cell that begins with this. So i think i must use wildcards but i don't know how.
please, could anyone help me to achieve this??
thank you!! BR.
Here a working solution which is able to use regex as well:
Add-Type -AssemblyName Microsoft.Office.Interop.Excel
$excel = New-Object -ComObject Excel.Application
$excel.Visible = $True
$excel.DisplayAlerts = $False
$workbook = $excel.Workbooks.Open( "C:\Users\john\Desktop\wb.xlsx", [System.Type]::Missing, $false )
$worksheet = $workbook.WorkSheets.item("Sheet1")
[void]$worksheet.activate()
$searchRange = $worksheet.Range("A:A").EntireColumn
$searchFor = '^.*B\-.*$'
$foundCell = $null
foreach( $cell in $searchRange.Cells ) {
if( $cell.Value2 -match $searchFor ) {
$foundCell = $cell
break
}
}
if( $foundCell ) {
$foundCell.Value2
}
[void]$workbook.Close()
[void]$excel.Quit()
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($excel) | Out-Null
I'm writing a little GUI to ease working on some excel documents. It has a button that starts this function to open excel file and select required row.
Function open_bible_file
{
$Excel = New-Object -ComObject excel.application
$Excel.WindowState= "xlMaximized"
$Excel.visible = $true
$WorkBook = $Excel.Workbooks.Open($SCOMBibleFile)
$Worksheet = $Workbook.WorkSheets.item("(1) Alerts")
$worksheet.activate()
$Range = $Worksheet.Cells.Item($excelrow,1).EntireRow
[void]$Range.Select()
}
}
It opens the file and selects the row as it should. But when I use this button again it just opens excel one more time and again selects another row. When I've tried to do another button to just select rows It does not know anything about already opened worksheets. How can I get around it?
The code should check if Excel is already running and if so, if the workbook (file $SCOMBibleFile) is present. If that is the case, re-activate Excel, otherwise start a new instance.
This should work:
function open_bible_file {
[CmdletBinding()]
Param(
[Parameter(Mandatory = $true, Position = 0)]
[string]$Path,
[Parameter(Mandatory = $false, Position = 1)]
[int]$RowToSelect = 1
)
$WorkBook = $null
# check if Excel is already open
try {
# Note: this only gets the excel instances that were started
# by the same user that runs this powershell function.
$Excel = [Runtime.Interopservices.Marshal]::GetActiveObject('Excel.Application')
# test if the $Path workbook is present in this Excel instance
foreach ($wb in $Excel.Workbooks) {
if ($wb.FullName -match [regex]::Escape($Path)) {
$WorkBook = $wb
break
}
}
}
catch {
# Excel wasn't opened yet, create a new instance
$Excel = New-Object -ComObject Excel.Application
}
if (!($Excel)) { Write-Error "Error opening Excel"; return }
if (!($WorkBook)) {
$WorkBook = $Excel.Workbooks.Open($Path)
}
# see https://learn.microsoft.com/en-us/office/vba/api/excel.xlwindowstate
$xlMaximized = -4137
$Excel.Visible = $true
$Excel.WindowState = $xlMaximized
$Excel.ActiveWindow.Activate()
$Worksheet = $Workbook.WorkSheets.item("(1) Alerts")
$worksheet.activate()
$Range = $Worksheet.Cells.Item($RowToSelect, 1).EntireRow
[void]$Range.Select()
}
$SCOMBibleFile = '<PATH TO YOUR .xlsx FILE>'
open_bible_file -Path $SCOMBibleFile -RowToSelect 3
As you can see, I have changed the open_bible_file function to take parameters. The first (-Path) is where you give it the filename to open. The second (-RowToSelect) is the row number you want selected.
Hope this helps
$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.
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.