we have a print server and lots of printers on it. We access them like this:
\\print-server-name\printer1
\\print-server-name\printer1_color
\\print-server-name\printer2
...etc.
I now need a list of all printers on that server. Until now, I could only find all printers installed locally on the machine. I found this while googling which gave me only the local printers aswell:
PrintServer lps = new PrintServer();
PrintQueueCollection prQueue = lps.GetPrintQueues(new[] { EnumeratedPrintQueueTypes.Connections });
liServerPrinterNames = (from printer in prQueue select printer).ToList();
Actually I only need the names of all printers on the server in a string array, I don't even need objects for interaction, only the names of all printers as string. Is that possible? How?
Thanks for any help in advance!
Gets all InstalledPrinters
foreach (string printer in PrinterSettings.InstalledPrinters)
Using WMI Windows Management Instrumentation
SelectQuery query = new SelectQuery("SELECT * FROM Win32_Printer");
ManagementObjectSearcher mos= new ManagementObjectSearcher(mos, query);
System.Management.ManagementObjectCollection moc= mos.Get();
foreach (ManagementObject Printers in moc )
Printers["Name"]; //GetPrinterName
}
Here is how I did it:
using System.Printing;
string serverAddress = #"\\server.domain.local"
PrintServer printServer = new PrintServer($#"{serverAddress}")
PrintQueueCollection queues = printServer.GetPrintQueues(new[] { EnumeratedPrintQueueTypes.Local });
foreach (var item in queues)
{
Console.WriteLine(item.Name)
}
If you want the full name (\\server.domain.local\PrinterName) use property FullName instead of Name :)
Related
I am printing using PrintDocument class.
I have a DB table having doc info to be printed. Instead of having its PrintName I just have IP address of the printer. All printers are installed locally. And I'm working on a windows service that will print those documents.
There is another app, out of my scope, where the user chose one printer, but just its IP is stored at DB... so
How can I set PrinterSettings.PrinterName having just its IP address??
By printername I assume you mean the name the printer is set up with in Windows and not the printer model, or sharename.
I don't really understand what you mean by the printers are installed locally. Is your computer acting as a printserver for the printers, since you have their IP address, or are they installed and shared from another printserver?
What you are actually looking for, when you only have the IP address is the printers TCPIPPrinterPort, which then is related to a printer. Unfortunatly the PrintServer class in C# doesn't return the hostaddress of the associated port (which is why we always name our ports "IP_10.200.49.230" or the like, because then you can find the port by name instead of hostaddress, which IS included in the printserver class.
In your situation I would do something like this:
static void Main(string[] args)
{
String serverName = "Print-Server"; //set servername (your own computername if you truly are hosting the printers locally)
String ipToSearchFor = "10.91.40.75";//ip to search for in this example
//this loads all TCPPrinterPorts into a Dictionary indexed by the ports Hostaddress (IP)
//I'm loading all because I assume you are going to iterate over them at some point, since It seems you have a list
Dictionary<string, ManagementObject> printerPorts = LoadScope(serverName, "select * from Win32_TCPIPPrinterPort");
//after we've got the ports, open the printserver
using (PrintServer ps = new PrintServer("\\\\" + serverName))
{
//find the queue where queueport.name equals name of port we look up from IP
var queue = ps.GetPrintQueues().Where(p => p.QueuePort.Name == printerPorts[ipToSearchFor]["Name"].ToString()).FirstOrDefault();
//print sharename
Console.WriteLine(queue.ShareName);
}
}
//Loads everything in scope into a dictionary, in this case indexed by hostaddress
private static Dictionary<string, ManagementObject> LoadScope(string server, string query)
{
ManagementScope scope = new ManagementScope("\\\\" + server + "\\root\\cimv2");
scope.Connect();
SelectQuery q = new SelectQuery(query);
ManagementObjectSearcher search = new ManagementObjectSearcher(scope, q);
ManagementObjectCollection pp = search.Get();
Dictionary<string, ManagementObject> objects = new Dictionary<string, ManagementObject>();
foreach (ManagementObject p in pp)
{
string name = p["HostAddress"].ToString().ToLower();
if (!objects.ContainsKey(name))
objects.Add(name, p);
}
return objects;
}
I would advise for you to loop through your list and from here on, also save the sharename and servername of the printer.
I've developed a printer search application that search for all online printers on the network. Im referring to this site - here
The button event handler is something like:
private void btnGetPrinters_Click(object sender, EventArgs e)
{
// Use the ObjectQuery to get the list of configured printers
System.Management.ObjectQuery oquery =
new System.Management.ObjectQuery("SELECT * FROM Win32_Printer");
System.Management.ManagementObjectSearcher mosearcher =
new System.Management.ManagementObjectSearcher(oquery);
System.Management.ManagementObjectCollection moc = mosearcher.Get();
foreach (ManagementObject mo in moc)
{
System.Management.PropertyDataCollection pdc = mo.Properties;
foreach (System.Management.PropertyData pd in pdc)
{
if ((bool)mo["Network"])
{
cmbPrinters.Items.Add(mo[pd.Name]);
}
}
}
}
but it's not working. I've debugged by line an found that the ((bool)mo["Network"]) cond. return false. Anyone have idea why this happen? I've checked my network and printers conn. It's all working fine. please advice.
I'm using ManagementObjectSearcher to load all the printers available in the network. There all the printers are returned in a ManagementObjectCollection. Is there anyway to find out all the details returned?
I used the debugging of c# to preview the object but it does not show all the data in there. I want to know what is available other than Printers[Name],Printers[Local],Printers[Network]. Is there a possible way to do this?
Code
System.Management.ManagementScope objMS =
new System.Management.ManagementScope(ManagementPath.DefaultPath);
objMS.Connect();
SelectQuery objQuery = new SelectQuery("SELECT * FROM Win32_Printer");
ManagementObjectSearcher objMOS = new ManagementObjectSearcher(objMS, objQuery);
System.Management.ManagementObjectCollection objMOC = objMOS.Get();
foreach (ManagementObject Printers in objMOC)
{
System.Management.PropertyDataCollection pdc = Printers.Properties;
if (Convert.ToBoolean(Printers["Local"])) // LOCAL PRINTERS.
{
comboBox8.Items.Add(Printers["Name"]);
}
if (Convert.ToBoolean(Printers["Network"])) // ALL NETWORK PRINTERS.
{
comboBox9.Items.Add(Printers["Name"]);
}
}
Generate strongly typed classes for Win32_Printer that will show you everything you need.
http://msdn.microsoft.com/en-us/library/2wkebaxa(v=vs.110).aspx - Mgmtclassgen.exe (Management Strongly Typed Class Generator)
You can enumerate the ManagementBaseObject.Properties property, and PropertyData.Qualifiers.
foreach (PropertyData property in properties)
{
Console.WriteLine(property.Name);
foreach (QualifierData q in property.Qualifiers)
{
if(q.Name.Equals("Description"))
{
Console.WriteLine(
processClass.GetPropertyQualifierValue(
property.Name, q.Name));
}
}
Console.WriteLine();
}
From MSDN
presently I am writing a small piece of code to get the list of web services hosted on IIS in a remote system,
the working code right now is :
string q2 = "select * from Win32_PerfFormattedData_W3SVC_WebService";
ManagementScope scope2 = new ManagementScope(string.Format(#"\\dtp-robaro2\{1}", host, ns), options);
// ns here is string ns = #"root\cimv2";
scope2.Connect();
ManagementObjectSearcher search2 = new ManagementObjectSearcher(scope, new ObjectQuery(q2));
foreach (ManagementObject mo in search2.Get())
{
Console.WriteLine(mo.ClassPath);
Console.WriteLine(mo.GetText(TextFormat.Mof));
}
now I was wondering if WMI is turned off on the remote system that i am querying then is there any alternative way to access the information i get with the above code?
Use tool Service Control - SC.EXE
I have converted this from VB.Net to C# so it may not be exactly correct, but this will do what you need:
public List<string> GetSites(string MachineName)
{
List<string> siteList = new List<string>();
DirectoryEntry iis = new DirectoryEntry(string.Format("IIS://{0}/w3svc/1/root", MachineName));
foreach (DirectoryEntry site in iis.Children) {
if (site.SchemaClassName == "IIsWebServer") {
siteList.Add(site.Properties("ServerComment").Value.ToString());
}
}
return siteList;
}
Is there a straightforward way to enumerate all visible network printers in .NET? Currently, I'm showing the PrintDialog to allow the user to select a printer. The problem with that is, local printers are displayed as well (along with XPS Document Writer and the like). If I can enumerate network printers myself, I can show a custom dialog with just those printers.
Thanks!!
Get the default printer from LocalPrintServer.DefaultPrintQueue
Get the installed printers (from user's perspective) from PrinterSettings.InstalledPrinters
Enumerate through the list:
Any printer beginning with \\ is a network printer - so get the queue with new PrintServer("\\UNCPATH").GetPrintQueue("QueueName")
Any printer not beginning with \\ is a local printer so get it with LocalPrintServer.GetQueue("Name")
You can see which is default by comparing FullName property.
Note: a network printer can be the default printer from LocalPrintServer.DefaultPrintQueue, but not appear in LocalPrintServer.GetPrintQueues()
// get available printers
LocalPrintServer printServer = new LocalPrintServer();
PrintQueue defaultPrintQueue = printServer.DefaultPrintQueue;
// get all printers installed (from the users perspective)he t
var printerNames = PrinterSettings.InstalledPrinters;
var availablePrinters = printerNames.Cast<string>().Select(printerName =>
{
var match = Regex.Match(printerName, #"(?<machine>\\\\.*?)\\(?<queue>.*)");
PrintQueue queue;
if (match.Success)
{
queue = new PrintServer(match.Groups["machine"].Value).GetPrintQueue(match.Groups["queue"].Value);
}
else
{
queue = printServer.GetPrintQueue(printerName);
}
var capabilities = queue.GetPrintCapabilities();
return new AvailablePrinterInfo()
{
Name = printerName,
Default = queue.FullName == defaultPrintQueue.FullName,
Duplex = capabilities.DuplexingCapability.Contains(Duplexing.TwoSidedLongEdge),
Color = capabilities.OutputColorCapability.Contains(OutputColor.Color)
};
}).ToArray();
DefaultPrinter = AvailablePrinters.SingleOrDefault(x => x.Default);
using the new System.Printing API
using (var printServer = new PrintServer(string.Format(#"\\{0}", PrinterServerName)))
{
foreach (var queue in printServer.GetPrintQueues())
{
if (!queue.IsShared)
{
continue;
}
Debug.WriteLine(queue.Name);
}
}
found this code here
private void btnGetPrinters_Click(object sender, EventArgs e)
{
// Use the ObjectQuery to get the list of configured printers
System.Management.ObjectQuery oquery =
new System.Management.ObjectQuery("SELECT * FROM Win32_Printer");
System.Management.ManagementObjectSearcher mosearcher =
new System.Management.ManagementObjectSearcher(oquery);
System.Management.ManagementObjectCollection moc = mosearcher.Get();
foreach (ManagementObject mo in moc)
{
System.Management.PropertyDataCollection pdc = mo.Properties;
foreach (System.Management.PropertyData pd in pdc)
{
if ((bool)mo["Network"])
{
cmbPrinters.Items.Add(mo[pd.Name]);
}
}
}
}
Update:
"This API function can enumerate all network resources, including servers, workstations, printers, shares, remote directories etc."
http://www.planet-source-code.com/vb/scripts/ShowCode.asp?txtCodeId=741&lngWId=10
PrinterSettiings.InstalledPrinters should give you the collection you want
In another post(https://stackoverflow.com/a/30758129/6513653) relationed to this one, Scott Chamberlain said "I do not believe there is anything in .NET that can do this, you will need to make a native call". After to try all the possible .NET resource, I think he is right.
So, I started to investigate how ADD PRINTER dialog does its search. Using Wireshark, I found out that ADD PRINTER send at least two types of packages to all hosts in local network: two http/xml request to 3911 port and three SNMP requests.
The first SNMP request is a get-next 1.3.6.1.2.1.43, which is Printer-MIB. The second one, is a get 1.3.6.1.4.1.2699.1.2.1.2.1.1.3 which is pmPrinterIEEE1284DeviceId of PRINTER-PORT-MONITOR-MIB. This is the most interesting because is where ADD PRINTER takes printer name. The third is a get 1.3.6.1.2.1.1.1.0, which is sysDescr of SNMP MIB-2 System.
I do believe that the second SNMP request is enough to find most of network printers in local network, so I did this code. It works for Windows Form Application and it depends on SnmpSharpNet.
Edit: I'm using ARP Ping instead normal Ping to search active hosts in network. Link for an example project: ListNetworks C# Project
Note that if you're working over RDP it seems to complicate this because it looks like it just exports everything on the host as a local printer.
Which is then a problem if you're expecting it to work the same way when not on RDP.