使用ManagementClass将打印机添加到本地计算机



我看到参考资料和提示,可以通过编程方式使用ManagementClass等将联网打印机添加到本地计算机。然而,我还没有找到任何实际的教程这样做。

是否有人实际使用了管理类来做到这一点?

我正在做这个:

var connectionOption = new ConnectionOption();
var mgmScope = new ManagementScope("rootcimv2",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);   

这样做会产生一个错误"Generic Failure"

我不知道我错过了什么.....如有任何帮助或想法,我将不胜感激。

我想我需要更好地解释我正在努力做什么…当所需的打印机没有绑定到打印服务器时,我需要:创建一个tcpip原始端口,通过tcp/ip连接打印机安装驱动程序,

我希望WMI基本上可以处理所有这些,但情况似乎并非如此。

谢谢!

WMI Win32_Printer类提供了一个名为AddPrinterConnection的方法来将网络打印机添加到本地打印机列表中。下面的代码显示如何使用Win32_Printer类连接网络打印机。

请注意,在某些条件下AddPrinterConnection失效连接远程打印机。在下面的例子中,我列出了大多数常见错误案例。

using (ManagementClass win32Printer = new ManagementClass("Win32_Printer"))
{
  using (ManagementBaseObject inputParam =
     win32Printer.GetMethodParameters("AddPrinterConnection"))
  {
    // Replace <server_name> and <printer_name> with the actual server and
    // printer names.
    inputParam.SetPropertyValue("Name", "\\<server_name>\<printer_name>");
    using (ManagementBaseObject result = 
        (ManagementBaseObject)win32Printer.InvokeMethod("AddPrinterConnection", inputParam, null))
    {
      uint errorCode = (uint)result.Properties["returnValue"].Value;
      switch (errorCode)
      {
        case 0:
          Console.Out.WriteLine("Successfully connected printer.");
          break;
        case 5:
          Console.Out.WriteLine("Access Denied.");
          break;
        case 123:
          Console.Out.WriteLine("The filename, directory name, or volume label syntax is incorrect.");
          break;
        case 1801:
          Console.Out.WriteLine("Invalid Printer Name.");
          break;
        case 1930:
          Console.Out.WriteLine("Incompatible Printer Driver.");
          break;
        case 3019:
          Console.Out.WriteLine("The specified printer driver was not found on the system and needs to be downloaded.");
          break;
      }
    }
  }
}

我几乎花了一个星期的时间在这个问题上!我的目标有点复杂,我想把c#代码包装在一个由SharePoint插件调用的WCF服务中,这个WCF服务应该远程调用客户端来安装打印机。因此,我努力尝试WMI。同时,我设法使用rundll32解决方案(这需要首先创建端口),并且还做了一个powershell变体,真的是最简单的:

$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

真正棘手的部分是知道打印机的名称,它应该与INF文件中的字符串匹配!

但是回到c#解决方案:我创建了一个具有printerName, printerIP和managementScope作为属性的类。和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);
        }
    }

最后安装驱动程序。我还需要进一步测试它是否能在干净的Windows上运行。在我的测试中是否安装/卸载了很多驱动程序

为了做到这一点,我最终不得不做一个2步…

首先建立一个命令行来启动:

rundll32.exe printui.dll,PrintUIEntry /if /b "test" /f x2DSPYP.inf /r 10.5.43.32 /m "845 PS"

然后生成它:

    public static string ShellProcessCommandLine(string cmdLineArgs,string path)
    {
        var sb = new StringBuilder();
        var pSpawn = new Process
        {
            StartInfo =
                {
                    WorkingDirectory = path, 
                    FileName = "cmd.exe", 
                    CreateNoWindow = true,
                    Arguments = cmdLineArgs,
                    RedirectStandardInput = true,
                    RedirectStandardOutput = true,
                    UseShellExecute = false
                }
        };
        pSpawn.OutputDataReceived += (sender, args) => sb.AppendLine(args.Data);
        pSpawn.Start();
        pSpawn.BeginOutputReadLine();
        pSpawn.WaitForExit();
        return sb.ToString();
    }

这似乎工作…不是理想的方法,但对于那些不在打印服务器上的打印机,它似乎可以完成工作。

我想补充一个答案,因为有另一种方法,微软建议现在使用Microsoft. management . infrastructure而不是System.Management.

这是微软文档的链接:https://msdn.microsoft.com/en-us/library/microsoft.management.infrastructure.aspx

请注意,你必须在c#项目中添加引用到Microsoft.Management.Infrastructure dll:其中Microsoft.Management.Infrastructure

您可能还需要在机器上配置winrmhttps://learn.microsoft.com/en-us/windows/desktop/winrm/installation-and-configuration-for-windows-remote-management

下面是使用c# 将打印机从打印服务器添加到本地机器的示例代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Management.Infrastructure;
using Microsoft.Management.Infrastructure.Generic;
using Microsoft.Management.Infrastructure.Options;

namespace MMITest
{
class Program
{
    static void Main(string[] args)
    {
        using (var session = CimSession.Create("localhost"))
        {
            using (var cimMethodParameters = new CimMethodParametersCollection())
            {
                cimMethodParameters.Add(CimMethodParameter.Create("Name", @"\PrintServerNamePrinterName", CimFlags.Parameter));
                session.InvokeMethod(@"rootcimv2", "Win32_Printer", "AddPrinterConnection", cimMethodParameters);
            }
        }
        Console.ReadLine();
    }
}

}

最新更新