Powershell: Search for word in file and change it, if the file exists

104 Views Asked by At

In the company I work for, we wanted to change a timer to an .ini file for around 310 computers, in order to extend this timer.
So I searched around and did find some scripts, but they were not doing exactly what we wanted.
So i sat down googled around and found the way, on how to make this work.
Below you can find the script I created.

In order to run the script what I did was:

  1. I created a group policy in Computer Configuration -> Policies -> Windows Settings -> Scripts (Startup / Shutdown) and then I clicked in Show Files... and placed the .ps1 file in there. (it should be something like \domain.local\SysVol\domain.local\Policies{907A196A-0859-4AFB-9BE7-6BD4BFA94265}\Machine\Scripts\Startup)
  2. I pressed Add, clicked on Browse and choose the .ps1 file.

Also in the same Policy I placed a small delay for the script to be executed for 4 minutes. Computer Configuration -> Administrative Templates -> System -> Group Policy --> Configure Logon Script Delay.

I also executed this script by using Lansweeper, which was easier and quicker to be run.

Try it, if you like.
Change it, if you will.
Correct what ever you find wrong, so we can all be helped.
(Just please, write it down, what needs to be changed, so we can all benefit from it!)

Below you can find the script.
Just be carefull when copying it.
The symbols needs to be re-checked.
(Copying-pasting from web pages, breaks some symbols)

$FilePath = "" #Within the quotation marks, you need to place, the path and name of the file, you would like to search and change e.g c:\Test\file.ini
$Search_entry_existing = "" # Within the quotation marks, you need to place, what you are looking for
$Search_entry_change = "" # Within the quotation marks, you need to place, what you want to change in the $Search_entry_existing with the $Search_entry_change
Test-Path -Path $FilePath -PathType Leaf # Checks if the file exists
Select-String -Path $FilePath -Pattern "" # Within the quotation marks, selects the pattern you wish to search for
If (Test-Path $FilePath) {  
    $Check = Select-String -Path $FilePath -Pattern "" # Within the quotation marks, type the pattern you wish to search for
    If ((Get-Content $FilePath) -notcontains 'TimerC=120') { # Within the apostrophes, type the pattern you wish to search, in order to search for something withing the file, that does NOT exist like that TimerC=120 I placed  
        cls  
        echo "File Exists"  
        echo "************************************************************"  
        echo "*** The File $FilePath contains the string $Check ***"  
        echo "*** Changing the setting to TimerC to 120 seconds" # Yes I was playing with a timer. The name of what i was trying to change started with TimerC=75 and I wanted to change it to 120 seconds.
        (Get-Content $FilePath) -replace '(TimerC)(.*)', '$1=120' | Set-Content $FilePath  # Replaces of the string we would like to change and saves the file.`  
    }  
    else {  
        # If the $Search_entry_change is what we wanted already, then no change will be done.    
        cls  
        echo " The File $FilePath contains the string $Search_entry_change ***"  
        echo "*** No Need to Change. TimerC already 120 seconds ***"  
    }  
}  
else {  
    # In case the script does not finds the file in the path we gave earlier in the $FilePath then this means the file does not exists.  
    Write-Host "File Doesn't Exists. So the Program is not installed !!!"  
}
1

There are 1 best solutions below

1
On

First of all to execute this script on 310 machines simultaneously you need to use WMI in case if you do not have any program to help about it. Powershell remoting could help you. You need to select a computer which can be trusted and you should add this machine to other machines as trustable. Otherwise powershell remoting will not work.

Let's say your trusted machine is machine A. You should always be calling powershel remoting from machine A. You can not call like A -> B -> C -> D. You can call like A -> B A -> C A -> D

Maybe you can add parallel execution also but it could make the script complex.

You can check the link below for powershell remoting https://www.howtogeek.com/117192/how-to-run-powershell-commands-on-remote-computers/

For the parallel what i mean is like this within a simple example;

workflow testExample
{
    parallel
    {
        sequence
        {
            for ($a=1; $a -lt 11; $a++)
            {
                InlineScript
                {
                    "A" + $Using:a
                }
            }
        }

        sequence
        {
            for ($b=1; $b -lt 11; $b++)
            {
                InlineScript
                {
                    "B" + $Using:b
                }
            }
        }

        sequence
        {
            for ($c=1; $c -lt 11; $c++)
            {
                InlineScript
                {
                    "C" + $Using:c
                }
            }
        }

        sequence
        {
            for ($d=1; $d -lt 11; $d++)
            {
                InlineScript
                {
                    "D" + $Using:d
                }
            }
        }
    }
}
testExample

With this approach if you can make the same path as a standard for all computers and if your authorization is enough (i do not know which user you are logging on) you can call 310 computers. At least maybe you are able to execute the job 2 by 2 or 4 by 4 not within sequence ant 1 by 1. But this approach should be used and tested really carefully because it uses lots of thread and limitation of pararlel executions properly can be changed according to the hardware of the machine.

For the code side, i would prefer some .NET approach. It can be more readable with that way i think. I did not change it too much;

$FilePath = ""  
#Within the quotation marks, you need to place, the path and name of the file, you would like to search and change e.g c:\Test\file.ini
$Search_entry_existing = ""  
#Within the quotation marks, you need to place, what you are looking for
$Search_entry_change = ""   
#Within the quotation marks, you need to place, what you want to change in the $Search_entry_existing with the $Search_entry_change
Test-Path -Path $FilePath -PathType Leaf #Checks if the file exists
Select-String -Path $FilePath -Pattern "" #Within the quotation marks, selects the pattern you wish to search for
If(Test-Path $FilePath) {  
    #$Check = Select-String -Path $FilePath -Pattern "" #Within the quotation marks, type the pattern you wish to search for
    If((get-content $FilePath) -notcontains 'TimerC=120') #Within the apostrophes, type the pattern you wish to search, in order to search for something withing the file, that does NOT exist like that TimerC=120 I placed
    {  
        cls  
        echo "File Exists"  
        echo "************************************************************"  
        echo "*** The File $FilePath contains the string $Check ***"  
        echo "*** Changing the setting to TimerC to 120 seconds" #Yes I was playing with a timer. The name of what i was trying to change started with TimerC=75 and I wanted to change it to 120 seconds.
        [string]$textContent = [System.IO.File]::ReadAllText($FilePath)
        if ($textContent.Contains("(TimerC)(.*)"))
        {
            #File found and content exists. Otherwise there is a file but our content does not exist
            $textContent = $textContent.Replace("(TimerC)(.*)","$1=120") #You have the variables already you can replace variables
            Set-Content $FilePath   
        }
        #(get-content $FilePath) -replace '(TimerC)(.*)','$1=120' | Set-Content $FilePath #Replaces of the string we would like to change and saves the file.`  
    }  
    else  #If the $Search_entry_change is what we wanted already, then no change will be done.  
    {  
        cls  
        echo " The File $FilePath contains the string $Search_entry_change ***"  
        echo "*** No Need to Change. TimerC already 120 seconds ***"  
    }  
}  
else #In case the script does not finds the file in the path we gave earlier in the $FilePath then this means the file does not exists.
{  
    Write-Host "File Doesn't Exists. So the Program is not installed !!!"  
}