#195492 - 2009-08-20 06:44 PM
Script to install printer based on IP is not running on logon
|
getelevated
Fresh Scripter
Registered: 2009-08-20
Posts: 8
Loc: Boston
|
Hello,
I have a portion of a script that is not working as expected. The script installs printers based on IP address and I got it from this thread: http://www.kixtart.org/forums/ubbthreads.php?ubb=showflat&Number=195486&fpart=1 (thanks Glenn). It was very helpful for a customer office move that we just went through.
We put the script together and during our testing all of the printers were installed flawlessly on each subnet. But now that the move has been completed there is one strange issue. When the users first log on, the script starts to run and the "No printers were mapped!" comment appears. But the users should have received at least one printer. Now here's the tricky part; if I manually run the kix script when the user is logged in (going to the sysvol share via command line) the printers get mapped correctly. Any ideas?
Here is the script, stating with the select state for the AD site that this office is in. Everything works but the printer install on login:
CASE @Site = "ADSITE"
? "Logging in from Site"
WriteValue("Software\Microsoft\Windows\CurrentVersion\Internet Settings", "MaxConnectionsPerServer", "6", "REG_DWORD")
; Map S drive for application
use s: "\\DC1\Applications\APPS"
SELECT
CASE INGROUP("Facilities")
use g: "\\DC2\Facilities"
CASE INGROUP("Technology")
use g: "\\DC2\Tech"
CASE INGROUP("Call Center")
use g: "\\DC2\TSR"
CASE INGROUP("Finance")
use g: "\\DC2\Finance"
CASE INGROUP("Operations")
use g: "\\DC2\Operations"
CASE INGROUP("Human Resources")
use g: "\\DC2\HumanResources"
CASE INGROUP("Employee Development")
use g: "\\DC2\Corporate Training"
CASE INGROUP("Marketing")
use g: "\\DC2\MKT"
ENDSELECT
IF INGROUP("Group1")
use U: "\\server\drive"
ENDIF
IF INGROUP("Group1")
use I: "\\DC2\Intranet"
use w: "\\Intranet\Documents"
ENDIF
IF INGROUP("Case Files")
use r: /delete
use r: "\\server6\share"
ENDIF
; Copy file to user directory to run script once
IF EXIST ("%appdata%\Microsoft\printers.txt")
; do nothing
ELSE
copy "\\DC2\PrintTemp$\printers.txt" "%appdata%\Microsoft\printers.txt" /c
sleep 2
; Delete all existing Network Printer Connections
function DelPrinterConnections()
dim $c,$bk,$conn
$c=0
$bk="HKEY_CURRENT_USER\Printers\Connections"
$conn=enumkey($bk,$c)
while @error=0
$c=$c+0
$conn=delkey($bk+"\"+$conn)
$conn=enumkey($bk,$c)
loop
endfunction
DelPrinterConnections()
; Install new printers based on workstation subnet
; Break On
; Uses an INI file for subnet/printer mapping
; The INI file in this example is called NetPrint.ini, and uses one section
; called MAPPINGS. Each value consists of a comma-delimited pair of data
; representing the network/mask and printer share UNC in the format
; sitename=w.x.y.z/mask,\\server\printer
$Mapped = 0 ; value showing that printer was not mapped
$MyIP = Join(Split(@IPADDRESS0, ' '), '') ; Get the local IP address, removing spaces
; Load an array from the INI file
$Mappings = EnumIni('.\netprint.ini', 'MAPPINGS')
For Each $SiteName in $Mappings
; create a 2-element array by splitting the data at the comma
; element 0 contains the network/mask, and element 1 contains the printer UNC
$NetPrint = Split(ReadProfileString('.\netprint.ini', 'MAPPINGS', $SiteName), ',')
; see if the local IP is inside the network
If InSubnet($MyIP, $NetPrint[0])
; these print statements are for diagnostic/testing
? 'My ip address (' $MyIP ') exists in the ' $SiteName ' site (' $NetPrint[0] ')' ?
? 'Mapping printer ' $NetPrint[1] ?
; make the printer connection
AddPrinterConnection($NetPrint[1])
; show that at least 1 printer mapped successfully
If Not @ERROR
$Mapped = 1
EndIF
EndIF
Next
If Not $Mapped
? 'No printers were mapped!' ?
EndIf
; do not modify anything after this line!!!
;;
;;======================================================================
;;
;;FUNCTION InSubnet()
;;
;;ACTION Determines if a specific IP address is in a subnet
;;
;;AUTHOR Glenn Barnas
;;
;;VERSION 1.0 / 2008/01/20
;;
;;SYNTAX InSubnet(Address, Network)
;;
;;PARAMETERS Address - REQUIRED, IP address in dotted-decimal (w.x.y.z)
;;
;; Network - REQUIRED, Network in CIDR format (w.x.y.z/mask)
;;
;;REMARKS
;;
;;RETURNS 1 if ip address is in the defined subnet, 0 otherwise
;;
;;DEPENDENCIES none
;;
;;TESTED WITH W2K, WXP, W2K3, Vista, X64
;;
;;EXAMPLES If InSubnet('192.168.12.243', '192.168.8.0/21')
;; 'Is in subnet!' ?
;; EndIf
;
Function InSubnet($_IPAddr, $_Network)
Dim $_aAdd ; array of address values
Dim $_Mask ; Mask value
Dim $_Hosts ; hosts in subnet
; Convert the supplied IP address to a double value representing the decimal address
$_aAdd = Split($_IPAddr, '.')
$_IPAddr = (CDbl($_aAdd[0]) * 16777216.0) + (CDbl($_aAdd[1]) * 65536.0) + (CDbl($_aAdd[2]) * 256.0) + (CDbl($_aAdd[3]) * 1.0)
; Convert the network from a w.x.y.z/mask format to a decimal value
; this is the starting network address value
$_Network = Split($_Network, '/')
$_Mask = Val($_Network[1])
$_aAdd = Split($_Network[0], '.')
$_Network = (CDbl($_aAdd[0]) * 16777216.0) + (CDbl($_aAdd[1]) * 65536.0) + (CDbl($_aAdd[2]) * 256.0) + (CDbl($_aAdd[3]) * 1.0)
; Set the number of hosts in the defined network
$_Hosts = 1.0
For $_I = 31 to $_Mask Step -1
$_Hosts = ($_Hosts * 2.0)
Next
; return the value
$InSubnet = 0
If $_IPAddr >= $_Network And $_IPAddr < ($_Network + $_Hosts)
$InSubnet = 1
EndIf
Exit 0
EndFunction
;;
;;======================================================================
;;
;;FUNCTION EnumIni()
;;
;;ACTION Enumerates sections or keys of an INI file
;;
;;AUTHOR Glenn Barnas
;;
;;VERSION 2.0
;;
;;DATE CREATED 2003/11/17
;;
;;DATE MODIFIED 2004/10/16
;;
;;SYNTAX EnumIni(File [, Section])
;;
;;PARAMETERS File - REQUIRED, path/name of INI file to examine
;;
;; Section - OPTIONAL, Section name to parse
;;
;;REMARKS Returns an array containing the sections in an INI file, or
;; an array of key names in a specified section. Errors are returned
;; for non-existant files or INI file reads. If the specified file
;; contains no sections, or the specified section contains no keys,
;; the UDF exits with error 13 and returns a null array. Thus, a For-Each loop
;; will properly perform no iterations if no data is returned.
;;
;; CAUTION - Error 13 is returned for empty files, or nonexistant sections.
;; This is not necessarily a "failure".
;;
;;RETURNS Array of sections or keys in a section
;;
;;DEPENDENCIES none
;;
;;TESTED WITH Kix 4.2+, NT4, W2K, WXP, W2K3
;;
;;EXAMPLES $Sections = EnumIni('.\config.ini')
;; $Keys = EnumIni('.\config.ini', 'Common')
;
Function EnumIni($_fSrcFile, OPTIONAL $_fSectName)
Dim $_fSectList
; die if the file doesn't exist
If Exist($_fSrcFile) = 0
Exit 2
EndIf
; Get the list of sections or keys
$_fSectList = ReadProfileString($_fSrcFile, $_fSectName, '')
; Return if error occurred
If @ERROR
Exit @ERROR
EndIf
; If len is >0, return an array of sections
; If len is 0, either no sections or keys exist, or an invalid section name was specified. Return nothing.
If Len($_fSectList) > 0
$EnumIni = Split(Left($_fSectList,len($_fSectList)-1), Chr(10))
Exit 0
EndIF
; return an error here for value not found (no sections or no keys in section)
Exit 13
EndFunction
ENDIF
|
|
Top
|
|
|
|
#195505 - 2009-08-21 02:02 PM
Re: Script to install printer based on IP is not running on logon
[Re: getelevated]
|
Glenn Barnas
KiX Supporter
   
Registered: 2003-01-28
Posts: 4403
Loc: New Jersey
|
I ran your code through KGen to get a Sanity and CodeMap report. Ignoring the "Undeclared Variable" warnings because I don't have your complete script, I got the following: Warning: Variable referenced inside string.
Variable Name: $
In function: Main
Referenced on line: 59
59: copy "\\DC2\PrintTemp$\printers.txt" "%appdata%\Microsoft\printers.txt" /c If you don't declare NoVarsInStrings, this could cause a problem copying the file. I assume this is some kind of tag file indicating that some task has completed. I'm not a big fan of this concept. Use a reg key something like SOFTWARE\MyCompany\StatusID:Value in HKLM or HKCU. Faster and less susseptible to user interaction.
CodeMap shows the following:000001: Main
000010: Select
000036: EndSelect
000038: IF INGROUP("Group1")
000040: EndIf
000042: IF INGROUP("Group1")
000045: EndIf
000047: IF INGROUP("Case Files")
000050: EndIf
000055: IF EXIST ("%appdata%\Microsoft
000063: Function: DelPrinterConnections
- WARNING: Open If when defining function. 1
<snip>
WARNING: 1 Unterminated If statement(s)! This is why I use KGen even for the simplest scripts..
Your If Exist is backwards, in addition to missing a closing EndIf. Since we're troubleshooting, change this to If Exist('%appdata%\Microsoft\printers.txt')
'Tag file exists - not mapping!'
Else
. . . That might provide a clue or three.. A better implementation (after the diagnostic process is complete) would beIf Not Exist('%appdata%\Microsoft\printers.txt') and eliminate the empty If clause.
I'm also troubled by your DelPrinterConnections logic. You enumerate the values in a registry key and delete them. Without creating and then deleting a bunch of registry keys to test this, I'm going to simply discuss the illogicical part by commenting your code. My concerns are in ALL CAPSfunction DelPrinterConnections()
Dim $C, $Bk, $Conn ; Declare index pointer, BaseKey, & Connection vars
$C=0 ; initialize index pointer
$Bk='HKEY_CURRENT_USER\Printers\Connections' ; initialize Base Key
$Conn = EnumKey($Bk,$C) ; locate the first subkey in the key
While @ERROR = 0 ; loop until EOF error
; SINCE WE ARE ADDING NOTHING TO NOTHING, WHAT'S THE POINT OF $C??
$C = $C + 0 ; increment pointer - BUT NOT REALLY!!!
; REUSING AN ACTIVE VARIABLE CAN BE DANGEROUS - DECLARE AND USE $RC INSTEAD
$Conn = DelKey($bk + '\' + $Conn) ; Delete the key
; HERE'S MY REAL CONCERN. YOU JUST DELETED KEY 0, AND NOW YOU'RE ENUMERATING KEY 0.
; A. IT DOESN'T EXIST, SO RETURNS AN ERROR AND THE FUNCTION EXITS, DELETING ONLY ONE PRINTER KEY
; B. THE SECOND KEY MOVES UP TO BE ENUMERATED IN POSITION 0. IF THIS IS THE CASE, REMOVE THE
; "$C = $C + 0" LINE, THE $C DECLARATION, AND REPLACE ALL OTHER REFERENCES TO $C WITH 0 (ZERO)
$Conn = EnumKey($Bk, $C) ; Enumerate the NEXT?? key ? ? ? ? ? ?
Loop
EndFunction Glenn
_________________________
Actually I am a Rocket Scientist!
|
|
Top
|
|
|
|
#195552 - 2009-08-24 04:56 PM
Re: Script to install printer based on IP is not running on logon
[Re: Glenn Barnas]
|
getelevated
Fresh Scripter
Registered: 2009-08-20
Posts: 8
Loc: Boston
|
Thanks for the reply Glenn.
The text copy portion of the script is working, both on initial logon and if I manually run the script. The If statement is closed, that ENDIF is just not included in the portion I pasted above. That's the only portion of the script that I know is working, since I routinely remove that text file for testing.
The printer deletion script came from here: http://www.kixtart.org/forums/ubbthreads.php?ubb=showflat&Number=142166&site_id=1#import but now that you mention it, the +0 enumeration does not make much sense (I blame my lack of caffeine and trying to put together a script made up of bits and pieces from other posts...)
Anyway, aside from the errors in the Deletion portion of the script that doesn't solve my problem. I have commented out that portion of the script in testing and it still does not correctly run during the logon process. But it does work fine when run manually. I still end up with just the No Printers Mapped result, but when the script is run from the command line it maps as it should. I'm trying to figure out where the issue may lie but I'm having trouble since it works manually.
Regards, Conor
|
|
Top
|
|
|
|
#195553 - 2009-08-24 05:38 PM
Re: Script to install printer based on IP is not running on logon
[Re: getelevated]
|
Glenn Barnas
KiX Supporter
   
Registered: 2003-01-28
Posts: 4403
Loc: New Jersey
|
When I encouner unusual things like this, I break the code down into smaller chunks and add diag messages. Simple things, like printing out section numbers so I know where a process is, to displaying values of variables - even when I think I know what they are - er - should be! While unlikely, it's possible that the environment was not set when Kix ran during logon but is later when run from the command prompt. Display the content of the %appdata% variable, and the @IPADDRESS as well - are they valid? Do they contain what you expect?
The $C=0+0 was discussed in the thread you referenced, but incrementing by 0.5 is not correct. As I thought, the values move up when one is deleted, so referencing zero all the time is correct.
Unless you've cut and pasted many separate sections of code into your example, you're EndIf is either missing or out of place. You should have an EndIf before any of the functions start, and not later on in the code. Also, while valid, placing functions inline with your code makes the application more difficult to troubleshoot - especially when they are within other code pairs like loops or If/Endifs. Put all your functions first or last. I create my core code, then include functions dedicated to the script, and then those that are from the shared-code library. Not right or wrong, just helps maintain hairs in your head.
Glenn
_________________________
Actually I am a Rocket Scientist!
|
|
Top
|
|
|
|
#195554 - 2009-08-24 06:13 PM
Re: Script to install printer based on IP is not running on logon
[Re: Glenn Barnas]
|
getelevated
Fresh Scripter
Registered: 2009-08-20
Posts: 8
Loc: Boston
|
Good points. I'll start with the @IPAddress as I think that's where the issue is.
Thanks for the suggestions. It's been a while since I've done this much with Kix and I appreciate the input. I'll let you know how it goes.
|
|
Top
|
|
|
|
#195558 - 2009-08-24 10:23 PM
Re: Script to install printer based on IP is not running on logon
[Re: Glenn Barnas]
|
getelevated
Fresh Scripter
Registered: 2009-08-20
Posts: 8
Loc: Boston
|
I did some testing with printing the variables to the screen. I think the problem is here:
For Each $SiteName in $Mappings
; create a 2-element array by splitting the data at the comma
; element 0 contains the network/mask, and element 1 contains the printer UNC
$NetPrint = Split(ReadProfileString('.\netprint.ini', 'MAPPINGS', $SiteName), ',')
; see if the local IP is inside the network
If InSubnet($MyIP, $NetPrint[0])
; these print statements are for diagnostic/testing
'My ip address (' $MyIP ') exists in the ' $SiteName ' site (' $NetPrint[0] ')' ?
'Mapping printer ' $NetPrint[1] ?
; make the printer connection
AddPrinterConnection($NetPrint[1])
; show that at least 1 printer mapped successfully
If Not @ERROR
$Mapped = 1
EndIF
EndIF
Next
When the user logs in initially, this doesn't run. I did a inside that For Each and it doesn't show on logon. It does show up and run correctly when run manually after the user logs in. Anyone seen this behavior before?
|
|
Top
|
|
|
|
#195562 - 2009-08-24 10:58 PM
Re: Script to install printer based on IP is not running on logon
[Re: Gargoyle]
|
getelevated
Fresh Scripter
Registered: 2009-08-20
Posts: 8
Loc: Boston
|
It's the result of another function. That detail is below, but it's in full context in my first post in the thread.
$Mappings = EnumIni('.\netprint.ini', 'MAPPINGS')
;;
;;======================================================================
;;
;;FUNCTION EnumIni()
;;
;;ACTION Enumerates sections or keys of an INI file
;;
;;AUTHOR Glenn Barnas
;;
;;VERSION 2.0
;;
;;DATE CREATED 2003/11/17
;;
;;DATE MODIFIED 2004/10/16
;;
;;SYNTAX EnumIni(File [, Section])
;;
;;PARAMETERS File - REQUIRED, path/name of INI file to examine
;;
;; Section - OPTIONAL, Section name to parse
;;
;;REMARKS Returns an array containing the sections in an INI file, or
;; an array of key names in a specified section. Errors are returned
;; for non-existant files or INI file reads. If the specified file
;; contains no sections, or the specified section contains no keys,
;; the UDF exits with error 13 and returns a null array. Thus, a For-Each loop
;; will properly perform no iterations if no data is returned.
;;
;; CAUTION - Error 13 is returned for empty files, or nonexistant sections.
;; This is not necessarily a "failure".
;;
;;RETURNS Array of sections or keys in a section
;;
;;DEPENDENCIES none
;;
;;TESTED WITH Kix 4.2+, NT4, W2K, WXP, W2K3
;;
;;EXAMPLES $Sections = EnumIni('.\config.ini')
;; $Keys = EnumIni('.\config.ini', 'Common')
;
Function EnumIni($_fSrcFile, OPTIONAL $_fSectName)
Dim $_fSectList
; die if the file doesn't exist
If Exist($_fSrcFile) = 0
Exit 2
EndIf
; Get the list of sections or keys
$_fSectList = ReadProfileString($_fSrcFile, $_fSectName, '')
; Return if error occurred
If @ERROR
Exit @ERROR
EndIf
; If len is >0, return an array of sections
; If len is 0, either no sections or keys exist, or an invalid section name was specified. Return nothing.
If Len($_fSectList) > 0
$EnumIni = Split(Left($_fSectList,len($_fSectList)-1), Chr(10))
Exit 0
EndIF
; return an error here for value not found (no sections or no keys in section)
Exit 13
EndFunction
|
|
Top
|
|
|
|
#195590 - 2009-08-25 04:40 PM
Re: Script to install printer based on IP is not running on logon
[Re: Glenn Barnas]
|
getelevated
Fresh Scripter
Registered: 2009-08-20
Posts: 8
Loc: Boston
|
The netprint.ini file was it. The .\netprint.ini call was failing on login. I added the UNC path and it worked. Thanks for the help.
I do know the script maps from AD Sites, OU, Group, etc as I am using that extensively throughout the rest of the script. I didn't know that it worked by subnet but I'll check part out.
Thanks again!
|
|
Top
|
|
|
|
Moderator: Jochen, Allen, Radimus, Glenn Barnas, ShaneEP, Ruud van Velsen, Arend_, Mart
|
0 registered
and 2870 anonymous users online.
|
|
|