Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

VBscript to Search / Modify Windows Services file 1

Status
Not open for further replies.

getzjd

IS-IT--Management
May 8, 2008
17
US
Background: SAP system will be modified and a change is required in the Windows services file on all domain computers. I am not a programmer, but can tinker and understand the basics. Essentially, I am a danger to myself and all around me when I play with code lol

What I would like to accomplish is for this script to search for the following text within the windows services file:
sapmsPUB XXXXXX
sapmsPDB XXXXXX
sapmsUP2 XXXXXX
sapmsQDB XXXXXX
sapmsDDB XXXXXX

Where (xxxxxx) would be any existing services port on that line

If found, I would like to delete those lines and insert these at the bottom of the services file followed by two blank lines
sapmsPUB 3605/tcp
sapmsPDB 3602/tcp
sapmsUP2 3600/tcp
sapmsQDB 3602/tcp
sapmsDDB 3600/tcp
BLANK LINE
BLANK LINE

The script should only run once. I am guessing this can be accomplished through the use of something such as service.ack file. Once script executes, create a new file service.ack. If service.ack exists, go to end type scenario.

What I have below is a horrid abomination of code, but this will search the services file for a single string sapmspub, if found, delete the entire line. It will then insert the necessary services at the end of the file followed by two blank lines. What I am missing is a way to search for the additional lines to be deleted. such as sapmsddb, sapmsqdb, sapup2, and sapmspdb. I am also missing the creation of a service.ack file in C:\Windows\System32\drivers\etc\services which, if exists, will cause the script to exit without modifying.

I am open to any and all suggestions. Thanks!

Code:
Const ForReading = 1
Const ForWriting = 2

Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.OpenTextFile("C:\Windows\System32\drivers\etc\services", ForReading)

Do Until objFile.AtEndOfStream
    strLine = objFile.ReadLine
    If InStr(strLine, "sapmspub")= 0 Then
        strNewContents = strNewContents & strLine & vbCrLf
    End If
Loop

objFile.Close

Set objFile = objFSO.OpenTextFile("C:\Windows\System32\drivers\etc\services", ForWriting)
objFile.Write strNewContents

objFile.Close



set fs = CreateObject("Scripting.FileSystemObject") 
set file = fs.opentextfile("C:\Windows\system32\drivers\etc\services.", 8) 
file.writeline "sapmsPUB  3605/tcp"
file.writeline "sapmsPDB  3602/tcp"
file.writeline "sapmsUP2  3600/tcp"
file.writeline "sapmsQDB  3602/tcp"
file.writeline "sapmsDDB  3600/tcp"
file.writeline ""
file.writeline ""
file.close
 
I am not a programmer, but can tinker and understand the basics. Essentially, I am a danger to myself and all around me when I play with code lol

Danger, Will Robinson, Danger! Seriously, make sure you understand the repercussions of mucking with "services" in the C:\Windows\System32\drivers\etc folder before proceeding. I sure don't know what it does.

Also to scare you a little more, the below code is not tested.

But from a vbscript point of view, you can create a function (LineShouldBeDeleted in this case) that can look for the existence of all the strings you want and return a pass/fail value. Again, not tested:

Code:
Do Until objFile.AtEndOfStream
    strLine = objFile.ReadLine
    [highlight #FCE94F]If Not LineShouldBeDeleted(strLine)[/highlight]
        strNewContents = strNewContents & strLine & vbCrLf
    [highlight #FCE94F]End If[/highlight]
Loop

Then at the end add:
Code:
Function LineShouldBeDeleted(strLine)
    Dim arrDeleteIfPresent, SearchString
    LineShouldBeDeleted = False

    arrDeleteIfPresent = Array( _
        "sapmspub", _
        "sapmsddb", _
        "sapmsqdb", _
        "sapup2", _
        "sapmspdb")

    For each SearchString in arrDeleteIfPresent
        If InStr(strLine, SearchString) <> 0 Then
            LineShouldBeDeleted = True
        End If
    Next
End Function
 
Thank you for the suggestions. I know the ramifications of modifying the Services file in the wrong manner [bigsmile] Trust me, when testing, I simply move a copy of a services file off to something such as C:\temp and adjust paths accordingly.

I will toy around with your suggestions and see if I can get something moving in the right direction.
 
Here is another option using regular expressions.
Code:
Set objFSO = CreateObject("Scripting.FileSystemObject")

'Check if the service.ack file exist.  If it does then stop the execution as the script already ran.
If objFSO.FileExists("C:\Windows\System32\drivers\etc\service.ack") Then
	WScript.Echo "The script already ran.  Terminate execution."
	WScript.Quit
End If

Set r = New RegExp
	With r
		.Pattern = "sapms.{3}\s.{6}"
		.Global = True
		.IgnoreCase = True
	End With
	
Set ReadFile = objFSO.OpenTextFile("C:\Windows\System32\drivers\etc\services",1)

Do Until ReadFile.AtEndOfStream
	TextLine = ReadFile.ReadLine
	If  r.Test(TextLine) = False Then
		NewContent = NewContent & TextLine & vbCrLf
	End If 
Loop

ReadFile.Close

Set WriteFile = objFSO.OpenTextFile("C:\Windows\System32\drivers\etc\services",2)

WriteFile.Write NewContent & "sapmsPUB  3605/tcp" & vbCrLf &_
	"sapmsPUB  3605/tcp" & vbCrLf &_
	"sapmsUP2  3600/tcp" & vbCrLf &_
    "sapmsQDB  3602/tcp" & vbCrLf &_
    "sapmsDDB  3600/tcp" & vbCrLf &_
    vbCrLf & vbCrLf

WriteFile.Close

'Create service.ack.
Set ScriptComplete = objFSO.CreateTextFile("C:\Windows\System32\drivers\etc\service.ack")
ScriptComplete.Close
 
JKSpeed,

This is perfect! I just removed WScript.Echo "The script already ran. Terminate execution." and this is exactly what was needed!

Thank you!
 
Actually.. only one hitch.. I am getting a 800A0046 Permission denied error when it tries to write the ack file. Our previous batch script temporarily made the ETC folder not read only through
attrib -r %windir%\system32\drivers\etc\*.* /D and then changed it back near the end rem attrib +r %windir%\system32\drivers\etc\*.* /D

JKSpeed, if you can assist, that would be great, but in the meantime, I will start experimenting with some code to make writable.

 
You don't need to create the file in the etc folder. I don't even think it's a good idea. Since the file is simply a way to check if the service file was edited, I recommend creating the service.ack file in a temp folder. Afterall, the file won't be missed after your project is complete. So in the script, the routine to check if the file exist is.
Code:
If objFSO.FileExists("C:\Temp1\service.ack") Then
	WScript.Quit
End If

And the routine to create the file is.
Code:
If objFSO.FolderExists("C:\Temp") = False Then
	objFSO.CreateFolder "C:\Temp"
End If

Set ScriptComplete = objFSO.CreateTextFile("C:\Temp\service.ack")
ScriptComplete.Close

Since I do share guitarzan's concern of editing the services file, I recommend backing it up first. This can also be integrated in your script.
 
Ugh... another permission error line 26. I must have tweaked my local services file when testing from a non-standard security setting.

Is there anyway to pass through an administrator username/password for the file write or maybe change the attributes of services to allow writing then replacing them?


Set WriteFile = objFSO.OpenTextFile("C:\Windows\System32\drivers\etc\services",2)
 
I doubt if that can be accomplished from within the script. If I were to venture a solution, I would write another script that calls this script. See an example here.
 
What I did was create a GPO with a scheduled task to execute the script and it works well. I have the following code:

'--------------
'Start of UAC workaround code

If WScript.Arguments.length =0 Then
Set objShell = CreateObject("Shell.Application")

objShell.ShellExecute "wscript.exe", Chr(34) & _
WScript.ScriptFullName & Chr(34) & " uac", "", "runas", 1
Else

'--------------
'Start of code

Set objFSO = CreateObject("Scripting.FileSystemObject")

'Check if the service.ack file exist. If it does then stop the execution as the script already ran.
If objFSO.FileExists("C:\Temp1\service.ack") Then
WScript.Quit
End If

Set r = New RegExp
With r
.Pattern = "sapms.{3}\s.{6}"
.Global = True
.IgnoreCase = True
End With

Set ReadFile = objFSO.OpenTextFile("C:\Windows\System32\drivers\etc\services",1)

Do Until ReadFile.AtEndOfStream
TextLine = ReadFile.ReadLine
If r.Test(TextLine) = False Then
NewContent = NewContent & TextLine & vbCrLf
End If
Loop

ReadFile.Close

Set WriteFile = objFSO.OpenTextFile("C:\Windows\System32\drivers\etc\services",2)


WriteFile.Write NewContent & "sapmsPUB 3605/tcp" & vbCrLf &_
"sapmsPDB 3602/tcp" & vbCrLf &_
"sapmsUP2 3600/tcp" & vbCrLf &_
"sapmsQDB 3602/tcp" & vbCrLf &_
"sapmsDDB 3600/tcp" & vbCrLf &_
vbCrLf & vbCrLf

WriteFile.Close

'Create service.ack.
If objFSO.FolderExists("C:\Temp1") = False Then
objFSO.CreateFolder "C:\Temp1"
End If

Set ScriptComplete = objFSO.CreateTextFile("C:\Temp1\service.ack")

ScriptComplete.Close

'--------------
'End of code


'--------------
'End of UAC workaround code

End If


The problem is that each time the script runs, it places 2 blank lines between sapgw99 3399/tcp and sapmsPUB 3605/tcp


sapgw97 3397/tcp
sapgw98 3398/tcp
sapgw99 3399/tcp


sapmsPUB 3605/tcp
sapmsPDB 3602/tcp
sapmsUP2 3600/tcp
sapmsQDB 3602/tcp
sapmsDDB 3600/tcp


If the script runs again, it would create the following and so on.

sapgw97 3397/tcp
sapgw98 3398/tcp
sapgw99 3399/tcp




sapmsPUB 3605/tcp
sapmsPDB 3602/tcp
sapmsUP2 3600/tcp
sapmsQDB 3602/tcp
sapmsDDB 3600/tcp
 
Blank lines in the original file are not skipped. To do so, update the following line.
Code:
If r.Test(TextLine) = False Then
To
Code:
If r.Test(TextLine) = False And Len(TextLine) > 0 Then
Again, please test thoroughly before you deploy.
 
If you are going to use Regular Expressions, then you shouldn't need to process the file line by line ...

Code:
[blue]
With r
    .Pattern = "^sapms[\s\S]+\r\n"
    .Global = True
    .MultiLine = True
    .IgnoreCase = True
End With

Set readfile = objFSO.OpenTextFile("c:\download\services_X", 1) [green]' Example uses a copy of the services file[/green]
NewContent = r.Replace(readfile.ReadAll, "")
readfile.Close

Set WriteFile = objFSO.OpenTextFile("C:\download\services_Y", 2, True)

WriteFile.Write NewContent & vbCrLf & _
"sapmsPUB 3605/tcp" & vbCrLf & _
"sapmsPDB 3602/tcp" & vbCrLf & _
"sapmsUP2 3600/tcp" & vbCrLf & _
"sapmsQDB 3602/tcp" & vbCrLf & _
"sapmsDDB 3600/tcp" & vbCrLf & _
vbCrLf & vbCrLf

WriteFile.Close[/blue]
 
@strongm
Good option! It has been weeks since I worked on this. As far as I can remember, the original poster also wants the blank lines removed from the original file.
 
jkspeed, you are correct. I needed to remove blank lines as well. We actually have this in place and it is working well. I simply created a GPO and a task in task scheduler that will execute this script and the services file is updated.

Mind you we only need to update the services file once in a blue moon, typically if something in our SAP landscape changes such as our upgrade from ecc5 to ecc6. If we need to updated it now, all I do is modify the centralized script file on a DFS share, modify the ACK file line in that script so it executes once and done.

I thank everyone for their assistance with this!
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top