Question

Okay so I JUST started bash scripting two weeks ago, and I ran into an issue last week that I just cannot fix. I'll describe my problem as best I can and I've included my script. I welcome any criticisms on what I am doing wrong with this code; Actually, I implore you to please provide as much criticism on my technique as you can so that I can learn from it.


Objectives

I installed a new Zimbra Collaboration Suite for my company, and am in the process of migrating user accounts. I am trying to create a bash script to do the following:

  1. Pull all user accounts from active directory via LDAP.
  2. Format the LDAP query results to be used in a zmprov ca command.
  3. Enumerate the lines of the formatted results.
  4. Iterate through each line and run it as a zmprov command.

Assumptions for the purposes of this example

  • Name of the bash file = zdap
  • My Active Directory domain = MYLOCALDOMAIN
  • My username for LDAP = admin
  • My password for LDAP = P@ssw0rd
  • My LDAP IP address = 1.2.3.4

Script

Here is my script:

#!/bin/bash

#Use this script to pull user information from Company Active Directory

argerror="Usage: company-ldap domain username"

if [ "$1" == "local" ]; then
    domain=MYLOCALDOMAIN
    ou=MAIN
else
    echo "$argerror"
    exit
fi

if [ -z $2 ]; then 
    echo "$argerror"
    exit
else
    user=$2
fi

password=P@ssw0rd

ldapsearch -h 1.2.3.4 -p 389 -D "cn=$user,ou=$ou,dc=$domain,dc=COM" \
           -w "$password" -b "ou=$ou,dc=$domain,dc=COM" \
           "(&(name=*)(mail=*)(givenName=*)(sn=*))" \
           'name' 'mail' 'givenName' 'sn' -LLL -S 'name' |
grep -B 1 'name\|mail\|sn\|givenName' |
grep -v '^dn:' | tr '\n' ' ' |
sed -e 's/ -- /\n/g' |
awk '{s=""; for (i=1;i<NF;i++) s = s $i " ";print $NF " " s}' |
sed -e 's/sn: /sn '\''/g' |
sed -e 's/ givenName: /'\'' gn '\''/g' |
sed -e 's/ mail: / /g' |
sed -e 's/ name: /'\'' displayName '\''/g' |
awk '{print "ca " $0"'\''"}' |
sed -e 's/ '\''$/'\''/g' |
awk '{($2 = $2 " tempzimbrapw1234"); print $0}' |
while read line ; do zmprov $line ; done

I call the command with this:

./zdap local admin

Requested edit... The zmprov command for a given user (Joe Smith) looks like this:

zmprov ca joe.smith@mylocaldomain.com tempzimbrapw1234 sn 'Smith' gn 'Joe' displayName 'Joe Smith'

Results and my Problem

  • The ldap query runs perfectly (e.g., if I run that command separately, it will return the proper ldap results...so the issue isn't LDAP credentials/connection/query related).
  • If I echo the command, it also looks just fine (e.g., if I type the command out to match the echoed version and it will actually add the account like I want).

However, when I run the zdap bash script I wrote, I expect to get a create account confirmation from Zimbra, but instead get this message:

zimbra@CPU-00154:~$ ./zdap local admin
usage: createAccount(ca) {name@domain} {password} [attr1 value1 [attr2 value2..
For general help, type : zmprov --help

Unfortunately I have tried too many solutions to list them all here. I've spent a week reading manuals, forums, etc. and have tried tons of tweaks, adjustments, new commands, etc. but to no avail.

Once again, I would greatly appreciate any criticisms regarding my script or overall method for accomplishing this. Please try to include examples with your suggestions so that I can see what I'm doing wrong here. Thank you in advance.

EDIT:

I thought I should include the format of the LDAP query result so you can see what my command is working with:

dn: CN=admin,OU=MAIN,DC=MYLOCALDOMAIN,DC=COM
name: admin
mail: admin@mylocaldomain.com
--    
dn: CN=Jane Doe,OU=MAIN,DC=MYLOCALDOMAIN,DC=COM    
name: Jane Doe
mail: jane.doe@mylocaldomain.com
--    
dn: CN=Joe Smith,OU=MAIN,DC=MYLOCALDOMAIN,DC=COM    
name: Joe Smith
mail: joe.smith@mylocaldomain.com

UPDATE

I managed to work out the issue using the printf command (special thanks to rici for that suggestion). The output from printf was this...

<|zmprov|> <|ca|> <|joe.smith@mylocaldomain.com|> <|tempzimbrapw1234|> <|#|> <|sn|> <|'Smith'|> <|gn|> <|'Joe'|> <|displayName|> <|'Joe|> <|Smith'|>

As you can see, the value of the last argument (displayName) was being misinterpreted.

Was it helpful?

Solution

It would still be helpful if you included (2) from my first comment, especially the printf version:

printf '<|%s|> ' $line && printf '\n'

That printf statement will put <| |> around each argument, which makes it possible to see the difference between:

<|zmprov|> <|ca|> ... <|displayName|> <|'Joe Smith'|>

and

<|zmprov|> <|ca|> ... <|displayName|> <|'Joe|> <|Smith'|>

But I venture to guess that what you really want is:

<|zmprov|> <|ca|> ... <|displayName|> <|Joe Smith|>

Shell script quoting takes a bit of time to get your head around. Tools like that printf statement will help. Experiment a bit with simple commands. Pay attention to how variables are expanded. (And note that quotes in the values of variables are just ordinary characters.) Also make sure you understand the difference between zmprov $line and zmprov "$line".

Finally, read the bash FAQ on quoting: http://mywiki.wooledge.org/BashFAQ/050

Also, sed can execute more than one command in a single invocation, and awk can do most of the things sed can do. I suspect you could simplify that massive line into a simple awk program.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top