#212573 - 2017-07-04 05:11 PM
Best Procedure for using server names in script
|
Robdutoit
Hey THIS is FUN
Registered: 2012-03-27
Posts: 363
Loc: London, England
|
Seems like ages since I last visited as I hardly do much scripting anymore as everything is working! Hope that everyone is alive and well and enjoying life.
I have encountered a problem that really needs resolving. Years ago when I setup my existing clients, I gave the servers the same names at each client so as to make scripting easy in that my current global coding is $ServerName = "\\Serverwhatever" etc.
This made it easy to just use $servername everywhere in the script for Wsus, locations to text files required by the scripts etc.
However, with new clients coming onboard this year and with them using different names for their servers, the Global Coding $ServerName = "\\Serverwhatever" in my udfs.kix file is not practical as I have to keep changing the "\\serverwhatever" to whatever the server name is in the udf file. I use the same script for every client, so I only have one script to update.
Why do you guys do to address this issue as I don't think a readline (handle) type coding works in global. But if I want to install a printer for example, I need to have \\servername\printername in the script. I do a readline (handle) for the printer name, no problem, but thats not global and I need the server names global as there are many lines of coding pointing to \\servername\location whether is wsus, printer, a specific directory, mapped drive etc.
Thanks
|
Top
|
|
|
|
#212574 - 2017-07-04 05:21 PM
Re: Best Procedure for using server names in script
[Re: Robdutoit]
|
Allen
KiX Supporter
Registered: 2003-04-19
Posts: 4545
Loc: USA
|
Use INI files, dude. The tools are built into kix for easy manipulation.
Better yet, Glenn wrote complete replacements UDFs for manipulating INI files as arrays. These things are slick as butter, have been thoroughly tested, and kept up to date.
There is a version here that is not the most current although I doubt you would run into any of the issues that were fixed afterwords: http://www.kixtart.org/forums/ubbthreads.php?ubb=showflat&Number=202790#Post202790
Might need Glenn to post a link to the newer version as his link in the UDF page is broken now
|
Top
|
|
|
|
#212576 - 2017-07-04 05:41 PM
Re: Best Procedure for using server names in script
[Re: Allen]
|
Allen
KiX Supporter
Registered: 2003-04-19
Posts: 4545
Loc: USA
|
Until Glenn can update all his links to where ever his new site is, here is the current version.
;;
;;=====================================================================================-----
;;
;;FUNCTION IniArray()
;; ReadIniArray() - subfunction for reading array
;; WriteIniArray() - subfunction for writing array
;;
;;ACTION Reads INI file into an array;
;; Writes array to INI format file & reloads the array with fresh data
;; ReadIniArray() reads a Section:Key:Data set from the array
;; WriteIniArray() writes a Section:Key:Data set to the array
;;
;;AUTHOR Glenn Barnas
;;
;;VERSION 1.3 - 2014/06/23 - Fixed issue when data contained equal signs.
;; 1.2 - 2013/04/20 - Read empty section or file, write empty section,
;; WriteIniArray() - fix error if duplicate write of null data Added Options
;; to IniArray for Write to add blank lines between sections.
;; 1.1 - 2013/04/17 - Improve file load time on large files.
;; 1.0 - 2011/08/02
;;
;;SYNTAX IniArray(filename [,array] [,options])
;;
;;PARAMETERS Filename - REQUIRED - String
;; - The name of the INI file to read/write
;;
;; Array - OPTIONAL - Array
;; - The properly formatted array to write
;;
;; Options - OPTIONAL - Integer
;; - A bitwise settings to control output formatting
;; Value Mode Description
;; 1 Write Adds blank lines between Sections when true
;; 2 Write Suppress the array reload on write, useful when no further INI manipulation is planned.
;;
;;REMARKS Reads an entire INI file into an array for processing. There is no
;; limit on the size of the INI file, other than any Kix limits on
;; general file sizes. On read, blank lines and comments (lines that
;; begin with ";" or "#") are ignored. On write, only sections that
;; contain data/value pairs are written, mimicing the action of
;; WriteProfileString(). Similarly, only Keys that have non-null
;; values are written.
;;
;; The secondary functions ReadIniArray() and WriteIniArray() make
;; using the IniArray() UDF as easy to use as ReadProfileString()
;; and WriteProfileString(), simply requiring calls to IniArray to
;; load and then save the INI file. The Read and Write sub-functions
;; use the same syntax as the ProfileString functions but reference
;; the array instead of the INI file.
;;
;; NOTE: The WriteIniArray function returns the updated array. This
;; is the only significant deviation from the WriteProfileString operation.
;;
;; NOTE: During array manipulation, deleted records are set to null
;; and not reused. Similarly, when a new key/data pair is added, deleted
;; array items are not reused. When the array is written to disk, the
;; null records are skipped. When the file is again read, the array will
;; only contain valid data with no empty records.
;; WRITING an array causes a RE-READ operation, cleaning the empty records.
;;
;; NOTE: IMPORTANT - When using WriteIniArray() to create a new Ini-array,
;; you MUST first declare the array via Dim $array[1, 0]. This is not
;; necessary if you read an INI file first.
;;
;;RETURNS Returns a two-dimensional array of two-dimensional arrays. The first
;; element is the section name, the second element is a two-dimensional
;; array consisting of the key/data pairs.
;;
;; Consider the following simple INI file:
;; [COLORS]
;; Apple=Red
;; Lime=Green
;; [TASTES]
;; Apple=sweet
;; Lime=sour
;;
;; The call $aINI = IniArray('inifile.ini) would return an array that
;; contained the following values:
;; $aINI[0,0] contains "COLORS"
;; $aINI[1,0] contains an array of data/value pairs from this section
;; - extract with $aData = $aINI[1,0]
;; $aData[0,0] contains "Apple"; $aData[1,0] contains "Red"
;; $aData[0,1] contains "Lime"; $aData[1,1] contains "Green"
;;
;; $aINI[0,1] contains "TASTES"
;; $aINI[1,1] contains Array of data/value pairs from this section
;; - extract with $aData = $aINI[1,1]
;; $aData[0,0] contains "Apple"; $aData[1,0] contains "Sweet"
;; $aData[0,1] contains "Lime"; $aData[1,1] contains "Sour"
;;
;; ; the following would return "Sweet", just like ReadProfileString
;; $Taste = ReadIniArray($aINI, 'TASTES', 'Apple')
;;
;;
;;DEPENDENCIES none
;;
;;TESTED WITH W2K, WXP, W2K3, W2K8, W7
;;
;;EXAMPLES INI FILE READ:
;; $aIni = IniArray('testfile.ini')
;; 'File contains ' UBound($aIni, 2) + 1 ' sections' ?
;;
;; ENUMERATE:
;; For $I = 0 to UBound($aIni, 2)
;; $aData = $aIni[1, $I]
;;
;; 'Section: ' $aIni[0, $I] ' contains ' UBound($aData, 2) + 1 ' Data/Value elements' ?
;; ' Press a key: ' get $ ?
;;
;; For $J = 0 to UBound($aData, 2)
;; $J ': ' $aData[0, $J] ' = ' $aData[1, $J] ?
;; Next
;; Next
;;
;; ELEMENT READ:
;; ; Return a specific value
;; $Value = ReadIniArray($aIni, 'SectionName', 'keyname')
;; ; Return an array of all section names
;; $aSections = Split(ReadIniArray($aIni), Chr(10))
;; ; Return an array of Keys in a specific section
;; $aKeys = Split(ReadIniArray($aIni, 'SectionName'), Chr(10))
;;
;; ELEMENT WRITE/UPDATE:
;; ; Write a key/value pair in the named section
;; $aIni = WriteIniArray($aIni, 'SectionName', 'keyname', 'Data')
;;
;; ELEMENT DELETE:
;; ; Remove the named key from the defined section
;; $aIni = WriteIniArray($aIni, 'SectionName', 'keyname')
;;
;; SECTION DELETE:
;; ; Remove all key/value pairs from the section, deleting the section
;; $aIni = WriteIniArray($aIni, 'SectionName')
;;
;; INI FILE WRITE:
;; ; Flush the array to the file and then reload the array
;; $aIni = IniArray('testfile.ini', $aIni)
;
Function IniArray($_fSrcFile, OPTIONAL $_aDataWrite, OPTIONAL $_Options)
Dim $_ ; temp var
Dim $_Fp ; file pointer
Dim $_C, $_I, $_J, $K ; index pointers
Dim $_AddLine, $_NoRead ; Option Vars
Dim $_Sect ; Section Name
Dim $_aDat ; Data pair array
Dim $_aSect[1, 499], $_aData[1, 499] ; Section & Data Arrays
$_NoRead = 0 ; perform read after write
If $_Options
If $_Options & 1
$_AddLine = @CRLF
EndIf
If $_Options & 2
$_NoRead = 1 ; write & exit w/o re-reading
EndIf
EndIf
; Obtain a File Handle for Read or Write operations
; ============================================================
$_Fp = FreeFileHandle ; locate an available file handle
If Not $_Fp
Exit 1 ; none available - exit
EndIf
; WRITE: verify that we have properly formatted data
; ============================================================
If VarType($_aDataWrite) > 0 ; Write the array to the INI file and exit
If VarType($_aDataWrite) < 8192 ; data but not an array - exit!
Exit 87
EndIf
Del $_fSrcFile ; delete any pre-existing file
$_ = Open($_Fp, $_fSrcFile, 5) ; open the file for write/create
If @ERROR Exit @ERROR EndIf ; exit if error opening
; Write the section data. If no data exists in the section, do not write anything!
For $_I = 0 to UBound($_aDataWrite, 2)
$_Sect = $_aDataWrite[0, $_I] ; Section name to write
$_aData = $_aDataWrite[1, $_I] ; Data array
If UBound($_aData, 2) > -1 ; create Sect and write data if data is present
$_ = '[' + $_Sect + ']' + @CRLF ; section name
$_C = 0
For $_J = 0 to UBound($_aData, 2) ; key/data pairs
If $_aData[1, $_J] ; only write keys that have non-null data
$_C = 1
$_ = $_ + $_aData[0, $_J] + '=' + $_aData[1, $_J] + @CRLF
EndIf
Next
If $_C
$_ = WriteLine($_Fp, $_ + $_AddLine) ; write the output line
EndIf
If @ERROR
$_ = Close($_Fp) ; close the file
Exit @ERROR
EndIf ; exit if error writing
EndIf
Next
$_ = Close($_Fp) ; close the file
ReDim $_aData[1, 0] ; clear array
If $_NoRead
exit 0 ; exit here without a re-read of the freshly written data
EndIf
EndIf
; READ: Load the ini file into an array
; ============================================================
$_I = -1 $_J = -1 ; Initialize index pointers
$_ = Open($_Fp, $_fSrcFile, 2) ; open the file for read
If @ERROR
ReDim $_aSect[1, 0]
ReDim $_aData[1, 0]
$_aSect[1, 0] = $_aData
$IniArray = $_aSect ; return an empty array
Exit @ERROR ; exit if error opening
EndIf
ReDim $_aSect[1, 499], $_aData[1, 499] ; Prep Section & Data Arrays for Read
$_ = Trim(ReadLine($_Fp)) ; remove leading/trailing spaces
While Not @ERROR ; loop through the file contents
If Left($_, 1) = '[' ; found a section
If $_I >= 0 ; process prior section data, if any
If $_J >= 0
ReDim Preserve $_aData[1, $_J] ; trim data array to size
$_aSect[1, $_I] = $_aData
ReDim $_aData[1, 499] ; create the
$_J = -1
Else
$_I = $_I - 1 ; ignore empty sections
EndIf
EndIf
$_I = $_I + 1 ; increment the section index
If $_I Mod 499 = 0 And $_I > 0
ReDim Preserve $_aSect[1, $_I + 500]
EndIf
$_aSect[0, $_I] = Split(SubStr($_, 2), ']')[0]
Else
If Not InStr(';#', Left($_, 1)) And Len($_) > 2
$_aDat = Split($_, '=') ; break into array
If UBound($_aDat) > 1 ; does data have embedded = signs?
$_ = $_aDat[1]
For $K = 2 to UBound($_aDat) ; extract them into a single value
$_ = $_ + '=' + $_aDat[$K]
Next
$_aDat[1] = $_
ReDim Preserve $_aDat[1]
EndIf
$_J = $_J + 1 ; increment the data index
If $_J Mod 499 = 0 And $_J > 0
ReDim Preserve $_aData[1, $_J + 500]
EndIf
$_aData[0, $_J] = $_aDat[0] ; Store the value
$_aData[1, $_J] = $_aDat[1] ; Store the data
EndIf
EndIf
$_ = Trim(ReadLine($_Fp)) ; remove leading/trailing spaces
Loop ; done with input data
$_ = Close($_Fp) ; close the file
$_ = 2 ; prep for Not Found exit
; process the last/only section
If $_I >= 0
If $_J >= 0
ReDim Preserve $_aData[1, $_J] ; trim data array to size
$_aSect[1, $_I] = $_aData
Else
ReDim Preserve $_aData[1, 0]
$_aSect[1, $_I] = $_aData
EndIf
ReDim Preserve $_aSect[1, $_I] ; trim section array to size
$_ = 0
EndIf
$IniArray = $_aSect ; return the array
Exit $_ ; exit success
EndFunction
Function ReadIniArray($_aIniFile, OPTIONAL $_Section, OPTIONAL $_Key)
; exit immediately if the data format is invalid
If VarType($_aIniFile) < 8192 ; data but not an array - exit!
Exit 87
EndIf
Dim $_aSectIdx[UBound($_aIniFile, 2)] ; Section Index Array
Dim $_I, $_J ; Index pointers
Dim $_aData ; Array of Key/Data pairs
; Create a section index array
For $_I = 0 to UBound($_aIniFile, 2)
$_aSectIdx[$_I] = $_aIniFile[0, $_I]
Next
; If the Section is null, return a delimited string of Sections [same as ReadProfileString(file)]
If Not $_Section
$ReadIniArray = Join($_aSectIdx, Chr(10))
Exit 0
EndIf
; Search the index for a section
$_I = aScan($_aSectIdx, $_Section)
If $_I < 0 Exit 2 EndIf ; section not found - Exit
$_aData = $_aIniFile[1, $_I] ; Extract the key/value array
; Create a Key index for the requested section
Dim $_aKeyIdx[UBound($_aData, 2)]
For $_J = 0 to UBound($_aData, 2)
$_aKeyIdx[$_J] = $_aData[0, $_J]
Next
; If the Key is null, return a delimited string of Keys [same as ReadProfileString(file, section)]
If Not $_Key
$ReadIniArray = Join($_aKeyIdx, Chr(10))
Exit 0
EndIf
; Search the index for a Key
$_J = aScan($_aKeyIdx, $_Key)
If $_J < 0 Exit 2 EndIf ; Key not found
$ReadIniArray = $_aData[1, $_J]
Exit 0
EndFunction
Function WriteIniArray($_aIniFile, $_Section, OPTIONAL $_Key, OPTIONAL $_Data)
; exit immediately if the data format is invalid
If VarType($_aIniFile) < 8192 ; data but not an array - exit!
Exit 87
EndIf
Dim $_aSectIdx[UBound($_aIniFile, 2)] ; Section Index Array
Dim $_I, $_J ; Index pointers
Dim $_aData ; Key/Data array
; Create a section index array
For $_I = 0 to UBound($_aIniFile, 2)
$_aSectIdx[$_I] = $_aIniFile[0, $_I]
Next
; Search the index for a section
$_I = aScan($_aSectIdx, $_Section)
; If the section does not exist and Keydata is present - add the section and key/value pair (new Sect:Key:Data)
If $_I < 0 ; section not found - Add if Data is present
If $_Key And $_Data
$_I = 0 ; default to empty array
If $_aIniFile[0, 0]
$_I = UBound($_aIniFile, 2) + 1 ; find next section index
EndIf
ReDim Preserve $_aIniFile[1, $_I] ; Add new section
ReDim $_aData[1, 0] ; create data array
$_aData[0,0] = $_Key ; key
$_aData[1,0] = $_Data ; data
$_aIniFile[0, $_I] = $_Section ; section name
$_aIniFile[1, $_I] = $_aData ; section data
Else
Exit 0 ; nothing to do
EndIf
Else ; the section does exist, locate the Key
; If the Key is null, delete the section (delete Section)
If Not $_Key
ReDim $_aData[1, 0] ; create empty keys array
$_aIniFile[1, $_I] = $_aData ; write to section
$_aIniFile[0, $_I] = '' ; write null section name
Else
$_aData = $_aIniFile[1, $_I] ; Extract the key/value array
; Create a Key index for the requested section
Dim $_aKeyIdx[UBound($_aData, 2)]
For $_J = 0 to UBound($_aData, 2)
$_aKeyIdx[$_J] = $_aData[0, $_J] ; create the index
Next
$_J = aScan($_aKeyIdx, $_Key) ; find the key
; If the key does not exist, add the key/data (new Key/data)
If $_J < 0
If $_Data
$_aData = $_aIniFile[1, $_I] ; array of key/data pairs
$_J = UBound($_aData, 2) + 1 ; find next key index
ReDim Preserve $_aData[1, $_J] ; create data array
$_aData[0, $_J] = $_Key ; key
$_aData[1, $_J] = $_Data ; data
$_aIniFile[1, $_I] = $_aData ; section data
Else
$WriteIniArray = $_aIniFile ; return original array
Exit 0 ; nothing to do (no data)
EndIf
Else ; the key exists - either Update or Delete
; if the data is not null, write the new data (update key)
If $_Data
$_aData[1, $_J] = $_Data
; If the data is null, write empty key and data values (delete key)
Else
$_aData[0, $_J] = '' ; delete key
$_aData[1, $_J] = '' ; clear data value
EndIf
$_aIniFile[1, $_I] = $_aData ; update the array
EndIf
EndIf
EndIf
$WriteIniArray = $_aIniFile
Exit 0
EndFunction
|
Top
|
|
|
|
#212596 - 2017-07-15 02:17 AM
Re: Best Procedure for using server names in script
[Re: Allen]
|
Glenn Barnas
KiX Supporter
Registered: 2003-01-28
Posts: 4396
Loc: New Jersey
|
When I teach my scripting class, one of the guidelines is to consider your data elements, plan how they are organized, then write the code to load, manipulate, and then possibly write/update the results.
I do this with every script no matter how simple. For Kix, I create the INI file to hold and manage my data before the script writing begins. Next, I write the script header and fill out blocks of comments to describe each processing component. Finally, I flesh out the logic, block by block, testing as I go. Takes a bit longer to complete development, but I'm using Kix scripts to perform monitoring, maintenance, and alert processing for thousands of endpoints.
FYI - the IniArray is slightly slower than direct reads, which is why I don't use it in my login script (where performance must parallel reliability), but most other applications that have more than a section or two do use it. LARGE (over 64K) INI files do read slowly, but there's no other way to use them. Allen's got some pretty large INI files he manages with this UDF.
Glenn
_________________________
Actually I am a Rocket Scientist!
|
Top
|
|
|
|
#212603 - 2017-07-21 01:40 PM
Re: Best Procedure for using server names in script
[Re: Robdutoit]
|
Glenn Barnas
KiX Supporter
Registered: 2003-01-28
Posts: 4396
Loc: New Jersey
|
Something like this:[Drive G]
PATH=\\server\folder
NAME=The cool kids share
DISK=G:
GROUPS=group1,group2 Repeat as needed.
Then, simple ReadProfileString() functions are all you need.
; Get a list of drive mappings from the INI file
$aMappings = Splic(ReadProfileString('config.ini', '', ''), Chr(10))
For Each $Map in $aMappings
$Path = ReadProfileString('config.ini', $Map, 'PATH')
$DISK = ReadProfileString('config.ini', $Map, 'DISK')
; Get list of groups
$Grps = ReadProfileString('config.ini', $Map, 'GROUPS')
$OK = 1 ; OK to map this resource
If $Grps ; if Grps is defined, check for membership
If Not InGroup($Grps)
$OK = 0 ; not a member, so NOT OK
EndIf
EndIf
If $OK ; OK to map resource
USE $Disk $Path
EndIf
Next This is somewhat oversimplified - could use error checking, logging, user messages, etc, but this is the basic premise of using external data. Using a more advanced drive mapping UDF will allow you to use the NAME parameter as the mapped drive description, which is why I added it. These UDFs provide much more control and enhanced features compared to the Use command.
There are UDFs available that will read the INI and return a list of sections, but that's basically what the first step does - the list of drive mappings can then be enumerated easily and each processed one at a time.
You should never worry about the size of a UDF - it does the job and you should never modify it - just add it to your code. I write simple scripts with just 10-15 lines of actual logic, then KGen identifies and includes all the UDFs that I used and the script becomes 1000+ lines - so what? I never look at the UDFs once they are written and placed into a script.
As for "@DOMAIN", that will reference your DC, not a file server. Putting shares on a DC is a significant security risk. DCs should be small systems that provide security and DNS services ONLY. We don't install any apps (like Acrobat, Zip/rar, net scan), services (no DHCP even!), or other non-security roles. IAS/RADIUS is one of the only features we might add to a DC. When we bring on a new client, we clean up the DC to meet security standards, as more and more companies are being audited by their customers to identify and mitigate risk of data breach. A dedicated file and app server and a few hours of consulting time is much less expensive than losing a client or dealing with a data breach.
Glenn
_________________________
Actually I am a Rocket Scientist!
|
Top
|
|
|
|
Moderator: Jochen, Allen, Radimus, Glenn Barnas, ShaneEP, Ruud van Velsen, Arend_, Mart
|
0 registered
and 557 anonymous users online.
|
|
|