public/Edit-ExcelWorkbookText.ps1

function Edit-ExcelWorkbookText {
    <#
    .SYNOPSIS
        Find and Replace text a string pattern within XLSX files in a given location
    .DESCRIPTION
        Search all XLSX workbook files for matching text string and replace with a new text string.
    .PARAMETER Path
        Path (folder) where .XLSX files reside
    .PARAMETER SearchPattern
        Text string to search for
    .PARAMETER ReplaceWith
        Text string to insert in place of [SearchPattern] text string
    .PARAMETER LogFile
        CSV output path+filename
    .PARAMETER NoRecurse
        Scan xlsx files in Path location only, do not scan into subfolders
    .PARAMETER Apply
        Confirm saving changes to workbooks
    .EXAMPLE
        Edit-ExcelWorkbookText -Path "\\server123\docs" -SearchPattern "Server543" -ReplaceWith "Server9022" -Apply
        
        Replaces instances of "Server543" with "Server9022" within any cells on any sheets of workbooks in
        the path \\server123\docs. Saves changes back to workbooks.
    .EXAMPLE
        Edit-ExcelWorkbookText -Path "\\server123\docs" -SearchPattern "Server543" -ReplaceWith "Server9022" -NoRecurse -Apply
        
        Searches for instances of "Server543" within any cells on any sheets of workbooks in
        the path \\server123\docs, but no subfolders, and save to CSV file. Saves changes back to workbooks.
    .EXAMPLE
        $results = Edit-ExcelWorkbookText -Path "\\server123\docs" -SearchPattern "Server543" -ReplaceWith "Server9022"
        $results | Group-Object Workbook | Select-Object Count,Name

        Returns counts of matching instances by workbook filename
    .LINK
        https://github.com/Skatterbrainz/helium/blob/master/docs/Edit-ExcelWorkbookText.md
    #>

    [CmdletBinding()]
    param (
        [parameter(Mandatory=$False)][string]$Path = '$($env:HOME)\Documents',
        [parameter(Mandatory=$False)][string]$SearchPattern = '',
        [parameter(Mandatory=$False)][string]$ReplaceWith = '',
        [parameter(Mandatory=$False)][switch]$Apply
    )
    [string]$LogFile = "$($env:HOME)\Documents\excel_replace_$(Get-Date -f 'yyyyMMddhhmm').csv"

    if ([string]::IsNullOrEmpty($Path) -or [string]::IsNullOrEmpty($SearchPattern)) {
        Write-Warning "Path and SearchPattern inputs cannot be empty"
        break
    }
    if (!(Test-Path $Path)) {
        Write-Warning "Path not found: $Path"
        break
    }

    function release-comobject($ref) {
        while ([System.Runtime.InteropServices.Marshal]::ReleaseComObject($ref) -gt 0) {}
        [void][System.GC]::Collect()
    }

    try {
        [array]$files = Get-ChildItem -Path $Path -Filter "*.xlsx" -ErrorAction Stop
        Write-Host "$($files.Count) workbook files were found"
    } catch {
        Write-Warning "Unable to retrieve any workbook files from $Path"
    }

    Write-Verbose "Opening excel application session"
    $excel = New-Object -ComObject Excel.Application
    $excel.Visible = $False

    $logresults = @()

    Write-Host "Begin processing"
    foreach ($file in $files) {
        Write-Host "file: $($file.FullName)"
        $Workbook = $Excel.Workbooks.Open($file.FullName)
        $worksheets = $workbook.Worksheets
        foreach ($worksheet in $worksheets) {
            Write-Verbose "worksheet: $($worksheet.Name)"
            $found = $worksheet.UsedRange.Find($SearchPattern)
            if ($null -ne $found) {
                Write-Verbose "match was found"
                $address1 = $found.Address(0,0,1,1)
                $row = $found.Row
                $col = $found.Column
                [string]$formula = $worksheet.cells($row,$col).Formula
                [string]$changed = $formula.Replace($SearchPattern,$ReplaceWith)
                if ($formula -ne $changed) {
                    if ($Apply) { 
                        $worksheet.Cells($row,$col).Formula = $changed
                        $logresults += (
                            [PSCustomObject]@{
                                File      = $file.FullName
                                Worksheet = $($worksheet.Name)
                                Row       = $row
                                Column    = $col
                                OldText   = $formula
                                NewText   = $changed
                            }
                        )
                    }
                }
                while ($found = $worksheet.UsedRange.FindNext($found)) {
                    $address2 = $found.Address(0,0,1,1)
                    if ($address1 -eq $address2) { break }
                    $row = $found.Row
                    $col = $found.Column
                    [string]$formula = $worksheet.cells($row,$col).Formula
                    [string]$changed = $formula.Replace($SearchPattern,$ReplaceWith)
                    if ($formula -ne $changed) {
                        if ($Apply) {
                            $worksheet.Cells($row,$col).Formula = $changed
                            $logresults += (
                                [PSCustomObject]@{
                                    File      = $file.FullName
                                    Worksheet = $($worksheet.Name)
                                    Row       = $row
                                    Column    = $col
                                    OldText   = $formula
                                    NewText   = $changed
                                }
                            )
                        }
                    }
                } # while
            } else {
                Write-Verbose "no matches found"
            }
        } # foreach worksheet
        if ($Apply) {
            if (!$workbook.Saved) {
                Write-Verbose "saving changes to workbook"
                $workbook.Save()
            }
        }
        $workbook.Close($False)
    } # foreach file

    $excel.quit()

    Write-Verbose "release: worksheet"
    release-comobject $worksheet
    Write-Verbose "release: worksheets"
    release-comobject $worksheets
    Write-Verbose "release: workbook"
    release-comobject $workbook
    Write-Verbose "terminating all excel.exe processes"
    Get-Process 'excel' | Stop-Process -Force

    if ($logresults.Count -gt 0) {
        $logresults | Export-Csv -Path $LogFile -NoTypeInformation -Force
        Write-Host "Complete! Change log saved to $LogFile"
    } else {
        Write-Host "Complete! No changes were applied"
    }
}