aggiungi stampante al computer locale usando ManagementClass

Vedo riferimenti e suggerimenti che a livello di programmazione si può aggiungere una stampante in rete a un computer locale utilizzando ManagementClass e così via. Tuttavia non sono stato in grado di trovare alcun tutorial effettivo su come fare proprio questo.

qualcuno ha effettivamente usato il ManagementClass per fare questo?

Lo sto facendo:

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); 

Tutto ciò è creare un errore “Generic Failure”

Non riesco a capire cosa mi manca ….. qualsiasi aiuto o pensiero su questo sarebbe apprezzato.

Penso di dover spiegare meglio cosa sto cercando di fare … quando le stampanti necessarie non sono legate a un server di stampa, ho bisogno di: creare una porta raw tcpip, connettere una stampante tramite tcp / ip, installare i driver, opzionalmente imposta default.

Speravo che WMI potesse occuparsi di tutto questo, ma non sembra essere il caso.

Grazie!

La Win32_Printer WMI Win32_Printer fornisce un metodo chiamato AddPrinterConnection per aggiungere una stampante di rete all’elenco delle stampanti locali. Il codice seguente mostra come connettere una stampante di rete usando la class Win32_Printer .

Si noti che, in determinate condizioni, AddPrinterConnection non riesce a connettere la stampante remota. Nell’esempio seguente ho elencato i casi di errore più comuni.

 using (ManagementClass win32Printer = new ManagementClass("Win32_Printer")) { using (ManagementBaseObject inputParam = win32Printer.GetMethodParameters("AddPrinterConnection")) { // Replace  and  with the actual server and // printer names. inputParam.SetPropertyValue("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; } } } } 

Per fare questo ho finito per dover fare un 2 stepper …

prima costruisci una riga di comando per sparare:

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

Quindi genera:

  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(); } 

Questo sembra funzionare … non il metodo ideale ma per quelle stampanti non su un server di stampa sembra fare il lavoro.

Ho trascorso quasi una settimana su questo argomento! Il mio objective è un po ‘più complicato, voglio racchiudere il codice C # in un servizio WCF chiamato da un componente aggiuntivo di SharePoint, e questo servizio WCF dovrebbe chiamare in remoto il client per installare le stampanti. Così ho provato con WMI. Nel frattempo, sono riuscito a utilizzare la soluzione rundll32 (che richiede prima di creare la porta), e ho anche fatto una variante di PowerShell, davvero la più semplice:

 $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 

La parte davvero difficile è conoscere il nome della stampante, dovrebbe corrispondere alla stringa nel file INF!

Ma torniamo alla soluzione C #: ho creato una class con printerName, printerIP e managementScope come attributi. E 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); } } 

finalmente installa il driver. Ho ancora bisogno di ulteriori test se funziona su un Windows pulito. Ho fatto molte installazioni / disinstallazioni del driver durante i miei test

Volevo aggiungere una risposta in quanto esiste un altro modo e Microsoft consiglia di utilizzare Microsoft.Management.Infrastructure ora su System.Management.

Ecco il link alla documentazione Microsoft: https://msdn.microsoft.com/en-us/library/microsoft.management.infrastructure.aspx

Si noti che è necessario aggiungere un riferimento nel progetto c # alla Microsoft.Management.Infrastructure dll: Dove Microsoft.Management.Infrastructure

Potrebbe anche essere necessario configurare winrm sulla macchina https://docs.microsoft.com/en-us/windows/desktop/winrm/installation-and-configuration-for-windows-remote-management

Ecco un esempio di codice per aggiungere una stampante alla macchina locale da un server di stampa usando 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", @"\\PrintServerName\PrinterName", CimFlags.Parameter)); session.InvokeMethod(@"root\cimv2", "Win32_Printer", "AddPrinterConnection", cimMethodParameters); } } Console.ReadLine(); } } 

}