Last active
July 8, 2024 00:08
-
-
Save davidlu1001/e78cccf1bebf1bdee705b8cc4338cc8a to your computer and use it in GitHub Desktop.
Update Config With CSV (includes old and new value)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| [CmdletBinding()] | |
| param( | |
| [Parameter(ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)] | |
| [string[]]$ComputerNames = @($env:COMPUTERNAME), | |
| [string[]]$ScanPaths = @("D:\", "E:\"), | |
| [string]$OldNewDnsFile = "old_new_dns.csv", | |
| [string]$OutputFile = "scanConfigResult_$(Get-Date -Format 'yyyyMMdd_HHmmss').csv", | |
| [string]$LogFile = "ScanLog_$(Get-Date -Format 'yyyyMMdd_HHmmss').log", | |
| [int]$MaxConcurrentJobs = 5, | |
| [int]$BatchSize = 1000, | |
| [switch]$DryRun | |
| ) | |
| $ErrorActionPreference = "SilentlyContinue" | |
| function Write-Log { | |
| param([string]$Message) | |
| $logMessage = "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') - $Message" | |
| Add-Content -Path $LogFile -Value $logMessage | |
| Write-Verbose $logMessage | |
| } | |
| function Update-ConfigFiles { | |
| param ( | |
| [string]$ComputerName, | |
| [string[]]$Paths, | |
| [array]$OldNewDnsEntries, | |
| [int]$BatchSize, | |
| [bool]$IsDryRun | |
| ) | |
| $scriptBlock = { | |
| param($Paths, $OldNewDnsEntries, $BatchSize, $IsDryRun) | |
| function Process-FileBatch { | |
| param($Files) | |
| $results = @() | |
| foreach ($file in $Files) { | |
| try { | |
| Write-Verbose "Processing file: $($file.FullName)" | |
| $content = [System.IO.File]::ReadAllText($file.FullName) | |
| $fileResults = @() | |
| foreach ($entry in $OldNewDnsEntries) { | |
| $matchCount = ([regex]::Matches($content, [regex]::Escape($entry.oldValue), [System.Text.RegularExpressions.RegexOptions]::IgnoreCase)).Count | |
| if ($matchCount -gt 0) { | |
| if ($IsDryRun) { | |
| Write-Host "DryRun: In $($file.FullName), $($entry.oldValue) will be replaced with $($entry.newValue), with matchCount $matchCount" | |
| } else { | |
| $content = [regex]::Replace($content, [regex]::Escape($entry.oldValue), $entry.newValue, [System.Text.RegularExpressions.RegexOptions]::IgnoreCase) | |
| Write-Host "Replaced $($entry.oldValue) with $($entry.newValue) in $($file.FullName) ($matchCount occurrences)" | |
| } | |
| $fileResults += [PSCustomObject]@{ | |
| ComputerName = $env:COMPUTERNAME | |
| ConfigPath = $file.FullName | |
| OldValue = $entry.oldValue | |
| NewValue = $entry.newValue | |
| MatchCount = $matchCount | |
| Result = if ($IsDryRun) { "WillReplace" } else { "Replaced" } | |
| } | |
| } | |
| } | |
| if ($fileResults.Count -eq 0) { | |
| $fileResults += [PSCustomObject]@{ | |
| ComputerName = $env:COMPUTERNAME | |
| ConfigPath = $file.FullName | |
| OldValue = "NA" | |
| NewValue = "NA" | |
| MatchCount = 0 | |
| Result = "NotFound" | |
| } | |
| } | |
| $results += $fileResults | |
| if (-not $IsDryRun -and $fileResults.Where({$_.Result -eq "Replaced"}).Count -gt 0) { | |
| [System.IO.File]::WriteAllText($file.FullName, $content) | |
| } | |
| } | |
| catch { | |
| Write-Warning "Error processing file $($file.FullName): $_" | |
| } | |
| } | |
| return $results | |
| } | |
| $allFiles = @() | |
| foreach ($path in $Paths) { | |
| try { | |
| Write-Verbose "Scanning path: $path" | |
| $allFiles += Get-ChildItem -Path $path -Recurse -Include *.config, *.json -ErrorAction Stop | |
| } | |
| catch { | |
| Write-Warning "Error accessing path $path: $_" | |
| } | |
| } | |
| $totalFiles = $allFiles.Count | |
| Write-Verbose "Total files found: $totalFiles" | |
| $results = @() | |
| for ($i = 0; $i -lt $totalFiles; $i += $BatchSize) { | |
| $batch = $allFiles | Select-Object -Skip $i -First $BatchSize | |
| Write-Verbose "Processing batch $($i / $BatchSize + 1) of $([math]::Ceiling($totalFiles / $BatchSize))" | |
| $batchResults = Process-FileBatch -Files $batch | |
| $results += $batchResults | |
| Write-Verbose "Processed $($i + $batch.Count) of $totalFiles files" | |
| } | |
| return $results | |
| } | |
| try { | |
| Write-Verbose "Executing on computer: $ComputerName" | |
| if ($ComputerName -eq $env:COMPUTERNAME) { | |
| return & $scriptBlock $Paths $OldNewDnsEntries $BatchSize $IsDryRun | |
| } else { | |
| $session = New-PSSession -ComputerName $ComputerName -ErrorAction Stop | |
| return Invoke-Command -Session $session -ScriptBlock $scriptBlock -ArgumentList $Paths, $OldNewDnsEntries, $BatchSize, $IsDryRun | |
| } | |
| } | |
| catch { | |
| Write-Log "Error updating config files on $ComputerName: $_" | |
| return $null | |
| } | |
| finally { | |
| if ($session) { | |
| Remove-PSSession $session | |
| } | |
| } | |
| } | |
| try { | |
| Write-Log "Starting update process on computers: $($ComputerNames -join ', ')" | |
| Write-Verbose "DryRun mode: $DryRun" | |
| # Read old_new_dns.csv | |
| Write-Verbose "Reading old_new_dns.csv file" | |
| $oldNewDnsEntries = Import-Csv -Path $OldNewDnsFile | |
| Write-Verbose "Found $($oldNewDnsEntries.Count) entries in old_new_dns.csv" | |
| $jobs = @() | |
| foreach ($computer in $ComputerNames) { | |
| Write-Log "Initiating update on $computer" | |
| $job = Start-Job -ScriptBlock ${function:Update-ConfigFiles} -ArgumentList $computer, $ScanPaths, $oldNewDnsEntries, $BatchSize, $DryRun | |
| $jobs += $job | |
| while (($jobs | Where-Object { $_.State -eq 'Running' }).Count -ge $MaxConcurrentJobs) { | |
| Write-Verbose "Waiting for a job to complete. Current running jobs: $(($jobs | Where-Object { $_.State -eq 'Running' }).Count)" | |
| $completedJob = $jobs | Wait-Job -Any | |
| $results = Receive-Job $completedJob | |
| if ($results) { | |
| $results | Export-Csv -Path $OutputFile -NoTypeInformation -Append | |
| } | |
| Remove-Job $completedJob | |
| $jobs = @($jobs | Where-Object { $_.State -ne 'Completed' }) | |
| } | |
| } | |
| while ($jobs) { | |
| Write-Verbose "Waiting for remaining jobs to complete. Jobs left: $($jobs.Count)" | |
| $completedJob = $jobs | Wait-Job -Any | |
| $results = Receive-Job $completedJob | |
| if ($results) { | |
| $results | Export-Csv -Path $OutputFile -NoTypeInformation -Append | |
| } | |
| Remove-Job $completedJob | |
| $jobs = @($jobs | Where-Object { $_.State -ne 'Completed' }) | |
| } | |
| Write-Log "Update process complete. Results saved to $OutputFile" | |
| # stats | |
| Write-Verbose "Calculating final statistics" | |
| $results = Import-Csv -Path $OutputFile | |
| $hostCount = @($results | Select-Object -Unique ComputerName).Count | |
| $replacedCount = @($results | Where-Object { $_.Result -eq "Replaced" -or $_.Result -eq "WillReplace" }).Count | |
| $notFoundCount = @($results | Where-Object { $_.Result -eq "NotFound" }).Count | |
| $totalMatchCount = ($results | Measure-Object -Property MatchCount -Sum).Sum | |
| Write-Log "Processed $hostCount hosts, replaced/will replace $replacedCount entries, $notFoundCount entries not found, total matches: $totalMatchCount" | |
| Write-Verbose "Hosts processed: $hostCount" | |
| Write-Verbose "Entries replaced/will be replaced: $replacedCount" | |
| Write-Verbose "Entries not found: $notFoundCount" | |
| Write-Verbose "Total matches: $totalMatchCount" | |
| } | |
| catch { | |
| Write-Log "Critical error in main script execution: $_" | |
| } | |
| finally { | |
| Write-Log "Script execution completed" | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment