Skip to content

Instantly share code, notes, and snippets.

@MartinMiles
Last active November 4, 2025 18:26
Show Gist options
  • Select an option

  • Save MartinMiles/5b18e93d78684d895979b483336644ce to your computer and use it in GitHub Desktop.

Select an option

Save MartinMiles/5b18e93d78684d895979b483336644ce to your computer and use it in GitHub Desktop.
Iterate through you sitecore environment and replace all the texts
# Minimal SPE find and replace across Single-Line Text, Multi-Line Text, Rich Text
# Static inputs
$FindText
$ReplaceText
$ScopePaths = "/sitecore/content" # comma separated for multiple roots, for example "/sitecore/content/SiteA, /sitecore/content/SiteB"
$CaseSensitive = $true
$DryRun = $false
if ([string]::IsNullOrWhiteSpace($FindText)) { throw "Find cannot be empty." }
# Prepare scope
$paths = $ScopePaths -split "," | ForEach-Object { $_.Trim() } | Where-Object { $_ }
if (-not $paths) { $paths = "/sitecore/content" }
# Prepare regex
$pattern = [regex]::Escape($FindText)
$regexOptions = if ($CaseSensitive) { [System.Text.RegularExpressions.RegexOptions]::None } else { [System.Text.RegularExpressions.RegexOptions]::IgnoreCase }
# Field types to update
$allowedTypes = @("Single-Line Text","Multi-Line Text","Rich Text")
# Counters
$totalItems = 0
$itemsChanged = 0
$fieldsChanged = 0
$errCount = 0
# Database
$database = "master"
$stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
# Collect all items under scope, all languages, all versions
$items = foreach ($root in $paths) {
Get-ChildItem -Path "$database`:$root" -Recurse -Language * -ErrorAction SilentlyContinue
}
if (-not $items) { Write-Host "No items found in scope."; return }
Write-Host "Scanning $($items.Count) items in $database. DryRun=$DryRun CaseSensitive=$CaseSensitive"
# Faster bulk update and disable security
$bulk = New-Object Sitecore.Data.BulkUpdateContext
$sec = New-Object Sitecore.SecurityModel.SecurityDisabler
try {
foreach ($item in $items) {
$totalItems++
if ($item.Paths.Path -like "/sitecore/system*") { continue }
$itemHadHits = $false
$fieldHitsOnItem = 0
$versions = $item.Versions.GetVersions($true)
if (-not $versions -or $versions.Count -eq 0) { $versions = @($item) }
foreach ($ver in $versions) {
$editStarted = $false
foreach ($field in $ver.Fields) {
if ($null -eq $field) { continue }
if ($field.ReadOnly) { continue }
if ($field.Type -notin $allowedTypes) { continue }
$current = [string]$field.Value
if ([string]::IsNullOrEmpty($current)) { continue }
if ([regex]::IsMatch($current, $pattern, $regexOptions)) {
$newValue = [regex]::Replace($current, $pattern, [System.Text.RegularExpressions.MatchEvaluator]{ param($m) $ReplaceText }, $regexOptions)
if (-not $DryRun) {
if (-not $ver.Editing.IsEditing) { $ver.Editing.BeginEdit() | Out-Null; $editStarted = $true }
$field.Value = $newValue
}
$itemHadHits = $true
$fieldHitsOnItem++
}
}
if ($editStarted -and $ver.Editing.IsEditing) {
$ver.Editing.EndEdit() | Out-Null
}
}
if ($itemHadHits) {
$fieldsChanged += $fieldHitsOnItem
$itemsChanged++
Write-Host "[HIT] $($item.Paths.Path) [$($item.Language)] fields: $fieldHitsOnItem"
}
if ($totalItems % 200 -eq 0) {
$pct = [int](100 * $totalItems / [math]::Max(1, $items.Count))
Write-Progress -Activity "Processing items" -Status "$totalItems scanned, $itemsChanged items with hits" -PercentComplete $pct
}
}
}
catch {
$errCount++
Write-Warning "Error: $_"
}
finally {
if ($bulk) { $bulk.Dispose() }
if ($sec) { $sec.Dispose() }
$stopwatch.Stop()
}
Write-Host ""
Write-Host "Done. Scanned items: $totalItems"
Write-Host "Items with hits: $itemsChanged"
Write-Host "Field replacements: $fieldsChanged"
Write-Host "Dry run: $DryRun"
Write-Host "Elapsed: $([int]$stopwatch.Elapsed.TotalSeconds)s"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment