Powershell loop for excel replace - excel

I have found a bit of code here on stack overflow, and added a few bits. It works like a charm with the current settings... On Sheet1 in the columns from A to D.
I would like it to run on all the sheets in the workbook. But I cant fold my brain around the a solotion that works.
This is my code that works on Sheet1:
$replacecount = 0
$file = "H:\test4.xlsx"
$Excel = New-Object -ComObject Excel.Application
$Excel.Visible = $false
$Workbook = $Excel.workbooks.open($file)
$SearchString = "2019-AUG"
$replacestring = "2020-MAY"
$Worksheet = $Workbook.Worksheets.Item(1)
$Range = $Worksheet.Range("A1:D1").EntireColumn
write-output $worksheet.index
$Search = $Range.find($SearchString)
if ($search -ne $null) {
$FirstAddress = $Search.Address
do {
$search.Value() = $Search.value() -Replace $SearchString, $replacestring
$search = $Range.FindNext($search)
$replacecount++
} while ($search -ne $null -and $search.Address -ne $FirstAddress)
}
Write-output "status Close"
Write-output $replacecount
$WorkBook.Save()
$WorkBook.Close()
I'm thinking that I should be using a FOREACH (sheet in worksheet) but when I try to set the range inside the loop I get an error

Consider looping through Excel's Sheets.Count property:
$num = $Workbook.Sheets.Count()
For ($i = 1; $i -le $num; $i++) {
write-host $Workbook.Worksheets.Item($i).Name
$Worksheet = $Workbook.Worksheets.Item($i)
$Range = $Worksheet.Range("A1:D1").EntireColumn
write-output $worksheet.index
$Search = $Range.find($SearchString)
if ($search -ne $null) {
$FirstAddress = $Search.Address
do {
$search.Value() = $Search.value() -Replace $SearchString, $replacestring
$search = $Range.FindNext($search)
$replacecount++
} while ($search -ne $null -and $search.Address -ne $FirstAddress)
}
}
Alternatively, directly loop on worksheets and not via sheet index with Item as #Theo comments:
foreach ($Worksheet in $Workbook.Worksheets){
write-host $Worksheet.Name
# $Worksheet = $Workbook.Worksheets.Item($i) REMOVE THIS ASSIGNMENT
...
}

Related

Powershell Excel Code changing table info

Hello all I need a little help with my code not sure what I am doing wrong or why its not working. Slowly learning PS to automate some of my work.
I have this code, What I am trying to do it have it clear all filters of all the excel files in a folder. Then have it search some of the columns in a table and replace all the blanks with N\A.
So far I have it working to clear all filters and it replaces blanks with N/A but it does not stop in the table it just continues.
$Path = "C:\Users\Username\Downloads\Workstations (21)\Workstations\"
$files = Get-ChildItem "C:\Users\Username\Downloads\Workstations (21)\Workstations" -Filter *.xlsx
ForEach ($item in $files) {
$Excel = New-Object -ComObject Excel.Application
$Excel.visible = $true
$Workbook = $Excel.workbooks.open($Path + [System.IO.Path]::GetFileName("$item"))
$Worksheets = $Workbooks.worksheets
$Worksheet = $Workbook.Worksheets.Item(2)
$worksheet.AutoFilter.ShowAllData()
$SearchString = "" #String to Find
$Range = $Worksheet.ListObjects("Table1").ListColumns("Column3").Range # Column or Columns want to search single "R4" multi "R4:Y4"
$Search = $Range.find($SearchString) }
$Search = $Range.find($SearchString)
if ($search -ne $null) {
$FirstAddress = $search.Address
do {
$Search.value() = "N/A" # Replacement Value
$search = $Range.FindNext($search)
} while ( $search -ne $null -and $search.Address -ne $FirstAddress)
}
$WorkBook.Save()
$WorkBook.Close()
[void]$excel.quit()

Replace a string of text in multiple Excel files using a PowerShell script

I have multiple Excel files that have similar data, and I want a PowerShell script that searches and replaces a string of text in all Excel files in a specified folder.
So far, I have the following PowerShell script that opens all my Excel files and attempts to replace matching strings in the second Worksheet, but the expected changes are not made:
$Path = "C:\Users\mabrant\Downloads\Workstations (21)\Workstations\"
$files = Get-ChildItem "C:\Users\mabrant\Downloads\Workstations (21)\Workstations" -Filter *.xlsx
ForEach ($item in $files) {
$Excel = New-Object -ComObject Excel.Application
$Excel.visible = $true
$Workbook = $Excel.workbooks.open($Path + [System.IO.Path]::GetFileName("$item"))
$Worksheets = $Workbooks.worksheets
$Worksheet = $Workbook.Worksheets.Item(2)
$SearchString = "NEW" #String to Find
$Range = $Worksheet.Range("S4:Y4").EntireColumn #Range of Cells to look at
$Search = $Range.find($SearchString) }
$Search = $Range.find($SearchString)
if ($search -ne $null) {
$FirstAddress = $search.Address
do {
$Search.value() = "Installed" # Replacement Value
$search = $Range.FindNext($search)
} while ( $search -ne $null -and $search.Address -ne $FirstAddress)
}
$WorkBook.Save()
$WorkBook.Close()
[void]$excel.quit() `
Seems like you were really close to having a working script. I believe the main problem is that your ForEach block should include everything except the $excel.quit() so that you save and close each workbook as you go.
I reformatted your code to make it easier to see the entire ForEach block, I removed the duplicate $Search = $Range.find($SearchString) statement, and I set some Excel.Application properties to $false to make it work better.
Here is the updated code:
$Path = "C:\Users\mabrant\Downloads\Workstations (21)\Workstations\"
$files = Get-ChildItem $Path -Filter *.xlsx
$Excel = New-Object -ComObject Excel.Application
$Excel.Visible = $false
$Excel.EnableEvents = $false
$Excel.DisplayAlerts = $false
ForEach ($item in $files) {
$Workbook = $Excel.Workbooks.Open($Path + [System.IO.Path]::GetFileName("$item"))
$Worksheet = $Workbook.Worksheets.Item(2)
$SearchString = "NEW" #String to Find
$Range = $Worksheet.Range("S4:Y4").EntireColumn #Range of Cells to look at
$Search = $Range.find($SearchString)
if ($Search -ne $null) {
$FirstAddress = $Search.Address
do {
$Search.Value() = "Installed" # Replacement Value
$Search = $Range.FindNext($Search)
} while ( $Search -ne $null -and $Search.Address -ne $FirstAddress)
}
$WorkBook.Save()
$WorkBook.Close()
}
$Excel.Quit()

How do I set the path correctly so that my code works for subfolders?

I have a code that allows me to search and replace in multiple Excel files within a folder and its subfolders.
However, this does not work properly yet, because I think that the following line contains an error:
$Workbook = $Excel.workbooks.open($Path + [System.IO.Path]::GetFileName("$item"))
All Excel files located directly in the main "test" folder are opened and saved correctly. However, the Excel files in the subfolders are not opened and saved.
This is the code:
$Path = "G:\test"
$files = Get-ChildItem -Path G:\test -Filter *.xlsx -Recurse -ErrorAction SilentlyContinue -Force
ForEach ($item in $files) {
$Excel = New-Object -ComObject Excel.Application
$Excel.visible = $false
$Workbook = $Excel.workbooks.open($Path + [System.IO.Path]::GetFileName("$item"))
$Worksheets = $Workbooks.worksheets
$Worksheet = $Workbook.Worksheets.Item(1)
$SearchString = "Test" #String to Find
$Range = $Worksheet.Range("A1:DZ100000").EntireColumn #Range of Cells to look at
$Search = $Range.find($SearchString)
if ($search -ne $null) {
$FirstAddress = $search.Address
do {
$Search.value() = $Search.value().Replace($SearchString, "Test2") #String to Update
$search = $Range.FindNext($search)
} while ( $search -ne $null -and $search.Address -ne $FirstAddress)
}
$WorkBook.Save()
$WorkBook.Close()
[void]$excel.quit()
}
I hope someone can help me.

PowerShell - Open Excel and Unlock Certain Cells Based On Value

I have a report that I am running via SSRS to brings down some data that I need people to give comments on. I am attempting to write a PowerShell script that will open the file and unprotect certain cells based on their value.
This is what the report looks like:
The default for SSRS is that all cells are automatically protected. However, I would like to unprotect all the cells in column A (the column with the yellow text boxes) that do not have the value of "Manager Comments".
I am not really sure how to go about this. I have this so far for my script:
Param(
[string] $FolderPath,
[string] $FileName
)
Write-Output $FolderPath
Write-Output $FileName
$Files = Dir $FolderPath -Recurse | ? {$_.Name -eq $FileName} | Select -ExpandProperty FullName
$excl=New-Object -ComObject "Excel.Application"
foreach ($file in $Files)
{
$wrkb=$excl.Workbooks.Open($file, 0, $false)
$wrkb.Worksheets("Comments").Range("A1:A100").Locked = $False
$wrkb.Save()
$wrkb.Close()
}
$excl.Quit()
But this will just unprotect all of column A. Does anyone know how to have it look at the values and only unprotect those blank values? Bonus points if it can just look for certain colors (the yellow).
And yes, I know that this is a terrible way of doing this...but I work with what I have.
A little progress update...I now can pull the value and cell color index in a loop, but I am not sure how to write the IF statement to lock the cell if the $Color value is equal to "36".
Param(
[string] $FolderPath = "C:\Root\Data\VisualCron\Development\",
[string] $FileName = "Combined Master Report.xlsx"
)
Write-Output $FolderPath
Write-Output $FileName
$Files = Dir $FolderPath -Recurse | ? {$_.Name -eq $FileName} | Select -ExpandProperty FullName
$SheetName = "Comments"
$Excel = New-Object -ComObject "Excel.Application"
foreach ($File in $Files)
{
$Workbook = $Excel.Workbooks.Open($File, 0, $False)
$Sheet = $Workbook.Worksheets.Item("Comments")
$MaxRow = ($Sheet.UsedRange.Rows).Count
$Row,$Column = 1,1
for ($i = 0; $i -le $MaxRow - 1; $i++)
{
$Color = $Sheet.Cells.Item($Row+$i,$Column).Interior.ColorIndex
$Value = $Sheet.Cells.Item($Row+$i,$Column).Text
Write-Host ("Color Value:" + $Color + " " + $i + " " + $Value)
}
#$Workbook.Worksheets("Comments").Range("A3:A50").Locked = $False
#$Workbook.Worksheets("Comments").Protect('Test',1,1,1,1,0,0,0,0,0,0,0,0,0,0,0)
$Workbook.Save()
$Workbook.Close()
}
$excl.Quit()
Another update:
I have gotten it to work, but it is a little strange. When I first go through my loop, the color index appears to be "36", but once I change one value, the yellow index changes to "5". I am not really sure why it does that, but I wrote this script, and hopefully, it is consistent.
Param(
[string] $FolderPath = "C:\Root\Data\VisualCron\Development\",
[string] $FileName = "Combined Master Report.xlsx"
)
Write-Output $FolderPath
Write-Output $FileName
$Files = Dir $FolderPath -Recurse | ? {$_.Name -eq $FileName} | Select -ExpandProperty FullName
$SheetName = "Comments"
$Excel = New-Object -ComObject "Excel.Application"
foreach ($File in $Files)
{
$Workbook = $Excel.Workbooks.Open($File, 0, $False)
$Sheet = $Workbook.Worksheets.Item("Comments")
$MaxRow = ($Sheet.UsedRange.Rows).Count
$Row,$Column = 1,1
for ($i = 1; $i -le $MaxRow - 1; $i++)
{
$Color = $Sheet.Cells.Item($Row+$i,$Column).Interior.ColorIndex
$Value = $Sheet.Cells.Item($Row+$i,$Column).Text
#Write-Output ($Color)
$Range = "A" + ($Row + $i) + ":A" + ($Row + $i)
if ($Color -eq 36 -or $Color -eq 5)
{
$Range = "A" + ($Row + $i) + ":A" + ($Row + $i)
$Workbook.Worksheets("Comments").Range($Range).Locked = $False
#Write-Host $Range
}
}
$Workbook.Worksheets("Comments").Protect('Test',1,1,1,1,0,0,0,0,0,0,0,0,0,0,0)
$Workbook.Save()
$Workbook.Close()
}
$Excel.Quit()
Does anyone have any ideas on why the color index would be changing?

Find and Replace in Excel with PowerShell

I have a column with computer names however the names are formatted like this domain\computer name. Usually in Excel I can use find/replace and search for *\ and replace with blank leaving just the computer name. I have a powershell script that finds *\ however it replaces the whole cell with nothing. It's like its searching for any cell that contains *\ and replacing that instead of just leaving the computer name.
$file = "C:\reports\report.xls"
$Excel = New-Object -ComObject Excel.Application
$Excel.Visible = $true
$Workbok = $Excel.workbooks.open($file)
$Worksheets = $Workbook.worksheets
$Worksheet = $Workbook.Worksheets.Item(1)
$Worksheet = $Workbok.Worksheets.Item(1)
$SearchString = "*\"
$Range = $Worksheet.Range("A1").EntireColumn
$Search = $Range.find($SearchString)
if($search -ne $null){
$FirstAddress = $Search.Address
do{
$Search.value() = ""
$search = $Range.FindNext($search)
}while ($search -ne $null -and $search.Address -ne $FirstAddress)
In your Do-While loop you are taking the value of the search and setting it to an empty string. $Search.value() = "". If you take that and change it something like this $search.Value() = $Search.value() -replace "^.*\\",'' it should work. I used -replace with some regex to replace everything from the backslash until the beginning of the line.
Cleaned up your code a bit because it seems you had some misspelled variables
$file = "C:\reports\report.xls"
$Excel = New-Object -ComObject Excel.Application
$Excel.Visible = $true
$Workbook = $Excel.workbooks.open($file)
$Worksheet = $Workbook.Worksheets.Item(1)
$SearchString = "*\"
$Range = $Worksheet.Range("A1").EntireColumn
$Search = $Range.find($SearchString)
if ($search -ne $null) {
$FirstAddress = $Search.Address
do {
$search.Value() = $Search.value() -Replace "^.*\\", ''
$search = $Range.FindNext($search)
} while ($search -ne $null -and $search.Address -ne $FirstAddress)
}

Resources