Jump to content

Conventional Printer to IPP


laidback01
 Share

Recommended Posts

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!

; 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 by laidback01
Link to comment
Share on other sites

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

  • 2 weeks later...
  • 3 years later...

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 :oops:

Link to comment
Share on other sites

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 account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...