i have an app written in c#, that creates a list of all network drives that are mapped.
I used WMI to achieve this, here is how i did it:
List < NetworkConnection > networkConnections = new List < NetworkConnection > ();
try {
var path = new ManagementPath();
path.NamespacePath = "\\ROOT\\CIMV2";
path.ClassName = "Win32_NetworkConnection"; //https://msdn.microsoft.com/en-us/library/aa394220(v=vs.85).aspx
var management = new ManagementClass(path);
foreach(ManagementObject obj in management.GetInstances()) {
NetworkConnection networkConnection = new NetworkConnection() {
LocalName = (string) obj.Properties["LocalName"].Value,
Name = (string) obj.Properties["Name"].Value,
RemotePath = (string) obj.Properties["RemotePath"].Value,
UserName = (string) obj.Properties["UserName"].Value,
IsPersistent = (bool) obj.Properties["Persistent"].Value,
ConnectionState = (string) obj.Properties["ConnectionState"].Value
};
networkConnections.Add(networkConnection);
}
} catch (Exception ex) {
log.Error($ "Failed to get network connections.", ex);
}
return networkConnections;
While this does work on my test clients W7 and W8 64 and 32 bit. It wont work on my W10 clients.
On W10 I just get an emtpy list back.
It looks like management.GetInstances() does not return anything. But why?
Any help is greatly appreciated! Thanks!
Related
Update:
For me, LDAP way only worked for finding email addresses inside AD groups, for eg: named ITSolutionDeliveryDevelopers group. NOT inside Exchange Distribution Lists, for eg: named abc#domainname.com.
// I was able to figure out entry as suggested by #Gabriel Luci and
// all of the following possible formats worked for me:
// ngroupnet.com is my company domain name.
var entry = new DirectoryEntry();
var entry = new DirectoryEntry("LDAP://ngroupnet.com");
var entry = new DirectoryEntry("LDAP://ngroupnet.com", "MyAccountUsername", "MyAccountPassword");
var entry = new DirectoryEntry("LDAP://ngroupnet.com", "MyName#mycompany.com", "MyEmailAccountPassword");
For my complete answer, take a look below: https://stackoverflow.com/a/71518937/8644294
Original Question:
What is the best way to get all the individual email addresses comprising an exchange distribution list?
For eg: I have this distribution list called abc#domainname.com that has email addresses:
a#domainname.com
b#domainname.com
c#domainname.com
Now I need to get these addresses using C# code.
I found solution using LDAP but I felt it'd be a hassle to figure out LDAP path to my Active Directory.
// How do I get this LDAP Path, username and password?
// Is the username and password service account credentials of the app?
// And do they need to be registered in AD?
var entry = new DirectoryEntry("LDAP Path");//, username, password);
LDAP Way:
public static List<string> GetDistributionListMembers(string dlName = "abc#domainname.com")
{
var result = new List<string>();
try
{
// How do I get this LDAP Path?
var entry = new DirectoryEntry("LDAP Path");//, username, password);
var search = new DirectorySearcher(entry);
search.Filter = $"CN={dlName}";
int i = search.Filter.Length;
string str = "", str1 = "";
foreach (SearchResult AdObj in search.FindAll())
{
foreach (String objName in AdObj.GetDirectoryEntry().Properties["member"])
{
str += Convert.ToString(objName) + "<Br>";
int selIndex = objName.IndexOf("CN=") + 3;
int selEnd = objName.IndexOf(",OU") - 3;
str1 += objName.Substring(selIndex, selEnd).Replace("\\", "");
DirectorySearcher dsSearch = new DirectorySearcher(entry);
dsSearch.Filter = "CN=" + objName.Substring(selIndex, selEnd).Replace("\\", "");
foreach (SearchResult rs in dsSearch.FindAll())
{
//str1 += "<p align='right'><font face='calibri' color='#2266aa' size=2>" + Convert.ToString(rs.GetDirectoryEntry().Properties["mail"].Value) + "|" + Convert.ToString(rs.GetDirectoryEntry().Properties["displayName"].Value) + "|" + Convert.ToString(rs.GetDirectoryEntry().Properties["sAMAccountName"].Value) + "|" + Convert.ToString(rs.GetDirectoryEntry().Properties["department"].Value) + "|" + Convert.ToString(rs.GetDirectoryEntry().Properties["memberOf"].Value) + "</font></p>";
str1 = Convert.ToString(rs.GetDirectoryEntry().Properties["mail"].Value);
result.Add(str1);
}
}
}
return result;
}
catch (Exception ex)
{
//Do some logging or what have you.
throw;
}
}
So I just went with the EWS route.
EWS Way:
public static static List<string> GetDistributionListMembers(string dlName = "abc#domainname.com")
{
try
{
var service = new ExchangeService();
var cred = new WebCredentials("sharedmailbox#domain.com", "some_password");
service.Credentials = cred;
service.Url = new Uri("https://outlook.office365.com/ews/exchange.asmx");
service.TraceEnabled = true;
service.TraceFlags = TraceFlags.All;
var expandedEmailAddresses = new List<string>();
ExpandGroupResults myGroupMembers = service.ExpandGroup(dlName);
foreach (EmailAddress address in myGroupMembers.Members)
{
expandedEmailAddresses.Add(address.Address);
}
return expandedEmailAddresses;
}
catch (Exception ex)
{
// The DL doesn't have any members. Handle it how you want.
// Handle/ Log other errors.
}
}
Is EWS approach a good way?
If Yes, then I'm good. If not, I'll have to figure out that LDAP path.
Or if there's even a better way, please let me know.
If the computer you run this from is joined to the same domain as the group you're looking for, then you don't need to figure out the LDAP path. You can just do:
var search = new DirectorySearcher();
If your computer is not joined to the same domain, then you just use the domain name:
var entry = new DirectoryEntry("LDAP://domainname.com");
This requires that there is no firewall blocking port 389 between your computer and the domain controller(s). If you need to pass credentials, then do that:
var entry = new DirectoryEntry("LDAP://domainname.com", username, password);
The credentials can be any user on the domain.
That said, there are a lot of inefficiencies in your code that will make it run much slower than needed. I wrote an article about this that can help you update your code: Active Directory: Better Performance
Is EWS approach a good way?
If it works, it works. I'm not an expert on EWS (although I have used it), but I'm fairly certain that's using Basic Authentication, which is going to be disabled in October.
If all the Mailboxes are on Office365 then i would suggest you use the Graph API instead eg https://learn.microsoft.com/en-us/graph/api/group-list-members?view=graph-rest-1.0&tabs=http . There are several advantage in terms of security eg you could use Application permissions and all you need is access to the directory while if you did the same thing in EWS it would require full access to at least one mailbox.
LDAP will be best performing of the 3 if ultimate speed in the only thing that is important.
My complete solution for future reference. :)
EWS Way - For expanding Exchange Distribution Lists
public class SomeHelper
{
private static ExchangeService _exchangeService = null;
public static async Task<HashSet<string>> GetExchangeDistributionListMembersAsync(IEnumerable<string> dlNames)
{
var allEmailAddresses = new HashSet<string>();
foreach (var dlName in dlNames)
{
if (!SomeCache.TryGetCachedItem(dlName, out var dlMembers))
{
var groupEmailAddresses = new List<string>();
var exchangeService = await GetExchangeServiceAsync();
try
{
var myGroupMembers = exchangeService.ExpandGroup(dlName);
// Add the group members.
foreach (var address in myGroupMembers.Members)
{
groupEmailAddresses.Add(address.Address);
}
}
catch (Exception ex)
{
//If it can't expand the dlName, just return it.
groupEmailAddresses.Add(dlName);
//groupEmailAddresses.Add($"Attempting to expand '{dlName}' resulted in error message: '{ex.Message}'.");
}
// Cache the groupEmailAddresses for 7 days.
// Because Distribution Lists rarely change and expanding DL is an expensive operation.- AshishK Notes
SomeCache.AddItemToCache(dlName, groupEmailAddresses, 10080);
allEmailAddresses.UnionWith(groupEmailAddresses);
}
else
{
allEmailAddresses.UnionWith((List<string>)dlMembers);
}
}
return allEmailAddresses;
}
private static async Task<ExchangeService> GetExchangeServiceAsync()
{
if (_exchangeService == null)
{
_exchangeService = new ExchangeService();
var exchangeUrl = "https://outlook.office365.com/ews/exchange.asmx";
var cred = new WebCredentials("sharedmailbox#domain.com", "some_password");
_exchangeService.Credentials = cred;
//_exchangeService.AutodiscoverUrl("sharedmailbox#domain.com");
_exchangeService.Url = new Uri(exchangeUrl);
_exchangeService.TraceEnabled = true;
_exchangeService.TraceFlags = TraceFlags.All;
return _exchangeService;
}
else
{
return _exchangeService;
}
}
}
public class SomeCache
{
private static readonly ObjectCache _cache = MemoryCache.Default;
public static void AddItemToCache(string key, object itemToAdd, int cacheDurationMinutes)
{
var _policy = new CacheItemPolicy
{
Priority = CacheItemPriority.Default,
AbsoluteExpiration = DateTimeOffset.Now.AddMinutes(cacheDurationMinutes)
};
_cache.Set(key, itemToAdd, _policy);
}
public static bool TryGetCachedItem(string key, out object cachedObject)
{
try
{
cachedObject = _cache[key] as object;
}
catch (Exception ex)
{
cachedObject = null;
}
return !(cachedObject == null);
}
}
LDAP Way - For expanding Active Directory Groups
public static List<string> GetADGroupDistributionListMembers(string adGroupName)
{
var returnResult = new List<string>();
var entry = GetDirectoryEntry();
DirectorySearcher groupSearch = new DirectorySearcher(entry)
{
Filter = "(SAMAccountName=" + adGroupName + ")"
};
groupSearch.PropertiesToLoad.Add("member");
SearchResult groupResult = groupSearch.FindOne(); // getting members who belong to the adGroupName
if (groupResult != null)
{
for (int iSearchLoop = 0; iSearchLoop < groupResult.Properties["member"].Count; iSearchLoop++)
{
string userName = groupResult.Properties["member"][iSearchLoop].ToString();
int index = userName.IndexOf(',');
userName = userName.Substring(0, index).Replace("CN=", "").ToString(); // the name of the user will be fetched.
DirectorySearcher search = new DirectorySearcher(entry)
{
Filter = "(name=" + userName + ")"
};
search.PropertiesToLoad.Add("mail");
SearchResult result = search.FindOne(); //finding the mail id
if (result != null)
{
returnResult.Add(result.Properties["mail"][0].ToString());
}
}
}
return returnResult;
}
public static DirectoryEntry GetDirectoryEntry()
{
DirectoryEntry entryRoot = new DirectoryEntry("LDAP://RootDSE");
string Domain = (string)entryRoot.Properties["defaultNamingContext"][0];
DirectoryEntry de = new DirectoryEntry
{
Path = "LDAP://" + Domain,
AuthenticationType = AuthenticationTypes.Secure
};
return de;
}
I'm building a C# HID library for the Trezor. It's working well. I'm able to get past the pin entry and retrieve my xpub, and I can get addresses. However, none of the addresses that are getting returned match any of my addresses in the Trezor wallet website.
You can see the HID doco here:
https://doc.satoshilabs.com/trezor-tech/api-workflows.html#passphrase-meta-workflow
This is not really a C# question. Rather, it's a general question for any Trezor HID developers. The big problem is that if I pass a HDNodePathType message as the Multisig property of the GetAddress method, I get the error "Can't encode address'". What do I need to pass with the GetAddress message to get a valid address?
Here is an Android repo:
https://github.com/trezor/trezor-android
This problem has now been resolved. Trezor.Net has a working example can be cloned here.
Here is the code for getting an address:
public async Task<string> GetAddressAsync(IAddressPath addressPath, bool isPublicKey, bool display, AddressType addressType, InputScriptType inputScriptType, string coinName)
{
try
{
var path = addressPath.ToArray();
if (isPublicKey)
{
var publicKey = await SendMessageAsync<PublicKey, GetPublicKey>(new GetPublicKey { CoinName = coinName, AddressNs = path, ShowDisplay = display, ScriptType = inputScriptType });
return publicKey.Xpub;
}
else
{
switch (addressType)
{
case AddressType.Bitcoin:
//Ultra hack to deal with a coin name change in Firmware Version 1.6.2
if ((Features.MajorVersion <= 1 && Features.MinorVersion < 6) && coinName == "Bgold")
{
coinName = "Bitcoin Gold";
}
return (await SendMessageAsync<Address, GetAddress>(new GetAddress { ShowDisplay = display, AddressNs = path, CoinName = coinName, ScriptType = inputScriptType })).address;
case AddressType.Ethereum:
var ethereumAddress = await SendMessageAsync<EthereumAddress, EthereumGetAddress>(new EthereumGetAddress { ShowDisplay = display, AddressNs = path });
var sb = new StringBuilder();
foreach (var b in ethereumAddress.Address)
{
sb.Append(b.ToString("X2").ToLower());
}
var hexString = sb.ToString();
return $"0x{hexString}";
default:
throw new NotImplementedException();
}
}
}
catch (Exception ex)
{
Logger?.Log("Error Getting Trezor Address", LogSection, ex, LogLevel.Error);
throw;
}
}
I am using active directory and want a list of all users, basically in dotnet core. But I am receiving an exception:
Search result reference received, and referral following is off
Below is my code.
LdapSearchResults lsc = lc.Search("DC = xyz, DC = local", LdapConnection.SCOPE_ONE , "(|(objectClass = person)(objectClass = user))", null, false);
Necromancing - just in case the links go dark.
To fix it in your application, set ReferralFollowing to true.
if you get the message
Search result reference received, and referral following is off
, add
Novell.Directory.Ldap.LdapSearchConstraints cons = lc.SearchConstraints;
cons.ReferralFollowing = true;
lc.Constraints = cons;
to your code.
Example:
public static void GetUsers()
{
System.Collections.Generic.List<ARSoft.Tools.Net.Dns.SrvRecord> lsLdap = GetLdap();
ARSoft.Tools.Net.Dns.SrvRecord ldap = lsLdap[0];
string[] attrs = new string[] { "cn", "distinguishedName", "sAMAccountName", "userPrincipalName", "displayName", "givenName", "sn", "mail", "mailNickname", "memberOf", "homeDirectory", "msExchUserCulture" };
// CN = Common Name
// OU = Organizational Unit
// DC = Domain Component
string searchBase = "DC=cor,DC=local";
string searchFilter = "(&(objectClass=user)(objectCategory=person))";
string ldapHost = MySamples.TestSettings.ldapHost;
int ldapPort = MySamples.TestSettings.ldapPort;//System.Convert.ToInt32(args[1]);
string loginDN = MySamples.TestSettings.loginDN; // args[2];
string password = MySamples.TestSettings.password; // args[3];
Novell.Directory.Ldap.LdapConnection lc = new Novell.Directory.Ldap.LdapConnection();
int ldapVersion = Novell.Directory.Ldap.LdapConnection.Ldap_V3;
try
{
// connect to the server
lc.Connect(ldap.Target.ToString(), ldap.Port);
// bind to the server
lc.Bind(ldapVersion, loginDN, password);
Novell.Directory.Ldap.LdapSearchConstraints cons = lc.SearchConstraints;
cons.ReferralFollowing = true;
lc.Constraints = cons;
// To enable referral following, use LDAPConstraints.setReferralFollowing passing TRUE to enable referrals, or FALSE(default) to disable referrals.
Novell.Directory.Ldap.LdapSearchResults lsc = lc.Search(searchBase,
Novell.Directory.Ldap.LdapConnection.SCOPE_SUB,
searchFilter,
attrs,
false,
(Novell.Directory.Ldap.LdapSearchConstraints)null);
while (lsc.HasMore())
{
Novell.Directory.Ldap.LdapEntry nextEntry = null;
try
{
nextEntry = lsc.Next();
}
catch (Novell.Directory.Ldap.LdapReferralException eR)
{
// https://stackoverflow.com/questions/46052873/ldap-referal-error
// The response you received means that the directory you are requesting does not contain the data you look for,
// but they are in another directory, and in the response there is the information about the "referral" directory
// on which you need to rebind to "redo" the search.This principle in LDAP are the referral.
// https://www.novell.com/documentation/developer/ldapcsharp/?page=/documentation/developer/ldapcsharp/cnet/data/bp31k5d.html
// To enable referral following, use LDAPConstraints.setReferralFollowing passing TRUE to enable referrals, or FALSE (default) to disable referrals.
// are you sure your bind user meaning
// auth.impl.ldap.userid=CN=DotCMSUser,OU=Service Accounts,DC=mycompany,DC=intranet
// auth.impl.ldap.password = mypassword123
// has permissions to the user that is logging in and its groups?
System.Diagnostics.Debug.WriteLine(eR.LdapErrorMessage);
}
catch (Novell.Directory.Ldap.LdapException e)
{
// WARNING: Here catches only LDAP-Exception, no other types...
System.Console.WriteLine("Error: " + e.LdapErrorMessage);
// Exception is thrown, go for next entry
continue;
}
var atCN = nextEntry.getAttribute("cn");
var atUN = nextEntry.getAttribute("sAMAccountName");
var atDN = nextEntry.getAttribute("distinguishedName");
var atDIN = nextEntry.getAttribute("displayName");
if (atCN != null)
System.Console.WriteLine(atCN.StringValue);
if (atUN != null)
System.Console.WriteLine(atUN.StringValue);
if (atDN != null)
System.Console.WriteLine(atDN.StringValue);
if (atDIN != null)
System.Console.WriteLine(atDIN.StringValue);
System.Console.WriteLine("\n" + nextEntry.DN);
Novell.Directory.Ldap.LdapAttributeSet attributeSet = nextEntry.getAttributeSet();
System.Collections.IEnumerator ienum = attributeSet.GetEnumerator();
while (ienum.MoveNext())
{
Novell.Directory.Ldap.LdapAttribute attribute = (Novell.Directory.Ldap.LdapAttribute)ienum.Current;
string attributeName = attribute.Name;
string attributeVal = attribute.StringValue;
System.Console.WriteLine(attributeName + "value:" + attributeVal);
}
}
}
catch (System.Exception ex)
{
System.Console.WriteLine(ex.Message);
}
finally
{
// disconnect with the server
lc.Disconnect();
}
}
You have to activate the behaviour which will follow the referral returned by the directory.
The response you received means that the directory you are requesting does not contain the data you look for, but they are in another directory, and in the response there is the information about the "referral" directory on which you need to rebind to "redo" the search. This principle in LDAP are the referral.
I don't know how to do it in C#, but maybe have a look at :
https://www.novell.com/documentation/developer/ldapcsharp/?page=/documentation/developer/ldapcsharp/cnet/data/bp31k5d.html
I have a C#.net Windows form Application with SQL Server. My application use in Multiple user by local Network. Now I need to find Hard disk Serial Number which hard disk installed sql server (Note: By Using C#.net Application Data source ).
How can i find Hard disk Serial number throw by application data source?
This might be useful
using System;
using System.Management;
using System.Collections;
namespace WmiControl
{
public class WMI
{
public bool GetDiskSerial(string Computername)
{
try
{
ManagementScope scope = new ManagementScope(#"\\" + Computername + #"\root\cimv2");
scope.Connect();
ArrayList hdCollection;
ManagementObjectSearcher searcher;
if (GetDiskDrive(scope, out hdCollection, out searcher) || GetDiskSerial(scope, hdCollection, ref searcher))
return true;
else
return false;
}
catch (ManagementException)
{
return false;
}
}
private bool GetDiskSerial(ManagementScope scope, ArrayList hdCollection, ref ManagementObjectSearcher searcher)
{
try
{
ObjectQuery query1 = new ObjectQuery("SELECT * FROM Win32_PhysicalMedia");
searcher = new ManagementObjectSearcher(scope, query1);
int i = 0;
string sDiskSerial = "";
foreach (ManagementObject wmi_HD in searcher.Get())
{
// get the hard drive from collection
// using index
if (i < hdCollection.Count)
{
HardDrive hd = (HardDrive)hdCollection[i];
if (wmi_HD["SerialNumber"] == null)
hd.SerialNo = "";
else
hd.SerialNo = wmi_HD["SerialNumber"].ToString();
}
++i;
}
foreach (HardDrive hd in hdCollection)
{
if (!String.IsNullOrEmpty(hd.SerialNo))
{
sDiskSerial = hd.SerialNo;
break;
}
}
return true;
}
catch (Exception)
{
return false;
}
}
private bool GetDiskDrive(ManagementScope scope, out ArrayList hdCollection, out ManagementObjectSearcher searcher)
{
try
{
ObjectQuery query = new ObjectQuery("SELECT * FROM Win32_DiskDrive");
hdCollection = new ArrayList();
searcher = new ManagementObjectSearcher(scope, query);
foreach (ManagementObject wmi_HD in searcher.Get())
{
HardDrive hd = new HardDrive();
hd.Model = wmi_HD["Model"].ToString();
hd.Type = wmi_HD["InterfaceType"].ToString();
hdCollection.Add(hd);
return true;
}
return true;
}
catch (Exception)
{
hdCollection = null;
searcher = null;
return false;
}
}
}
class HardDrive
{
private string model = null;
private string type = null;
private string serialNo = null;
public string Model
{
get { return model; }
set { model = value; }
}
public string Type
{
get { return type; }
set { type = value; }
}
public string SerialNo
{
get { return serialNo; }
set { serialNo = value; }
}
}
}
See here for more info
You might want also to study CLR
You'll need to resort to WMI. With the proper privileges on the SQL Server machine, you can get the serial number of the hard-drives on it. See here for an example on retrieving the hard-disk's serial number using WMI.
You'll need to figure out which disk holds SQL Server and how to access the SQL Server machine on your own.
You have to do it in 3 stages:
The connection string of the data source gives you the name of the machine on which SQL Server is installed
You must then query the machine to find out the drive which drive SQL Server is installed on
You can then use the code supplied by others here to get the serial number
I developed an application that use the "finditemsAdvanced" api call of ebay.
It works without problem on windows 7 but when i try it on xp machines the function returns null!!!! I tried to debug it on xp, with vs2010 and vs 2008 but nothing!!!!
here the search class:
public SearchResult Search(Job searchedjob)
{
try
{
EbayFind service = new EbayFind();
service.Url = "http://svcs.ebay.com/services/search/FindingService/v1";
FindItemsAdvancedRequest findrequest = new FindItemsAdvancedRequest();
ItemFilter[] filtro = new ItemFilter[1];
int filter = 0;
//Tempo rimanente
filtro[filter] = new ItemFilter();
filtro[filter].name = ItemFilterType.EndTimeTo;
filtro[filter].value = new string[]
{
searchedjob.TimeLeft.ToString("yyyy-MM-ddTHH:mm:ss.000Z")
};
filter++;
findrequest.keywords = "canon";
findrequest.itemFilter = filtro;
findrequest.descriptionSearch = false;
// Setting the pagination
PaginationInput pagination = new PaginationInput();
pagination.entriesPerPageSpecified = true;
pagination.entriesPerPage = 25;
pagination.pageNumberSpecified = true;
pagination.pageNumber = 1;
findrequest.paginationInput = pagination;
findrequest.paginationInput = pagination;
// Creating an object to the BestMatchService class
FindItemsAdvancedResponse resp = service.findItemsAdvanced(findrequest);
SearchResult res = resp.searchResult;
return res;
}
and here the ebay call:
class EbayFind : FindingService
{
protected override System.Net.WebRequest GetWebRequest(Uri uri)
{
try
{
HttpWebRequest request = (HttpWebRequest)base.GetWebRequest(uri);
request.Headers.Add("X-EBAY-SOA-SECURITY-APPNAME", "myappid");
request.Headers.Add("X-EBAY-SOA-OPERATION-NAME", "findItemsAdvanced");
request.Headers.Add("X-EBAY-SOA-SERVICE-NAME", "FindingService");
request.Headers.Add("X-EBAY-SOA-MESSAGE-PROTOCOL", "SOAP11");
request.Headers.Add("X-EBAY-SOA-SERVICE-VERSION", "1.0.0");
request.Headers.Add("X-EBAY-SOA-GLOBAL-ID", "EBAY-US");
return request;
}
catch (Exception ex)
{
throw ex;
}
}
}
This code works on w7 machines, i don't understand why "res" is always null on xp!!!
The net framework installed is 3.5 and 4.0, it's not a framework issue i think.
Any ideas??
Thanks!
Stab in the dark -- Windows Firewall.
Try disabling it in the control panel while debugging. If it makes a difference, configure an exception to allow the api calls from your application through.