Last active
November 16, 2021 16:06
-
-
Save liveaverage/4503265 to your computer and use it in GitHub Desktop.
Python alternative to getadsmtp.pl; Runs faster and performs the same AD query for valid SMTP recipients. Credits noted in the comments.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
#Credits: Marc Smith, http://marcitland.blogspot.com/2011/02/python-active-directory-linux.html | |
# DarkPixel, https://github.com/darkpixel/scripts/blob/master/getadsmtp.py | |
# JR, http://liveaverage.com | |
import sys, ldap, argparse | |
import ldap.modlist as modlist | |
from ldap.controls import SimplePagedResultsControl | |
parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter, description="Retrieve e-mail addresses from an LDAP server in postfix format") | |
parser.add_argument('-c', '--connect', required=True, action='store', help='The host to connect to (AD/Exchange Server)') | |
parser.add_argument('-r', '--port', action='store', help='Port to use for connecting, defaults to 636') | |
parser.add_argument('-u', '--user', action='store', required=True, help='Username to use (either cn=blah,dc=cust,dc=local or [email protected] format)') | |
parser.add_argument('-p', '--password', action='store', required=True, help='Password') | |
parser.add_argument('-o', '--ou', action='store', required=True, help='Org Unit (Base DN) to export from') | |
arg = parser.parse_args() | |
LDAP_SERVER = 'ldaps://%s:%s' %(arg.connect, arg.port or '3269') | |
BIND_DN = arg.user | |
BIND_PASS = arg.password | |
USER_FILTER = "(& (mailnickname=*) (| (objectClass=publicFolder)(&(objectCategory=person)(objectClass=user)(!(homeMDB=*))(!(msExchHomeServerName=*)))(&(objectCategory=person)(objectClass=user)(|(homeMDB=*)(msExchHomeServerName=*)))(objectCategory=person)(objectCategory=group)(objectClass=msExchDynamicDistributionList) ) (!(objectClass=contact)) )" | |
USER_BASE = arg.ou | |
PAGE_SIZE = 500 | |
# LDAP connection | |
try: | |
ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER) | |
ldap_connection = ldap.initialize(LDAP_SERVER) | |
ldap_connection.set_option(ldap.OPT_REFERRALS, 0) | |
ldap_connection.set_option(ldap.OPT_PROTOCOL_VERSION, 3) | |
ldap_connection.set_option(ldap.OPT_X_TLS,ldap.OPT_X_TLS_DEMAND) | |
ldap_connection.set_option( ldap.OPT_X_TLS_DEMAND, True ) | |
ldap_connection.set_option( ldap.OPT_DEBUG_LEVEL, 255 ) | |
ldap_connection.simple_bind_s(BIND_DN, BIND_PASS) | |
except ldap.LDAPError, e: | |
sys.stderr.write('Error connecting to LDAP server: ' + str(e) + '\n') | |
sys.exit(1) | |
# Lookup usernames from LDAP via paged search | |
paged_results_control = SimplePagedResultsControl( | |
ldap.LDAP_CONTROL_PAGE_OID, True, (PAGE_SIZE, '')) | |
accounts = [] | |
pages = 0 | |
while True: | |
serverctrls = [paged_results_control] | |
try: | |
msgid = ldap_connection.search_ext(USER_BASE, | |
ldap.SCOPE_SUBTREE, | |
USER_FILTER, | |
attrlist=['proxyAddresses'], | |
serverctrls=serverctrls) | |
except ldap.LDAPError, e: | |
sys.stderr.write('Error performing user paged search: ' + | |
str(e) + '\n') | |
sys.exit(1) | |
try: | |
unused_code, results, unused_msgid, serverctrls = \ | |
ldap_connection.result3(msgid) | |
except ldap.LDAPError, e: | |
sys.stderr.write('Error getting user paged search results: ' + | |
str(e) + '\n') | |
sys.exit(1) | |
for result in results: | |
pages += 1 | |
accounts.append(result) | |
cookie = None | |
for serverctrl in serverctrls: | |
if serverctrl.controlType == ldap.LDAP_CONTROL_PAGE_OID: | |
unused_est, cookie = serverctrl.controlValue | |
if cookie: | |
paged_results_control.controlValue = (PAGE_SIZE, cookie) | |
break | |
if not cookie: | |
break | |
# LDAP unbind | |
ldap_connection.unbind_s() | |
#Address Counter: | |
ac = 0 | |
for entry in accounts: | |
#DEBUG: Convert entry to string and print: | |
#print "%s" % str(entry) | |
if hasattr(entry[1], 'has_key') and entry[1].has_key('proxyAddresses'): | |
addresses = entry[1]['proxyAddresses'] | |
for addr in addresses: | |
if 'smtp:' in addr.lower(): | |
ac += 1 | |
print "%s OK" % (addr.lower().split('smtp:')[1]) | |
#DEBUG: Convert addr to string and print: | |
#print "%s" % str(addr) | |
print "# %d results" % len(accounts) | |
#print "%d proxyAddresses" % ac |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Revised the original script's LDAP filter to include Public Folders when scraping Exchange for valid proxyAddresses. I found out the hard way it wasn't adding PFs with associated mail addresses.