IP address need to replace in text file

Hi All,

i have created a script to replace the IP address on the multiple files. Script will get the user Input IP address and find the in the text file and replace an new IP address. When i try to replace the IP address, its not replacing properly with match condition.

$server = Get-Content "F:\Scripts\Replace_DNS_IP\server.txt"
$_DNSList = @()

#Get the input from the user
$_DNSList = New-Object System.Net.IPAddress(0x1521A8C0)

$_DNSList = READ-HOST "Enter the DNS Servers IP address(use , comma for addditional IPs )"
#$_DNSList = $_DNSListip.Split(',').Split(' ')
#splitting the list of input as array by Comma & Empty Space
$_DNSList = $_DNSList.Split(',').Split(' ')

$_ReplaceDNSList = @()
$_ReplaceDNSList = New-Object System.Net.IPAddress(0x1521A8C0)
#Get the input from the user
$_ReplaceDNSList = READ-HOST "Enter the Replace DNS Servers IP address(use , comma for addditional IPs )"
#$_ReplaceDNSList =$_ReplaceDNSListip.Split(',').Split(' ')

#splitting the list of input as array by Comma & Empty Space
$_ReplaceDNSList = $_ReplaceDNSList.Split(',').Split(' ')

foreach ($input in $server) {

    $LogPath = Get-Item "F:\Scripts\Replace_DNS_IP\PSD Backup\$input.psd1"

    $Lines = Get-Content $LogPath | Where-Object {$_ -match "DNSServerAddress"}

    Foreach ($Line in $Lines) {

        #$IP =@()
        #$ip = New-Object System.Net.IPAddress(0x1521A8C0)
        $IP = ($Line | Select-String -Pattern "\d{1,3}(\.\d{1,3}){3}" -AllMatches).Matches.Value

        foreach ($IPs in $IP) {
            if ($IPs -match $_DNSList[0]) {
                Write-Host "Replacing DNS1"
                (Get-Content -Path $LogPath).Replace($IPs, $_ReplaceDNSList[0]) | Set-Content -Path $LogPath
            }
            elseif ($IPs -match $_DNSList[1]) {
                Write-Host "Replacing DNS2"
                (Get-Content -Path $LogPath).Replace($IPs, $_ReplaceDNSList[1]) | Set-Content -Path $LogPath
            }
            elseif ($IPs -match $_DNSList[2]) {
                Write-Host "Replacing DNS3"
                (Get-Content -Path $LogPath).Replace($IPs, $_ReplaceDNSList[2]) | Set-Content -Path $LogPath
            }
            #elseif($IPs -match $_DNSList[3])
            {
                Write-Host "Replacing DNS4"
                (Get-Content -Path $LogPath).Replace($IPs, $_ReplaceDNSList[3]) | Set-Content -Path $LogPath
            }#>
            else
            {
                Write-Host "DNS IP address is not Matching with Input"
            }
        }
    }
}

Output of the script

Via the script am replacing 3 IP address in text file. for example Source IP{8.8.8.8,4.4.4.4,5.5.5.5}

  1. if i try to replace 8.8.8.8,5.5.5.5, script will replace the new IP address, but 4.4.4.4 will be changed to blank " "
  2. if i try to replace 4.4.4.4, script is replacing only first number of the IP address"1" inside of "198.166.1.1
Kindly help me to fix it.

Thanks & Regards

Manikandan.K

Hi All,

i have fixed the blank space replacement issue. But am facing during Single IP address replacement. If i provide the Single IP address, i was replacing entire IP address on the text file

Manikandan.K,

It would help if you could post your revised code. In the meantime, some suggestions for your code:

  1. It is not ideal to use $_ as a variable prefix because it's too close to the $psitem/$_ used in loops/error handing
  2. You'd want to consider refactoring the foreach statement (similar to below) for logic to make more sense and the code easier to read:
    $IPAddresses = ($Line | Select-String -Pattern "\d{1,3}(\.\d{1,3}){3}" -AllMatches).Matches.Value
    # previously $IP = ($Line ...
    

    foreach ($IP in $IPAddresses) {

    }

  3. Replace all the if/elseif statements with one switch statement:
    # inside foreach ($IP in IPAddresses)
    

    switch ($IP) {
    { $_ -match $DNSList[0] } {
    Write-Host “Replacing DNS1”
    (Get-Content -Path $LogPath).Replace($
    , $ReplaceDNSList[0]) | Set-Content -Path $LogPath
    }
    { $
    -match $DNSList[1] } {
    Write-Host “Replacing DNS2”
    (Get-Content -Path $LogPath).Replace($
    , $_ReplaceDNSList[1]) | Set-Content -Path $LogPath
    }

    }

Hi Aaron,

Kindly fine the below revised code. And also i will check you code too.

$server = Get-Content "F:\Scripts\Replace_DNS_IP\server.txt"

$regex = '\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b'

$_DNSList= @()

#Get the input from the user
$_DNSList = New-Object System.Net.IPAddress(0x1521A8C0)
$_DNSList = READ-HOST "Enter the DNS Servers IP address(use , comma for addditional IPs )"

#splitting the list of input as array by Comma & Empty Space
$_DNSList = $_DNSList.Split(',').Split(' ')

$_ReplaceDNSList= @()
$_ReplaceDNSList = New-Object System.Net.IPAddress(0x1521A8C0)

#Get the input from the user
$_ReplaceDNSList= READ-HOST "Enter the Replace DNS Servers IP address(use , comma for addditional IPs )"

#splitting the list of input as array by Comma & Empty Space
$_ReplaceDNSList = $_ReplaceDNSList.Split(',').Split(' ')

foreach($input in $server)
{

$LogPath = Get-Item "F:\Scripts\Replace_DNS_IP\PSD Backup\$input.psd1"

$Lines = Get-Content $LogPath | Where-Object {$_ -match "DNSServerAddress"}

Foreach ($Line in $Lines)

{

$IPs = ($Line | Select-String -Pattern $regex -AllMatches).Matches.Value

foreach($IP in $IPs)

{

if(($IP -match $_DNSList[0]) -and ($_ReplaceDNSList[0] -ne $null))
{
Write-Host "Replacing $IP DNS Address to $_ReplaceDNSList[0] Address "
(Get-Content -Path $LogPath).Replace($IP,$_ReplaceDNSList[0]) | Set-Content -Path $LogPath
}
elseif(($IP -match $_DNSList[1]) -and ($_ReplaceDNSList[1] -ne $null))
{
Write-Host "Replacing $IP DNS Address to $_ReplaceDNSList[1] Address"
(Get-Content -Path $LogPath).Replace($IP,$_ReplaceDNSList[1]) | Set-Content -Path $LogPath
}
elseif(($IP -match $_DNSList[2]) -and ($_ReplaceDNSList[2] -ne $null))
{
Write-Host "Replacing $IP DNS Address to $_ReplaceDNSList[2] Address"
(Get-Content -Path $LogPath).Replace($IP,$_ReplaceDNSList[2]) | Set-Content -Path $LogPath
}
elseif(($IP -match $_DNSList[3]) -and ($_ReplaceDNSList[3] -ne $null))
{
Write-Host "Replacing $IP DNS Address to $_ReplaceDNSList[3] Address "
(Get-Content -Path $LogPath).Replace($IP,$_ReplaceDNSList[3]) | Set-Content -Path $LogPath
}
else
{
Write-Host "DNS IP address is not Matching with provided Input"
}
}

}
}

@manikandank8286 - please use code formatting tags or use gist.github.com to post code in the forums.

https://powershell.org/forums/topic/read-me-before-posting-youll-be-glad-you-did/

After reviewing your inquiry again, there’s a bit of repurposing of variables which can make code harder to follow.

What is the difference between F:\Scripts\Replace_DNS_IP\server.txt and $LogPath = Get-Item “F:\Scripts\Replace_DNS_IP\PSD Backup$input.psd1” ? Can you provide samples from both? What is the purpose of both files? .psd1 is normally a PowerShell module manifest file, and not used for logging.

Are you open to users using an advanced function instead of manually typing IPs with commas? It would take care of the input validation for you.

Hi Aaron,

We are using Powershell DSC and SMA servers to build the Windows 2016 servers. All the information(CPU, memory, IP address, storage etc) about the server will be in .psd1 file. .psd1 file name will be the server name. i want to update the DNS IP address on more than 50 servers at a time. To avoid the manual work to update the DNS IP address in *.psd1 file, trying to develop a script. Server.txt will have the server name. i have updated the files on the GitHub for your reference GitHub - Manik8286/Powershellscripts.

 

Thanks for the details. Sorry for the delay as I’ve been in the midst of a deployment.

While this could be more solidified (and some .NET), this script would work.

It’s an advanced function that takes the file path (.psd1), the IPs you want to replace in it, and the new IPs. If “DNSServerAddress” does not exists in the file, the file will be skipped.

Otherwise, each old IP is replaced with the new one based their matching index (in the parameter arguments). Below, 4.4.4.4 is replaced by 192.168.10.1, and so on.

The code after the function automates the process for all servers. In the splat, the specified Confirm = $false will run the script without the user being prompted to confirm the changes for each file update. Without this, you’ll be prompted for each server. The final output shows what IPs were ‘replaced’ in which files.

function Invoke-DNSServerAddressUpdate {
    [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High')]
    param (
        [Parameter(Mandatory)]
        [ValidateScript( { Test-Path -Path $_ } )]
        [System.IO.FileInfo]
        $FilePath,

        [Parameter(Mandatory)]
        [ipaddress[]]
        $IPAddress,

        [Parameter(Mandatory)]
        [ipaddress[]]
        $NewIPAddress
    )

    if ($NewIPAddress.Count -ne $IPAddress.Count) {
        Write-Error "IP count mismatch" -ErrorAction Stop
    }#if

    $psd1Content = Get-Content -Path $FilePath

    # Check if "DNSServerAddress =" exists in file, ignore if it doesn't
    if ($psd1Content -match "DNSServerAddress\s?=") {

        # Counter for matching indexes of IPAddress to NewIPAddress
        $counter = 0

        foreach ($ip in $IPAddress) {
            # Update content by replacing IPAddress(es) with NewIPAddress(es)
            $oldIP       = $ip.IPAddressToString
            $newIP       = $NewIPAddress[$counter].IPAddressToString
            $psd1Content = $psd1Content -replace $oldIP, $newIP
            $counter    += 1

            [pscustomobject]@{
                FilePath = $FilePath.FullName
                OldIPAddress = $oldIP
                NewIPAddress = $newIP
            }
        }#foreach

        if ($PSCmdlet.ShouldProcess("Update IP Address(es) in $FilePath")) {
            $psd1Content | Set-Content -Path $FilePath -Force
        }#if
    }#if
}#function


# Run against all servers
$parentPath  = './Powershellscripts-master'

# Get server names
$serverNames = Get-Content -Path (Join-Path -Path $parentPath -ChildPath server.txt)

# Get server.psd1 paths
$serverFiles = $serverNames | ForEach-Object { Join-Path $parentPath -ChildPath "$_.psd1" }

# In all files, replace old IPs with new ones
foreach ($file in $serverFiles) {
    $params = @{
        FilePath     = $file
        IPAddress    = '4.4.4.4', '5.5.5.5', '8.8.8.8'
        NewIPAddress = '192.168.10.1', '192.168.10.7', '192.168.10.10'
        Confirm      = $false # do not prompt to overwrite files
    }

    Invoke-DNSServerAddressUpdate @params
}#foreach

Thanks for support to fix the issue with Advance function to replace the single IP address and multiple IP address. Script is going to use more the 10 person. So i planned to get the IP address via command line input, dont want to modify the IP address in script. Below line need to change in script as user input. How can i proceed in Hashing Array.

IPAddress = ‘4.4.4.4’, ‘5.5.5.5’, ‘8.8.8.8’
NewIPAddress = ‘192.168.10.1’, ‘192.168.10.7’, ‘192.168.10.10’

Thanks & Regards

Just use the function and not the code below it (which was meant for predefining IPs and just running it against every file).

For the more interactive style, dot-sourcing the .ps1 file allows you to enter one IP per prompt:

PS />. ./Invoke-DNSServerAddressUpdate.ps1
PS />Invoke-DNSServerAddressUpdate -FilePath ./server200.psd1
...
IPAddress[0]: 4.4.4.4
IPAddress[1]:
NewIPAddress[0]: 192.168.10.4
NewIPAddress[1]:
...

(Output shown here)

The output shows what IPs would have been replaced by new IPs, like a history, and not just what was actually replaced in the file.

And an oversight on my part… Though you may not need it at the moment, the splat starting on line 37 should be:

[pscustomobject]@{
    FilePath     = Convert-Path -Path $FilePath # not FilePath.FullName
    OldIPAddress = $oldIP
    NewIPAddress = $newIP
}

Hi Aaron,

Am able to replace the IP address on single file. Not able to update in multiple *.psd file. File is updating only last entry of the server.txt.

 

Hi Aaron,

Am able to replace the IP address on single file. Not able to update in multiple *.psd file. File is updating only last entry of the server.txt.

Hi,

Made some changes in Code and now its working as expected. Thanks for your help.

function Invoke-DNSServerAddress {
[CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High')]
param (

[Parameter(Mandatory)]
[ipaddress[]]
$IPAddress,

[Parameter(Mandatory)]
[ipaddress[]]
$NewIPAddress
)

$server = Get-Content "F:\Scripts\Replace_DNS_IP\server.txt"

foreach($input in $server)
{
Write-Host "*******Backing Up the file**********" -ForegroundColor DarkRed
Copy-Item -Path "Z:\MachineData.Current\$input.psd1" -Destination "F:\Scripts\Replace_DNS_IP\PSD Backup"
$LogPath = Get-Item "Z:\MachineData.Current\$input.psd1"
#$LogPath = Get-Item "F:\Scripts\Replace_DNS_IP\PSD Backup\$input.psd1"

$Lines = Get-Content -Path $LogPath

if ($Lines -match "DNSServerAddress\s?=") {

# Counter for matching indexes of IPAddress to NewIPAddress
$counter = 0

foreach ($ip in $IPAddress) {
# Update content by replacing IPAddress(es) with NewIPAddress(es)
$oldIP = $ip.IPAddressToString
$newIP = $NewIPAddress[$counter].IPAddressToString
$Lines = $Lines -replace $oldIP, $newIP
$counter += 1

[pscustomobject]@{
FilePath = $LogPath#.FullName
OldIPAddress = $oldIP
NewIPAddress = $newIP
WrittenTime = get-item "$LogPath" | select -Property Lastwritetime
}

}
if ($PSCmdlet.ShouldProcess("Update IP Address(es)")) {
$Lines | Set-Content -Path $LogPath -Force
}
}
}

}Invoke-DNSServerAddress

Thanks & Regards

Manikandan.K

Excellent, glad it works (and sorry for delays).