laidback01 Posted February 15, 2009 Share Posted February 15, 2009 (edited) A little background might be needed here. We have a relatively large operation here, 2k users, 1k pcs, 200 servers, and around 500 printers. Now, this is an abnormally high amount of printers given the amount of users, but many of these printers are just label printers, and, therefore specific to a task. A side effect of the amount an variety of the printers is a high amount of drivers and issues with those drivers. We are stiting at 206 different drivers for those printers. Long story short - our Windows printservers are crashing on a daily/weekly basis, and Microsoft support tells us to split up our printers by type into different servers. This seems like a bad idea given our users who are very used to a single point of use for the printers. So... in comes linux with Cups. Cups is cool in that it's a stateless protocol, etc. But how do we convert from old to new without having to touch everyone's PC? Well, I'm just starting down the line here, and so this is my first script. It's useable, and can convert from \\printserver\PRINTER to an IPP based PRINTER. So far this is working well. I aim to mysql-ize this because there is much to do with the linux side of this. However, I thought I'd share just in case anyone else needs something like this. Many of you will recognize your code Many of you will recognize code from the help pages. I thank all of you who unknowingly helped! expandcollapse popup; pConvertManual ; 16 Feb 2009 ; Converts printers from specified servers (update $servers array) to IPP printers. #include <Constants.au3> #include <GuiConstantsEx.au3> #include <GUIListBox.au3> #include <ListBoxConstants.au3> #include <WindowsConstants.au3> Opt("TrayIconDebug", 1) ; I like to know what line the script is on when it's all locked up or whatnot. Opt('MustDeclareVars', 1) ; Keeping things clean and simple. Declare vars at top of script. Local $command = @SystemDir&"\cscript.exe "&@SystemDir&"\prnmngr.vbs" Local $myPrinters="" Local $hGUI = GUICreate("pConvert - Manual", 200, 450) Local $hListBox = _GUICtrlListBox_Create($hGUI, "pConvert - Manual", 10, 30, 180, 380, BitOR($WS_BORDER, $LBS_HASSTRINGS, $LBS_MULTIPLESEL, $WS_VSCROLL)) Local $servers[5]=["printserver","10.6.0.19","10.6.0.20","10.6.0.25","printserver-adm"] Local $printers[1][4], $count, $knownString, $testString, $pSelected=0, $arrayRow _GUICtrlListBox_BeginUpdate($hListBox) _GUICtrlListBox_ResetContent($hListBox) _GUICtrlListBox_InitStorage($hListBox, 100, 4096) _GUICtrlListBox_EndUpdate($hListBox) Local $hButton = GUICtrlCreateButton("Select All", 10, 400, 80, 20) Local $cButton = GUICtrlCreateButton("Convert", 111, 400, 80, 20), $a Local $rButton = GUICtrlCreateButton("Rescan", 10, 425, 80, 20) Local $eButton = GUICtrlCreateButton("Exit", 111, 425, 80, 20) Local $wLabel = GUICtrlCreateLabel ("Ready", 10, 10, 180) GUISetState() ; Initially load the ListBox GUICtrlDelete($cButton) GUICtrlDelete($hButton) changeLabel("Scanning",$wLabel) $myPrinters=getMyPrinters($command) parsePrintersToArray($myPrinters, $printers,$servers) loadListBox($hListBox, $printers, $servers) changeLabel("Ready",$wLabel) $hButton = GUICtrlCreateButton("Select All", 10, 400, 80, 20) $cButton = GUICtrlCreateButton("Convert", 111, 400, 80, 20) While 1 Switch GUIGetMsg() Case $rButton GUICtrlDelete($cButton) GUICtrlDelete($hButton) emptyListBox($hListBox, $printers) changeLabel("Scanning",$wLabel) $myPrinters=getMyPrinters($command) parsePrintersToArray($myPrinters, $printers,$servers) loadListBox($hListBox, $printers, $servers) ; Return the buttons changeLabel("Ready",$wLabel) $hButton = GUICtrlCreateButton("Select All", 10, 400, 80, 20) $cButton = GUICtrlCreateButton("Convert", 111, 400, 80, 20) Case $cButton ; Disable the buttons now that it's been run. GUICtrlDelete($cButton) GUICtrlDelete($hButton) changeLabel("Converting",$wLabel) $pSelected = (_GUICtrlListBox_GetSelItems($hListBox)-1) If $pSelected[0] >=1 Then For $count = 1 to $pSelected[0] ; do a quick verification to make sure we have the right printer: $knownString = $printers[$pSelected[$count]][0]&" on "&$servers[$printers[$pSelected[$count]][2]] $testString = _GUICtrlListBox_GetText($hListBox, $pSelected[$count]) if $knownString == $testString Then $arrayRow = $pSelected[$count] If Not(verifyPrinter($printers[$arrayRow][0])) Then convertToIPP($arrayRow, $printers, "http://printserver.krh.int:631/printers/", "Cups Rocks") EndIf ; Now get rid of the old one... If (verifyPrinter($printers[$arrayRow][0])) Then deletePrinter("\\"&$servers[$printers[$arrayRow][2]]&"\"&$printers[$arrayRow][0]) EndIf ; update the view. If Not(verifyPrinter("\\"&$servers[$printers[$arrayRow][2]]&"\"&$printers[$arrayRow][0])) Then _GUICtrlListBox_DeleteString($hListBox,$pSelected[$count]) _GUICtrlListBox_InsertString($hListBox,$printers[$arrayRow][0]&" converted",$pSelected[$count]) EndIf EndIf Next EndIf changeLabel("Ready",$wLabel) $hButton = GUICtrlCreateButton("Select All", 10, 400, 80, 20) $cButton = GUICtrlCreateButton("Convert", 111, 400, 80, 20) Case $hButton $count=Ubound($printers) -1 _GUICtrlListBox_SelItemRange ($hListBox, 0, $count) Case $GUI_EVENT_CLOSE Exit Case $eButton Exit EndSwitch WEnd Func convertToIPP($arrayRow, ByRef $printersArray, $IPPPrintserver, $comment) ; $printersArray expected to be of size [x][4] Local $rundll32="C:\windows\system32\rundll32.exe", $exitcode Local $install_command = $rundll32&' printui.dll,PrintUIEntry /b '&$printersArray[$arrayRow][0]&' /x /n "'&$comment&'" /if /f %windir%\inf\ntprint.inf /r '&$IPPPrintserver&$printersArray[$arrayRow][0]&' /u /m "'&$printersArray[$arrayRow][1]&'"' $exitcode=RunWait(@ComSpec & " /c " & $install_command, @SystemDir, @SW_HIDE) ; Test exitcode - make sure it's something suitable, if so, mark the delete flag in the $printersArray EndFunc Func verifyPrinter($printerName) Local $command = @SystemDir&"\cscript.exe "&@SystemDir&"\prncnfg.vbs -g -p "&$printerName Local $standardout, $string="", $line="", $temparray, $printerExists=0, $i, $count $standardout = Run(@ComSpec & " /c " & $command, @SystemDir, @SW_HIDE, $STDOUT_CHILD) While 1 $line = StdoutRead($standardout) If @error Then ExitLoop $string = $string&$line Wend $tempArray=StringSplit($string,@crlf,1) $count=UBound($tempArray)-1 $i=0 For $i=0 to $count If ("Printer name" == StringLeft($tempArray[$i],12)) Then ;StringLeft($line,stringlen($potential_name $printerExists=1 ExitLoop EndIf Next return $printerExists EndFunc Func deletePrinter($printerName) Local $success=0 Local $command=@SystemDir&'\cscript.exe '&@SystemDir&'\prnmngr.vbs -d -p "'&$printerName&'"' $success = RunWait(@ComSpec & " /c " & $command, @WindowsDir, @SW_HIDE) ; the return var is so odd, always positive, doesn't matter if the commande worked or not. Guess I'll need to use verifyPrinter to see if the delete command worked or not. EndFunc Func changeLabel($state, ByRef $label) Switch $state Case "Ready" GUICtrlDelete($label); $label = GUICtrlCreateLabel ("Ready", 10, 10, 180) GUICtrlSetColor($label,0x000000) Case "Scanning" GUICtrlDelete($label) $label = GUICtrlCreateLabel ("Please wait, scanning for printers...", 10, 10, 180) GUICtrlSetColor($label,0xff0000) ; Red Case "Converting" GUICtrlDelete($label) $label = GUICtrlCreateLabel ("Please wait, converting printers now.", 10, 10, 180) GUICtrlSetColor($label,0xff0000) ; Red EndSwitch EndFunc Func parsePrintersToArray($printersString, ByRef $printers, ByRef $servers); $printers is expected to be [x][4] Local $tempArray=StringSplit($printersString,@crlf,1) Local $lineCount=(Ubound($tempArray)-1), $i, $j, $line, $knownString, $testString, $serverCount=0 Local $driverLineBegins="Driver name", $shareLineBegins="Share name", $element=0 ReDim $printers[2] ; Seems to me there ought to be a better way to just empty the array, but I don't know it. ReDim $printers[1][4] for $i = 0 to $lineCount $line = $tempArray[$i] ; see if this line matches any kind of expected output. $serverCount=UBound($servers)-1 for $j = 0 to $serverCount $knownString="printer name \\"&$servers[$j]&"\" $testString = StringLeft($line,stringlen($knownString)) if (($knownString) == StringLower($testString)) Then $i+= 1 ; the next in line is the actual printer name. ; The reason I didn't test for this directly is that I need to know the server load into the $printers[x][2] position for later use. $line = $tempArray[$i] if ($shareLineBegins == StringLeft($line,stringlen($shareLineBegins))) Then ; make sure it all matches up as expected. $printers[$element][0] = StringStripWS(StringRight($line,Stringlen($line)-Stringlen($shareLineBegins)),3) ; gather ONLY the printername this way. EndIf $i+= 1 ; now the driver. $line = $tempArray[$i] if ($driverLineBegins == StringLeft($line,stringlen($driverLineBegins))) Then $printers[$element][1] = StringStripWS(StringRight($line,Stringlen($line)-Stringlen($driverLineBegins)-1),3) EndIf $printers[$element][2] = $j ; marks which server it came from $element += 1 ReDim $printers[(UBound($printers)+1)][4] ; EndIf Next Next EndFunc Func loadListBox($hListBox, ByRef $printers, ByRef $servers) ; $printers is 2d array, $servers is 1d. Local $count=(Ubound($printers) -1), $i, $line If $count >= 1 then for $i = 0 to $count $line = $printers[$i][0]&" on "&$servers[$printers[$i][2]] If ($printers[$i][0] <> "") Then _GUICtrlListBox_AddString($hListBox,$line) EndIf Next EndIf EndFunc Func emptyListBox($hListBox, ByRef $printers) $count=Ubound($printers) -1 If $count >= 1 then for $i = 0 to $count _GUICtrlListBox_DeleteString($hListBox,0) Next EndIf EndFunc Func getMyPrinters($command) ; Load a string with every printer loaded on the system. ; Wonder what the max is that I can have in a string. Local $list, $string, $line $list = Run(@ComSpec & " /c " & $command&" -l ", @SystemDir, @SW_HIDE, $STDOUT_CHILD) While 1 $line = StdoutRead($list) If @error Then ExitLoop $string = $string&$line Wend return $string EndFunc Edited February 16, 2009 by laidback01 Link to comment Share on other sites More sharing options...
gseller Posted February 15, 2009 Share Posted February 15, 2009 Cool, I am sure this will be beneficial to many. At my place of work we only have an ip printer at different areas and each user uses the one closest to their cube. Please keep us updated with your progress.. Link to comment Share on other sites More sharing options...
laidback01 Posted February 16, 2009 Author Share Posted February 16, 2009 Cool, I am sure this will be beneficial to many. At my place of work we only have an ip printer at different areas and each user uses the one closest to their cube. Please keep us updated with your progress..heh, I don't think very many folks will find this useful really, but it's handy if you need something like this. Mostly this would be useful for ppl who have Samba fileservers/printservers and quite a few printers - colleges, hospitals, etc. Normal users won't really care.Anyway, the script is now functional. It's smart enough not to recreate printers (eg no Copy1, Copy2, etc printers), does a few safety checks, etc. Still, use at your own risk. If someone has already done this and I'm just re-inventing this wheel, I'd like to know, because I'm sure the way I code isn't so hot (I just do what it take to get the job done). Anyway, if you do happen to use it, and it errors out, it'd be nice to know I've only got access to XP and win2k3 machines, so if it's a vista thing, I've no idea whats wrong, and really don't wish to try to fix it.Oh, I've posted the lastest version of the code too...have a good one!Jack Link to comment Share on other sites More sharing options...
LiHang Posted February 25, 2009 Share Posted February 25, 2009 Hi, Cool script. But I found you invoke those vbscript from system a lot. Why not use COM interface within AutoIT? I'm trying to write such script recently. If I could finish it, I'll post it here. :-) Link to comment Share on other sites More sharing options...
ptrex Posted February 25, 2009 Share Posted February 25, 2009 @Allfor those who are not familiar with IPP :Internet Printing ProtocolGoing to test your script soon.ThanksRegards,ptrex Contributions :Firewall Log Analyzer for XP - Creating COM objects without a need of DLL's - UPnP support in AU3Crystal Reports Viewer - PDFCreator in AutoIT - Duplicate File FinderSQLite3 Database functionality - USB Monitoring - Reading Excel using SQLRun Au3 as a Windows Service - File Monitor - Embedded Flash PlayerDynamic Functions - Control Panel Applets - Digital Signing Code - Excel Grid In AutoIT - Constants for Special Folders in WindowsRead data from Any Windows Edit Control - SOAP and Web Services in AutoIT - Barcode Printing Using PS - AU3 on LightTD WebserverMS LogParser SQL Engine in AutoIT - ImageMagick Image Processing - Converter @ Dec - Hex - Bin -Email Address Encoder - MSI Editor - SNMP - MIB ProtocolFinancial Functions UDF - Set ACL Permissions - Syntax HighLighter for AU3ADOR.RecordSet approach - Real OCR - HTTP Disk - PDF Reader Personal Worldclock - MS Indexing Engine - Printing ControlsGuiListView - Navigation (break the 4000 Limit barrier) - Registration Free COM DLL Distribution - Update - WinRM SMART Analysis - COM Object Browser - Excel PivotTable Object - VLC Media Player - Windows LogOnOff Gui -Extract Data from Outlook to Word & Excel - Analyze Event ID 4226 - DotNet Compiler Wrapper - Powershell_COM - New Link to comment Share on other sites More sharing options...
laidback01 Posted March 28, 2012 Author Share Posted March 28, 2012 Okay, so, after several other projects, I've come back to AutoIT stuff and working with this rather minor project. Li Hang:Hi,Cool script. But I found you invoke those vbscript from system a lot. Why not use COM interface within AutoIT?I'm trying to write such script recently.If I could finish it, I'll post it here.:-)Thanks for the compliment, however, I don't know how to use the COM interface. I'll take a look at it. To tell you the truth, I'm a unix guy working in the windows world, so a bit of this stuff is tough for me to get a handle on. WIll take a look though, thanks for the tip!So... onward and upward. Latest version of AutoIT downloaded, time to see how many better ways there are to accomplish this task Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now