Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

add printer to local computer using ManagementClass

Tags:

c#

printing

I see references and hints that programmatically one can add a networked printer to a local computer using the ManagementClass and such. However I have not been able to find any actual tutorials on doing just this.

has anyone actually used the ManagementClass to do this?

I am doing this:

var connectionOption = new ConnectionOption();
var mgmScope = new ManagementScope("root\cimv2",connectionOptions);

var printerClass = new ManagementClass(mgmScope, new ManagementPath("Win32_Printer"),null);
var printerObj = printerClass.CreateInstance();

printerObj["DeviceID"] = prnName;     //
printerObj["DriverName"] = drvName;   // full path to driver
printerObj["PortName"] = "myTestPort:";

var options = new PutOptions {Type = PutType.UpdateOrCreate};
printerObj.Put(options);   

All this does is create an error "Generic Failure"

I cant figure out what I am missing..... any help or thoughts about this would be appreciated.

I think I need to better explain what I am trying to do... when the printers needed are not tied to a print server, I need to: create a tcpip raw port, connect a printer via tcp/ip, install drivers, optionally set default.

I was hoping WMI could basically take care of all of this but it doesnt appear to be the case.

thanks!

like image 458
Kixoka Avatar asked Apr 16 '13 14:04

Kixoka


People also ask

How do I add a printer using TCP IP?

In the Devices and Printers window click on Add a printer. Choose "Add a local printer or network printer with manual settings", then click Next. Select Create a new port and choose Standard TCP/IP Port, then click Next. Under Hostname or IP address: Type in the IP address of the printer you intend to connect to.


1 Answers

I spent almost the week on that issue! My target is a bit more complicated, I want to wrap the C# code in a WCF service called by a SharePoint Add-In, and this WCF service should call remotely the client to install the printers. Thus I tried hard with WMI. In the mean time, I managed to use rundll32 solution (which requires first to create the port), and also did a powershell variant, really the simplest:

$printerPort = "IP_"+ $printerIP
$printerName = "Xerox WorkCentre 6605DN PCL6"
Add-PrinterPort -Name $printerPort -PrinterHostAddress $printerIP
Add-PrinterDriver -Name $printerName
Add-Printer -Name $printerName -DriverName $printerName -PortName $printerPort

The really tricky part is to know the name of the printer, it should match the string in the INF file!

But back to C# solution: I created a class with printerName, printerIP and managementScope as attributes. And driverName = printerName

    private string PrinterPortName
    {
        get {  return "IP_" + printerIP; }
    }

    private void CreateManagementScope(string computerName)
    {
        var wmiConnectionOptions = new ConnectionOptions();
        wmiConnectionOptions.Impersonation = ImpersonationLevel.Impersonate;
        wmiConnectionOptions.Authentication = AuthenticationLevel.Default;
        wmiConnectionOptions.EnablePrivileges = true; // required to load/install the driver.
        // Supposed equivalent to VBScript objWMIService.Security_.Privileges.AddAsString "SeLoadDriverPrivilege", True 

        string path = "\\\\" + computerName + "\\root\\cimv2";
        managementScope = new ManagementScope(path, wmiConnectionOptions);
        managementScope.Connect();
    }

    private bool CheckPrinterPort()
    {
        //Query system for Operating System information
        ObjectQuery query = new ObjectQuery("SELECT * FROM Win32_TCPIPPrinterPort");
        ManagementObjectSearcher searcher = new ManagementObjectSearcher(managementScope, query);

        ManagementObjectCollection queryCollection = searcher.Get();
        foreach (ManagementObject m in queryCollection)
        {
            if (m["Name"].ToString() == PrinterPortName)
                return true;
        }
        return false;
    }

    private bool CreatePrinterPort()
    {
        if (CheckPrinterPort())
            return true;

        var printerPortClass = new ManagementClass(managementScope, new ManagementPath("Win32_TCPIPPrinterPort"), new ObjectGetOptions());
        printerPortClass.Get();
        var newPrinterPort = printerPortClass.CreateInstance();
        newPrinterPort.SetPropertyValue("Name", PrinterPortName);
        newPrinterPort.SetPropertyValue("Protocol", 1);
        newPrinterPort.SetPropertyValue("HostAddress", printerIP);
        newPrinterPort.SetPropertyValue("PortNumber", 9100);    // default=9100
        newPrinterPort.SetPropertyValue("SNMPEnabled", false);  // true?
        newPrinterPort.Put();
        return true;
    }

    private bool CreatePrinterDriver(string printerDriverFolderPath)
    {
        var endResult = false;
        // Inspired from https://msdn.microsoft.com/en-us/library/aa384771%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396
        // and http://microsoft.public.win32.programmer.wmi.narkive.com/y5GB15iF/adding-printer-driver-using-system-management
        string printerDriverInfPath = IOUtils.FindInfFile(printerDriverFolderPath);
        var printerDriverClass = new ManagementClass(managementScope, new ManagementPath("Win32_PrinterDriver"), new ObjectGetOptions());            
        var printerDriver = printerDriverClass.CreateInstance();
        printerDriver.SetPropertyValue("Name", driverName);
        printerDriver.SetPropertyValue("FilePath", printerDriverFolderPath);
        printerDriver.SetPropertyValue("InfName", printerDriverInfPath);

        // Obtain in-parameters for the method
        using (ManagementBaseObject inParams = printerDriverClass.GetMethodParameters("AddPrinterDriver"))
        {
            inParams["DriverInfo"] = printerDriver;
            // Execute the method and obtain the return values.            

            using (ManagementBaseObject result = printerDriverClass.InvokeMethod("AddPrinterDriver", inParams, null))
            {
                // result["ReturnValue"]
                uint errorCode = (uint)result.Properties["ReturnValue"].Value;  // or directly result["ReturnValue"]
                // https://msdn.microsoft.com/en-us/library/windows/desktop/ms681386(v=vs.85).aspx
                switch (errorCode)
                {
                    case 0:
                        //Trace.TraceInformation("Successfully connected printer.");
                        endResult = true;
                        break;
                    case 5:
                        Trace.TraceError("Access Denied.");
                        break;
                    case 123:
                        Trace.TraceError("The filename, directory name, or volume label syntax is incorrect.");
                        break;
                    case 1801:
                        Trace.TraceError("Invalid Printer Name.");
                        break;
                    case 1930:
                        Trace.TraceError("Incompatible Printer Driver.");
                        break;
                    case 3019:
                        Trace.TraceError("The specified printer driver was not found on the system and needs to be downloaded.");
                        break;
                }
            }
        }
        return endResult;
    }

    private bool CreatePrinter()
    {
        var printerClass = new ManagementClass(managementScope, new ManagementPath("Win32_Printer"), new ObjectGetOptions());
        printerClass.Get();
        var printer = printerClass.CreateInstance();
        printer.SetPropertyValue("DriverName", driverName);
        printer.SetPropertyValue("PortName", PrinterPortName);
        printer.SetPropertyValue("Name", printerName);
        printer.SetPropertyValue("DeviceID", printerName);
        printer.SetPropertyValue("Location", "Front Office");
        printer.SetPropertyValue("Network", true);
        printer.SetPropertyValue("Shared", false);
        printer.Put();
        return true;
    }


    private void InstallPrinterWMI(string printerDriverPath)
    {
        bool printePortCreated = false, printeDriverCreated = false, printeCreated = false;
        try
        {                
            printePortCreated = CreatePrinterPort();
            printeDriverCreated = CreatePrinterDriver(printerDriverPath);
            printeCreated = CreatePrinter();
        }
        catch (ManagementException err)
        {
            if (printePortCreated)
            {
                // RemovePort
            }
            Console.WriteLine("An error occurred while trying to execute the WMI method: " + err.Message);
        }
    }

finally install the driver. I still need further tests if its works on a clean Windows. Did many install/uninstall of the driver during my tests

like image 70
EricBDev Avatar answered Nov 15 '22 17:11

EricBDev