Watch www.cute-solutions.de
Introduction
Outlooksignature is a simple Windows Console Application which generates Outlook signatures automatically using Information in the Active Directory. It makes it very easy to generate a huge number of signatures.
Background
The basic idea behind this application is to use a general signature in Enterprises. I was searching for some programs with this function, but there are only a few very expensive solutions.
Configure the Application using the OSG.INI
[DatabaseParams]
SearchFilterpart1=
SearchFilterpart2=
SearchFilterpart3=
SearchFilterpart4=
SearchFilterpart5=
SearchFilterpart6=
Fields=samaccountname,...
[SignatureParams]
PathSignaturen=
SignaturVorlPath=
VorlagenDateien=signatur.txt,signatur.rtf,...
The key fields "SearchFilterpart1 to SearchFilterpart6" are for registering the LDAP search filter (e.g. (& (ObjectClass=user) (cn=Maier)) for all users called Maier). The finally used search consists of the 6 parts. Each individual part should not exceed the length of 160 characters.
The key field "Fields" defines which user information from the AD is selected. Here the account name MUST stand always in the first place! The name of the key field in the Active Directory should be the same string which should be replaced in the template (in the AD cn - in the template * ~cn~ *).
In the key field "PathSignaturen" is located the path in which the finished generated signatures are stored (this path must already exist).
In the field "SignaturVorlPath" is located the path in which the signature templates are.
IMPORTANT: Each path must be written instead of with \ with \ \.
The key field "VorlagenDateien" contains the file names of the templates (separated through , ). These file names must contain the string "signatur" - it is replaced by the accountname.
Using the Code
The method searchEntry()
The most important part in the application is the method searchEntry() in the class Program. This method searches for entries in the Active Directory. Therefore I use the System.DirectoryServices.
This following part initializes the DirectorySearcher. It also reads the filter string from the osg.ini.
public static void searchEntry()
{
DirectorySearcher ds = new DirectorySearcher();
ds.SearchRoot = new DirectoryEntry();
StringBuilder filter = new StringBuilder();
filter.Append(IniFile.a.IniReadValue("DatabaseParams", "SearchFilterpart1").ToString());
filter.Append(IniFile.a.IniReadValue("DatabaseParams", "SearchFilterpart2").ToString());
filter.Append(IniFile.a.IniReadValue("DatabaseParams", "SearchFilterpart3").ToString());
filter.Append(IniFile.a.IniReadValue("DatabaseParams", "SearchFilterpart4").ToString());
filter.Append(IniFile.a.IniReadValue("DatabaseParams", "SearchFilterpart5").ToString());
filter.Append(IniFile.a.IniReadValue("DatabaseParams", "SearchFilterpart6").ToString());
Now the filter string is given to the DirectorySearcher and the PropertyNamesOnly attribute is set to true.
ds.Filter = filter.ToString();
ds.PropertyNamesOnly = true;
To know which information the DirectorySearcher must load, we must load the attributes from the getAttribute() method into the DS.
string[] attributes = getAttribute();
for (int i = 0; i < attributes.Length; i++)
{
ds.PropertiesToLoad.Add(attributes[i]);
}
Now the ReferralChasing attribute is turned off and the result of the Directory Searcher is saved in the SearchResultCollection src.
ds.ReferralChasing = ReferralChasingOption.None;
SearchResultCollection src = ds.FindAll();
data.global_count = System.Convert.ToInt32(src.Count);
output.log.WriteLine("Es wurden " + data.global_count + " Einträge gefunden");
Console.WriteLine("Es wurden " + data.global_count + " Einträge gefunden");
We now know how many entries we have found and so we can initialise the global_data array. After that, the attributes are written into the first row.
data.initData(data.global_attribute.Length, data.global_count + 1);
for (int i = 0; i < data.global_attribute.Length; i++)
{
data.global_data[i, 0] = data.global_attribute[i];
}
data.global_array_counter = 1;
After all, it writes the entries found in the Active Directory into the global_data array.
try
{
foreach (SearchResult sr in src)
data.globalDataWrite(sr.GetDirectoryEntry());
}
catch (Exception e)
{
Console.WriteLine(e.Message);
output.log.WriteLine(e.Message);
}
src.Dispose();
ds.Dispose();
}
The Method signatur(...)
Another important method is signatur(string vorlage, string vorlagePath). This generates the signatures using the Templates.
The first part looks at which extension the current template has. This is important if there are any characters like ä, ü, ö, ß in the template. So it is no problem if the template is a *.rtf or a *.htm file.
public static void signatur(string vorlage, string vorlagePath)
{
string[] typearr = vorlage.Split('.');
string type = typearr[typearr.Length-1];
Now the SreamReader tr is initialised. It reads the template file row by row. The LinkedList list is to save the rows of the template file.
StreamReader tr = new StreamReader(vorlagePath+
"\\"+vorlage,System.Text.Encoding.UTF7);
//a list in which each row of the template is saved
LinkedList<string> list = new LinkedList<string>();
It reads the template file row by row until the EndOfStream is reached and saves the rows inside the list. Then a temporary list temp is initialised.
while(!tr.EndOfStream)
{
list.AddLast(tr.ReadLine().ToString());
}
tr.Close();
LinkedList<string> temp;
Defining the destination paths:
String Path = vorlagePath;
String Path1 = vorlage;
This part is done for each entry is the global_data array. First the string "signatur" in the destination path is replaced by the accountname (data.global_data[0,i]).
Then initialise a StreamWriter wr which writes into the destination file. Now copy the LinkedList list into temp.
for (int i = 1; i < data.global_array_counter; i++)
{
Path1 = vorlage;
Path1 = Path1.Replace("signatur", data.global_data[0, i].ToString());
Path = data.PathSignaturen.ToString() + "\\" + Path1;
//StreamWriter th write the signature file
StreamWriter wr = new StreamWriter(Path);
log.WriteLine(Path1 + " wurde erfolgreich erzeugt");
//the list with the rows of the template is copied into the temp list
temp = new LinkedList<string>(list);
And now for each entry in the LinkedList temp. In each row search for the patterns which should be replaced by AD information and replace this:
while (temp.Count > 0)
{
String Zeile = temp.First.Value.ToString();
for (int p = 0; p < data.global_attribute.Length; p++)
{
try
{
if (type == "htm")
{
Zeile = Zeile.Replace("÷", "ö");
Zeile = Zeile.Replace("õ", "ä");
Zeile = Zeile.Replace("³", "ü");
Zeile = Zeile.Replace("Í", "Ö");
Zeile = Zeile.Replace("-", "Ä");
Zeile = Zeile.Replace("_", "Ü");
Zeile = Zeile.Replace("¯", "ß");
}
else if (type == "rtf")
{
Zeile = Zeile.Replace("÷", "\\'f6");
Zeile = Zeile.Replace("õ", "\\'e4");
Zeile = Zeile.Replace("³", "\\'fc");
Zeile = Zeile.Replace("Í", "\\'d6");
Zeile = Zeile.Replace("-", "\\'c4");
Zeile = Zeile.Replace("_", "\\'dc");
Zeile = Zeile.Replace("¯", "\\'df");
}
string reg = "*~" + data.global_data[p, 0].ToString() + "~*";
if (data.global_data[p, i].ToString() == null)
{
}
else
{
Zeile = Zeile.Replace(reg, data.global_data[p, i].ToString());
}
}
catch(Exception w)
{
string reg = "*~" + data.global_data[p, 0].ToString() + "~*";
Zeile = Zeile.Replace(reg, "");
}
}
After replacing, write the line into the destination file and remove the first entry in the LinkedList temp. Then do it again with the next row.
wr.WriteLine(Zeile);
data.global_state_counter++;
temp.RemoveFirst();
Close the StreamWriter wr and close the file.
}
data.statusFortschritt(data.global_array_counter, data.global_state_counter);
wr.Close();
}
}
To read the other code, please download the source code.
A Possible Template
An example for a template is:
Regards
*~title~**~sn~* *~givenname~*
*~physicalDeliveryOfficeName~*
Liebherr-Hydraulikbagger GmbH
*~streetaddress~*
*~postalcode~* *~l~*
Tel.: *~telephonenumber~*
Fax.: *~facsimiletelephonenumber~*
E-Mail: *~mail~*
All the *~anything~* tags are replaced. These should be named the same way like the attribute in the Active Directory.
The application also supports *.html and *.rtf signatures.
Class Diagram
History