Wednesday, 30 September 2015

Office 365 Non Delivery Reports with Powershell

The article helps you to get non delivery messages and failure reason from Office 365 by using powershell. In Exchange Online, we can generate message traffic reports by using the powershell cmdlet Get-Messagetrace.

Note: Before proceed, Connect Exchange Online Remote PowerShell.

The following command gets all the message traffic details for last 7 days.
Get-Messagetrace -Start (Get-Date).AddDays(-7).ToString() -End (Get-Date).ToString()
You need to apply filter if you want to track only non delivered messages.
Get-Messagetrace -Start (Get-Date).AddDays(-7).ToString() -End (Get-Date).ToString() | Where-Object { $_.Status -eq 'Failed'}
The Get-Messagetrace cmdlet returns the columns Received (Message Time), Sender Address, Recipient Address, Subject and Status. For non delivered message, the status column returns the value 'Failed' and it doesn't return the actual reason for the failure message. So, we need to use the another cmdlet Get-MessageTraceDetail to get failure reason of the non delivered message.

The following powershell script lists office 365 non delivered messages and its failure reason.
$failedTraces = Get-Messagetrace -Start (Get-Date).AddDays(-7).ToString() -End (Get-Date).ToString() | Where-Object { $_.Status -eq 'Failed'}
$failedTraces | Foreach-Object{
     $trace = $_      
     $stats = $trace |Get-MessageTraceDetail -event FAIL  
     New-Object -TypeName PSObject -Property @{
     MessageTime = $trace.Received
     Sender = $trace.SenderAddress
     Recipients = $trace.RecipientAddress
     Subject =$trace.Subject
     MessageSize = $trace.Size     
     StatusMessage =$stats.Detail
   }} 

Export Office 365 Non Delivery Reports to CSV

We can use the powershell cmedlet Export-CSV to export powershell output into CSV file. The following script exports all non delivered (failed) messages and its failure reason to csv file.
$failedTraces = Get-Messagetrace -Start (Get-Date).AddDays(-7).ToString() -End (Get-Date).ToString() | Where-Object { $_.Status -eq 'Failed'}
$failedTraces | Foreach-Object{
     $trace = $_      
     $stats = $trace |Get-MessageTraceDetail -event FAIL  
     New-Object -TypeName PSObject -Property @{
     MessageTime = $trace.Received
     Sender = $trace.SenderAddress
     Recipients = $trace.RecipientAddress
     Subject =$trace.Subject
     MessageSize = $trace.Size     
     StatusMessage =$stats.Detail
   }} |
Export-CSV "C:\\Office365NonDeliveryReport.csv" -NoTypeInformation -Encoding UTF8

List Distribution Group Members in office 365 Powershell

The article helps you to list distribution group members from office 365 by using powershell script. We can list distribution groups by using the powershell cmdlet Get-DistributionGroup and get distribution group members by using the cmdlet Get-DistributionGroupMember.

Note: Before proceed, Connect Exchange Online Remote PowerShell.

The following command lists all the office 365 distribution groups.
Get-DistributionGroup | Select DisplayName,GroupType,PrimarySmtpAddress

List Office 365 Distribution Group Members

Use the below powershell command to select members of single distribution group.
Get-DistributionGroupMember -Identity '[group_name]'
If you want to list members of all the cloud exchange distribution groups, first, we need to get the results of the Get-DistributionGroup cmdlet to a variable. Then we can pipe the variable to ForEach-Object and get members for all the distribution groups.
$Groups = Get-DistributionGroup
$Groups | ForEach-Object {
$group = $_.Name
Get-DistributionGroupMember $group | ForEach-Object {
      New-Object -TypeName PSObject -Property @{
       Group = $group
       Member = $_.Name
       EmailAddress = $_.PrimarySMTPAddress
       RecipientType= $_.RecipientType
}}}

Export All Distribution Group Members to CSV

We can export powershell output into CSV file using Export-CSV cmdlet. The following command exports all the office 365 distribution group members to CSV file.
$Groups = Get-DistributionGroup
$Groups | ForEach-Object {
$group = $_.Name
Get-DistributionGroupMember $group | ForEach-Object {
      New-Object -TypeName PSObject -Property @{
       Group = $group
       Member = $_.Name
       EmailAddress = $_.PrimarySMTPAddress
       RecipientType= $_.RecipientType
}}} |

Export-CSV "C:\\DistributionGroupMembers.csv" -NoTypeInformation -Encoding UTF8

List Distribution Groups in Office 365 Powershell

We can get all the office 365 distribution groups by using the powershell cmdlet Get-DistributionGroup. Before proceed, Connect Exchange Online Remote PowerShell.

The below command select and lists all the office 365 distribution groups.
Get-DistributionGroup | Select DisplayName,GroupType,PrimarySmtpAddress

List Distribution Group Members

We can use the powershell cmdlet Get-DistributionGroupMember to find and list office 365 distribution group members.
Get-DistributionGroupMember -Identity '<group_name>'
The following powershell command list all the distribution group members.
$Groups = Get-DistributionGroup
$Groups | ForEach-Object {
$group = $_.Name
Get-DistributionGroupMember $group | ForEach-Object {
      New-Object -TypeName PSObject -Property @{
       Group = $group
       Member = $_.Name
       EmailAddress = $_.PrimarySMTPAddress
       RecipientType= $_.RecipientType
}}}

Saturday, 26 September 2015

Set Office 365 user password via Powershell

We can set an Office 365 user password by using the Azure Active Directory powershell cmdlet Set-MsolUserPassword. To use this cmdlet we need to install Microsoft Online Services Sign-In Assistant and Azure Active Directory Powershell Module.

Note: Before proceed, Install and Configure Azure AD PowerShell

Set-MsolUserPassword –UserPrincipalName [UserPrincipalName] –NewPassword [New Password] -ForceChangePassword $False
The below command set the password for the user "Kevin@mts.com"
Set-MsolUserPassword –UserPrincipalName 'Kevin@mts.com' –NewPassword 'MyPa$$w0rd' -ForceChangePassword $False

Thursday, 24 September 2015

Change Password - Exception has been thrown by the target of an invocation

You may receive the error "System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation" when you try to change an AD user password with System.DirectoryServices.DirectoryEntry in C#.NET with following code.
var userEntry = new DirectoryEntry("LDAP://<GUID=" + guid + ">");
    userEntry.Invoke("ChangePassword", new object[] { oldPassword, newPassword });
    userEntry.CommitChanges();

Solution:

The error "Exception has been thrown by the target of an invocation" is a common error, it may occurs due to following cases:

1) The new password doesn't meet the domain complexity requirements.

2) Minimum Password Age is > 0.

3) Enforce password history may configured.

4) Any of the passwords is incorrect.

5) The user property "UserCannotChangePassword" set as True (Account options: User cannot change password).

You might have received on of the below error message.
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.UnauthorizedAccessException: Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))
   --- End of inner exception stack trace ---
   at System.DirectoryServices.DirectoryEntry.Invoke(String methodName, Object[] args)
   at System.DirectoryServices.AccountManagement.SDSUtils.ChangePassword(DirectoryEntry de, String oldPassword, String newPassword)
   at System.DirectoryServices.AccountManagement.ADStoreCtx.ChangePassword(AuthenticablePrincipal p, String oldPassword, String newPassword)
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.DirectoryServices.DirectoryServicesCOMException (0x8007202F): A constraint violation occurred. (Exception from HRESULT: 0x8007202F)

Exception has been thrown by the target of an invocation - Access is denied

Problem:

I have received the error "System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.UnauthorizedAccessException: Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED)) --- End of inner exception stack trace --- at System.DirectoryServices.DirectoryEntry.Invoke(String methodName, Object[] args) at System.DirectoryServices.AccountManagement.SDSUtils.ChangePassword(DirectoryEntry de, String oldPassword, String newPassword) at System.DirectoryServices.AccountManagement.ADStoreCtx.ChangePassword(AuthenticablePrincipal p, String oldPassword, String newPassword)" when I try to change an AD user password using C# code.

This is my C# code:

var userEntry = new DirectoryEntry("LDAP://<GUID=" + guid + ">");
    userEntry.Invoke("ChangePassword", new object[] { oldPassword, newPassword });
    userEntry.CommitChanges();

Solution:

In my case, the reason for this error is that the problematic user has the property "UserCannotChangePassword" as true. You can check the user's Account options: User cannot change password through ADUC console.

Change AD Password Exception has been thrown by the target of an invocation - Access is denied

Saturday, 19 September 2015

Get AD Nested Group Members with Powershell

This article helps you to query nested AD group members using powershell. We can get group members by using the Active Directory powershell cmlet Get-ADGroupMember. The Get-ADGroupMember cmdlet provides the option to get all the nested group members by passing the parameter -Recursive. This powershell script also handles circular membership (infinite loop) problem.
Import-Module ActiveDirectory

function Get-ADNestedGroupMembers {
  [cmdletbinding()]
  param ( [String] $Group )            
  Import-Module ActiveDirectory
  $Members = Get-ADGroupMember -Identity $Group -Recursive
  $members
}

Get-ADNestedGroupMembers "Domain Admins" | Select Name,DistinguishedName

Export Nested Group Members to CSV:

We can export the nested group members output to csv file by using the powershell cmdlet Export-CSV.
Import-Module ActiveDirectory

function Get-ADNestedGroupMembers {
  [cmdletbinding()]
  param ( [String] $Group )            
  Import-Module ActiveDirectory
  $Members = Get-ADGroupMember -Identity $Group -Recursive
  $members
}

Get-ADNestedGroupMembers "Domain Admins" | Select Name,DistinguishedName |
Export-CSV "C:\\ADNestedGroupMembers.csv" -NoTypeInformation -Encoding UTF8

Friday, 18 September 2015

Multiple LEFT JOINs in MS Access Database

If you are joining related link tables in MS Access database as like SQL Server database, it will work fine for a single link table, but it will not work for more than one join query. The below single join query will work fine in both MS Access and SQL database.
SELECT A.ca, B.cb
FROM TableA AS A LEFT JOIN TableB AS B ON B.id = A.id

Join more than one table in MS Access

If you want to join more than one tables, the below sql like join query will work only in SQl database.
SELECT A.ca, B.cb, C.cc
FROM TableA AS A LEFT JOIN TableB AS B ON B.id = A.id
LEFT JOIN TableC AS C ON C.id = A.id
If you run the above query in MS Access database, you will get the error "Syntax error (missing operator) in query expression".

To make multiple joins work in MS Access database, we need to enclose join query with parentheses.
SELECT A.ca, B.cb, C.cc
FROM (TableA AS A LEFT JOIN TableB AS B ON B.id = A.id)
LEFT JOIN TableC AS C ON C.id = A.id

Join more than two or more tables in MS Access

Like the above query, we need to add parentheses for every join query to make multiple joins work in MS Access database.
SELECT A.ca, B.cb, C.cc,D.cd
FROM ((TableA AS A LEFT JOIN TableB AS B ON B.id = A.id)
LEFT JOIN TableC AS C ON C.id = A.id)
LEFT JOIN TableD AS D ON D.id = A.id

Saturday, 12 September 2015

Remove Full Access Permission Office 365 Powershell

We can remove full access permission from an Exchange Online mailbox using the powershell cmdlet Remove-MailboxPermission.

Note: Before proceed, Connect Exchange Online Remote PowerShell.

Run the following command to remove the user Morgan's full access permission from Kevin’s mailbox.
Remove-MailboxPermission -Identity "Kevin@mts.com" -User "Morgan@mts.com" -AccessRights FullAccess
Identity - The name of the user on which the full access permission to be removed.
User - The mailbox that has the full access permission.

List mailbox permissions

Use the below command to list permissions of a mailbox.
Get-MailboxPermission -Identity 'Kevin@mts.com' | Select User, AccessRights, Deny
Use the below command to list permissions of all the mailboxes.
Get-Mailbox -ResultSize Unlimited | Get-MailboxPermission | Select Identity, User, AccessRights, Deny

Set Full Access Permissions Office 365 Powershell

We can set or grant full access permission for an office 365 mailbox using the powershell cmdlet Add-MailboxPermission .

Note: Before proceed, Connect Exchange Online Remote PowerShell.

Run the following command to grant full access permission to Morgan on the user Kevin’s mailbox.
Add-MailboxPermission -Identity "Kevin@mts.com" -User "Morgan@mts.com" -AccessRights FullAccess
Identity - The name of the user on which the full access permission should be added.
User - The mailbox that should be granted the full access permission.

Grant Full Access to all Mailboxes in Office 365

Use the below powershell script to configure full access permission for all the mailbox users in your Office 365.
Get-Mailbox -ResultSize Unlimited | Add-MailboxPermission -User "Morgan@mts.com" -AccessRights FullAccess

List mailbox permissions

If you want to list permissions of a mailbox, use the below command.
Get-MailboxPermission -Identity 'Kevin@mts.com' | Select User, AccessRights, Deny

Friday, 11 September 2015

Get AD Nested Group Membership with Powershell

This article helps you to understand how to query nested group memberships using powershell. The Microsoft given AD powershell cmdlet Get-ADPrincipalGroupMembership doesn’t provide option to get all the groups part of a nested group membership.

The below powershell command returns only direct memberships of a user.
Get-ADPrincipalGroupMembership "[username]"

Consider the scenario:

  • Consider the user "Smith" is member of the group "DG1".
  • And "DG1" in-turn member of the group "DG2".
  • And "DG2" in-turn member of the group "DG3".
In this case, if you run the above command, you will get only "DG1" as user Smith's membership group. But the user is member of all the three groups ("DG1","DG2","DG3") through nested members hierarchy. To address this need, you can use the below powershell function that helps you to get all direct and indirect membership of a user in Active Directory. This function will recursively enumerate memberships of a given user along with nesting level and parent group information and it will also handle circular membership (infinite loop) problem by holding nested group names in a hashtable.
Import-Module ActiveDirectory

function GetNestedADGroupMembership {
Param([parameter(Mandatory=$true)] $user,
  [parameter(Mandatory=$false)] $grouphash = @{})

   $groups = @(Get-ADPrincipalGroupMembership -Identity $user | select -ExpandProperty distinguishedname)
   foreach ($group in $groups) {
      if ( $grouphash[$group] -eq $null) {
         $grouphash[$group] = $true
         $group
         GetNestedADGroupMembership $group $grouphash
      }
   }
}

GetNestedADGroupMembership 'CN=Smith,OU=TestOU,DC=TestDomain,DC=com'

Thursday, 10 September 2015

Class not registered at ADOX.CatalogClass.Create

Problem:

When i try to create MS Access database (.mdb) file, I am getting an error "Class not registered at ADOX.CatalogClass.Create(String ConnectString) from Microsoft OLE DB Service Components". I am using below C# code to create MS Access .mdb file using OLEDB Connection.
ADOX.Catalog cat = new ADOX.Catalog();
cat.Create("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\\test.mdb");
Received below error message:
Class not registered : at ADOX.CatalogClass.Create(String ConnectString) at MyApp.DB.CreateDatabase()

Solution 1:

The OLEDB provider is supported only 64 bit application, so, to fix this problem, we have to change our application's build configuration to 32 bit mode.

Solution 2:

For me, the problem solved after changing my C# project's build configuration to x86 platform. If you received this error from IIS Server, follow the below steps to fix the issue.
  • Go to IIS and Application Pools in the left menu.
  • Right-click on the problematic Application Pool.
  • Click Advanced Settings. 
  • In General Tab, make the Enable 32 Bit Applications entry to "True"
Microsoft OLE DB - Class not registered - Microsoft.Jet.OLEDB.4.0

ERROR [IM002] [Microsoft][ODBC Driver Manager] Data source name not found and no default driver specified

Problem:

When i tried to connect MS Access database. I am getting an error "ERROR [IM002] [Microsoft][ODBC Driver Manager] Data source name not found and no default driver specified". I am using below C# code to connect MS Access .mdb file using Odbc Connection.
using (OdbcConnection myConnection = new OdbcConnection())
{
    myConnection.ConnectionString = @"Driver={Microsoft Access Driver (*.mdb)};" + "Dbq=C:\\test.mdb";
    myConnection.Open();    
};

Solution 1:

The ODBC Driver Manager is supported only 64 bit application, so, we have to force our application to build in 32 bit mode.

Solution 2:

The problem solved for me after changing my C# project's build configuration to x86 platform. If you faced this error from IIS service, do the below steps to fix the problem.
  • Go to IIS and Application Pools in the left menu.
  • Right-click on the problematic Application Pool.
  • Click Advanced Settings. 
  • In General Tab, make the Enable 32 Bit Applications entry to "True"
ERROR [IM002] [Microsoft][ODBC Driver Manager] Data source name not found and no default driver specified

Wednesday, 9 September 2015

Convert SID to Username using C#

In C#, we can use the P-Invoke function LookupAccountSid to resolve user name from sid and we can also use the C# .NET class SecurityIdentifier to translate security identifier (SID) to user name and use NTAccount class to translate user name to security identifier (SID).

Summary:

Convert SID to Username using P-Invoke:

The below C# code resolve user name from security identifier (SID).
const int NO_ERROR = 0;
const int ERROR_INSUFFICIENT_BUFFER = 122;

enum SID_NAME_USE
{
    SidTypeUser = 1,
    SidTypeGroup,
    SidTypeDomain,
    SidTypeAlias,
    SidTypeWellKnownGroup,
    SidTypeDeletedAccount,
    SidTypeInvalid,
    SidTypeUnknown,
    SidTypeComputer
}

[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern bool LookupAccountSid(
    string lpSystemName, [MarshalAs(UnmanagedType.LPArray)] byte[] Sid, StringBuilder lpName,
    ref uint cchName, StringBuilder ReferencedDomainName, ref uint cchReferencedDomainName, out SID_NAME_USE peUse);

static void Main(string[] args)
{
    // Sid for BUILTIN\Administrators
    GetUsernameFromSID("S-1-5-21-745457877-148782331-813991262-500");
}

private static void GetUsernameFromSID(string strSid)
{
    StringBuilder name = new StringBuilder();
    uint cchName = (uint)name.Capacity;
    StringBuilder referencedDomainName = new StringBuilder();
    uint cchReferencedDomainName = (uint)referencedDomainName.Capacity;
    SID_NAME_USE sidUse;

    var sid = new SecurityIdentifier(strSid);
    byte[] byteSid = new byte[sid.BinaryLength];
    sid.GetBinaryForm(byteSid, 0);

    int err = NO_ERROR;
    if (!LookupAccountSid(null, byteSid, name, ref cchName, referencedDomainName, ref cchReferencedDomainName, out sidUse))
    {
        err = System.Runtime.InteropServices.Marshal.GetLastWin32Error();
        if (err == ERROR_INSUFFICIENT_BUFFER)
        {
            name.EnsureCapacity((int)cchName);
            referencedDomainName.EnsureCapacity((int)cchReferencedDomainName);
            err = NO_ERROR;
            if (!LookupAccountSid(null, byteSid, name, ref cchName, referencedDomainName, ref cchReferencedDomainName, out sidUse))
                err = System.Runtime.InteropServices.Marshal.GetLastWin32Error();
        }
    }
    if (err == 0)
        Console.WriteLine(@"Found account {0} : {1}\{2}", sidUse, referencedDomainName.ToString(), name.ToString());
    else
        Console.WriteLine(@"Error : {0}", err);
}

Convert SID to Username using SecurityIdentifier:

The below C# code translate security identifier (SID) to username using SecurityIdentifier class.
private static void GetUsernameFromSID(string sid)
{
    SecurityIdentifier s = new SecurityIdentifier(sid);
    string username = s.Translate(typeof(NTAccount)).Value;
    Console.WriteLine(username);
}

Convert Username to SID using NTAccount:

The below C# code translate user account to SID using NTAccount class.
private static void GetSIDFromUsername(string username)
{
    NTAccount ntAcc = new NTAccount(username);
    string objectsid = ntAcc.Translate(typeof(SecurityIdentifier)).Value;
    Console.WriteLine(objectsid);
}

Tuesday, 8 September 2015

Convert SID to Username using Powershell

You might come across the object sid value in Active Directory environment. We can use the .NET Framework class System.Security.Principal.SecurityIdentifier in Windows PowerShell script to translate security identifier (SID) to user name and we can use the class System.Security.Principal.NTAccount to translate user name to security identifier (SID).

Convert SID to Username using Powershell

The below powershell script converts security identifier (SID) to user name. You can replace the variable $SID with your own sid value that you want to translate into user name.
$SID ='S-1-5-21-1924530255-1943933946-939161726-500'
$objSID = New-Object System.Security.Principal.SecurityIdentifier($SID)
$objUser = $objSID.Translate([System.Security.Principal.NTAccount])
Write-Host "Resolved user name: " $objUser.Value

Convert Username to SID using Powershell

The below powershell script converts user name to security identifier (SID). You can replace the variable $user with your own user account that you want to translate into sid.
$user ='TestDomain\Morgan'
$objUser = New-Object System.Security.Principal.NTAccount($user)
$objSID = $objUser.Translate([System.Security.Principal.SecurityIdentifier])
Write-Host "Resolved user's sid: " $objSID.Value

Monday, 7 September 2015

Export Office 365 Mailbox Size Report Powershell

We can get mailbox size and total messages count by using the office 365 powershell cmdlet Get-MailboxStatistics.

Note: Before proceed, Connect Exchange Online Remote PowerShell.

The below powershell command returns total mailbox size and messages count for the office 365 user 'Kevin'.
Get-MailboxStatistics -Identity 'Kevin' | Select DisplayName,ItemCount,TotalItemSize

Export all Mailbox Sizes to CSV on Office 365:

We have to use the powershell cmdlet Get-Mailbox to get all the Office 365 mailboxes and pipe the results into Get-MailboxStatistics cmdlet to get mailbox size and total messages count for all the Mailbox users. The below powershell script exports all mailbox sizes to csv and the output is sorted by mailbox size in descending order.
Get-Mailbox -ResultSize Unlimited  | Get-MailboxStatistics |
Select-Object -Property @{label=”User”;expression={$_.DisplayName}},
@{label=”Total Messages”;expression= {$_.ItemCount}},
@{label=”Total Size (MB)”;expression={[math]::Round(`
($_.TotalItemSize.ToString().Split("(")[1].Split(" ")[0].Replace(",","")/1MB),2)}} |
Sort "Total Size (MB)" -Descending |
Export-CSV "C:\\Office-365-Mailbox-Size.csv" -NoTypeInformation -Encoding UTF8

Check Mailbox Size Office 365 with Powershell

We can find mailbox size of all users by using the office 365 powershell cmdlet Get-MailboxStatistics. The Get-MailboxStatistics cmdlet is used to obtain information about a mailbox, such as the total size of the mailbox, the number of messages it contains, and the mailbox logon activity.

Note: Before proceed, Connect Exchange Online Remote PowerShell.

The below powershell command returns mailbox size and total mail count for the office 365 user 'Kevin'
Get-MailboxStatistics -Identity 'Kevin' | Select DisplayName,ItemCount,TotalItemSize

Get Mailbox size and usage for all Office 365 users:

You can use the powershell cmdlet Get-Mailbox to get all the mailboxes and pipe the results into Get-MailboxStatistics cmdlet to get mailbox size and total message count for all the users.
Get-Mailbox -ResultSize Unlimited  | Get-MailboxStatistics |
Select-Object -Property @{label=”User”;expression={$_.DisplayName}},
@{label=”Total Messages”;expression= {$_.ItemCount}},
@{label=”Total Size (MB)”;expression={[math]::Round(`
($_.TotalItemSize.ToString().Split("(")[1].Split(" ")[0].Replace(",","")/1MB),2)}}
Use the below command to sort mailbox list by mailbox size in descending order.
Get-Mailbox -ResultSize Unlimited  | Get-MailboxStatistics |
Select-Object -Property @{label=”User”;expression={$_.DisplayName}},
@{label=”Total Messages”;expression= {$_.ItemCount}},
@{label=”Total Size (MB)”;expression={[math]::Round(`
($_.TotalItemSize.ToString().Split("(")[1].Split(" ")[0].Replace(",","")/1MB),2)}} |
Sort "Total Size (MB)" -Descending

Wednesday, 2 September 2015

Exchange Server Role - msExchCurrentServerRoles attribute

We can use the Active Directory schema attribute "msExchCurrentServerRoles" to determine the role installed on the server. You can use this attribute, if you want to find the server role information through LDAP instead of exchange powershell. This attribute resides on the exchange server objects that exists in the Configuration container. You can check it through ADSIEdit by selecting Configuration context as well known Naming Context.
CN=<Servername>,CN=Servers,CN=Exchange Administrative Group,CN=Administrative Groups,CN=<Organization name>,CN=Microsoft Exchange,CN=Services,CN=Configuration,DC=<Domain Name>,DC<com>
The attribute msExchCurrentServerRoles holds maskable integer value, it includes the following values.
Mailbox role – 2
Client Access role (CAS) – 4
Unified Messaging role – 16
Hub Transport role – 32
Edge Transport role – 64
Use the below LDAP filters to get exchange servers by filtering with exchange server role:

Mailbox role:

(&(objectCategory=msExchExchangeServer)(msExchCurrentServerRoles:1.2.840.113556.1.4.803:=2))

Client Access role (CAS):

(&(objectCategory=msExchExchangeServer)(msExchCurrentServerRoles:1.2.840.113556.1.4.803:=4))

Unified Messaging role:

(&(objectCategory=msExchExchangeServer)(msExchCurrentServerRoles:1.2.840.113556.1.4.803:=16))

Hub Transport role:

(&(objectCategory=msExchExchangeServer)(msExchCurrentServerRoles:1.2.840.113556.1.4.803:=32))

Edge Transport role:

(&(objectCategory=msExchExchangeServer)(msExchCurrentServerRoles:1.2.840.113556.1.4.803:=64))

Find name of Exchange Organization in C#

In .NET C#, you can find the name your Exchange Organization using DirectoryEntry class from Configuration context store. Use the below C# code to get the name of your Exchange Organization by passing global catalog server.
//using System.DirectoryServices;
//-------------------------
private static string GetExchangeOrganizationName(string global_catalog_server)
{
    string organization = string.Empty;
    DirectoryEntry rootDSE = new DirectoryEntry("LDAP://" + global_catalog_server + "/rootDSE");
    string configDN = rootDSE.Properties["configurationNamingContext"].Value.ToString();
    string exOrgPath = "CN=Microsoft Exchange,CN=Services," + configDN;
    DirectoryEntry orgEntry = new DirectoryEntry("LDAP://" + global_catalog_server + "/" + exOrgPath);
    if (orgEntry.Children != null)
    {
        foreach (DirectoryEntry child in orgEntry.Children)
        {
            organization = child.Name.ToString().Replace("CN=", "");
            break;
        }
    }
    return organization;
}