| Welcome to the Zimbra :: Forums! | |
Welcome, if you would like to post a comment please register.
We also encourage you to explore all things Zimbra with our team and members of the community.
|  | | 
01-16-2012, 05:53 AM
| | | O.o Great JOB!!!!!!!!!!!!!!!!!!!!!!!!!! | 
01-16-2012, 01:45 PM
| | Special Member | |
Posts: 138
| | kolomalo, thanks. I'm glad you tickled my thread. I recently found out my scripts needed an overhaul surrounding the automated purge function. I thought I had tested it out but apparently not (DoH!). Needless to say, my storage finally filled up and now the new-n-improved scripts work like they are supposed to.
I have updated the following scripts: In case anyone is interested, I have begun rolling out the Zimbra Desktop clients via Group Policy. I'm adding a few dozen machines to the policy every couple of days to minimize the impact of the login process when they 1st turn on their PCs. The 1st time they reboot after their machine has been added to the policy will do nothing more than download the latest group policy. The 2nd reboot will force the download of the 200 MB msi file and run the install before they are allowed to login (which can be fairly slow on our older PCs)
The next step is figuring out how I will be doing the cut-over from our production MS Exchange server to the Zimbra server. I'll also have to test out the migration wizard to see how that works. Hopefully, the migration wizard will let me convert all the mailboxes at once without having to do each mailbox one at a time (although I am willing to do it if necessary to get Zimbra in production!) I just need to make sure it won't take longer than a day. I do have a possible window to do this starting at 1pm on a Saturday as long as I am finished by 6am Monday. EDIT 2012-01-30: I noticed the Zimbra server hogging up the CPU and after a little bit of investigation, I found that it was running the nighttime offline backup script in the middle of the day...which was compressing the archive at the time...hence the high CPU utilization. The date/time was off by a whopping 8 hours! So I modified the root crontab schedule by adding an hourly update of the time service to fix that problem.
LHammonds
Last edited by LHammonds; 01-30-2012 at 02:53 PM..
| 
03-09-2012, 06:48 AM
| | | Your guide is absolutely fantastic. I have pretty much the exact same setup as you and I'm trying to integrate AD and Zimbra using your scripts but I'm having a problem with permissions.
This is probably a really noob problem, and I apologize if you covered this in your guide and I missed it, but I can't get any zm* (zmprov, etc) commands to run with out SU'ing to zimbra first, but that asks me for a password, which doesn't work for an automated script. Your script doesn't use SUDO for the chown/chmod commands or SU for the zmprov commands, so how do you do get the script to run?
Right now I'm just running the script manually from the command line as a proof-of-concept before I attempt to automate it.
Again, thanks for the amazing guide! | 
03-14-2012, 03:01 AM
| | | Really useful for deployment, thanks | 
03-18-2012, 10:39 AM
| | Special Member | |
Posts: 138
| | Quote:
Originally Posted by digidt I can't get any zm* (zmprov, etc) commands to run with out SU'ing to zimbra first, but that asks me for a password, which doesn't work for an automated script. Your script doesn't use SUDO for the chown/chmod commands or SU for the zmprov commands, so how do you do get the script to run? | Howdy, sorry for not replying sooner, I just got back from vacation.
The reason I have not been using SUDO commands is that I configured the root password as one of the 1st things I did after logging into Ubuntu. Once I set the root password, I then logged in as root or did an "su" into the root account with the password I configured for it. From there, running the commands do not require SUDO because the account is already the super user.
Typically, you don't want to login to your servers with root access...however, when setting the server up, it can save a lot of time at the cost of great potential for messing up...however, in the case of a new server being setup, I don't see this as being a problem.
The schedules that run the scripts are done under the root user account and thus also do not require the SUDO system and prompting for passwords. Quote:
Originally Posted by jackychen.rlc Really useful for deployment, thanks | You're welcome. I just hope it is good enough to run a production system.
I really need to get busy testing and documenting the mailbox conversion process so I get this project done.
LHammonds | 
03-24-2012, 01:44 PM
| | | Updated "Export AD users to a comma-delimited file" script I've modified your VBscript and Shell scripts to accommodate multiple email domains based on Active Directory group membership and also identify disabled AD users so their email accounts can be closed automatically in Zimbra.
I've also modified the VBScript to put the CSV on a share on the mail server instead of the shell script reaching out to a share on my Windows server. The reason for this is that the Shell script needs domain authentication to read/write to an Windows share and I felt that putting a cleartext domain username/password in a script would be bad.
So let's say you have the following domain names in your Zimbra deployment: acme.com, widgets.com and derp.com and some of your employees (but not necessarily all) need an email account in two or more of these domains. All you'd do is add your users to the appropriate "zimbraDomain_" group and voila! the scripts will create a user account for all of the domains that they need.
My script looks for the following AD groups:
zimbraDomain_acme.com, zimbraDomain_widgets.com and zimbraDomain_derp.com and so on.
When it finds an AD group with "zimbraDomain_" in the name it isolates the domain name portion (acme.com for example) and places it in the CSV file. If you need to add another domain all you need to do is create it in Zimbra and then create a new AD group like "zimbraDomain_ ", add your users to it and they'll automagically be added to the new domain.
There's also a bit of code that identifies if the user has been disabled in AD and if it is the VBscript inserts "AccountDisabled" it into the CSV file.
Modified VBScript Code: Option Explicit
'****************************************
'** Name: export_zimbra_ad_users.vbs
'** Version: 1.2
'** Date: 2012-03-24
'** Authors: LHammonds, digidt
'** Purpose: Export AD users to a comma-delimited file
'** that are authorized to have a Zimbra mailbox.
'****************************************
'* Field #1 = LoginID
'* Field #2 = First Name
'* Field #3 = Middle Initial
'* Field #4 = Last Name
'* Field #5 = Full Name
'* Field #6 = Title
'* Field #7 = Description
'* Field #8 = Comments
'* Field #9 = Telephone
'* Field #10 = Home Phone
'* Field #11 = Mobile Phone
'* Field #12 = Fax Number
'* Field #13 = Pager
'* Field #14 = Company
'* Field #15 = Office
'* Field #16 = Street Address
'* Field #17 = PO Box
'* Field #18 = City
'* Field #19 = State
'* Field #20 = Postal Code
'* Field #21 = Country
'* Field #21 = Password Replacement Value
'* Field #22 = Account disabled TRUE or FALSE
'* Field #22 = Domain to add the user too in Zimbra
'* Field #23 = Unused (mainly to avoid the end-of-line character being read into the last value)
'** NOTE: This could use a data cleanup routine that replaces all commas in a **
'** variable with something else such as a period instead to avoid CSV issues. **
Const ForAppending = 8
Const FilePath = "UNC TO SHARE ON MAIL ZERVER\adlist.csv"
Const ZimbraDomainGroup = "zimbraDomain_"
Const DefaultPassword = "ChangeThisPassword"
Dim objRootDSE, strDNC, objDomain, objFSO, objFile
Set objRootDSE = GetObject("LDAP://RootDSE")
strDNC = objRootDSE.Get("DefaultNamingContext")
Set objDomain = GetObject("LDAP://" & strDNC)
'** Create / Overwrite the export file. **
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.CreateTextFile(FilePath)
objFile.Close
Set objFile = Nothing
Call TrollTheFolders(objDomain)
'msgbox "Done!"
Sub TrollTheFolders(pobjDomain)
'** Function: Traverse the AD structure to find users wherever they may reside. **
'** The trick is that this function is called recursively in order to **
'** inspect every sub-folder that may contain user accounts. **
Dim lobjFile, lobjFSO, lobjMember, lstrLine, lblnInZimbraGroup
Dim lstrSamAccountName, lstrFirstName, lstrInitials, lstrLastName
Dim lstrFullName, lstrTitle, lstrDescription, lstrComment
Dim lstrTelephoneNumber, lstrHomePhone, lstrMobile, lstrFaxNumber, lstrPager
Dim lstrCompany, lstrOffice, lstrStreetAddress, lstrPostOfficeBox
Dim lstrCity, lstrState, lstrPostalCode, lstrCountry, lstrPassword
Dim lcolGroups, lobjGroup, lstrTemp
Dim lstrAccountDisabled, userEmailDomain, domainName
For Each lobjMember In pobjDomain
'** Examine each object but process only "user" objects. **
If lobjMember.Class = "user" Then
Set lobjFile = objFSO.OpenTextFile (FilePath, ForAppending, True)
If Not (isempty(lobjMember.samAccountName)) Then lstrSamAccountName = lobjMember.samAccountName Else lstrSamAccountName = "" End If
If Not (isempty(lobjMember.GivenName)) Then lstrFirstName = lobjMember.GivenName Else lstrFirstName = "" End If
If Not (isempty(lobjMember.initials)) Then lstrInitials = lobjMember.initials Else lstrInitials = "" End If
If Not (isempty(lobjMember.sn)) Then lstrLastname = lobjMember.sn Else lstrLastName = "" End If
If Not (isempty(lobjMember.CN)) Then lstrFullName = lobjMember.CN Else lstrFullName = "" End If
If Not (isempty(lobjMember.title)) Then lstrTitle = lobjMember.title Else lstrTitle = "" End If
If Not (isempty(lobjMember.Description)) Then lstrDescription = lobjMember.Description Else lstrDescription = "" End If
If Not (isempty(lobjMember.comment)) Then lstrComment = lobjMember.comment Else lstrComment = "" End If
If Not (isempty(lobjMember.telephoneNumber)) Then lstrTelephoneNumber = lobjMember.telephoneNumber Else lstrTelephoneNumber = "" End If
If Not (isempty(lobjMember.homePhone)) Then lstrHomePhone = lobjMember.homePhone Else lstrHomePhone = "" End If
If Not (isempty(lobjMember.mobile)) Then lstrMobile = lobjMember.mobile Else lstrMobile = "" End If
If Not (isempty(lobjMember.otherFacsimileTelephoneNumber)) Then lstrFaxNumber = lobjMember.otherFacsimileTelephoneNumber Else lstrFaxNumber = "" End If
If Not (isempty(lobjMember.pager)) Then lstrPager = lobjMember.pager Else lstrPager = "" End If
If Not (isempty(lobjMember.company)) Then lstrCompany = lobjMember.company Else lstrCompany = "" End If
If Not (isempty(lobjMember.physicalDeliveryOfficeName)) Then lstrOffice = lobjMember.physicalDeliveryOfficeName Else lstrOffice = "" End If
If Not (isempty(lobjMember.streetAddress)) Then lstrStreetAddress = lobjMember.streetAddress Else lstrStreetAddress = "" End If
If Not (isempty(lobjMember.postOfficeBox)) Then lstrPostOfficeBox = lobjMember.postOfficeBox Else lstrPostOfficeBox = "" End If
If Not (isempty(lobjMember.l)) Then lstrCity = lobjMember.l Else lstrCity = "" End If
If Not (isempty(lobjMember.st)) Then lstrState = lobjMember.st Else lstrState = "" End If
If Not (isempty(lobjMember.postalCode)) Then lstrPostalCode = lobjMember.postalCode Else lstrPostalCode = "" End If
If Not (isempty(lobjMember.countryCode)) Then lstrCountry = lobjMember.countryCode Else lstrCountry = "" End If
lstrPassword = DefaultPassword
lblnInZimbraGroup = 0
For Each lobjGroup in lobjMember.Groups
'** See if this member belongs to the group that allows Zimbra mailboxes **
If instr(lobjGroup.cn,ZimbraDomainGroup) Then
'** Strips the "zimbraDomain_" from the group name leaving only the domain name
domainName = replace(lobjGroup.cn,ZimbraDomainGroup,"")
if lobjMember.AccountDisabled = TRUE then
lstrAccountDisabled = "AccountDisabled"
else
lstrAccountDisabled = ""
end if
'** Member is associated to the Zimbra Email group and thus allowed to have a Zimbra mailbox. **
lstrLine = lstrSamAccountName & "," & lstrFirstName & "," & lstrInitials & "," & lstrLastName & "," & lstrFullName & "," &_
lstrTitle & "," & lstrDescription & "," & lstrComment & "," & lstrTelephoneNumber & "," & lstrHomePhone & "," & lstrMobile & "," &_
lstrFaxNumber & "," & lstrPager & "," & lstrCompany & "," & lstrOffice & "," & lstrStreetAddress & "," & lstrPostOfficeBox & "," &_
lstrCity & "," & lstrState & "," & lstrPostalCode & "," & lstrCountry & "," & lstrPassword & "," & lstrAccountDisabled & "," &_
domainName & "," & ",unused"
lobjFile.WriteLine(lstrLine)
End If
Next
lobjFile.Close
Set lobjFile = Nothing
End If
If lobjMember.Class = "organizationalUnit" or lobjMember.Class = "container" Then
'** Recurse further down to find the users. **
TrollTheFolders(lobjMember)
End If
Next
End Sub
Function writeUserInfo(domainName)
End Function Modified import-ad.sh script: Code: #!/bin/bash
#############################################
## Name : import-ad.sh
## Version : 1.2
## Date : 2011-11-02
## Author : LHammonds
## Purpose : Add mailbox accounts for AD users that have none.
## Compatibility : Verified on Ubuntu Server 10.04.3 LTS, Zimbra 7.1.2 - 7.1.3 OSE
## Requirements : Zimbra must be online, must be run as root user.
## Run Frequency : Run very frequently (every minute)
## Exit Codes :
## 0 = Success
## 1 = Failure
################ CHANGE LOG #################
## DATE WHO WHAT WAS CHANGED
## ---------- --- ----------------------------
## 2011-10-11 LTH Created script.
## 2011-10-29 LTH Better logging, mail support, bug fixes.
## 2011-11-02 LTH Moved standard variables/functions to external file.
## 2012-03-24 DIGIDT Closes account if AD user account is disabled
#############################################
## Import standard variables and functions. ##
source /var/scripts/common/standard.conf
LOGFILE="${TEMPDIR}/import-ad.log"
MAILFILE="${TEMPDIR}/import-ad-mail.$$"
ADLISTORG="${SHAREDIR}/adlist.csv"
ADLISTNEW="${TEMPDIR}/import-ad-adlist.$$"
ZMUSERS="${TEMPDIR}/import-ad-zmuserlist.$$"
ZMCMD="${TEMPDIR}/import-ad-zmcmd.$$"
NEWUSERS=""
RETURNVALUE=0
## Temporarily change the default field separator to a comma. #
OLDIFS="${IFS}"
IFS=","
## If the Active Directory user list file is not found, exit the script. #
if [ ! -f ${ADLISTORG} ]; then
## No file to process. Exit script.
## echo no adlist.csv found
exit 0
fi
sudo echo "`date +%Y-%m-%d_%H:%M:%S` - Active Directory file found! Import process started." >> ${LOGFILE}
## Create files and set permissions for only the root user. #
touch ${ZMCMD}
touch ${ZMUSERS}
sudo chmod 0600 ${ZMCMD}
sudo chmod 0600 ${ZMUSERS}
## Take ownership and set permissions for only the root user. #
sudo chown root:root ${ADLISTORG}
sudo chmod 0400 ${ADLISTORG}
## Move the file to a working folder. #
sudo mv ${ADLISTORG} ${ADLISTNEW}
sudo chmod 777 ${ADLISTNEW}
## Create a list of users in Zimbra for the specified domain. #
${ZIMBRADIR}/bin/zmprov -l getAllAccounts ${MYDOMAIN} > ${ZMUSERS}
## Loop through the Active Directory user list. #
while read -a ADLINE ; do
## Slot 0 = UserID
## Slot 1 = First Name (GivenName)
## Slot 2 = Initials
## Slot 3 = Last Name (sn)
## Slot 4 = Full Name (CN)
## Slot 5 = Title
## Slot 6 = Description
## Slot 7 = Comment
## Slot 8 = Telephone / Work Number
## Slot 9 = Home Phone
## Slot 10 = Mobile Phone
## Slot 11 = Fax Number (facsimileTelephoneNumber)
## Slot 12 = Pager
## Slot 13 = Company
## Slot 14 = Office (physicalDeliveryOfficeName)
## Slot 15 = Street Address
## Slot 16 = Post Office Box
## Slot 17 = City (l)
## Slot 18 = State (st)
## Slot 19 = Postal Code
## Slot 20 = Country Code (co)
## Slot 21 = Password
## Slot 22 = Account Disabled TRUE or FALSE
## Slot 23 = Email domain that the user belongs too
## Set the "Found Match" variable to false #
FOUND=0
## Loop through the Zimbra User List. #
while read -a ZMLINE ; do
## Convert Usernames to lower case. #
ZMUSERID=${ZMLINE[0],,}
ADUSERID=${ADLINE[0],,}
## Add domain address to the end of the AD Username #
ADUSERID=${ADUSERID}"@"${ADLINE[23]}
## Compare the lowercase AD username to the lower case Zimbra username. #
if [ ${ADUSERID} == ${ZMUSERID} ]; then
## Close account in Zimbra if AD account is disabled #
if [[ ${ADLINE[22]} == "AccountDisabled" ]]; then
${ZIMBRADIR}/bin/zmprov ma ${ZMUSERID} zimbraAccountStatus closed
sudo echo "`date +%Y-%m-%d_%H:%M:%S` --- Closed account for disabled AD user: ${ADLINE[0]}@${ADLINE[23]}" >> ${LOGFILE}
fi
## Match found. Exit this while loop. #
FOUND=1
break
fi
done < ${ZMUSERS}
if [ ${FOUND} -eq 0 ]; then
## We have an AD user that does not have a Zimbra mailbox. #
NEWUSERS="${NEWUSERS}${ADLINE[0]}@${ADLINE[23]}\n"
sudo echo "`date +%Y-%m-%d_%H:%M:%S` --- Adding new user: ${ADLINE[0]}@${ADLINE23}" >> ${LOGFILE}
sudo echo "createAccount ${ADUSERID} \"${ADLINE[21]}\" displayName \"${ADLINE[4]}\" gn \"${ADLINE[1]}\" initials \"${ADLINE[2]}\" sn \"${ADLINE[3]}\" cn \"${ADLINE[4]}\" title \"${ADLINE[5]}\" description \"${ADLINE[6]}\" zimbraNotes \"${ADLINE[7]}\" telephoneNumber \"${ADLINE[8]}\" homePhone \"${ADLINE[9]}\" mobile \"${ADLINE[10]}\" facsimileTelephoneNumber \"${ADLINE[11]}\" pager \"${ADLINE[12]}\" company \"${ADLINE[13]}\" physicalDeliveryOfficeName \"${ADLINE[14]}\" street \"${ADLINE[15]}\" postOfficeBox \"${ADLINE[16]}\" l \"${ADLINE[17]}\" st \"${ADLINE[18]}\" postalCode \"${ADLINE[19]}\" co \"${ADLINE[20]}\"">> ${ZMCMD}
fi
done < ${ADLISTNEW}
## If the Zimbra command file is not empty, we need to process it. #
if [ -s ${ZMCMD} ]; then
${ZIMBRADIR}/bin/zmprov < ${ZMCMD} 1>/dev/null 2>&1
RETURNVALUE=$?
if [ ${RETURNVALUE} -ne 0 ]; then
## Something went wrong with the mailbox creation.
## This error should notify administrators to the problem.
sudo echo "`date +%Y-%m-%d_%H:%M:%S` --- ERROR: zmprov reported the following error: ${RETURNVALUE}" >> ${LOGFILE}
sudo echo "`date +%Y-%m-%d_%H:%M:%S` - Import aborted. EXIT CODE = 1" >> ${LOGFILE}
f_sendmail "Zimbra Active Directory Import" "ERROR: zmprov reported the following error: ${RETURNVALUE}\n\nRemaining temporary files:\n${ZMUSERS}\n${ZMCMD}\n${ADLISTNEW}\n"
exit 1
fi
## Send email notification of the new users added to Zimbra. #
## NOTE: To be 100% sure about this, we could loop through the users #
## and verify that they now have Zimbra mailboxes. #
f_sendmail "Zimbra Notification - New Users" "The following users were added to Zimbra:\n\n${NEWUSERS}"
else
## There were no new users to process. #
sudo echo "`date +%Y-%m-%d_%H:%M:%S` --- No new users to import." >> ${LOGFILE}
fi
sudo echo "`date +%Y-%m-%d_%H:%M:%S` - Active Directory import completed." >> ${LOGFILE}
## Restore the default field separator value. #
IFS="${OLDIFS}"
## Remove temporary files. #
sudo rm -f ${ZMUSERS}
sudo rm -f ${ZMCMD}
sudo rm -f ${ADLISTNEW} Modified Standard.Conf: NOTE: I've disabled the OFFSITEDR sections! Code: #!/bin/bash
## Global Variables ##
TEMPDIR="/var/tmp"
ZIMBRADIR="/opt/zimbra"
SHAREDIR="/var/scripts/share"
MYDOMAIN="yourdomainname.com"
ADMINEMAIL="admin@${MYDOMAIN}"
REPORTEMAIL="admin@${MYDOMAIN}"
BACKUPDIR="/var/tmp"
OFFSITEDIR="/mnt/fakedir"
OFFSITETESTFILE="${OFFSITEDIR}/online.txt"
ARCHIVEMETHOD="tgz" ## Choices are tar.7z or tgz
HOSTNAME=$(hostname -s)
SCRIPTNAME=$0
MAILFILE="${TEMPDIR}/mailfile.$$"
## Global Functions ##
function f_sendmail() {
## Purpose: Send email message.
## Parameter #1 = Subject
## Parameter #2 = Body
echo "From: ${ADMINEMAIL}" > ${MAILFILE}
echo "To: ${REPORTEMAIL}" >> ${MAILFILE}
echo "Subject: ${1}" >> ${MAILFILE}
echo "" >> ${MAILFILE}
echo -e ${2} >> ${MAILFILE}
echo "" >> ${MAILFILE}
echo -e "\n\nServer: ${HOSTNAME}\nProgram: ${SCRIPTNAME}\nLog: ${LOGFILE}" >> ${MAILFILE}
${ZIMBRADIR}/postfix/sbin/sendmail -t < ${MAILFILE}
rm ${MAILFILE}
}
##function f_mount() {
## Mount the pre-configured Windows share folder.
## NOTE: The Windows share should have a file called online.txt
## if [ ! -f ${OFFSITEDIR}/online.txt ]; then
## mount -t cifs //kdc-doubletake/zimbra ${OFFSITEDIR} --options nouser,rw,nofail,noatime,noexec,credentials=/etc/cifspw
## fi
##}
##function f_umount() {
## Dismount the Windows share folder.
## NOTE: The unmounted folder should have a file called offline.txt
## if [ -f ${OFFSITEDIR}/online.txt ]; then
## umount ${OFFSITEDIR}
## fi
##} | 
04-27-2012, 09:16 AM
| | | amazing an amazing doc, a must have
Great Job
even if we (on our compagnie) have a network edition ti's a grest job
also you TodoList will be welcom as i gess must be usful on a so big plan
:-) | 
04-27-2012, 12:37 PM
| | Special Member | |
Posts: 138
| | Quote:
Originally Posted by genuix an amazing doc, a must have
Great Job | Thanks Quote:
Originally Posted by genuix also you TodoList will be welcom as i gess must be usful on a so big plan | If you have not noticed, I started a new thread with the current versions. I did not offer the ToDoList project file in that thread because I seem to have lost it...well, more like deleted it I am fairly sure. I had all my files arranged by version and when I got rid of the older zimbra folders, the ToDoList went with it.
I am re-building a new ToDoList but it won't be the huge monster it was (due to all the research notes contained in it for other mail servers too). This list is strictly for rolling out Zimbra. When I finish it up, I will post it on the new thread. ToDoList posted here.
================================================== =
New thread here --> Zimbra OSE and Ubuntu 10.04 MODERATORS: Please do not delete this thread...it has info the other will not. Thanks.
LHammonds
Last edited by LHammonds; 05-07-2012 at 03:08 PM..
| | Thread Tools | Search this Thread | | | | | Display Modes | Linear Mode | | Why Join? Registering let's you ask questions, makes it easier to search, displays any files attached to posts, and notifies you about replies.  |