#197989 - 2010-03-06 02:34 AM
Critique My Logon Script
|
cjutting
Fresh Scripter
Registered: 2010-02-05
Posts: 40
Loc: IA
|
Hey Guys. I'm building a kixtart script for a client and so far so good. Just want someone to take a look over it and maybe suggest where i could improve on. Also if anybody could lend a hand with maybe building in some error checking and reporting so if a drive doesn't map or if a printer doesn't map or set as default. Been looking through the forums here and not seeing alot of error reporting.
Anyways On to the Script:
;Current In Use Drive Letters
; C, D, K, L, P, R, U, V
; Note each time who changed this script and why
;****************************************************************
; Declare Variables Here:
$kixlib = @ldrive\UDF
call $kixlib + "\wshortcut.udf"
;******************************************************************
; Domain Type Mappings
; All Domain Users Get These Drives
if ingroup ("Domain Users")
use y: "\\server12\committee$"
use p: "\\server12\public$"
use u: "\\server12\"+@userid+"$$"
endif
;Super User Access
if ingroup ("SuperUsers")
use h: "\\server12\home$"
use i: "\\server12\departments$"
endif
;AC users
if ingroup ("Acute")
use m: "\\server12\acute$"
endif
;Administration
if ingroup ("Administration")
use m: "\\server12\administration$"
endif
;BO Mappings
if ingroup ("Business Office")
use m: "\\server12\business office$"
endif
;Pharmacy
if ingroup ("Pharmacy")
use m: "\\server12\pharmacy$"
endif
; End Drive Mappings
;*************************************************************************
;Set Screen Resolution
if ingroup ("Display")
if 0=exist ("C:\MultiRes.exe")
copy "\\@ldrive\multires.exe" "C:\"
endif
run "C:\multires.exe /1024,768,32,75 /exit"
endif
;**************************************************************************
;Printer Mappings For PC's
$computerprt = left (@wksta, 3)
select
case $computerprt = "ACU"
AddPrinterConnection ("\\server07\main")
case $computerprt = "AWC"
AddPrinterConnection ("\\server07\reception")
case $computerprt = "BO-"
AddPrinterConnection ("\\server07\BusinessOffice")
case $computerprt = "HIM"
AddPrinterConnection ("\\server07\HIM-Main")
case $computerprt = "LAB"
AddPrinterConnection ("\\server07\Lab")
endselect
;***************************************************************************
;Check If Current Paragon Installed
if 0=exist ("C:\Program Files\Client93")
run "\\server\client software\installclient.bat"
endif
if 0=exist ("C:\UpdatesInstalled.txt")
run "\\server\client software\patches.bat"
endif
;***************************************************************************
; All of the Stuff needed for the training pc's
$training = @hostname
Select
; CA Test Drive Mappings
case INSTR($training,"trainingpc")
? "Training PC"
use r: /del
use r: "\\server11\testclm"
use v: /del
use v: "\\server11\testdata"
; Add training Printer
AddPrinterConnection ("\\server2\training")
endselect
exit
Edited by cjutting (2010-03-06 03:04 AM)
|
Top
|
|
|
|
#197994 - 2010-03-07 12:37 PM
Re: Critique My Logon Script
[Re: cjutting]
|
Mart
KiX Supporter
Registered: 2002-03-27
Posts: 4672
Loc: The Netherlands
|
Three suggestions that pop up while browsing through your script.
- You are mapping drives based an group membership. Sure you can just map every time but if the drive is already mapped remapping it will fail. Users can also unmap and map a letter to a different share. This can screw up things that rely on a drive being mapped to a certain share. Deleting the drive before mapping would be better and safer. What I do is check if the drive exists, if it does check the path it maps to and delete and map or leave it alone depending on the results. This way all drives are always mapped to the correct share.
- The AddPrinterConnection function will return the results of mapping the printer. In your script it show the results on the screen. Might be a bit messy. Doing it like this way $rc = AddPrinterConnection(bla.....) all return codes are stuffed in the $rc variable. It acts like a garbage can collecting all unwanted screen output. Off course you can use any name you like for the variable. I use $rc as it stands for Return Code in my scripting book. For printermapping the same things goes as for drive mapping. Checking it delting and mapping or leave it alone if all is ok would be safer.
- For the screen resolution you do If 0 = exist(bla....) You could also just do if exist(bla....)
As for error checking I use a setup like below. First I start a small script that checks and creates new log files.
;Set name for text log file.
$txtlog = "c:\logfolder\txtlog.txt"
;Set name for ini log file.
$inilog = "c:\logfolder\inilog.ini"
;Check if and old text log exists.
If Exist( "c:\logfolder\txtlog.txt")
;Delete old text log.
Del "c:\logfolder\txtlog.txt"
;Create new empty text log by opening a file for writing and creating one if none exists.
$rc = Open(1, "c:\logfolder\txtlog.txt", 5)
;Close new empty text log.
$rc = Close(1)
Else
;Create new empty text log by opening a file for writing and creating one if none exists.
$rc = Open(1, "c:\logfolder\txtlog.txt", 5)
;Close new empty text log.
$rc = Close(1)
EndIf
;Check if and old ini log exists.
If Exist( "c:\logfolder\inilog.txt")
;Delete old ini log.
Del "c:\logfolder\inilog.txt"
;Create new empty ini log by opening a file for writing and creating one if none exists.
$rc = Open(1, "c:\logfolder\inilog.txt", 5)
;Close new empty ini log.
$rc = Close(1)
Else
;Create new empty ini log by opening a file for writing and creating one if none exists.
$rc = Open(1, "c:\logfolder\inilog.txt", 5)
;Close new empty ini log.
$rc = Close(1)
EndIf
Then my scripts run and write stuff to the error logs if something goes wrong.
;Write entry to log files if an error occurs.
;Read current number of errors from ini log and add 1.
$errornumber = ReadProfileString($inilog, "Errors", "NumberOfErrors") + 1
;Write new number of errors to ini based log file.
$rc = WriteProfileString($inilog, "Errors", "NumberOfErrors", $errornumber)
;Write entry in the text based log file.
$rc = WriteLog($txtlog, @WKSTA + ". User ID: " + @USERID + ". IP address: " + @IPADDRESS0 + ". - ERROR: ERROR TEXT GOES HERE.", 1)
When all scripts are done I run a small script that checks for errors and notifies IT by e-mail of there are more the 0 errors. It adds the text log file to the e-mail.
;All scripts are done. Check for errors and notify IT if there are more then 0 errors.
$errornumber = ReadProfileString($inilog, "Errors", "NumberOfErrors")
If $errornumber <> "" And $errornumber <> "0"
;Set a sender address
$Sender = "name@@domian.com"
;Set a recipient address.
$Recipients = "name@@domain.com"
;Set the subject.
$Subject = '"Report - Logon script error on: ' + @WKSTA + '"'
;Set an attachment.
$Attachment = '"' + $txtlog + '"'
;SMTP server to be used for sending the message.
$smtpserver = "mailserver"
;Create the body text.
$Body = '"Logon script error on: ' + @WKSTA + '.' + @CRLF + @CRLF +
$mdayno + '-' + $monthno + '-' + @YEAR + ' @@ ' + @TIME + @CRLF +
$mdayno + '-' + $monthno + '-' + @YEAR + ' @@ ' + @TIME + ' ERROR - Number of logon errors that occured during this session: ' + $errornumber + '.' + @CRLF +
$mdayno + '-' + $monthno + '-' + @YEAR + ' @@ ' + @TIME + ' User ID: ' + @USERID + ' - ' + @FULLNAME + '.' + @CRLF +
$mdayno + '-' + $monthno + '-' + @YEAR + ' @@ ' + @TIME + ' System ID: ' + @WKSTA + '.' + @CRLF +
$mdayno + '-' + $monthno + '-' + @YEAR + ' @@ ' + @TIME + ' IP address: ' + @IPADDRESS0 + '.' + @CRLF +
$mdayno + '-' + $monthno + '-' + @YEAR + ' @@ ' + @TIME + ' OS name: ' + @PRODUCTTYPE + '.' + @CRLF +
$mdayno + '-' + $monthno + '-' + @YEAR + ' @@ ' + @TIME + ' OS servicepack level: ' + @CSD + '.' + @CRLF + '"'
;Send the message.
$Send = BlatMailer($Recipients, $Sender, $Subject, $Body, $Attachment, $smtpserver)
Else
;No errors occurred. Do nothing.
EndIf
This requires two UDF's and Blat.exe. Blat can be downloaded for free from many sites. If you Google on Blat.exe there will be lots of links to download it.
Writelog UDF:
;FUNCTION WriteLog()
;
;AUTHOR
; Howard A. Bullock (hbullock@tycoelectronics.com)
;
;ACTION
; Generic logging facility for scripts. Appends log entry to a file with an optional TimeStamp.
;
;SYNTAX
; WriteLog($File, $text, [0|1])
;
;PARAMETERS
; $file (Required) - String value
; $text (Required) - String value
; $TimeStamp (Optional) Default(0) no TimeStamp (1 or 0)
;
;REMARKS
; This function writes (appends) an optionally time stamped log entry to the file defined in function.
; This function searches for the first unused file handle, open the file, and write the entry. T he file handle
; is then closed. When the function is unable to perform its it write the error is displayed&nbs p;in a message box.
;
;RETURNS
; Nothing
;
;DEPENDENCIES
; None
;
;EXAMPLES
; WriteLog("junk.txt","This is a test")
; WriteLog("junk.txt","This is a test",0)
; WriteLog("junk.txt","This is a test",1)
;
Function WriteLog($File, $Text, optional $TimeStamp)
Dim $rc, $fh
$fh = 1
$rc = Open($fh, $file, 5)
While $rc = -3
$fh = $fh + 1
$RC = Open($fh, $file, 5)
Loop
Select
Case $rc = 0
If ($timestamp = 1)
$timestamp = @Date + " @@ " + @Time + " - "
Else
$timestamp = ""
EndIf
$rc = WriteLine($fh, $timestamp + $text + @CRLF)
$rc = Close($fh)
Case $rc = -2
$text = "WriteLog: Invalid file handle " + $fh + " specified when trying to open " $file + "."
$rc = MessageBox($text, "Script Error", 48)
Case $rc = -1
$text = "WriteLog: Invalid file name " + $file + " specified for log file."
$rc = MessageBox($text, "Script Error", 48)
Case $rc = > 0
$text = "System Error " + $rc + " while attempting to open log file " + $File + "."
$rc = MessageBox($text, "Script Error", 48)
EndSelect
EndFunction
and the BlatM ailer UDF.
Function BlatMailer($Recipient,$Sender,$Subject,$Body,$Attachment,$smtpserver)
Dim $MailerLine
$MailerLine= 'path to blat.exe\blat.exe -' + ' -to ' + $recipient + ' -f ' + $sender + ' -subject ' + $subject + ' -body ' + $body + ' -Attach ' + $Attachment + ' -server ' + $smtpserver + ' -q '
Shell $MailerLine
EndFunction
_________________________
Mart
- Chuck Norris once sold ebay to ebay on ebay.
|
Top
|
|
|
|
#197995 - 2010-03-07 03:50 PM
Re: Critique My Logon Script
[Re: Mart]
|
cjutting
Fresh Scripter
Registered: 2010-02-05
Posts: 40
Loc: IA
|
Thanks for your input Mart. Couple of questions so I understand what your telling me.
Start with the printers.
What you are suggesting is:
if ingroup ("BO-")
$rc = AddPrinterConnection ("\\server\Business Office")
endif
Also interested in seeing how you check against how the user has a current drive mapping. My only thought was in the logon.bat put in a net use * /d /y to remove the drives and then remap them all.
I need to do more reading on how to use an ini file along with this.
But again thanks for your input
|
Top
|
|
|
|
#197997 - 2010-03-07 06:25 PM
Re: Critique My Logon Script
[Re: cjutting]
|
Glenn Barnas
KiX Supporter
Registered: 2003-01-28
Posts: 4396
Loc: New Jersey
|
DRIVE MAPPING Define a set of "user mapped" drives - drives that the users can freely use for "ad-hoc" mapping Either: - Unmap all drives execpt for those in the "user mapped" list before mapping or - Use a function that will "soft map" - will unmap if the path doesn't match, but will not "re-map" if the drive is already correctly mapped. Option 1 insures that drives reserved for admin-managed mappings won't be used, while option 2 helps performance. Our login script uses a combination of these to enforce the network configuration while maximizing performance.
Externalize your data - read your resource items from an INI file instead of hard coding the mappings. When the parameters are part of the code, you open yourself up to problems, since every time you change a mapping or resource, you're modifying your code. Our script is in use at hundreds of clients without any code change by using external data. A mis-configuration in the config file affectes only that resource, not the entire script.
You use M: for several mappings. This in itself isn't a problem, but you base your decision on group membership. What would happen if a user was a member of multiple groups? What I DON'T see is any method to handle that situation.
Use a UDF to map your drives, which will check the result code and handle error conditions. It simplifies your actual mapping process.
SCREEN RESOLUTION Setting screen resolution might be an ADA issue, unless you have an application that requires a specific screen res. If this is the case, doing it from a login script isn't a good idea because it only happens on login. You can control this via GPO, which not only sets the resolution but prevents users from modifying it.
APPLICATION INSTALLATION Just a bad idea for a login script, on so many levels. Users require admin rights on their PC. You say this is "for a client", so I assume you might want to write something that can be used at other clients with little or no modifications. We use the login script to detect when an application needs to be installed/updated, and it writes a request file to a server. That server monitors the folder, processes the request file and uses the task scheduler to install the application from a network share using admin credentials, the install starts during the login process, but runs out of the user context. This way, the user cannot affect the install process, even if they log off! The result - having a user detect and begin an install is almost the same, but it works regardless of their local rights.
Users have the ability to read just about anything. Collect your data and write a file to a central server share somewhere. You can use that data to trigger installs, but you can also collect asset and configuration data you might need for various IT reports.
RUN is an asynchronous process - your login script will have no ability to check its progress, determine if it was successful, or prevent it from being terminated. Further, you run "installclient.bat" and then, while it is running, you run "patches.bat". This could cause havoc if you are trying to patch the product you are installing.
OTHER COMMENTS At the end of the script, you set $training = @Hostname. I'm not sure why you need a FQDN unless your training PCs are in a different domain. If that's the case, I might handle this entirely differently, possibly even with a separate script.
You don't declare your variables.
Exit what? Exit requires a value.
Most Kix commands return an exit value. Some are positive logic and others are negative logic, which mirror the error status. Checking is easy - for positiv logic, use:If Not function(blah)
; error occurred - check error and attempt recovery, or display message
EndIf - just remove the "not" if the function uses negative logic. You need to evaluate these result codes and determine if they were successful. If they arent, you need to write code to handle the errors, either retrying or logging the error and presenting an appropriate error message.
When logging, I'd be very careful about using UDFs that repeatedly open/close the file. We open log file(s) when the script starts and write to them as needed. Alternatively, expand a variable with messages as needed, and write that variable at the end of your script. You could lose your messages using this method if Kix crashes, though. The single open/close with multiple writes is much faster. You will likely notice the performance gains when communicating over WAN links. This simple change reduced the login script processing time from 80+ seconds to less than 15 seconds on a WAN link at one client.
Login scripts affect every user on your network in an up-close and personal way. They need to connect the resources that the users need with minimal overhead. They need to be fast, unobtrusive, and above all - reliable.
Glenn
_________________________
Actually I am a Rocket Scientist!
|
Top
|
|
|
|
#197999 - 2010-03-08 09:56 AM
Re: Critique My Logon Script
[Re: cjutting]
|
Mart
KiX Supporter
Registered: 2002-03-27
Posts: 4672
Loc: The Netherlands
|
Thanks for your input Mart. Couple of questions so I understand what your telling me. Start with the printers. What you are suggesting is:
if ingroup ("BO-")
$rc = AddPrinterConnection ("\\server\Business Office")
endif
.... Exactly. This will prevent any return codes from being displayed on the screen.
.... Also interested in seeing how you check against how the user has a current drive mapping. My only thought was in the logon.bat put in a net use * /d /y to remove the drives and then remap them all.
I need to do more reading on how to use an ini file along with this.
Below is a piece of my script that does the drive mapping and checks. The example below handles one drive that everyone in our company should get so that's why it checks on membership of domain users. For other drives it is just a matter of copy paste and changing a few settings so it uses the correct letter, share and label. There are lots of comments in it that should make it clear what it is doing. The script below requires some UDF's. EnumNetworkDrives() - Returns the current network drive mapping information Label() - Read & Write Drive Label RemoveNullRows() - remove rows from an array that are blank/null
Break on
;Get all currently mapped network drives.
$networkdrives = EnumNetworkDrives()
;Create an array that will hold the letters of all mapped drives.
Dim $mapped[26]
If InGroup("Domain Users")
;Set drive letter.
$drive = "O:"
;Set path.
$path = "\\server\share"
;Check to see if the drive exists.
If Exist($drive + "\")
;Drive exists.
;Check to see if drive settings are correct.
For $i = 0 to UBound($networkdrives)
;Split the current network drives so you get two elements.
;One element holds the drive letter the other holds the path.
$networkdrive = Split($networkdrives[$i], ",")
$networkdriveletter = $networkdrive[0]
$networkdrivepath = $networkdrive[1]
;Check to see if the drive to map matches an existing drive.
If $networkdriveletter = $drive
;Check to see if the path to the drive is correct and if the drive has not
;been mapped by this script already.
If $networkdrivepath = $path And AScan($mapped, $drive) = -1
;Path to the drive is correct.
;Set the display name of the drive.
Label($drive, "User friendly name goes here")
;Set a variable to indicate that this drive has been mapped succesfully.
$mapped[$mappedindex] = $drive
;Increase the index by 1.
$mappedindex = $mappedindex + 1
Else
;Path to the current drive is not correct.
;Delete the drive that uses the drive letter to be mapped.
Use $drive /delete /persistent
;Map correct drive.
Use $drive $path
;Set the display name of the drive.
Label($drive, "User friendly name goes here")
;Set a variable to indicate that this drive has been mapped succesfully.
$mapped[$mappedindex] = $drive
;Increase the index by 1.
$mappedindex = $mappedindex + 1
EndIf
EndIf
Next
Else
;Drive does not exist.
;Map the correct drive.
Use $drive $path
;Set the display name of the drive.
Label($drive, "User friendly name goes here")
;Set a variable to indicate that this drive has been mapped successful.
$mapped[$mappedindex] = $drive
;Increase the index by 1.
$mappedindex = $mappedindex + 1
EndIf
EndIf
;Remove empty elements from the array that holds all mapped drives.
$mapped=removenullrows($mapped)
;Check all old network drives and compare them with the drives that are mapped by this script.
For $i = 0 to UBound($networkdrives)
;Split each drive on the comma.
$networkdrive = Split($networkdrives[$i],",")
$networkdriveletter = $networkdrive[0]
;Check to see if the old rive is listed in the array of newly mapped drives.
If AScan($mapped, $networkdriveletter) = -1
;Old drive is not listed so delete it.
Use $networkdriveletter /Del /Persistent
EndIf
Next
Also maybe I'm missing it, but how is kix keeping track of errors that are in turn written to the log files and then emailed to IT.
Every (sub) script of my logon script uses error tracking if needed. If there is an error it reads the current number of errors from the ini file, increases it by one and writes the new value back to the ini file. The text log is only used for admin purposes. A line is written to the text log any time something goes wrong. The last script I run checks for errors by reading the number of errors from the ini file and sends an e-mail if there are more than 0 errors. It also attaches the text log file to the e-mail so we can see what went wrong and fix it.
_________________________
Mart
- Chuck Norris once sold ebay to ebay on ebay.
|
Top
|
|
|
|
#198042 - 2010-03-11 09:08 PM
Re: Critique My Logon Script
[Re: Mart]
|
cjutting
Fresh Scripter
Registered: 2010-02-05
Posts: 40
Loc: IA
|
;Write entry to log files if an error occurs.
;Read current number of errors from ini log and add 1.
$errornumber = ReadProfileString($inilog, "Errors", "NumberOfErrors") + 1
;Write new number of errors to ini based log file.
$rc = WriteProfileString($inilog, "Errors", "NumberOfErrors", $errornumber)
;Write entry in the text based log file.
$rc = WriteLog($txtlog, @WKSTA + ". User ID: " + @USERID + ". IP address: " + @IPADDRESS0 + ". - ERROR: ERROR TEXT GOES HERE.", 1)
Mart. I'm trying to include this today and do some testing. I'm not using an ini file, but i am putting $rc in from of the use for the drives and the printer mappings. Since I'm not using the INI file how can I still get it to use the $rc to write to the log file?
Any idea's appreciated.
|
Top
|
|
|
|
#198044 - 2010-03-12 09:24 AM
Re: Critique My Logon Script
[Re: cjutting]
|
Richard H.
Administrator
Registered: 2000-01-24
Posts: 4946
Loc: Leatherhead, Surrey, UK
|
I'm assuming that you have the WriteLog() UDF loaded and have defined $textlog somewhere.
All you need to do is
- Assign the function return value to a variable ($rc)
- Check the both the value and @ERROR for error states - they are often the same when the function returns error states.
- Write to the log and handle the error
This very simple example attempts to open a non-existent file then logs the open error and exits the code segment.
;Write entry in the text based log file.
$sFile="C:\FOO\BAR"
$RC=Open(1,$sFile)
If $RC OR @ERROR
$RC=WriteLog($txtlog,@WKSTA+" "+Join(Split(@IPADDRESS0),"")+" "+@USERID+" RC="+$RC+" @@ERROR="+@ERROR+" @@SERROR="+@SERROR,1)
Exit 1
EndIf
Be carefull with @ERROR and @SERROR - if you do not save them and you call another function their values will be reset.
|
Top
|
|
|
|
#198053 - 2010-03-12 04:34 PM
Re: Critique My Logon Script
[Re: Mart]
|
cjutting
Fresh Scripter
Registered: 2010-02-05
Posts: 40
Loc: IA
|
call @ldrive\udf\alludf.kix
Something like that somewhere in my script? Assume alludf.kix has the WriteLog copied to it?
I'm trying this out, but either I really am getting no errors or it's not writing anything.
EDIT: YAHOO!!! it' writes information to the file... and gives me information. Now just to figure out what it means. All though I'm pretty sure I know what it means
Edited by cjutting (2010-03-12 05:08 PM)
|
Top
|
|
|
|
#198058 - 2010-03-12 07:41 PM
Re: Critique My Logon Script
[Re: cjutting]
|
Glenn Barnas
KiX Supporter
Registered: 2003-01-28
Posts: 4396
Loc: New Jersey
|
Reread my review from above... print it and keep it by your side.. tuck it under your pillow.. (well, maybe not that!)
Here's the main concept -
Use a UDF to evaluate a list of resources - is the user authorized to access the resource? (inGroup, InSite, InOU, ComputerInGroup, ComputerInOU, InSubnet, etc...) The resource list should be maintained externally so you don't have to keep hacking your code every time a resource is added, changed, or removed. Embedding data-specific logic in your code is a bad idea in most cases. Login scripts have very clearly defined requirements - "Is a user or computer authorized to access a resource?" Since these authorization methods are limited and standardized, you can develop a short set of rule-checking processes to determine if access is allowed. Throw away any resource record that isn't authorized.
Use another UDF to map your resources. The UDF handles the errors, logging, recovery, etc, and simply returns SUCCESS or FAIL. If the MapResource UDF handles everything, it really doesn't matter what the main script does with the success/fail result.. for example:
PHASE 1 = identify resources to be mapped. Ignore anything that isn't authorized or available, which leaves you with a short list of resources to map. PHASE 2 = Enumerate the resource "short list", calling a MapResource UDF for each resource. Pass the resource data set (resource type, UNC path, target, description) to the MapResource function. This then decides what kind of resource it is, how it should be mapped, and which parameters to use. This handles the error trapping & logging, simplifying the main process and centralizing the code. PHASE 3 = Almost unnecessary - either exit silently, or say "errors were encountered - call the help desk!"
Our script employs such methods. The code is compiled, and the same code is used at hundreds of different clients. We can process a set of around 250 resources, including 4 lookups with anywhere between 150 and 480 entries each in less than 5 seconds. That means, when someone logs in, we check almost 250 individual resource records (40 disk, 200 printer, 2 message, and 6 command at this larger client site). These checks run quickly and generate a "short list" of about 16 resources that are actually processed. Most users get about 9 drives, 2-3 printers, display 1-2 short messages, and run 2-3 brief commands.
The lookups translate macros in the resource record data to UNC path fragments based on various values. This alone can eliminate dozens of lines of coding. For example - when a user enters a branch office and logs into a computer, one of the lookup resources determines which OU the computer is in. The lookup translates the OU name to the UNC path of the server in that branch where the applications reside. It doesn't matter what OU or group the user is in (of course, we make sure that the user is authorized to access the data before we use a computer-based lookup).
Point is - employ UDFs, externalize data, and standardize the authorization logic as much as possible. The result will be a fast and reliable solution.
Glenn
_________________________
Actually I am a Rocket Scientist!
|
Top
|
|
|
|
Moderator: Jochen, Allen, Radimus, Glenn Barnas, ShaneEP, Ruud van Velsen, Arend_, Mart
|
0 registered
and 262 anonymous users online.
|
|
|