Wednesday, August 31, 2011

Reading Extended Rights on an Exchange database using ADSI and C#

Although there are a few better methods of doing this these days this is still handy to have especially if your running older versions of Exchange or you want to audit the raw ACE's that are being added by RBAC in Exchange 2010. Extended rights get used for a number of things EWS Impersonation is one, SendAs is another anyway here's an old C# sample I tripped over today.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.Security.AccessControl;
using System.DirectoryServices;

namespace showImpRights
{
class Program
{
static void Main(string[] args)
{
DirectoryEntry rootdse = new DirectoryEntry("LDAP://RootDSE");
DirectoryEntry cfg = new DirectoryEntry("LDAP://" + rootdse.Properties["configurationnamingcontext"].Value);
DirectoryEntry exRights = new DirectoryEntry("LDAP://cn=Extended-rights," + rootdse.Properties["configurationnamingcontext"].Value);
Hashtable exRighthash = new Hashtable();
foreach (DirectoryEntry chent in exRights.Children) {
if( exRighthash.ContainsKey(chent.Properties["rightsGuid"].Value) == false){
exRighthash.Add(chent.Properties["rightsGuid"].Value,chent.Properties["DisplayName"].Value);}
}

DirectorySearcher cfgsearch = new DirectorySearcher(cfg);
cfgsearch.Filter = "(objectCategory=msExchPrivateMDB)";
cfgsearch.PropertiesToLoad.Add("distinguishedName");
cfgsearch.SearchScope = SearchScope.Subtree;
SearchResultCollection res = cfgsearch.FindAll();
foreach (SearchResult se in res)
{
DirectoryEntry ssStoreObj = se.GetDirectoryEntry();
ActiveDirectorySecurity StoreobjSec = ssStoreObj.ObjectSecurity;
AuthorizationRuleCollection Storeacls = StoreobjSec.GetAccessRules(true, true, typeof(System.Security.Principal.SecurityIdentifier));
foreach (ActiveDirectoryAccessRule ace in Storeacls)
{
if (ace.IdentityReference.Value != "S-1-5-7" & ace.IdentityReference.Value != "S-1-1-0" & ace.IsInherited != true)
{
DirectoryEntry sidUser = new DirectoryEntry("LDAP://");
Console.WriteLine(sidUser.Properties["DisplayName"].Value.ToString());
Console.WriteLine(exRighthash[ace.ObjectType.ToString()].ToString());
}


}
}


}
}
}

Friday, August 05, 2011

Using the AllItems Search folder from Outlook 2010 on Exchange 2010 with Powershell and the EWS Managed API

Search folders in Exchange make searching for items in multiple folders a little more easier and/or allows you to group and find email with certain properties easier eg things like Unread email, Flagged for followup etc. Outlook 2010 makes use of these features for To-Do list etc. One useful search folder that gets created by Outlook 2010 when its used against a Exchange 2010 server is the AllItems search folder. eg this one




This is a search folder that gets created in the NON_IPM_Subtree folder and essentially allows you to do a generic search of all the folders within a Mailbox. This can be useful in a powershell script if you do need to enumerate every item within a mailbox to use the Allitems search folder you first need to do a search for this search folder in the Mailbox Root and then you can use some normal findItems enumeration code.

To filter a findfolders operation to only return search folders you can use the PR_Folder_Type extended property if this property is set to 2 then you know the folder is a search folder

$PR_FOLDER_TYPE = new-object Microsoft.Exchange.WebServices.Data.ExtendedPropertyDefinition(13825,[Microsoft.Exchange.WebServices.Data.MapiPropertyType]::Integer);


The following sample script shows how to return items that where received in January 2011 in all folders within a mailbox using the AllItems search folder with an AQS query. I've put a download of the code here the script itself looks like

$AqsString = "System.Message.DateReceived:01/01/2011..01/31/2011"
$MailboxName = "domain.com"

$dllpath = "C:\Program Files\Microsoft\Exchange\Web Services\1.1\Microsoft.Exchange.WebServices.dll"
[void][Reflection.Assembly]::LoadFile($dllpath)
$service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService([Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2010_SP1)
$service.Credentials = New-Object System.Net.NetworkCredential("user@domain.com","passwod")

$service.AutodiscoverUrl($MailboxName,{$true})
$PR_FOLDER_TYPE = new-object Microsoft.Exchange.WebServices.Data.ExtendedPropertyDefinition(13825,[Microsoft.Exchange.WebServices.Data.MapiPropertyType]::Integer);

"Checking : " + $MailboxName
$folderidcnt = new-object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Root,$MailboxName)
$fvFolderView = New-Object Microsoft.Exchange.WebServices.Data.FolderView(1000)
$fvFolderView.Traversal = [Microsoft.Exchange.WebServices.Data.FolderTraversal]::Shallow;
$sf1 = new-object Microsoft.Exchange.WebServices.Data.SearchFilter+IsEqualTo($PR_FOLDER_TYPE,"2")
$sf2 = new-object Microsoft.Exchange.WebServices.Data.SearchFilter+IsEqualTo([Microsoft.Exchange.WebServices.Data.FolderSchema]::DisplayName,"allitems")
$sfSearchFilterCol = new-object Microsoft.Exchange.WebServices.Data.SearchFilter+SearchFilterCollection([Microsoft.Exchange.WebServices.Data.LogicalOperator]::And)
$sfSearchFilterCol.Add($sf1)
$sfSearchFilterCol.Add($sf2)
$fiResult = $Service.FindFolders($folderidcnt,$sfSearchFilterCol,$fvFolderView)
$fiItems = $nulll
$ItemView = New-Object Microsoft.Exchange.WebServices.Data.ItemView(1000)
if($fiResult.Folders.Count -gt 0){
$fiResult.Folders[0].DisplayName
do{
$fiItems = $fiResult.Folders[0].findItems($AqsString,$ItemView)
$ItemView.offset += $fiItems .Items.Count
foreach($Item in $fiItems.Items){
$Item.Subject
}
}while($fiItems .MoreAvailable -eq $true)
}