If this is your first visit, be sure to
check out the FAQ by clicking the
link above. You may have to register
before you can post: click the register link above to proceed. To start viewing messages,
select the forum that you want to visit from the selection below.

Hello Guest,Our records indicate that you have never posted to our site before! Why not make your first post today by saying hello to our community in our Introductions forum.

Please review the forums rules, start with your first post today and become an active part of petri.co.il forums now!

How to use script parameters...

27th March 2007, 05:18

Hi, guys.
I wrote this script, to stop and disable a service on computers in my network. I want that the service's name will be taken from the command line that runs the script.
How do I do that? Somehow couldn't find it. Microsoft only says it's possible
And I would like to hear what do you think of the script (my first one, more complicated than copying files from here to there).

TIA

Code:

' This script checks the status of a service on a computer and
' if it's running, it will be stopped and disabled.
' The script logs the status of the service.
' The script checks that the computername shows in the log file and if not,
' the script will run (to avoid running all the time).
On Error Resume Next
Const FOR_READING = 1 ' To open a file for reading
Const FOR_WRITING = 2 ' To open a file for writing
Const FOR_APPENDING = 8 ' To open a file for adding
Const CREATE_FILE = "True" ' Create the file if it does not exist
strFile = "\\[server]\[share]\service.stopped.txt" ' The log file
Set objComputer = CreateObject("Shell.LocalMachine")
computerName = objComputer.MachineName ' Now I have the computer's name' If the file does not exist, it will be created and an empty line will
' be inserted
Set objFSO = CreateObject("Scripting.FileSystemObject")
If Not objFSO.FileExists(strFile) Then
Set objFile = objFSO.CreateTextFile (strFile)
Set objFile = objFSO.OpenTextFile (strFile, FOR_APPENDING)
objFile.WriteLine "."
objFile.Close
End If
' Check if the computer already shows in the log file. If not, runs the script.
Set objTextStream = objFSO.OpenTextFile _
(strFile, FOR_READING)
logContents = objTextStream.ReadAll
If (InStr(logContents, computerName) = 0) Then ' the computer was not found
Set objFile = objFSO.OpenTextFile _
(strFile, FOR_APPENDING)
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\CIMV2")
Set colItems = objWMIService.ExecQuery("SELECT * FROM Win32_Service" & _
" WHERE Name='Dhcp'")
For Each objItem In colItems
If objItem.State = "Running" Then
objItem.StopService()
objItem.ChangeStartMode("Disabled")
objFile.WriteLine computerName & " @ " & Now & _
" : The " & objItem.Name & " service is now stopped and disabled."
Else
objFile.WriteLine computerName & " @ " & Now & _
" : " & " The " & objItem.Name & " service wasn't running."
End If
Next ' Next Service
End If
objTextStream.Close
objFile.Close

Sorin Solomon

»»»»»
In order to succeed, your desire for success should be greater than your fear of failure. -
«««««

Comment

Now you planned to use script arguments you have to modify the script, so it can work with parameters.
If you are running this script with a computer GPO, you can put the parameters at the scriptparameters bar in the GPO

The part I personaly would change* in your script is the reading for computername from logfile. Better is to read the last written "state", so you would be able later-on to change setting with the same script if needed. (but then you have to separate logfiles per computer though. EDIT: But do keep in mind that the logfile can only be opened for appending or for writing by just one computer and one event the same time!)

example:

Code:

'// This script checks the status of a service on a computer and
'// if it's running, it will be stopped and disabled.
'// The script logs the status of the service.
'// The script checks that the computername shows in the log file and if not,
'// the script will run (to avoid running all the time).
strService = "Dhcp" '<---ServiceName will be Added by command-line
sNextState = "Stopped" '<---Values are: "Stopped" or "Running"
sNextStartMode = "Disabled" '<---Values are: "Disabled", "Manual", "Automatic", "System" or "Boot"
Set objComputer = CreateObject("Shell.LocalMachine") 'Get the name of this computer;
strComputer = objComputer.MachineName
strLogFile = "\\[server]\[share]\service("&strComputer&")log.txt" ' The output file,"per computer" this time, <- needed for the checking method I used in this example (just for the idea)
Const FOR_READING = 1 ' To open a file for reading
Const FOR_WRITING = 2 ' To open a file for writing
Const FOR_APPENDING = 8 ' To open a file for adding
Const CREATE_FILE = "True" ' Create the file if it does not exist
'Naming correction
logStartMode = sNextStartMode 'But if...
If sNextStartMode = "Automatic" then logStartMode = "Auto"
Set objFSO = CreateObject("Scripting.FileSystemObject")
'// If the logfile does not exist, it will be created and an empty line will
'// be inserted. And if the logfile do exist, it reads the last_state from it.
If Not objFSO.FileExists(strLogFile) Then
Set objFile = objFSO.CreateTextFile(strLogFile)
'Set objFile = objFSO.OpenTextFile(strLogFile, FOR_WRITING)
'objFile.WriteLine vbCr 'new empty line (or: vbCrLf & "this text on new line")
objFile.Close
logContents = Null
Else
'On Error Resume Next
'logContents = objFSO.OpenTextFile(strLogFile).ReadAll
'On Error GoTo 0
'*** Read only the last, not_empty, line of the log file
Set objFile = objFSO.OpenTextFile(strLogFile, FOR_READING)
Do Until objFile.AtEndOfStream
strNextLine = objFile.ReadLine
If Len(strNextLine) > 0 Then
logContents = strNextLine
End If
Loop
objFile.Close
End If
'// open the log file for appending,
'// first reads its content as a routine Check wether the script already
'// has stopped the service on this computer. If not, change the running service.
'*** Check the last state written by this script to the logfile
If InStr(UCase(logContents), UCase _
("service is "&sNextState&" and startup type is "&logStartMode))=0 then
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\CIMV2")
Set colItems = objWMIService.ExecQuery("SELECT * FROM Win32_Service " _
& "WHERE Name= '"& strService &"'")
For Each objItem In colItems
If UCase(sNextState) = "RUNNING" Then objItem.StartService()
If UCase(sNextState) = "STOPPED" Then objItem.StopService()
objItem.ChangeStartMode(sNextStartMode)
exit For '<-- there can be no other service with the same name.
Next 'or continue finding the right Service
'// Now check the new current_state and write to log
On Error Resume Next
WScript.Sleep 1111 '<--- hold-on while service is stopping (milisecs)
Set objFile = objFSO.OpenTextFile(strLogFile, FOR_APPENDING)
For Each objItem In colItems
objFile.WriteLine strComputer & " @ " & Now & _
" : The " & objItem.Name & " service is " & _
objItem.State & " and startup type is " & objItem.StartMode
exit For
Next
On Error GoTo 0
objFile.Close
End If
Set colItems = Nothing
wscript.quit

But even better and more reliable would be if you let the script perform a quick pre-check on the actual service settings if they matches the parameters then Quit, If not then continue the script to change settings and add changes to logfile. (and now there is no need to create separate logfiles any more, like my other suggestion). Besites the flexibility advantages these changes can give, I also think the second option can even make the script run faster because I expect that checking the actual state will be quicker that opening and searching the log file.

- - - - - -
With script parameters you can controle the variables "strService", "sNextState" and "sNextStartMode" (names I used in the example).
There are to ways you can use script arguments,
w/out switches -=or=- w/ switches (named arguments)
Without the switches it works the same as commandline_variables for batchfiles, the order you put the parameters is very important

With the switches you have more flexibility to use parameters.
If you like to use switches, then these are the lines you can use in the script:

*If you don't use all the parameters, nomally that would be no problem,
but it will if you use this part of the script I added; '*** Check the last state written by this script to the logfile <....lines 57 and 58...>
But If you instead just checking the computername like you did, or perform a quick pre-check of the current state, that will avoid an unnessesary grow of the logfile in this case.

Comment

10nx for your feedback, Rems. It is most important for me, this is the way to learn new things.
The check on the log file comes to solve the issue of running the logon script more than once, generally speaking. In this case, we're talking about a service, that's why is easy to check its present state and change it if need it. But when we are talking about something else, it might be a problem. I saw here in the forum people writing files on the disk or keys in the registry to assure running only once.
Anyway, I will thoroughly study your script. I will probably have more questions.
Thanks for your help.

Sorin Solomon

»»»»»
In order to succeed, your desire for success should be greater than your fear of failure. -
«««««

Comment

In this case, we're talking about a service, that's why is easy to check its present state and change it if need it.
But when we are talking about something else, it might be a problem. I saw here in the forum people writing files on the disk or keys in the registry to assure running only once.

Yes services are easy to check for a script.
(btw the "startup type" of services can also be managed by GPO).

I liked the idea though of using a central log that records all wat is changed by specific adminstrative-scripts (in this case it was managing services) on the computer.
And, if you want to use that log-file the same time as an indicator for a script whether it has or hasn't already runned once on the computer it needs someting extra.

So lets stick to that idea creating one central log for different administrative-scripts for a while.
The most reliable way would be one logfile per computer, because a logfile can only be in-use by one computer the time.
And then it properly is better to store the logfile on the computer it self.
That can all be written in the script. Then there are two things left to accomplish;
1. Not every kind of script can check a 'state' to determine whether it has runned already. So we need an indicator.
2. If the log is stored on the local computer then it is central for all script events on one computer, but it is not together with logs from all the computers.

A solution for 2. can be..
the script could, besites writing in the local logfile, also copy the entire log to a share when it has written someting to the log. It will overwrite the previous saved log. On that share there are ways how you can later on merge the logs from all the computers together if desired.
But copying to the share is optional, not realy needed if you do not personally want to check the logs. You always could run a script then that can read a log on a remote computer.

The solution for 1.
you mensioned that answer already.
- give every script a code# (or determine the unique name of the script and use that as a 'code').
When the script runs on the computer, it will first seach the logfile if there is already a line starting with this unique code#. If exist Then the script Quits.
If Not exists Then it will do its thing... and afterwards it writes -the event (completely between "quotes"), -the computername, -the script code# and -date in a certain order to one new line in the logfile.
(Each line in the log must have the same lay-out (containing always the same set of types of values in always the same order. That will make the file a usable csv-file), which is nessesary if you want the possibility to import or merge the file).

For protecting the log file you could store it in a specialy created folder in the %SystemRoot%. The logfile can only be edited by scripts runned as computer start-up script or by an administrator.

So here are all the extra administrative features you have to add everytime to each administrative-script:
- if not exist create the folder and logfile,
- handle the code#
- get results and write lines
- copying the log to a share (when needed)
For writing such script there is not much difference between the options; writing the runones-indicators by all the scripts in one and the same logfile, or, place 'markers' somewhere in separate files or as registrykeys on the computer. You still have to consider the features above when writing an administrative-script.

Like in this link, a good place for that particular marker is properly to attach it to its 'purpose', but that is not always possible for every kind of process.
Or.. it can have bennefits for an administrator if all markers are written to a central logfile on the computer.

\Rem

tip
It is recommended to always use 'On Error resume next' in scripts that opens files for writing. Then add 'On Error goTo 0' just before the line that will close the file. That way if an error occur the script won't leave the file opend.

This posting is provided "AS IS" with no warranties, and confers no rights.__________________