[Last Call] Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 325
  • Last Modified:

VB Script Help before mass enterprise deployment

Hello,
I wrote a script partially using existing snippets of code here and there, and am running into trouble with a string function.

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

Open in new window


This part of my code should look for "servicemanager.flextest.local" in file, if it finds it it should delete it. Ideally, it should only look for "servicemanager" but even when I put the entire string in the search parameter it still wont delete that line.

The script was written to modify the windows hosts file of everyone in a corporate network. If anyone sees any potential areas where I can add error trapping or improve the code in anyway please contribute. Thanks in advance.

Below is my code and an the file i am modifying.
' This Script will append your hosts file with the IP's of the 2 SCSM Servers
' This way you can connect directly to the portal by typing in the fqdn of the SCSM machine
' Script works by first setting the appropriate variables then checking to see if your host 
' file is already updated, if not it removes the previously added host in script v1 and adds
' the new hosts. :)
' Hosts Modification Script V2: By Ali Khoshkar for FlexITy Solutions Inc.

' Set some constants up for use within the script (a file can only be opened for one function at a time)
' The function OpenTextFile uses integers 1, 2, and others as parameters, easier to code when stored in 
' variables. Grabs the windows directory path and stores it in "WinDir"
Const ForReading = 1, ForWriting = 2, ReadOnly = 1
Set fso = CreateObject("Scripting.FileSystemObject")
Set WshShell=CreateObject("WScript.Shell")
WinDir =WshShell.ExpandEnvironmentStrings("%WinDir%")

' Defines Hosts file location and stores in variable
HostsFile = WinDir & "\System32\Drivers\etc\Hosts"

' Open the file for reading
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.OpenTextFile(HostsFile, ForReading)
' Go through the Hosts file until the last line to check if its already been modified, if so, quit
Do Until objFile.AtEndOfStream
 If InStr (objFile.ReadLine, "scsm.flextest.local") <> 0 Then
 WScript.Quit
 End If
 i = i + 1
Loop
objFile.Close

' Open the file for reading again
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.OpenTextFile(HostsFile, ForReading)
' Read Hosts file line by line each time appending the line in variable "strLine". If any lines
' contain the word "servicemanager" then remove them and go to the next line using visual
' basic carriage line feed
Do Until objFile.AtEndOfStream
    strLine = objFile.ReadLine
    If InStr(strLine, "servicemanager.flextest.local") = 0 Then
        strNewContents = strNewContents & strLine & vbCrLf
    End If
Loop
objFile.Close

' Makes sure the hosts file does not have a ReadOnly attribute before writing
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.GetFile(HostsFile)
If objFile.Attributes AND ReadOnly Then
 objFile.Attributes = objFile.Attributes XOR ReadOnly
End If

' Open HostsFile for writing
Set filetxt = fso.OpenTextFile(HostsFile, ForWriting, True)
' Dump contents of "strLine" (now void of all lines containing "servicemanager")
filetxt.Write strNewContents
' Add new hosts
filetxt.WriteLine(vbNewLine & "10.45.51.55	scsm.flextest.local #SCSM Test Management Server")
filetxt.WriteLine(vbNewLine & "10.45.51.56	scsm-cireson.flextest.local #SCSM Test Cireson Portal")
filetxt.WriteLine(vbNewLine & "10.45.51.57	scsm-portal.flextest.local #SCSM Test Portal Server")

filetxt.Close

' Quit
WScript.quit

Open in new window


Sample file to modify:
# This is a sample HOSTS file used by Microsoft TCP/IP for Windows.
#
# This file contains the mappings of IP addresses to host names. Each
# entry should be kept on an individual line. The IP address should
# be placed in the first column followed by the corresponding host name.
# The IP address and the host name should be separated by at least one
# space.
#
# Additionally, comments (such as these) may be inserted on individual
# lines or following the machine name denoted by a '#' symbol.
#
# For example:
#
# 102.54.94.97 rhino.acme.com # source server
# 38.25.63.10 x.acme.com # x client host

# localhost name resolution is handled within DNS itself.
# 127.0.0.1 localhost
# ::1 localhost

10.45.51.55	scsm.flextest.local #SCSM Test Management Server
10.45.51.57	scsm-portal.flextest.local #SCSM Test Portal Server
10.45.51.56	scsm-cireson.flextest.local #SCSM Test Cireson Portal

servicemanager.flextest.local deleteme

Open in new window

0
Sir Learnalot
Asked:
Sir Learnalot
  • 6
  • 6
  • 2
  • +1
2 Solutions
 
Randy PooleCommented:
have you tried to have it create a new file and write to that, just to make sure you are actually writing what you are thinking?
0
 
Sir LearnalotAuthor Commented:
yea... everything else works and this string function works.

Do Until objFile.AtEndOfStream
 If InStr (objFile.ReadLine, "scsm.flextest.local") <> 0 Then
 WScript.Quit
 End If
 i = i + 1
Loop
objFile.Close

Open in new window

0
 
RobSampsonCommented:
Hi, I have cleaned it up a bit, and changed the way you were searching for the existence of the new HOSTS entry before modifying it.  See if this works for you.

Regards,

Rob.

' This Script will append your hosts file with the IP's of the 2 SCSM Servers
' This way you can connect directly to the portal by typing in the fqdn of the SCSM machine
' Script works by first setting the appropriate variables then checking to see if your host 
' file is already updated, if not it removes the previously added host in script v1 and adds
' the new hosts. :)
' Hosts Modification Script V2: By Ali Khoshkar for FlexITy Solutions Inc.

' Set some constants up for use within the script (a file can only be opened for one function at a time)
' The function OpenTextFile uses integers 1, 2, and others as parameters, easier to code when stored in 
' variables. Grabs the windows directory path and stores it in "WinDir"
Const ForReading = 1, ForWriting = 2, ReadOnly = 1
Set WshShell=CreateObject("WScript.Shell")
WinDir =WshShell.ExpandEnvironmentStrings("%WinDir%")

' Defines Hosts file location and stores in variable
HostsFile = WinDir & "\System32\Drivers\etc\Hosts"

' Open the file for reading
Set objFSO = CreateObject("Scripting.FileSystemObject")
If objFSO.FileExists(HostsFile) Then
	Set objFile = objFSO.OpenTextFile(HostsFile, ForReading)
	strContents = objFile.ReadAll
	objFile.Close
	' Go through the Hosts file until the last line to check if its already been modified, if so, quit
	If InStr (strContents, "scsm.flextest.local") > 0 Then WScript.Quit
	
	' Open the file for reading again
	arrLines = Split(strContents, vbCrLf)
	' Read Hosts file line by line each time appending the line in variable "strLine". If any lines
	' contain the word "servicemanager" then remove them and go to the next line using visual
	' basic carriage line feed
	strNewContents = ""
	For Each strLine In arrLines
	    If InStr(LCase(strLine), LCase("servicemanager.flextest.local")) = 0 Then
			strNewContents = strNewContents & strLine & vbCrLf
	    End If
	Next
	
	' Makes sure the hosts file does not have a ReadOnly attribute before writing
	Set objFile = objFSO.GetFile(HostsFile)
	If objFile.Attributes AND ReadOnly Then
	 objFile.Attributes = objFile.Attributes XOR ReadOnly
	End If
	
	' Open HostsFile for writing
	Set objFile = objFSO.OpenTextFile(HostsFile, ForWriting, True)
	' Add new hosts
	strNewContents = strNewContents & "10.45.51.55" & vbTab & "scsm.flextest.local #SCSM Test Management Server" & vbCrLf
	strNewContents = strNewContents & "10.45.51.56" & vbTab & "scsm-cireson.flextest.local #SCSM Test Cireson Portal" & vbCrLf
	strNewContents = strNewContents & "10.45.51.57" & vbTab & "scsm-portal.flextest.local #SCSM Test Portal Server" & vbCrLf

	' Dump contents of "strLine" (now void of all lines containing "servicemanager")
	objFile.Write strNewContents
	objFile.Close
	
	' Quit
	WScript.quit
End If

Open in new window

0
Making Bulk Changes to Active Directory

Watch this video to see how easy it is to make mass changes to Active Directory from an external text file without using complicated scripts.

 
Sir LearnalotAuthor Commented:
@Rob, Hello and thanks for your help. However, I ran the script on the sample hosts file I included and its still not modifying the file; the line with "deleteme" is unchanged. Please advise, thanks in advance!
0
 
RobSampsonCommented:
Have you tried running the script from an elevated command prompt? Chances are the script does not have rights to do it. Are you seeing any errors? Open a command prompt "As Administrator" and run
Cscript.exe c:\scripts\modifyhostsfile.vbs
And see what happens.

Rob.
0
 
Sir LearnalotAuthor Commented:
The script was working fine its just a function within the script that's not working properly. I believe its the search function, doesn't seem to be finding the line with "servicemanager" or else it would get replaced. Regardless, I ran the script in elevated cmd with -verbose and still nothing, and no error message. Have you tried running the script yourself on your end?
0
 
RobSampsonCommented:
I haven't tried it yet but I just thought of something. Have you tried echoing the text from the file?
Under this line
      strContents = objFile.ReadAll
Put this
WScript.Echo strContents
And see if the text looks as you expect.

If that doesn't look right, the file must be Unicode. Change
Set objFile = objFSO.OpenTextFile(HostsFile, ForReading)
To this
Set objFile = objFSO.OpenTextFile(HostsFile, ForReading, False, -1)

And see how the text looks.

Rob.
0
 
Sir LearnalotAuthor Commented:
The text echo's fine but its still not working. Rob if you can, copy my sample hosts file into your hosts file directory (obviously make a backup of yours first) and run the script it would make the troubleshooting a lot more efficient. Thanks in advance!
0
 
RobSampsonCommented:
OK, I have tested it, and it worked fine for me, as long as I had run the script from an elevated command prompt.  When I ran it simply by double-clicking, I got Access Denied.

Anyway, I have added debugging output to the script, so we can hopefully get a better idea of what's happening.  Run this script from an elevated command prompt, using
cscript C:\Scripts\ChangeHosts.vbs
where I have set blnDebug = True and you will see the output as the script goes along.

Regards,

Rob.

' This Script will append your hosts file with the IP's of the 2 SCSM Servers
' This way you can connect directly to the portal by typing in the fqdn of the SCSM machine
' Script works by first setting the appropriate variables then checking to see if your host 
' file is already updated, if not it removes the previously added host in script v1 and adds
' the new hosts. :)
' Hosts Modification Script V2: By Ali Khoshkar for FlexITy Solutions Inc.

' Set some constants up for use within the script (a file can only be opened for one function at a time)
' The function OpenTextFile uses integers 1, 2, and others as parameters, easier to code when stored in 
' variables. Grabs the windows directory path and stores it in "WinDir"

blnDebug = True

Const ForReading = 1, ForWriting = 2, ReadOnly = 1
Set WshShell=CreateObject("WScript.Shell")
WinDir =WshShell.ExpandEnvironmentStrings("%WinDir%")

' Defines Hosts file location and stores in variable
HostsFile = WinDir & "\System32\Drivers\etc\Hosts"
If blnDebug = True Then WScript.Echo "HostFile: " & HostsFile

' Open the file for reading
Set objFSO = CreateObject("Scripting.FileSystemObject")
If objFSO.FileExists(HostsFile) Then
	On Error Resume Next
	Set objFile = objFSO.OpenTextFile(HostsFile, ForReading)
	If Err.number = 0 Then
		Err.Clear
		On Error GoTo 0
		strContents = objFile.ReadAll
		objFile.Close
		' Go through the Hosts file until the last line to check if its already been modified, if so, quit
		If InStr (strContents, "scsm.flextest.local") > 0 Then
			If blnDebug = True Then WScript.Echo "scsm.flextest.local already exists. Quitting."
			WScript.Quit
		Else
			If blnDebug = True Then WScript.Echo "scsm.flextest.local does not exist. Current contents:" & vbCrLf & strContents & vbCrLf
		End If
		
		' Open the file for reading again
		arrLines = Split(strContents, vbCrLf)
		' Read Hosts file line by line each time appending the line in variable "strLine". If any lines
		' contain the word "servicemanager" then remove them and go to the next line using visual
		' basic carriage line feed
		strNewContents = ""
		For Each strLine In arrLines
			' Ignore any lines with "servicemanager.flextext.local" in it
		    If InStr(LCase(strLine), LCase("servicemanager.flextest.local")) = 0 Then
				strNewContents = strNewContents & strLine & vbCrLf
			Else
				If blnDebug = True Then WScript.Echo "Skipping line: " & strLine
		    End If
		Next
		
		' Makes sure the hosts file does not have a ReadOnly attribute before writing
		Set objFile = objFSO.GetFile(HostsFile)
		If objFile.Attributes AND ReadOnly Then
			If blnDebug = True Then WScript.Echo "Setting ReadOnly attribute to FALSE"
			objFile.Attributes = objFile.Attributes XOR ReadOnly
		Else
			If blnDebug = True Then WScript.Echo "ReadOnly attribute is already FALSE"
		End If
		
		' Open HostsFile for writing
		On Error Resume Next
		Set objFile = objFSO.OpenTextFile(HostsFile, ForWriting, True)
		If Err.Number = 0 Then
			Err.Clear
			On Error GoTo 0
			' Add new hosts
			strNewContents = strNewContents & "10.45.51.55" & vbTab & "scsm.flextest.local #SCSM Test Management Server" & vbCrLf
			strNewContents = strNewContents & "10.45.51.56" & vbTab & "scsm-cireson.flextest.local #SCSM Test Cireson Portal" & vbCrLf
			strNewContents = strNewContents & "10.45.51.57" & vbTab & "scsm-portal.flextest.local #SCSM Test Portal Server" & vbCrLf
		
			' Dump contents of "strLine" (now void of all lines containing "servicemanager")
			If blnDebug = True Then WScript.Echo vbCrLf & "New contents to be written: " & vbCrLf & strNewContents & vbCrLf
			objFile.Write strNewContents
			objFile.Close			
		Else
			If blnDebug = True Then WScript.Echo "Error opening " & HostsFile & " for writing: " & Err.Description
		End If
	Else
		If blnDebug = True Then WScript.Echo "Error opening " & HostsFile & ": " & Err.Description
		Err.Clear
		On Error GoTo 0
	End If
Else
	If blnDebug = True Then WScript.Echo "File not found: " & HostsFile
End If
If blnDebug = True Then WScript.Echo vbCrLf & "Finished"

Open in new window

0
 
Sir LearnalotAuthor Commented:
Hello Rob,
Silly of me not to realize this was the case earlier, but thanks to your debugging I realized its not a problem with the code but more-so a logic flaw :) It's searching for "scsm.flextest.local" and if it finds it, it quits. Problem is, the line we want deleted is not in the exact same spot in every file (in this case its at the end of the file). So it's quitting the script before it gets to the line with "servicemanager". Can we instead change the behaviour to just pull the content of the host file, delete any lines with servicemanager, and add whatever fqdn is missing (out of the three I am adding)?
0
 
RobSampsonCommented:
Sir_Learnalot, my apologies for not getting back to you today, there were major issues at work to look after. It's late afternoon for me, so I will improve the logic in your script tomorrow for you.

Rob.
0
 
footechCommented:
If you're interested in PowerShell, the following should remove any line with "servicemanager" in it, and then add any missing entries.
$HostsFile = "$env:WinDir\System32\Drivers\etc\Hosts"
$Contents = Get-Content $HostsFile | Where {$_ -notmatch "servicemanager"}

$entries = "10.45.51.55`tscsm.flextest.local #SCSM Test Management Server",
    "10.45.51.56`tscsm-cireson.flextest.local #SCSM Test Cireson Portal",
    "10.45.51.57`tscsm-portal.flextest.local #SCSM Test Portal Server"

$Contents += Compare-Object $Contents $entries -PassThru | Where {$_.SideIndicator -eq "=>"} 
$Contents | Set-Content $HostsFile

Open in new window

0
 
RobSampsonCommented:
You can try this revision.  I haven't fully tested it, but I believe it should work.

It's obviously quite a lot more code than the Powershell version, and I must say footech, you make that look very easy!  Mind you, I've never seen -PassThru and .SideIndicator so I don't know what they do ;-)

Regards,

Rob.

' This Script will append your hosts file with the IP's of the 2 SCSM Servers
' This way you can connect directly to the portal by typing in the fqdn of the SCSM machine
' Script works by first setting the appropriate variables then checking to see if your host 
' file is already updated, if not it removes the previously added host in script v1 and adds
' the new hosts. :)
' Hosts Modification Script V2: By Ali Khoshkar for FlexITy Solutions Inc.

' Set some constants up for use within the script (a file can only be opened for one function at a time)
' The function OpenTextFile uses integers 1, 2, and others as parameters, easier to code when stored in 
' variables. Grabs the windows directory path and stores it in "WinDir"

blnDebug = True

arrPartialLinesToRemove = Array( _
	"servicemanager.flextest.local" _
	)

arrLinesToAdd = Array( _
	"10.45.51.55" & vbTab & "scsm.flextest.local #SCSM Test Management Server", _
	"10.45.51.56" & vbTab & "scsm-cireson.flextest.local #SCSM Test Cireson Portal", _
	"10.45.51.57" & vbTab & "scsm-portal.flextest.local #SCSM Test Portal Server" _
	)

Const ForReading = 1, ForWriting = 2, ReadOnly = 1
Set WshShell=CreateObject("WScript.Shell")
WinDir =WshShell.ExpandEnvironmentStrings("%WinDir%")

' Defines Hosts file location and stores in variable
HostsFile = WinDir & "\System32\Drivers\etc\Hosts"
If blnDebug = True Then WScript.Echo "HostFile: " & HostsFile

strLinesToAdd = ""
' Open the file for reading
Set objFSO = CreateObject("Scripting.FileSystemObject")
If objFSO.FileExists(HostsFile) Then
	On Error Resume Next
	Set objFile = objFSO.OpenTextFile(HostsFile, ForReading)
	If Err.number = 0 Then
		Err.Clear
		On Error GoTo 0
		strContents = objFile.ReadAll
		objFile.Close
		If blnDebug = True Then wscript.Echo "Current contents:" & vbCrLf & strContents & vbCrLf
		' Go through the Hosts file until the last line to check if its already been modified, if so, quit
		For Each strLineToAdd In arrLinesToAdd
			If InStr (LCase(strContents), LCase(strLineToAdd)) = 0 Then
				strLinesToAdd = strLinesToAdd & strLineToAdd & vbCrLf
				If blnDebug = True Then WScript.Echo strLineToAdd & " does not exist. Setting addition."
			Else
				If blnDebug = True Then WScript.Echo strLineToAdd & "already exists. Not setting addition."
			End If
		Next
		
		' Open the file for reading again
		If Split(strContents, vbCrLf)(UBound(Split(strContents, vbCrLf))) <> "" Then strContents = strContents & vbCrLf
		arrLines = Split(strContents, vbCrLf)
		' Read Hosts file line by line each time appending the line in variable "strLine". If any lines
		' contain the word "servicemanager" then remove them and go to the next line using visual
		' basic carriage line feed
		strNewContents = ""
		For Each strLine In arrLines
			' Ignore any lines with "servicemanager.flextext.local" in it
		    For Each strLineToRemove In arrPartialLinesToRemove
				If InStr(LCase(strLine), LCase(strLineToRemove)) = 0 Then
					If strNewContents = "" Then
						strNewContents = strLine
					Else
						strNewContents = strNewContents & vbCrLf & strLine
					End If
				Else
					If blnDebug = True Then WScript.Echo "Skipping line: " & strLine
				End If
			Next
		Next
		
		If strLinesToAdd <> "" Then strNewContents = Trim(strNewContents & strLinesToAdd)
		' Check if the new content (desired content) is different from the original content
		If Trim(strContents) <> Trim(strNewContents) Then
			If blnDebug = True Then WScript.Echo vbCrLf & "Content requires changing. New contents: " & vbCrLf & strNewContents & vbCrLf
			' Makes sure the hosts file does not have a ReadOnly attribute before writing
			Set objFile = objFSO.GetFile(HostsFile)
			If objFile.Attributes AND ReadOnly Then
				If blnDebug = True Then WScript.Echo "Setting ReadOnly attribute to FALSE"
				objFile.Attributes = objFile.Attributes XOR ReadOnly
			Else
				If blnDebug = True Then WScript.Echo "ReadOnly attribute is already FALSE"
			End If
			
			' Open HostsFile for writing
			On Error Resume Next
			Set objFile = objFSO.OpenTextFile(HostsFile, ForWriting, True)
			If Err.Number = 0 Then
				Err.Clear
				On Error GoTo 0
				' Write new contents
				If blnDebug = True Then WScript.Echo vbCrLf & "New contents to be written: " & vbCrLf & strNewContents & vbCrLf
				objFile.Write strNewContents
				objFile.Close			
			Else
				If blnDebug = True Then WScript.Echo vbCrLf & "Error opening " & HostsFile & " for writing: " & Err.Description
			End If
		Else
			If blnDebug = True Then WScript.Echo "File does not require changing."
		End If
	Else
		If blnDebug = True Then WScript.Echo "Error opening " & HostsFile & ": " & Err.Description
		Err.Clear
		On Error GoTo 0
	End If
Else
	If blnDebug = True Then WScript.Echo "File not found: " & HostsFile
End If
If blnDebug = True Then WScript.Echo vbCrLf & "Finished"

Open in new window

0
 
footechCommented:
-Passthru is a parameter of the Compare-Object cmdlet (other cmdlets have it as well).  What it does here is to specify that the Compare-Object command should output objects (essentially unmodified) which result from the comparison, to the pipeline.  "SideIndicator" is a property of those objects which indicates which input object (the reference object or the difference object) it belonged to.

One modification that could probably be made to my script is to compare the modified-in-memory version to the original, and only write out the file if there is a difference.  Looks like yours already does that.  If I added in all the console output that your script has it would probably triple the lines of code, but still not bad.

Without Compare-Object doing the heavy lifting, I suppose one method to check for the SCSM entries is to remove all the lines that match one of those three strings, and then just add them all back in. Would seem to work for either PS or VBScript.
0
 
Sir LearnalotAuthor Commented:
Thank you both so much for your efforts. I appreciate it, have a great weekend!
0

Featured Post

Configuration Guide and Best Practices

Read the guide to learn how to orchestrate Data ONTAP, create application-consistent backups and enable fast recovery from NetApp storage snapshots. Version 9.5 also contains performance and scalability enhancements to meet the needs of the largest enterprise environments.

  • 6
  • 6
  • 2
  • +1
Tackle projects and never again get stuck behind a technical roadblock.
Join Now