benmo | 发布于 2017-02-15 19:13:50 | 阅读量 907 | Email
发布于 2017-02-15 19:13:50 | Email

Exchange迁移至iRedMail(LDAP)

文档导航

  • Exchange导出用户列表与通讯组
  • 数据处理与导入LDAP
  • 同步用户历史邮件
  • 登录验证
  • 修改DNS解析
  • 其他需求

 

Exchange导出用户列表与通讯组

  • 导出Exchange用户列表

依次打开'Exchange Management Console' --> 'Microfoft Exchange On-Permiss(example.com)' --> 'Recipient Configuration'-->'Mailbox'

右键'Export list...',选择本地磁盘,保存为'user.txt'

 


  • 导出Exchange通讯组列表

  这里,我们不选择EMC中导出,因为单独的groups我们并没有用,需要与用户有对应关系的一个列表,so,这里我们使用Powershell导出这个关系

  打开powershell,依次执行如下操作

# 添加Exchange命令行管理程序(根据自己的版本执行下面命令)
# Exchange 2007
Add-PSSnapin Microsoft.Exchange.Management.PowerShell.Admin
# Exchange 2010
Add-PSSnapin Microsoft.Exchange.Management.PowerShell.E2010
# Exchange 2013
Add-PSSnapin Microsoft.Exchange.Management.PowerShell.SnapIn
# 也可以用*代替
Add-PSSnapin Microsoft.Exchange*            
# 保存下面脚本,使用powershell执行,完成后会在
# D:\exchange_contact下生成以通讯组命名的文件,文件内包含邮件用户
 param
(
# 定义日志输出路径
$temppath="D:\exchange_contact"
)
#判断日志路径是否存在,如果不存在则建立目录
if(!(Test-Path $temppath))
{
#建立日志路径
New-Item -Path $temppath -ItemType "directory"
}
$groupNum=get-distributiongroup
#将所有通讯组输出到一个变量
#变更命令执行路径
Set-Location $temppath
#循环通讯组
foreach($groupnow in $groupNum)
{
# 输出通讯组成员,并且只输出名字
$groupmember=get-distributiongroupmember -identity $groupnow.name|select name
#定义输出的通讯组成员导出的文件
$tmppath=$temppath+"\"+$groupnow.PrimarySmtpAddress
#将通讯组成员导出为csv 文件
$groupmember |Export-Csv -Path $tmppath -encoding utf8
}

数据处理与导入LDAP

这里我们需要张大'iRedMail'安装程序tools目录下提供的脚本'create_mail_user_OpenLDAP.py'脚本来导入用户,

在这之前,我们要先处理之前得到的文本数据,呈现出以下格式来给这个脚本处理

domain name, username, password, [common name], [quota_in_bytes], [groups] 

 

  • 将之前的'user.txt'与'exchange_contact'打包上传到你iRedMail所在的邮件服务器

[root@mail hkmail]# ls
exchange_contact   userlist.sh  user.txt

 

  • 写一个脚本处理user.txtexchange_contact,生成需要的csv
bash userlist.sh >> exchange_mail.csv

userlist.sh脚本内容如下:

#!/bin/bash
# 生成的密码格式为username123(不包括@和后面一截)
# 默认配额4G
while read line; do
    display_name=`echo $line | awk -F'"' '{print $2}'`
    mail_address=`echo $line | awk '{print $NF}'`
    user_name=`echo $mail_address | awk -F'@' '{print $1}'`
    domain_name=`echo $mail_address | awk -F'@' '{print $2}'`
    default_pass="${user_name}123"
    memberofgroups=`grep -i "$display_name" -R exchange_contact/ | \
    awk -F'[/:]' '{print $2}' | sort -n | uniq | tr '\n' ':' | sed 's/:$//'`
    echo "$domain_name, $user_name, $default_pass, $display_name,\
    4294967296, $memberofgroups"
done<user.txt

查看生成的csv是否正确

[root@mail hkmail]# tail -n 5 exchange_mail.csv 
example.com, Yan.Ho, Yan.Ho123, Yan Ho, 4294967296, fna@example.com
example.com, Yvonne.yan, Yvonne.yan123, Yvonne yan, 4294967296, sale@example.com
example.com, long.zhang, long.zhang123, Zhang Long, 4294967296, 
example.com, Zhang.Yu, Zhang.Yu123, Zhang Yu, 4294967296, 
example.com, Zheng.Honglian, Zheng.Honglian123, Zheng Honglian, 4294967296,

 

  • 添加虚拟域(域都没有怎么导入?iredmail后台添加)

 

  • 生成通讯组(这里使用一个脚本来完成工作)
# 提取通讯组列表到文件
[root@mail ldap]# ll exchange_contact/* | awk '{print $NF}' >> groups.txt

# 执行脚本添加通讯组
[root@mail ldap]# ./managerGroups.sh -f groups.txt -a
添加组: Message@example.com                        [  OK  ]
添加组: mail@example.com                           [  OK  ]
添加组: STXGRMSupportGroup@example.com             [  OK  ]
添加组: Support.stcdc.lehman@example.com           [  OK  ]
添加组: szucp@example.com                          [  OK  ]
添加组: VTCNSRSSupportGroup@example.com            [  OK  ]
添加组: WarehousePROSupportGroup@example.com       [  OK  ]
添加组: WhelanEmail@example.com                    [  OK  ]
成功数: 8, 失败数: 0

脚本如下(自行修改ldap密码和访问权限,使用: bash managerGroups.sh -h):

#!/bin/bash
#############################################
# 添加或者删除某个组
# Anthor: 本末丶
# filename: managerGroups.sh
#############################################
. /etc/rc.d/init.d/functions

# 修改成你的配置
Policy='domain'
rootdn="cn=manager,dc=iredmail,dc=org"
basedn='o=domains,dc=iredmail,dc=org'
ldapass="you_pass"

# 默认参数
times=$(date +%s)
tmpfile="./.tmp.${0##*/}.${times}.ldif"
ldapsearch="/usr/bin/ldapsearch"
ldapadd="/usr/bin/ldapadd"
ldapdelete="/usr/bin/ldapdelete"
args="$*"

### Function Begin ###
# 帮助
usage() {
echo -e "
ldap通讯组管理:
Usage: $0 [-g|-f] [-a|-d]
        -g      要新增的组名
        -f      组名列表文件,
        -a      添加组
        -d      删除组

Example:
1.新增组it@example.com
\e[32m$0 -g it@example.com -a\e[0m

2.删除组it@comero.com
\e[32m$0 -g it@example.com -d\e[0m

3.批量新增组
\e[32m$0 -f grouplist.txt -a\e[0m
"
exit 1
}

# 执行添加操作
ldapAdd() {
mail="$1"
name=`echo ${mail} | awk -F"@" '{print $1}'`
domain=`echo ${mail} | awk -F"@" '{print $2}'`
options="mail=${mail},ou=Groups,domainName=${domain},${basedn}"
value=`${ldapsearch} -LL -H ldap://127.0.0.1 -x -D "${rootdn}" -w ${ldapass} \
-b "${options}" -t mail=${mail} mail 2>/dev/nul | egrep -v "version|^$"`
if [[ -z ${value} ]];then
        cat > ${tmpfile} <<-EOF
                dn: mail=${mail},ou=Groups,domainName=${domain},${basedn}
                accountStatus: active
                mail: ${mail}
                objectClass: mailList
                objectClass: top
                enabledService: mail
                enabledService: deliver
                enabledService: displayedInGlobalAddressBook
                accessPolicy: ${Policy}
                description: ${name}
        EOF

        # 执行ldapadd导入新数据
        ${ldapadd} -x -D ${rootdn} -w ${ldapass} -f ${tmpfile} >/dev/null 2>&1
        if [ $? -eq 0 ];then
                success;echo -e $"添加组: \e[33m${mail}\e[0m"
                # 成功后删除临时文件
                rm -f ${tmpfile}
                return 0
        else
                failure;echo -e $"\e[31m添加组: ${mail}\e[0m"
                return 1
        fi
else
        failure;echo -e $"\e[31m已存在组: ${mail}\e[0m"
        return 1
fi
}

ldapDelete() {
mail="$1"
name=`echo ${mail} | awk -F"@" '{print $1}'`
domain=`echo ${mail} | awk -F"@" '{print $2}'`
options="mail=${mail},ou=Groups,domainName=${domain},${basedn}"
value=`${ldapsearch} -LL -H ldap://127.0.0.1 -x -D "${rootdn}" -w ${ldapass} \
-b "${options}" -t mail=${mail} mail 2>/dev/nul | egrep -v "version|^$"`
if [[ ! -z ${value} ]]; then
        ${ldapdelete} -x -D "${rootdn}" -w ${ldapass} "${options}"
        if [ $? -eq 0 ];then
                success;echo -e $"删除组: \e[33m${mail}\e[0m"
                return 0
        else
                failure;echo -e $"\e[31m添加组: ${mail}\e[0m"
                return 1
        fi
else
        failure;echo -e "\e[31m未查询到相关组: ${mail}\e[0m"    
        return 1
fi

}

groupAction() {
succ=0
fail=0
echo ""
# 判断操作的是文件还是单个用户
if $flag;then
        while read group; do
                ${action} $group
                if [ $? -eq 0 ];then
                        let succ+=1
                else
                        let fail+=1
                fi
        done<${groups}
else
        ${action} $groups
        if [ $? -eq 0 ];then
                let succ+=1
        else
                let fail+=1
        fi
fi
echo -e "成功数: \e[33m${succ}\e[0m, 失败数: \e[31m${fail}\e[0m\n"

}
### Function End ###

# 参数为空打印帮助
if [ ${#args} -lt 1 ];then
        usage
fi

# 获取选项参数
while getopts :f:g:ad opt; do
    case $opt in
        g) groups=$OPTARG
           flag=false
        ;;
        f) groups=$OPTARG
           flag=true
        ;;
        a) action="ldapAdd"
           msg="新增"
        ;;
        d) action="ldapDelete"
           msg="删除"
        ;;
        \?|-h|--help) usage ;;
    esac
done

# 参数判断执行
if [ ! -z $groups ]
then
        if [ ! -z $action ];then
                groupAction
        else
                usage
        fi
else
        usage
fi

 

  • 准备就绪,开始导入ldap

找到张大的脚本'create_mail_user_OpenLDAP.py',先修改下符合自己的需求

cd /opt/soft/iRedMail-0.9.5-1/tools/
vim create_mail_user_OpenLDAP.py

修改如下内容:

# LDAP server address.
LDAP_URI = 'ldap://127.0.0.1:389'
# LDAP base dn.
BASEDN = 'o=domains,dc=iredmail,dc=org'
# Bind dn/password
BINDDN = 'cn=Manager,dc=iredmail,dc=org'
BINDPW = 'you_pass'
# 我这里只支持SSHA
DEFAULT_PASSWORD_SCHEME = 'SSHA'

# 212行左右,我的组包含的域名后缀,修改下
# Get group list.
    if groups.strip() != '':
        groups = groups.strip().split(':')
        for i in range(len(groups)):
            #groups[i] = groups[i] + '@' + domain
            groups[i] = groups[i]

 

  • 执行脚本生成ldif
[root@mail tools]# python create_mail_user_OpenLDAP.py exchange_mail.csv
< INFO > Remove exist file: exchange_mail.csv.ldif
< INFO > User data are stored in /opt/soft/iRedMail-0.9.5-1/tools/hkmail.csv.ldif, you can verify it before importing it.
< INFO > You can import it with below command:
ldapadd -x -D cn=Manager,dc=iredmail,dc=org -W -f /opt/soft/iRedMail-0.9.5-1/tools/exchange_mail.csv.ldif

 

  • 导入数据
ldapadd -x -D cn=Manager,dc=iredmail,dc=org -W -f exchange_mail.csv.ldif -c

 

同步用户历史邮件(imapsync)

由于Exchange用户的密码我们不可知,所以需要一个账户有权限访问所有用户的邮件数据,

执行如下操作:

  • Exchange中新建账户'pengjk@example.com'
  • 授权改用户对所有用户完全访问权限
# powershell中执行
Add-PSSnapin Microsoft.Exchange.Management.PowerShell.E2010
# 注:下面是一条命令,生成PDF会把下面截断,我分开2行了,注意自己贴上
Get-Mailbox -ResultSize unlimited | Add-MailboxPermission -User #接下面
pengjk -AccessRights fullaccess -InheritanceType all

输出如下

PS D:\> & '.\full acccess permission.ps1'

Identity             User           AccessRights     IsInherited Deny
--------             ----           ------------     ----------- ----
EXAMPLE.COM/Us... EHK\pengjk        {FullAccess}     False       False
EXAMPLE.COM/EH... EHK\pengjk        {FullAccess}     False       False
EXAMPLE.COM/EH... EHK\pengjk        {FullAccess}     False       False
EXAMPLE.COM/EH... EHK\pengjk        {FullAccess}     False       False
EXAMPLE.COM/Us... EHK\pengjk        {FullAccess}     False       False
EXAMPLE.COM/EH... EHK\pengjk        {FullAccess}     False       False

 

  • iRedMail主机上安装imapsync
yum -y install imapsync

 

  • 执行同步

同步一个账户的命令

 imapsync --host1 imap.example.com --user1 test01@example.com \
 --authuser1 pengjk@example.com --password1 you_pass \
 --host2 imap.example02.com --user2 test02@example.com --password2 test02123   

为了批量同步,我们使用一个脚本(mail_sync.sh

#!/bin/bash
source_mail='imap.example.com'
source_admin='pengjk@example.com'
source_admin_pass='you_pass'

dest_mail='imap.example.com'
pass_code='123'

while read source_user
do
    dest_user=${source_user}
    dest_user_pass=`echo ${dest_user} | \
    awk -v code=${pass_code} -F'@' '{print $1code}'`
    imapsync -usecache --host1 ${source_mail} --user1 ${source_user} \
    --authuser1 ${source_admin} --password1 ${source_admin_pass} \
    --host2 ${dest_mail} --user2 ${dest_user} --password2 ${dest_user_pass} \
    >/dev/null
done<mail_user.txt

后台同步

# 用之前Exchange导出的用户列表生成一个同步的列表
awk '{print $NF}' user.txt >> mail_user.txt

# 同步比较慢,我们放后台同步(确保对端可连)
nohup ./mail_sync.sh &

登录验证(略)

自建DNS验证吧


修改DNS解析(略)


其他需求

导入的用户,每个用户的密码随机生成,迁移前,向每个用户发送一份邮件,邮件内容包括: 新的邮件服务器地址,用户名,随机密码

来,说做就做,

文本如下

[root@mail hkmail]# tail -n3 mailpass.txt 
abuse@example.com
admin.azure@example.com
admin.strawberrynet@example.com

 

  • 利用脚本处理文本修改密码,同时会生成一个“账户,密码”的关系表
[root@mail hkmail]# bash userPassword.sh -f mailpass.txt 
修改用户密码: abuse@example.com(OHjxaF391z)                [  OK  ]
修改用户密码: admin.azure@example.com(TOOk1Y4Nn9)          [  OK  ]
修改用户密码: admin.strawberrynet@example.com(kLjiSECO8d)  [  OK  ]
... ...
成功用户数:79, 失败用户数: 0

生成列表文件: ./mailpass.txt.1487231757.csv

脚本userPassword.sh如下(使用方法: ./userPassword.sh -h

#!/bin/bash
#############################################
# 用户密码管理
# Anthor: 本末丶
#############################################
. /etc/rc.d/init.d/functions

# 参数
times=$(date +%s)
tmpfile="./.tmp.${0##*/}.${times}.ldif"
rootdn="cn=manager,dc=iredmail,dc=org"
ldapass="qaz123"
ldapcmd="/usr/bin/ldapsearch"
args="$*"

usage() {
echo -e "
用户密码管理:
Usage: $0 [-u|-f] [-p]
        -u      用户邮件名称,不指定'-p'则生成随机密码
        -f      用户邮件列表文件,每行一个用户(随机密码),或用户+密码(指定密码)
        -p      修改指定密码

Example:
1.用户pengjk@example.com修改密码为随机密码
\e[32m$0 -u pengjk@example.com\e[0m

2.用户pengjk@example.com修改密码为'abc123456'
\e[32m$0 -u pengjk@example.com -p abc123456\e[0m

3.批量修改用户密码,自动生成密码的话,会生成一个列表文件名+时间戳.csv文件
\e[32m$0 -f mail_user.txt\e[0m
"
exit 1
}

modifyTmpFile() {
# 修改临时文件
tmpfile=$1
changeto=$2

passwd=`encryptPass ${changeto}`
sed -i "/^dn:/a\changetype: modify\nreplace: \
userPassword\nuserPassword: ${passwd}\n" ${tmpfile}
ldapmodify -h localhost -p 389 -D ${rootdn} -w ${ldapass} -c -f ${tmpfile} \
>/dev/null 2>&1
return $?
}

# 加密密码
encryptPass() {
pass=$1
doveadm pw -s 'ssha' -p "$pass"
}

# 随机密码
generate_passwd() {
tr -cd '[:alnum:]' < /dev/urandom | fold -w10 | head -n1
}

changeUser() {
suc=0
fail=0
# 判断用户是否存在,并导出用户dn
if $files;then
    while read user changeto
    do
        # 未设置密码就生成随机密码
        if [ -z $changeto ];then
            changeto=`generate_passwd`
            # 标记用于否写入关系列表文件
            flag=1
        fi
        value=`${ldapcmd} -LL -H ldap://127.0.0.1 -x  -D "${rootdn}" \
        -w ${ldapass} -b "o=Domains,dc=iredmail,dc=org" -t mail=${user} dn | \
        egrep -v "version|^$" | sed -re '/dn/N;s/\n\s+//'`
        if [ ! -z ${value} ];then
            echo ${value} > ${tmpfile}
            # 将账号密码对应关系写入文件
            [ ! -z $flag ] && echo "${user}, ${changeto}" >> \
            ./${listfile}.${times}.csv
            modifyTmpFile ${tmpfile} ${changeto}
            if [ $? -eq 0 ];then
                success;echo -e \
                $"修改用户密码: \e[33m${user}(${changeto})\e[0m \n"
                let suc+=1
                # 删除临时文件
                rm -f ${tmpfile}
            else
                failure;echo -e "失败用户: \e[31m${user}\e[0m"
                let fail+=1
            fi
        else
            failure;echo -e $"不存在用户: \e[31m${user}\e[0m"
            let fail+=1
        fi
    done<${listfile}
    echo -e "成功用户数: \e[33m${suc}\e[0m, 失败用户数: \e[33m${fail}\e[0m\n"
    [ ! -z $flag ] && echo -e \
    "生成列表文件: \e[32m./${listfile}.${times}.csv\e[0m"
else
    [ -z $changeto ] && changeto=`generate_passwd`
    value=`${ldapcmd} -LL -H ldap://127.0.0.1 -x  -D "${rootdn}" \
    -w ${ldapass} -b "o=Domains,dc=iredmail,dc=org" -t mail=${mailuser} dn | \
    egrep -v "version|^$" | sed -re '/dn/N;s/\n\s+//'`
    if [[ ! -z ${value} ]];then
        echo ${value} > ${tmpfile}
        modifyTmpFile ${tmpfile} ${changeto}
        res=$?
        if [ $res -eq 0 ];then
            success;echo -e \
            $"修改用户密码: \e[33m${mailuser}(${changeto})\e[0m \n"
            let suc+=1
            # 删除临时文件
            rm -f ${tmpfile}
        else
            failure;echo -e $"失败用户: \e[31m${mailuser}\e[0m"
            let fail+=1
        fi
    else
        failure;echo -e $"不存在用户: \e[31m${mailuser}\e[0m"
        let fail+=1
    fi
fi
}

# get args
if [ ${#args} -lt 1 ];then
        usage
fi
while getopts :u:f:p: opt; do
    case $opt in
        u) mailuser=$OPTARG
           files=false
        ;;
        f) listfile=$OPTARG
           files=true
        ;;
        p) changeto=$OPTARG
        ;;
        \?|-h|--help) usage ;;
    esac
done

# Run func
if [[ "$mailuser"x != ""x ]];then
    changeUser
elif [ "$listfile"x != ""x ];then
    changeUser
else
    usage
fi

 

  • 修改完密码后,我们需要发送一份邮件给迁移前的账户

    这里使用上一步生成的'mailpass.txt.1487231757.csv'文件,用python读取这个文本发送就好了

# python2.7,python3下正常,py2.6自行修改代码
[root@mail hkmail]# python3.5 mail_to_user.py mailpass.txt.1487231757.csv
[Info] Sent abuse@example.com OK
[Info] Sent admin.azure@example.com OK
[Info] Sent admin.strawberrynet@example.com OK
... ...
Total: 79

mail_to_user.py脚本内容如下

# -- encoding: utf8 --
from email.header import Header
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email import encoders
import smtplib
import sys

# 处理的文件
passfile = sys.argv[1]

# 发送方邮件的地址
mail_from = 'mailadmin@163.com'
smtpserver = 'smtp.163.com'
password = 'you_pass'

# 新邮件服务器地址
mail_domain = 'mail.example.com'

# 附件选择
attach_file = False
file_name = '邮件系统说明.zip'
file_path = '/home/pengjk'

# debug
mail_debug = 0

def mailSent(message,mail_to):
    msg = MIMEMultipart()
    msg['From'] = ('邮件管理员<%s>' % mail_from)
    msg['To'] = mail_to
    msg['Subject'] = Header(subject, 'utf-8').encode()
    msg.attach(MIMEText(message, 'html', 'utf-8'))

    if attach_file:
        with open('%s/%s' % (file_path, file_name), 'rb') as f:
            mime = MIMEBase('application', 'zip', filename=file_name)
            mime.add_header('Content-Disposition', 'attachment', filename=file_name)
            mime.add_header('Content-ID', '<0>')
            mime.add_header('X-Attachment-Id', '0')
            mime.set_payload(f.read())
            encoders.encode_base64(mime)
            msg.attach(mime)

    try:
        server = smtplib.SMTP(smtpserver, 25)
        server.set_debuglevel(mail_debug)
        server.login(mail_from, password)
        server.sendmail(mail_from, mail_to, msg.as_string())
        server.quit()
        print('[Info] Sent %s OK' % mail_to)

    except Exception as e:
        print('[Error]: %s' % e)

if __name__ == '__main__':
    total = 0
    subject = '新邮件服务器信息(注意保存邮件!)'
    f = open(passfile, 'r')
    for line in f.readlines():
        mail_line = line.split(',')
        mail_user = mail_line[0]
        mail_pass = mail_line[1]
        message = '''
        <html><body>
        <p><b>新邮件服务器登陆地址:</b> <a href="https://%s">%s</a></p>
        <ul>
        <li><b>默认账号:</b> <font color="#FF0000">%s</font></li>
        <li><b>默认密码:</b> <font color="#FF0000">%s</font></li>
        </ul>
        </body></html>
        ''' % (mail_domain, mail_domain, mail_user, mail_pass)
        mailSent(message,mail_user)
        total += 1
    f.close()
    print('Total: %s' %total)

 

 


内容更新于: 2017-09-15 19:17:54
链接地址: http://blog.leanote.com/post/benmo/Exchange%E8%BF%81%E7%A7%BB%E8%87%B3iRedMail

上一篇: Linux下PHP添加SQL Server的mssql拓展

下一篇: 无

907 人读过
立即登录, 发表评论.
没有帐号? 立即注册
0 条评论
文档导航