List all network printers per user - c#

at my work, we install printers on the per user basis. I'm trying to write a backup program that would list all networked printers given a username. Is that at all possible ? via WMI or System.IO would be OK. Here is the code that lists all the machines networked printers but not per user.
private void Button_Click(object sender, EventArgs e)
{
ConnectionOptions objConnection = new ConnectionOptions();
objConnection.Impersonation = ImpersonationLevel.Impersonate;
objConnection.EnablePrivileges = true;
string backupselectedcomputer = "Some Computer Name"
ManagementScope objScope = new ManagementScope("\\\\" + backupselectedcomputer +"\\root\\cimv2",objConnection);
objScope.Connect();
SelectQuery selectQuery = new SelectQuery();
selectQuery.QueryString = "Select * from win32_Printer Where Local = FALSE";
ManagementObjectSearcher MOS = new ManagementObjectSearcher(objScope, selectQuery);
ManagementObjectCollection MOC = MOS.Get();
foreach (ManagementObject mo in MOC)
{
//lbBackupprinters is a list box
lbBackupprinters.Items.Add(mo["Name"].ToString().ToUpper());
}
}

Figured out a way. Here is the code for anyone that comes across this issue.
private void ddlBackupselectuser_SelectionChangeCommitted(object sender, EventArgs e)
{
lbBackupprinters.Items.Clear();
string selecteduser = ddlBackupselectuser.Text;
string computer = ddlBackupselectcomp.Text;
string sid;
lblBackuppwd.Visible = true;
txtBackuppwd.Visible = true;
cboBackuppwdshow.Visible = true;
//BEGIN GRAB PRINTERS FROM REGISTRY
try
{
NTAccount ntuser = new NTAccount(selecteduser);
SecurityIdentifier sID = (SecurityIdentifier)ntuser.Translate(typeof(SecurityIdentifier));
lblBackupStatus.Text = sID.ToString();
sid = sID.ToString();
}
catch (IdentityNotMappedException)
{
lblBackupStatus.Text = "ERROR "+ ddlBackupselectuser.Text.ToString() + " contains no profile information";
lbBackupprinters.Items.Add("No Printers Found");
return;
}
ConnectionOptions co = new ConnectionOptions();
co.EnablePrivileges = true;
co.Impersonation = ImpersonationLevel.Impersonate;
System.Net.IPHostEntry h = System.Net.Dns.GetHostEntry(System.Net.Dns.GetHostName());
string IPAddress = h.AddressList.GetValue(0).ToString();
string lm = System.Net.Dns.GetHostName().ToString();
try
{
ManagementScope myScope = new ManagementScope("\\\\" + computer + "\\root\\default", co);
ManagementPath mypath = new ManagementPath("StdRegProv");
ManagementClass wmiRegistry = new ManagementClass(myScope, mypath, null);
const uint HKEY_LOCAL_MACHINE = unchecked((uint)0x80000002);
//ManagementClass wmiRegistry = new ManagementClass("root/default",
//"StdRegProv",null);
string keyPath = #"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Print\\Providers\\Client Side Rendering Print Provider\\" + sid + "\\Printers\\Connections";
object[] methodArgs = new object[] { HKEY_LOCAL_MACHINE, keyPath, null };
uint returnValue = (uint)wmiRegistry.InvokeMethod("EnumKey", methodArgs);
if (null != methodArgs[2])
{
string[] subKeys = methodArgs[2] as String[];
if (subKeys == null)
{
lbBackupprinters.Items.Add("No Printers Found");
return;
}
ManagementBaseObject inParam = wmiRegistry.GetMethodParameters("GetStringValue");
inParam["hDefKey"] = HKEY_LOCAL_MACHINE;
string keyName = "";
foreach (string subKey in subKeys)
{
//Display application name
keyPath = #"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Print\\Providers\\Client Side Rendering Print Provider\\" + sid + "\\Printers\\Connections" + subKey;
keyName = "DisplayName";
inParam["sSubKeyName"] = keyPath;
inParam["sValueName"] = keyName;
ManagementBaseObject outParam = wmiRegistry.InvokeMethod("GetStringValue", inParam, null);
lbBackupprinters.Items.Add(subKey);
}
}
else
{
lbBackupprinters.Items.Add("No Printers Found");
}
}
catch (Exception ex)
{
MessageBox.Show("Error: " + ex.Message);
}

Related

Getting the name of the installed program, its version and installation date WMI C#

I'm trying to get information about the programs installed on remote devices. At the moment, I found a way to output all installed programs. Is there a way to get the version and date of installation?
List<string> programs = new List<string>();
ConnectionOptions connectionOptions = new ConnectionOptions();
connectionOptions.Username = "USERNAME";
connectionOptions.Password = "USERPASS";
//connectionOptions.Impersonation = ImpersonationLevel.Impersonate;
string devicename = textBox8.Text;
ManagementScope scope = new ManagementScope("\\\\" + devicename + "\\root\\CIMV2", connectionOptions);
scope.Connect();
string softwareRegLoc = #"Software\Microsoft\Windows\CurrentVersion\Uninstall";
ManagementClass registry = new ManagementClass(scope, new ManagementPath("StdRegProv"), null);
ManagementBaseObject inParams = registry.GetMethodParameters("EnumKey");
inParams["hDefKey"] = 0x80000002;//HKEY_LOCAL_MACHINE
inParams["sSubKeyName"] = softwareRegLoc;
// Read Registry Key Names
ManagementBaseObject outParams = registry.InvokeMethod("EnumKey", inParams, null);
string[] programGuids = outParams["sNames"] as string[];
foreach (string subKeyName in programGuids)
{
inParams = registry.GetMethodParameters("GetStringValue");
inParams["hDefKey"] = 0x80000002;//HKEY_LOCAL_MACHINE
inParams["sSubKeyName"] = softwareRegLoc + #"\" + subKeyName;
inParams["sValueName"] = "DisplayName";
// Read Registry Value
outParams = registry.InvokeMethod("GetStringValue", inParams, null);
if (outParams.Properties["sValue"].Value != null)
{
string softwareName = outParams.Properties["sValue"].Value.ToString();
programs.Add(softwareName);
}
}
foreach (string softwareName in programs)
{
int n = dataGridView8.Rows.Add();
dataGridView8.Rows[n].DefaultCellStyle.BackColor = Color.LightGreen;
dataGridView8.Rows[n].Cells[0].Value = devicename;
dataGridView8.Rows[n].Cells[1].Value = softwareName;
dataGridView8.FirstDisplayedScrollingRowIndex = dataGridView8.RowCount - 1;
}
}
catch
{
MessageBox.Show("Something went wrong");
}
}
Welcome to Stack Overflow. Use ORMi library to get that information easily:
1) Install via NuGet:
Install-Package ORMi
2) Use the library:
using ORMi;
3) Instanciate and use:
WMIHelper helper = new WMIHelper("root\CimV2");
var programs = helper.Query("SELECT Name, Version, InstallDate FROM Win32_Product").ToList();
foreach(var p in programs)
{
Console.WriteLine(p.Name);
}
And that´s it. Then if you want to do some more advanced working you can define your model classes and query in a simpler way. You can read the docs on GitHub.

Lenovo BIOS WMI - InvalidQuery

I'm about to create a tool which gets some system information.
Only the Lenovo BIOS (WakeOnLAN) request isn't doing what I want.
The debugger always stops with a "invalid request" error message.
I tried the following...
ManagementObjectSearcher searcher = new ManagementObjectSearcher("\\\\" + textBox1.Text + "\\root\\wmi", "SELECT * FROM Lenovo_BiosSetting WHERE InstanceName='ACPI\\PNP0C14\\1_0'");
ManagementObjectSearcher searcher = new ManagementObjectSearcher("\\\\" + textBox1.Text + "\\root\\wmi:Lenovo_BiosSetting.InstanceName='ACPI\\PNP0C14\\1_0'");
Code:
//LenovoWOL
public string GetLenovoWOL()
{
ManagementObjectSearcher searcher = new ManagementObjectSearcher("\\\\" + textBox1.Text + "\\root\\wmi:Lenovo_BiosSetting", "SELECT * FROM ACPI\\PNP0C14\\1_0");
foreach (ManagementObject wmi in searcher.Get())
{
try
{
return Environment.NewLine + wmi.GetPropertyValue("CurrentSetting").ToString();
}
catch { }
}
return "Unknown";
}
Only if I remove the InstanceName part, the code works.
Could someone if you tell me, what I'm doing wrong.
Thanks for your help
Adrian
I found a solution.
Here my code. It's not pretty but it works.
ManagementPath path = new ManagementPath()
{
NamespacePath = #"root\wmi",
Server = textBox1.Text
};
ManagementScope scope = new ManagementScope(path);
SelectQuery Sq = new SelectQuery("Lenovo_BiosSetting");
ManagementObjectSearcher objOSDetails = new ManagementObjectSearcher(scope, Sq);
ManagementObjectCollection osDetailsCollection = objOSDetails.Get();
foreach (ManagementObject MO in osDetailsCollection)
{
if (MO["CurrentSetting"].ToString().Contains("WakeOnLAN"))
{
string[] arr = new string[3];
ListViewItem itm;
//add items to ListView
arr[0] = "";
arr[1] = "WakeOnLAN";
arr[2] = MO["CurrentSetting"].ToString();
itm = new ListViewItem(arr);
listView200.Items.Add(itm);
}
}
Adrian

I'm using WMI in C# to get all the installed softwares but it doesn't show all the softwares only Microsoft ones

public ManagementScope GetScope()
{
try
{
//string classScope="winmgmts:" + "{impersonationLevel=impersonate}!\\" + strComputer + "\\root\\cimv2";
string serverString = #"root\cimv2";
ManagementScope scope = new ManagementScope(serverString);
ConnectionOptions options = new ConnectionOptions
{
Impersonation = ImpersonationLevel.Impersonate,
Authentication = AuthenticationLevel.Connect,
EnablePrivileges = true
};
scope.Options = options;
return scope;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
throw;
}
}
public void InvokeMethodsFunctions1()
{
ManagementScope mScope = GetScope();
mScope.Connect();
if (mScope.IsConnected)
{
ManagementClass processClass =
new ManagementClass(mScope.Path);
ManagementObjectSearcher mos = new ManagementObjectSearcher(mScope, new ObjectQuery("SELECT * FROM Win32_Product"));
//get collection of WMI objects
ManagementObjectCollection queryCollection = mos.Get();
using (System.IO.StreamWriter file = new System.IO.StreamWriter(#"Result.txt"))
{
textBox1.Text = "";
//enumerate the collection.
foreach (ManagementObject m in queryCollection)
{
// access properties of the WMI object
string line = " " + m["Name"] + " , InstallDate : " + m["InstallDate"] + " LocalPackage : " + m["LocalPackage"];
Console.WriteLine(line);
file.WriteLine(line);
textBox1.Text += line + "\n";
}
}
}
}
So whats wrong in my Code ?
There is nothing wrong , the Win32_Product WMI class only list the products installed by the Windows Installer (MSI).
I just tested the following, simplified version of your code and I see everything installed on my pc, even services I wrote and installed myself:
var products = new ManagementObjectSearcher(new ObjectQuery("SELECT * FROM Win32_Product"));
var result = products.Get();
foreach (var product in result)
{
Console.WriteLine(product.GetPropertyValue("Name").ToString());
}
Console.ReadLine();
It looks like you are narrowing your query by scope, which is possibly why you aren't seeing everything, try the above and see if you have more luck.

c# - sharing a folder on local network

I try to share a folder on local network for a special group.
I create the group, then I add the current user to this group. After this I share the folder on the local network with all the permisson to access to this for the group. In network I see the folder, all the permissons is granted for the group, it seems everything fine, but I can't access the folder on the local network.
I use this code:
string ShareName = "SpecialShare";
string Description = "This is a test";
string folderPath = #"c:\ApplicationFolder\AppData";
try
{
NTAccount ntAccount = new NTAccount("SpecialGroup");
SecurityIdentifier oGroupSID = (SecurityIdentifier)ntAccount.Translate(typeof(SecurityIdentifier));
byte[] utenteSIDArray = new byte[oGroupSID.BinaryLength];
oGroupSID.GetBinaryForm(utenteSIDArray, 0);
ManagementClass oGroupTrustee = new ManagementClass(new ManagementPath("Win32_Trustee"), null);
oGroupTrustee["Name"] = "SpecialGroup";
oGroupTrustee["SID"] = utenteSIDArray;
ManagementClass oGroupACE = new ManagementClass(new ManagementPath("Win32_ACE"), null);
oGroupACE["AccessMask"] = 2032127; //full access
oGroupACE["AceFlags"] = AceFlags.ObjectInherit | AceFlags.ContainerInherit;
oGroupACE["AceType"] = AceType.AccessAllowed;
oGroupACE["Trustee"] = oGroupTrustee;
ManagementObject oGroupSecurityDescriptor = new ManagementClass(new ManagementPath("Win32_SecurityDescriptor"), null);
oGroupSecurityDescriptor["ControlFlags"] = 4;
oGroupSecurityDescriptor["DACL"] = new object[] { oGroupACE };
DirectoryInfo dInfo = new DirectoryInfo(folderPath);
DirectorySecurity dSecurity = dInfo.GetAccessControl();
dSecurity.AddAccessRule(new FileSystemAccessRule("SpecialGroup", FileSystemRights.FullControl, InheritanceFlags.ObjectInherit | InheritanceFlags.ContainerInherit, PropagationFlags.InheritOnly, AccessControlType.Allow));
dInfo.SetAccessControl(dSecurity);
ManagementClass managementClass = new ManagementClass("Win32_Share");
ManagementBaseObject inParams = managementClass.GetMethodParameters("Create");
//MessageBox.Show(managementClass.Derivation[0]);
inParams["Description"] = Description;
inParams["Name"] = ShareName;
inParams["Path"] = folderPath;
inParams["Type"] = 0; //Disk Drive
inParams["MaximumAllowed"] = null;
inParams["Password"] = null;
inParams["Access"] = oGroupSecurityDescriptor;
ManagementBaseObject outParams;
outParams = managementClass.InvokeMethod("Create", inParams, null);
if ((uint)(outParams.Properties["ReturnValue"].Value) != 0)
throw new Exception();
ManagementObject share = new ManagementObject(managementClass.Path + ".Name='" + ShareName + "'");
share.InvokeMethod("SetShareInfo", new object[] { Int32.MaxValue, Description, oGroupSecurityDescriptor });
dInfo.Refresh();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}

Problems Moving Computer in Active Directory with Distinguished Name

I was able to get the account-disabling part of my code to work, but to keep our AD tree even more clean, we have a specifically created !Disabled OU. I'd like my code to be able to both disable the computer account and move it into the !Disabled OU.
Here's what I have so far:
string computerName = Environment.MachineName;
using (PrincipalContext domainContext = new PrincipalContext(ContextType.Domain, null, "username", "password"))
{
ComputerPrincipal computer = ComputerPrincipal.FindByIdentity(domainContext, computerName);
if (computer != null)
{
try
{
computer.Enabled = false;
label3.Visible = true;
computer.Save();
label3.Text = "Computer was disabled in Active Directory." + "\n";
try
{
string LdapDomain = "prefix.domain.suffix";
string distinguishedName = string.Empty;
string connectionPrefix = "LDAP://" + LdapDomain;
DirectoryEntry entry = new DirectoryEntry(connectionPrefix);
DirectorySearcher mySearcher = new DirectorySearcher(entry);
mySearcher.Filter = "(&(objectClass=computer)(|(cn=" + computerName + ")(dn=" + computerName + ")))";
SearchResult result = mySearcher.FindOne();
if (result == null)
{
label3.Text += ("Unable to locate the distinguishedName for the object " + computerName + " in the " + LdapDomain + " domain." + "\n");
}
else if (result != null)
{
DirectoryEntry directoryObject = result.GetDirectoryEntry();
distinguishedName = "LDAP://" + directoryObject.Properties["distinguishedName"].Value;
label3.Text += ("Distinguished name is " + distinguishedName + "\n");
string newLocation = "OU=!Disabled,DC=prefix,DC=domain,DC=suffix";
DirectoryEntry nLocation = new DirectoryEntry("LDAP://" + newLocation);
string newName = directoryObject.Name;
//directoryObject.MoveTo(nLocation, newName);
DirectoryEntry moveParent = new DirectoryEntry(newLocation);
directoryObject.MoveTo(moveParent); //Comes from Microsoft example, as prior may have been possible cause of errors.
label3.Text += ("Successfully moved computer to the !Disabled OU");
nLocation.Close();
directoryObject.Close();
entry.Close();
entry.Dispose();
mySearcher.Dispose();
}
else
{
label3.Text += ("Unexpected error in moving computer.");
}
button1.Visible = true;
}
catch (Exception p)
{
label3.Text += ("Failed to move computer with exception " + p);
button1.Visible = true;
}
/*
public void Move(string objectLocation, string newLocation)
{
//For brevity, removed existence checks
DirectoryEntry eLocation = new DirectoryEntry("LDAP://" + objectLocation);
DirectoryEntry nLocation = new DirectoryEntry("LDAP://" + newLocation);
string newName = eLocation.Name;
eLocation.MoveTo(nLocation, newName);
nLocation.Close();
eLocation.Close();
}
*/
}
catch (Exception x)
{
label3.Visible = true;
label3.Text = "Unable to disable computer with exception " + x;
button1.Visible = true;
}
}
else if (computer == null)
{
label3.Visible = true;
label3.Text = "Computer was not found in Active Directory.";
button1.Visible = true;
}
else
{
label3.Visible = true;
label3.Text = "Unexpected error in computer search.";
button1.Visible = true;
}
}
The display aspects are pretty sloppy, but it's a quick and dirty Windows Form that displays all the things that are going on. The problem I'm having is that even though I have the distinguished name and can get a DirectoryEntry object from the search, when I call the MoveTo() method I get an error about the object not existing or not being found. Could someone point me in the right direction here?
I've considered binding to the two different OU's and using the DirectoryEntry.Children.Add() and DirectoryEntry.Children.Remove() methods as a workaround, but that doesn't fix the problem I'm having traversing AD.

Categories