我有以下代码通过某个字符串搜索全局通讯簿:
" CONF"
var esb = new ExchangeServiceBinding();
esb.Url = @"https://myurl.com/EWS/Exchange.asmx";
esb.Credentials = new NetworkCredential(_user,_pwd, _domain);
var rnType = new ResolveNamesType {ReturnFullContactData = true, UnresolvedEntry = "CONF"};
ResolveNamesResponseType response = esb.ResolveNames(rnType);
ArrayOfResponseMessagesType responses = resolveNamesResponse.ResponseMessages;
var responseMessage = responses.Items[0] as ResolveNamesResponseMessageType;
ResolutionType[] resolutions = responseMessage.ResolutionSet.Resolution;
问题在于它似乎正在做一个"从"开始搜索所以我的名字叫做:
" CONF-123"它会出现,但如果我有一个名字" JOE-CONF"然后它不会。
如何在此行上进行部分字符串搜索
var rnType = new ResolveNamesType {ReturnFullContactData = true, UnresolvedEntry = "CONF-"};
我希望有类似的东西:
var rnType = new ResolveNamesType {ReturnFullContactData = true, UnresolvedEntry = "%CONF-%"};
但这似乎不起作用。
答案 0 :(得分:5)
编辑: 2016年1月4日 - 添加了搜索AD的示例代码。
什么不行?
通过ResolveNames搜索GAL始终使用前缀字符串匹配来模糊名称解析(ARN)。虽然EWS文档没有明确说明,但Exchange ActiveSync文档可以。 EWS和Exchange ActiveSync只是协议;它们都依赖于下面的ARN,因此无论您使用的是ActiveSync协议还是EWS,都会遇到前缀匹配问题。
以下是Exchange ActiveSync文档(https://msdn.microsoft.com/en-us/library/ee159743%28v=exchg.80%29.aspx)
的相关引用使用提供给Search命令的文本查询字符串 在前缀字符串匹配
什么可行?
最好的办法取决于你的用例,但这里有一些想法:
在客户端程序中搜索Active Directory(包含您在问题中显示的代码的程序)
设置您自己的服务以搜索GAL。您的客户端程序将连接到Exchange和您的服务。或者您的服务可以代理EWS,因此客户端程序只需要连接到您的服务。
您将如何获得GAL数据?一种方法是重复使用EWS ResolveNames,一次获取GAL数据,100个条目,并在服务中缓存此数据。首先,检索所有" a" s,然后检索所有" b"等等。当然,可以有超过100个" a" s GAL,所以只需要获得所有" a" s就可以进行多次搜索 - 您将根据每次搜索返回的最后一个条目构建下一个搜索字符串。这可能是缓慢而痛苦的。您可能希望将此数据缓存在数据库中并定期刷新。
您也可以通过MAPI访问GAL。您可以直接使用MAPI(https://msdn.microsoft.com/en-us/library/cc765775%28v=office.12%29.aspx)或通过帮助库(如Redemption(http://www.dimastr.com/redemption/home.htm))。无论是直接使用MAPI还是通过Redemption,都需要在运行代码的计算机上安装Outlook(或Exchange)。由于此限制,最好不要在客户端程序中使用MAPI,而是将其粘贴在某个服务器上运行的服务中,并让客户端程序连接到该服务。
广告代码示例
另一个答案提供了搜索Active Directory的示例代码。我正在添加一个代码示例,可能更适合通过搜索找到此问题的人员的通用用法。与其他示例相比,下面的代码有以下改进:
如果搜索字符串包含任何特殊字符(如括号),则对它们进行转义,以使构造的过滤字符串有效。
仅通过samaccountname搜索就不够了。如果"大卫史密斯"有帐户名称" dsmith",搜索" David"通过samaccountname找不到他。我的示例显示了如何搜索更多字段,并提供了一些可能要搜索的字段。
从类似GC的根开始:"比尝试从Domain.GetComputerDomain()构建LDAP条目更健壮。
必须处理所有IDisposable
(通常在using
构造中使用它们。)
// Search Active Directory users.
public static IEnumerable<DirectoryEntry> SearchADUsers(string search) {
// Escape special characters in the search string.
string escapedSearch = search.Replace("*", "\\2a").Replace("(", "\\28")
.Replace(")", "\\29").Replace("/", "\\2f").Replace("\\", "\\5c");
// Find entries where search string appears in ANY of the following fields
// (you can add or remove fields to suit your needs).
// The '|' characters near the start of the expression means "any".
string searchPropertiesExpression = string.Format(
"(|(sn=*{0}*)(givenName=*{0}*)(cn=*{0}*)(dn=*{0}*)(samaccountname=*{0}*))",
escapedSearch);
// Only want users
string filter = "(&(objectCategory=Person)(" + searchPropertiesExpression + "))";
using (DirectoryEntry gc = new DirectoryEntry("GC:")) {
foreach (DirectoryEntry root in gc.Children) {
try {
using (DirectorySearcher s = new DirectorySearcher(root, filter)) {
s.ReferralChasing = ReferralChasingOption.All;
SearchResultCollection results = s.FindAll();
foreach (SearchResult result in results) {
using (DirectoryEntry de = result.GetDirectoryEntry()) {
yield return de;
}
}
}
} finally {
root.Dispose();
}
}
}
}
答案 1 :(得分:4)
虽然在EWS中无法进行通配符搜索,但在AD搜索中是可能的。 AD查询支持通配符。即,可以在AD中搜索* CONF *,这将返回包含“CONF”的所有结果。根据结果,查询相应Exchange对象的EWS。您需要找到一个参数,您可以使用该参数找到相应的EWS条目。我想电子邮件地址(用户名)应该足以找到相应的交换对象。
AD搜索代码段...
private SearchResultCollection SearchByName(string username, string password, string searchKeyword)
{
DirectorySearcher ds = new DirectorySearcher(new DirectoryEntry("LDAP://" + Domain.GetComputerDomain().ToString().ToLower(), username, password));
ds.Filter = "(&((&(objectCategory=Person)(objectClass=User)))(samaccountname=*" + searchKeyword + "*))";
ds.SearchScope = SearchScope.Subtree;
ds.ServerTimeLimit = TimeSpan.FromSeconds(90);
return ds.FindAll();
}
AD查询示例here。
答案 2 :(得分:0)
对索引文本字段的模糊搜索只能使用前缀(或后缀...)来完成。这就是为什么Exchange可能会将查询实现为LIKE&#39; CONF%&#39;。
我查看了文档并且没有任何方法可以绕过它 - 全表扫描(%CONF%必须是这种情况)似乎没有意义。
答案 3 :(得分:0)
我一直在尝试使用php-ews从PHP搜索GAL。在网页上,用户开始输入要搜索的名称,一旦输入了2个字符,就会调用read_contacts.php并传递输入的2个字符。 read_contacts.php使用EWS ResolveNames请求来检索有限的联系人列表。然后代码过滤某些条件,并检查displayName是否以输入的字符开头。然后返回过滤后的列表:
<?php
$staffName = $_GET['q'];
require_once './php-ews/EWSType.php';
require_once './php-ews/ExchangeWebServices.php';
require_once 'php-ews/EWSType/RestrictionType.php';
require_once 'php-ews/EWSType/ContainsExpressionType.php';
require_once 'php-ews/EWSType/PathToUnindexedFieldType.php';
require_once 'php-ews/EWSType/ConstantValueType.php';
require_once 'php-ews/EWSType/ContainmentModeType.php';
require_once 'php-ews/EWSType/ResolveNamesType.php';
require_once 'php-ews/EWSType/ResolveNamesSearchScopeType.php';
require_once 'php-ews/NTLMSoapClient.php';
require_once 'php-ews/NTLMSoapClient/Exchange.php';
$host = '[exchange server]';
$user = '[exchange user]';
$password = '[exchange password]';
$ews = new ExchangeWebServices($host, $user, $password);
$request = new EWSType_ResolveNamesType();
$request->ReturnFullContactData = true;
$request->UnresolvedEntry = $staffName;
$displayName = '';
$i = 0;
$staff_members = false;
$response = $ews->ResolveNames($request);
if ($response->ResponseMessages->ResolveNamesResponseMessage->ResponseClass == 'Error' && $response->ResponseMessages->ResolveNamesResponseMessage->MessageText == 'No results were found.') {
}
else {
$numNamesFound = $response->ResponseMessages->ResolveNamesResponseMessage->ResolutionSet->TotalItemsInView;
$i2=0;
for ($i=0;$i<$numNamesFound;$i++) {
if ($numNamesFound == 1) {
$displayName = $response->ResponseMessages->ResolveNamesResponseMessage->ResolutionSet->Resolution->Contact->DisplayName;
}
else {
$displayName = $response->ResponseMessages->ResolveNamesResponseMessage->ResolutionSet->Resolution[$i]->Contact->DisplayName;
}
echo "DisplayName: " . $displayName . "\n";
if (stripos($displayName, 'External') == true) {
}
else {
$searchLen = strlen($staffName);
if (strcasecmp(substr($displayName, 0, $searchLen), $staffName) == 0) {
if ($numNamesFound == 1) {
$emailAddress = $response->ResponseMessages->ResolveNamesResponseMessage->ResolutionSet->Resolution->Mailbox->EmailAddress;
}
else {
$emailAddress = $response->ResponseMessages->ResolveNamesResponseMessage->ResolutionSet->Resolution[$i]->Mailbox->EmailAddress;
}
$staff_members[$i2] = array( 'name' => $displayName,'email' => $emailAddress );
$i2++;
}
}
}
$staffJson = json_encode($staff_members);
echo $staffJson;
}
大部分时间这似乎都有效,即:'mi','jo'返回Mike,Michael或Joe,John,除非我为Simon发送'Si'或'si',然后ResolveNames调用从GAL返回前100个条目。
目前我已将输入的最小字符数增加到3,即:'sim',这样可行。问题是当我们让员工只有2个字符的名字时。
我只是想我会分享代码,看看它是否有帮助,看看是否有人知道为什么我的'si'无法正常工作。
我正在访问Exchange 2010