none
Outlook signature based on user information from Active Directory using Windows Powershell

    Question

  • Infrastructure Information:

    User Machines: Thin Clients

    Environment: Citrix XenApp 6 on Windows 2008 R2 SP1 (Remote Desktop Services)

    Outlook: 2010

    Description:

    We have deployed Outlook signature through login grouip policy based on user information from AD. The script gathers the user information (attributes) and generates a signature in outlook for the user. However this script only works (i.e. signature with correct information is generated) if user has at least 1 session open through Citrix.

    Below are the issues that we are facing:

    1. The script takes a lot of time to run and gather the information from AD. User has to wait for the application to open first (i.e. get connected to the server) and then wait for the script to complete before he can see his signature in outlook with his information.

    2. During the execution of the script, outlook icon is shown on the system tray. If the user clicks on that icon to open outlook. The outlook opens fine but his signature will show NO AD information (Blank Fields).

    What we want is to find out if there is a way to speed up the script execution process so that user does not have to wait for a long time? Secondly, if there is a way to hide the outlook icon from the system tray which comes up during the execution of the script? Lastly, is there a way that this signature information (Attributes) for each individual user can be stored on some network location like his roaming profile, home drive, etc?

    Appreciate your suggestions to resolve this issue.

    below is the script which we are using to accomplish this task:


    ###########################################################################"
    #
    # NAME: Set-OutlookSignature.ps1
    #
    # AUTHOR: Jan Egil Ring
    # Modifications by Darren Kattan
    #
    # COMMENT: Script to create an Outlook signature based on user information from Active Directory.
    #          Adjust the variables in the "Custom variables"-section
    #          Create an Outlook-signature from Microsoft Word (logo, fonts etc) and copy this signature to \\domain\NETLOGON\sig_files\$CompanyName\$CompanyName.docx
    #     This script supports the following keywords:
    #      DisplayName
    #   Title
    #   Email
    #          See the following blog-post for more information: http://blog.crayon.no/blogs/janegil/archive/2010/01/09/outlook-signature-based-on-user-information-from-active-directory.aspx
    #
    #          Tested on Office 2003,2007 and 2010
    #
    # You have a royalty-free right to use, modify, reproduce, and
    # distribute this script file in any way you find useful, provided that
    # you agree that the creator, owner above has no warranty, obligations,
    # or liability for such use.
    #
    # VERSION HISTORY:
    # 1.0 09.01.2010 - Initial release
    # 1.1 11.09.2010 - Modified by Darren Kattan
    # - Removed bookmarks. Now uses simple find and replace for DisplayName, Title, and Email.
    # - Email address is generated as a link
    # - Signature is generated from a single .docx file
    # - Removed version numbers for script to run. Script runs at boot up when it sees a change in the "Date Modified" property of your signature template.
    # 1.11 11.15.2010 - Revised by Darren Kattan
    #   - Fixed glitch with text signatures
    #
    #
    ###########################################################################"

    #Custom variables
    $CompanyName = 'XYZ'
    $DomainName = 'XYZ.com'

    $SigSource = "\\$DomainName\netlogon\sig_files\$CompanyName"
    $ForceSignatureNew = '1' #When the signature are forced the signature are enforced as default signature for new messages the next time the script runs. 0 = no force, 1 = force
    $ForceSignatureReplyForward = '1' #When the signature are forced the signature are enforced as default signature for reply/forward messages the next time the script runs. 0 = no force, 1 = force

    #Environment variables
    $AppData=(Get-Item env:appdata).value
    $SigPath = '\Microsoft\Signatures'
    $LocalSignaturePath = $AppData+$SigPath
    $RemoteSignaturePathFull = $SigSource+'\'+$CompanyName+'.docx'
    $SigVersion = (gci $RemoteSignaturePathFull).LastWriteTime #When was the last time the signature was written

    #Get Active Directory information for current user
    $UserName = $env:username
    $Filter = "(&(objectCategory=User)(samAccountName=$UserName))"
    $Searcher = New-Object System.DirectoryServices.DirectorySearcher
    $Searcher.Filter = $Filter
    $ADUserPath = $Searcher.FindOne()
    $ADUser = $ADUserPath.GetDirectoryEntry()
    $ADDisplayName = $ADUser.DisplayName
    $ADEmailAddress = $ADUser.mail
    $ADTitle = $ADUser.title
    $ADFax = $ADUser.facsimileTelephoneNumber
    $ADExt = $ADUser.telephoneAssistant
    $ADTelePhoneNumber = $ADUser.extensionAttribute10
    Write-Host "The telephone number for the user is $ADTelePhoneNumber ."

    #Setting registry information for the current user
    $CompanyRegPath = "HKCU:\Software\"+$CompanyName

    if (Test-Path $CompanyRegPath)
    {}
    else
    {New-Item -path "HKCU:\Software" -name $CompanyName}

    if (Test-Path $CompanyRegPath'\Outlook Signature Settings')
    {}
    else
    {New-Item -path $CompanyRegPath -name "Outlook Signature Settings"}

    if ((Get-ItemProperty $CompanyRegPath'\Outlook Signature Settings').SignatureVersion -eq $null)
    {
    Set-ItemProperty $CompanyRegPath'\Outlook Signature Settings' -name SignatureVersion -Value 2
    }

    if ((Get-ItemProperty $CompanyRegPath'\Outlook Signature Settings').ADVersion -eq $null)
    {
    Set-ItemProperty $CompanyRegPath'\Outlook Signature Settings' -name ADVersion -Value 2
    }

    #$SigVersion = (gci $RemoteSignaturePathFull).LastWriteTime #When was the last time the signature was written
    #$ForcedSignatureNew = (Get-ItemProperty $CompanyRegPath'\Outlook Signature Settings').ForcedSignatureNew
    #$ForcedSignatureReplyForward = (Get-ItemProperty $CompanyRegPath'\Outlook Signature Settings').ForcedSignatureReplyForward
    #$SignatureVersion = (Get-ItemProperty $CompanyRegPath'\Outlook Signature Settings').SignatureVersion
    #Set-ItemProperty $CompanyRegPath'\Outlook Signature Settings' -name SignatureSourceFiles -Value $SigSource
    #$SignatureSourceFiles = (Get-ItemProperty $CompanyRegPath'\Outlook Signature Settings').SignatureSourceFiles

    ###################################################################################################################

    #Retrieve registry information for the current user

    $SignatureVersion = (Get-ItemProperty $CompanyRegPath'\Outlook Signature Settings').SignatureVersion
    $ADVersion = (Get-ItemProperty $CompanyRegPath'\Outlook Signature Settings').ADVersion

    ###################################################################################################################

    #Copy signature sourcefiles and creating signature if signature-version are different from local version
    #or if Active Directory information has been updated

    if (($SignatureVersion -eq $SigVersion) -and ($ADVersion -eq $ADModify))
    {}
    else
    {
    #Create local signature directory if it doesn’t exist
    if (Test-Path $LocalSignaturePath)
    {}
    else
    {New-Item $LocalSignaturePath -itemType Directory}

    #Copy signature templates from domain to local Signature-folder
    Copy-Item “$SigSource\*” $LocalSignaturePath -Recurse -Force

    $ReplaceAll = 2
    $FindContinue = 1
    $MatchCase = $False
    $MatchWholeWord = $True
    $MatchWildcards = $False
    $MatchSoundsLike = $False
    $MatchAllWordForms = $False
    $Forward = $True
    $Wrap = $FindContinue
    $Format = $False

    #Insert variables from Active Directory to rtf signature-file
    $MSWord = New-Object -com word.application
    $fullPath = $LocalSignaturePath+'\'+$CompanyName+'.docx'
    $MSWord.Documents.Open($fullPath)

    $FindText = "DisplayName"
    $ReplaceText = $ADDisplayName.ToString()
    $MSWord.Selection.Find.Execute($FindText, $MatchCase, $MatchWholeWord, $MatchWildcards, $MatchSoundsLike, $MatchAllWordForms, $Forward, $Wrap, $Format, $ReplaceText, $ReplaceAll )

    $FindText = "extensionAttribute10"
    $ReplaceText = $ADTelePhoneNumber.ToString()
    $MSWord.Selection.Find.Execute($FindText, $MatchCase, $MatchWholeWord, $MatchWildcards, $MatchSoundsLike, $MatchAllWordForms, $Forward, $Wrap, $Format, $ReplaceText, $ReplaceAll )

    $FindText = "FaxNo"
    $ReplaceText = $ADFax.ToString()
    $MSWord.Selection.Find.Execute($FindText, $MatchCase, $MatchWholeWord, $MatchWildcards, $MatchSoundsLike, $MatchAllWordForms, $Forward, $Wrap, $Format, $ReplaceText, $ReplaceAll )

    $FindText = "ExtNo"
    $ReplaceText = $ADExt.ToString()
    $MSWord.Selection.Find.Execute($FindText, $MatchCase, $MatchWholeWord, $MatchWildcards, $MatchSoundsLike, $MatchAllWordForms, $Forward, $Wrap, $Format, $ReplaceText, $ReplaceAll )

    $FindText = "Title"
    $ReplaceText = $ADTitle.ToString()
    $MSWord.Selection.Find.Execute($FindText, $MatchCase, $MatchWholeWord, $MatchWildcards, $MatchSoundsLike, $MatchAllWordForms, $Forward, $Wrap, $Format, $ReplaceText, $ReplaceAll )

    $MSWord.Selection.Find.Execute("Email")
    $MSWord.ActiveDocument.Hyperlinks.Add($MSWord.Selection.Range, "mailto:"+$ADEmailAddress.ToString(), $missing, $missing, $ADEmailAddress.ToString())

    $saveFormat = [Enum]::Parse([Microsoft.Office.Interop.Word.WdSaveFormat], "wdFormatHTML");
    $path = $LocalSignaturePath+'\'+$CompanyName+".htm"
    $MSWord.ActiveDocument.saveas([ref]$path, [ref]$saveFormat)

    $saveFormat = [Enum]::Parse([Microsoft.Office.Interop.Word.WdSaveFormat], "wdFormatRTF");
    $path = $LocalSignaturePath+'\'+$CompanyName+".rtf"
    $MSWord.ActiveDocument.SaveAs([ref] $path, [ref]$saveFormat)

    $saveFormat = [Enum]::Parse([Microsoft.Office.Interop.Word.WdSaveFormat], "wdFormatText");
    $path = $LocalSignaturePath+'\'+$CompanyName+".txt"
    $MSWord.ActiveDocument.SaveAs([ref] $path, [ref]$SaveFormat)

    $MSWord.ActiveDocument.Close()
    $MSWord.Quit()

    #Forcing signature for New messages if enabled
    if ($ForcedSignatureNew -eq '1')
    {
    #Set company signature as default for New messages
    $MSWord = New-Object -com word.application
    $EmailOptions = $MSWord.EmailOptions
    $EmailSignature = $EmailOptions.EmailSignature
    $EmailSignatureEntries = $EmailSignature.EmailSignatureEntries
    $EmailSignature.NewMessageSignature=$CompanyName
    $MSWord.Quit()
    }

    #Forcing signature for Reply/Forward messages if enabled
    if ($ForcedSignatureReplyForward -eq '1')
    {
    #Set company signature as default for Reply/Forward messages
    $MSWord = New-Object -com word.application
    $EmailOptions = $MSWord.EmailOptions
    $EmailSignature = $EmailOptions.EmailSignature
    $EmailSignatureEntries = $EmailSignature.EmailSignatureEntries
    $EmailSignature.ReplyMessageSignature=$CompanyName
    $MSWord.Quit()
    }

    #Stop Microsoft Outlook task spawned by Microsoft Word
    #Stop-Process -name Outlook

    }

    ###################################################################################################################

    #Update registry values

    Set-ItemProperty $CompanyRegPath'\Outlook Signature Settings' -name SignatureVersion -Value $SigVersion
    Set-ItemProperty $CompanyRegPath'\Outlook Signature Settings' -name ADVersion -Value $ADModify

    ###################################################################################################################

    Thursday, April 26, 2012 6:42 AM

Answers

  • Remove flags the force signature.  The code is creating three copies of word.  This is a formula for disaster.

    Go into the code and count this lines:

    $MSWord = New-Object -com word.application

    I think you ned to test that code under a lot more conditions.  I keep finding more bugs.

    If you open a document in powershell and you don't out-null or viod the return it willspew out all of teh properies on the object.  The default behavior of powershell is to enumerate objects.

    Change this line:

    $MSWord.Documents.Open($fullPath)

    to this:

    [void]$MSWord.Documents.Open($fullPath)

    That will prevent delays caused by the enumeration which is unnecessary.

    Other delays are caused by the repeated saving of files.


    ¯\_(ツ)_/¯

    • Marked as answer by Mr-Hussam Tuesday, May 01, 2012 9:17 AM
    Sunday, April 29, 2012 12:25 PM

All replies

  • You have posted too much code.  Please narrow it down the parts of the code that you want to modify.

    Grant Ward, a.k.a. Bigteddy

    What's new in Powershell 3.0 (Technet Wiki)

    Thursday, April 26, 2012 6:45 AM
  • There are many Outlook signature scripts in teh repository.  You might try to find one that works.

    As BigTeddy notes.  No one here has the time required to go through a hundred lines of code looking for the proverbial needle.  You may have a system problem.  You will need to run the script outside of GP and try to fix it or use a different script. Consider contacting the original creator of the script for assistance.

    If you are on Exchange 2007 or later you can have exchange generate a stock corporate signature block.

    Logon scripts are not intended to beused for significant processing and loading of large subsystems like Outlook and Word.

    Signatures should be generated only once and not replaced at everylogon.  This can be done by having the user click a link or by modifying how Outlook starts up.

    To use a scripted signature generator in a logon script takes considerable technical skill to debug and make work smoothly.  We can answer specific question but we cannot easily analyze and troubleshoot your system.  You will have to do this yourself.


    ¯\_(ツ)_/¯

    Thursday, April 26, 2012 12:36 PM
  • This can be done by having the user click a link or by modifying how Outlook starts up.


    ¯\_(ツ)_/¯


    How would you do this?  I desperately need to have a standardized signature (customised for the user, of course), and it's a pain to log onto their profile and create the signature by hand each time I replace a computer.

    Grant Ward, a.k.a. Bigteddy

    What's new in Powershell 3.0 (Technet Wiki)

    Thursday, April 26, 2012 12:51 PM
  • This can be done by having the user click a link or by modifying how Outlook starts up.


    ¯\_(ツ)_/¯


    How would you do this?  I desperately need to have a standardized signature (customised for the user, of course), and it's a pain to log onto their profile and create the signature by hand each time I replace a computer.

    Grant Ward, a.k.a. Bigteddy

    What's new in Powershell 3.0 (Technet Wiki)

    Place a link in GP in your corporite Favorites.  The link will run the scrip from a share and create the signature.  Send the new user an email with the link in it as part of the welcome letter.  Note the link in favorites that will recreate the signature if anything about the signature changes.

    The preferred method is to let Exchange do it.

    To do it in Outlook either install a csutom add-in or create a module that checks a flag to see if the signature needs to be regenerated and run the code if needed.  This is fast and does not involve logon scripts.

    You can also place replace teh users signature by runniong a remote program.. Signatures are stored in the profile.  The files can be replaced as long as the original names are kept.  A process can run and check AD for changes and replace the generated files if necessary.

    Use Exchange.


    ¯\_(ツ)_/¯

    Thursday, April 26, 2012 1:27 PM
  • The only improvement I can suggest is in the method for retrieving information from AD. Instead of querying all of AD for the user, then binding to the user object (creating the DirectoryEntry). It would be more efficient to use the ADSystemInfo object to retrieve the DN of the current user and bind directly. For example, replace this code:


    #Get Active Directory information for current user
    $UserName = $env:username
    $Filter = "(&(objectCategory=User)(samAccountName=$UserName))"
    $Searcher = New-Object System.DirectoryServices.DirectorySearcher
    $Searcher.Filter = $Filter
    $ADUserPath = $Searcher.FindOne()
    $ADUser = $ADUserPath.GetDirectoryEntry()
    $ADDisplayName = $ADUser.DisplayName
    $ADEmailAddress = $ADUser.mail
    $ADTitle = $ADUser.title
    $ADFax = $ADUser.facsimileTelephoneNumber
    $ADExt = $ADUser.telephoneAssistant
    $ADTelePhoneNumber = $ADUser.extensionAttribute10

    -----

    with this:


    #Get Active Directory information for current user
    $SysInfo = New-Object -ComObject "ADSystemInfo"
    $UserDN = $SysInfo.GetType().InvokeMember("UserName", "GetProperty", $Null, $SysInfo, $Null)
    $ADUser = [ADSI]"LDAP://$UserDN"
    $ADDisplayName = $ADUser.DisplayName
    $ADEmailAddress = $ADUser.mail
    $ADTitle = $ADUser.title
    $ADFax = $ADUser.facsimileTelephoneNumber
    $ADExt = $ADUser.telephoneAssistant
    $ADTelePhoneNumber = $ADUser.extensionAttribute10

    -----

    This is slightely faster. Hoever I suspect most of the time required is due to the use of the Word application. I don't know if there is any way to avoid that.


    Richard Mueller - MVP Directory Services

    Saturday, April 28, 2012 12:50 AM
    Moderator
  • Richards code will speed up access to AD but that is not where this code is havingissues.  Launching MSWord during the logon process is a very bad and resource intensive thing.  Word is very slow to load.  Many AV programs aggravate this.

    There are a number of scripts in teh repository that all do this same thing.  The most effective ones are the simplest ones.  SOme do not use Word at all and create a corporate signature template stored in a cental location. This file is accessesd only when a new message is created.  The only thing that runs iat login is the code that grabs the AD info and saves it in the environment.  The HTML can have images etc.

    I am more in favor of a process that runs when Outlook starts.  This process just udates the sig files and only updates the registry if it has never run.  This is usually run as VBA code from within Outlook and can be deployed through Group Policy.  This is the most flexible, most efficient and safest way to do this short of writing a compiled add-in for Outlook.

    In Exchaneg 2007/2010 doing this on Exchnage is easist and most flexible.  It can also be done on Exchange 2003 but it is not as easy to do and takes a bit if setup to hook exchange with a script.

    Even if generating teh sugnature through Word it is much more efficient to yuse a Word template and just set the values and save it.  I think I put a copy of a sig generator that does this in the repository.

    You can have your Outlook code or login code check the date on the template to see if it has been changed ro determine if a siganature needs to be generated.

    In any and all cases you do NOT want to generate a signature on every login.  Thiswill definitely slow everything down.  It can have a very bad effect on a large Terminal Server system (MS or Citrix).  Neither like to run Office in the login phase.  Start teh script by checking to see if you really have to generate the files.  If not exit the script before trying to create a word instance.

    Running POwerSHell durin login will lso slow down the login as PowerSHell has to wait fo the Net classes to be available and it is not as lightweight as other shells.  Consider using a vbscript version.  VBScritp is usally already loaded and ready during login,

    DO not create on very long login script that calls other scripts.  This can create problems during login.  Use many small login scritps targeted to specific policies.  These can run concurrently and run more quickly as long as you do not have logins set to be synchronous.

    Citrix is a much more fussy login environment.  It is much busier during login because of all of the 'value added'  bits that Citrix applies toteh Terminal Server session. Remember Citrix sits on top of TS.  It is not a replacement for it.

    Citrix is good for many things especially graphics intensive environments.  CItrix is better at supporting foreign devices.  This comes at a cost much of which is delivered during login.  Citrix loads more user mode drivers and extensions than TS.  It also sets up the richer management environment. Adding a long POwerShel script to this may just be one too many.

    Note that you can profile the login process to see exactly what is crateing the delays.


    ¯\_(ツ)_/¯


    • Edited by jrv Saturday, April 28, 2012 10:16 AM
    Saturday, April 28, 2012 10:15 AM
  • What version of Exchange are you running? If it's Exchange 2010, you could create the signatures using a Transport Rule. There are built-in variables for the AD data and you can use html for the signature layout:

    $Signature = @"
    <div style="font-size:10pt; font-family: 'Calibri',sans-serif;">
    &nbsp;&nbsp;</br>
    <b>%%FirstName%% %%LastName%%</b></br>
    %%Title%%</br>
    %%Company%% - %%Department%%</br>
    Office phone: %%Phone%% - Cell phone: %%MobilePhone%% - Fax: %%Fax%%</br>
    <a href="mailto:%%WindowsEmailAddress%%">%%WindowsEmailAddress%%</a></br>
    </div>
    "@

     

    $SignatureRule = @{

     Name = 'Test Signature'
     Enabled = $true
     Comments = 'Standard Signature Transport Rule'
     Priority = 0
     ApplyHtmlDisclaimerLocation = 'Append'
     ApplyHtmlDisclaimerFallbackAction = 'Wrap'
     ApplyHtmlDisclaimerText = $Signature
     ExceptIfSubjectMatchesPattern = '^RE: ','^FW: '
     
     }


    New-TransportRule @SignatureRule

    Sorry if you don't have Exchange 2010....hopefully this helps someone out though :)

    Good Luck!

    -Dan


    Please click "Vote as Helpful" if this post was helpful to you. Thanks!

    Saturday, April 28, 2012 7:58 PM
    Moderator
  • We can do pretty much the same thing with Exchange 2007 and Exchange 2003.  In fact we can do it with any version of Exchange since since Exchange 5.  Of course EX2010 with PowerShell makes it real easy to add transport rules and design workflows.

    Now ask me how?


    ¯\_(ツ)_/¯

    Saturday, April 28, 2012 9:09 PM
  • We can do pretty much the same thing with Exchange 2007 and Exchange 2003.  In fact we can do it with any version of Exchange since since Exchange 5.  Of course EX2010 with PowerShell makes it real easy to add transport rules and design workflows.

    Now ask me how?


    ¯\_(ツ)_/¯

    I have found that you can set up disclaimers that can be used as signature in Exchange 2007.  Unfortunately, you can't embed images into these disclaimers. 


    Grant Ward, a.k.a. Bigteddy

    What's new in Powershell 3.0 (Technet Wiki)

    Saturday, April 28, 2012 10:34 PM
  • We can do pretty much the same thing with Exchange 2007 and Exchange 2003.  In fact we can do it with any version of Exchange since since Exchange 5.  Of course EX2010 with PowerShell makes it real easy to add transport rules and design workflows.

    Now ask me how?


    ¯\_(ツ)_/¯

    I have found that you can set up disclaimers that can be used as signature in Exchange 2007.  Unfortunately, you can't embed images into these disclaimers. 


    Grant Ward, a.k.a. Bigteddy

    What's new in Powershell 3.0 (Technet Wiki)

    There is yet another way....

    ¯\_(ツ)_/¯

    Saturday, April 28, 2012 10:49 PM
  • I've found this thread interesting because I have a real need to automate the creation of signatures for Outlook.  My only alternative is to offer Remote Assistance, and do it manually "over the shoulder".

    But I don't want a script that re-creates the signature every time Outlook is loaded.  The Exchange transport rules would seem like the answer, but corporate policy dictates 2 images in the signature:

    1. The company corporate logo

    2. The "Green" stamp: Please think of the trees before printing this email.

    So it would be:

    Regards,

    FirstName Surname

    Title

    Tel. ext.

    Logo 1

    Logo 2

    I am none the wiser after reading this thread as to how to achieve this.  You say it's possible?


    Grant Ward, a.k.a. Bigteddy

    What's new in Powershell 3.0 (Technet Wiki)

    Saturday, April 28, 2012 10:57 PM
  • Yes,  The SDK has long documented how to insert text into the body of a message.  The test can be HTML markup.

    I think EX2010 disables this in favor of transport rules.  EX2003 allows a sccript to interact with every mail message and to alter the message contents.


    ¯\_(ツ)_/¯

    Saturday, April 28, 2012 11:32 PM
  • It's definitely possible. Look at my example above, the HereString ($Signature) is HTML. All you need to do is put the images up on a web server or you could even create a new virtual directory on your Exchange Client Access Server, which is already a web server. Then use my example from above, with modifications:

    Add a logo:

    <div><img alt="My Logo" src="http://URLtoLogo.jpg"></div>

    Add a link to homepage:

    <a href="http://URLtoHomePage.com/"><i>Click Here To Check out our homepage!</i></a>

    You are basically creating a transport rule that appends an HTML signature to the end of the email. The %%Variables%% are mapped to the user's info in AD. You would want to use group policy to remove Outlook signature functionality because the Transport rule is applied after the message is sent. That could be a deal breaker for some people (hard to get used to change), but it works like a charm. Check out ADComparisonAttributes in the help for New-TransportRule :

    http://technet.microsoft.com/en-us/library/bb125138.aspx

    You can use predicates with the Transport rule to decide when to apply the signature, they are similar to Outlook Rules. In my example above, I used a simple match to exclude replies and forwards (if the subject wasn't altered...)...

    Let me know if I didn't explain this well enough.

    -Dan


    Please click "Vote as Helpful" if this post was helpful to you. Thanks!

    Sunday, April 29, 2012 12:14 AM
    Moderator
  • Daniel - no - your explanation is excellent.  Unfortunately it won't work with EX2007 0r 2003 and earlier.  For that we need assistance from the SDK.

    The setup is very easy however not as easy as using PowerShell in 2010.

    I think we need to the OP to tell us which server. If he is lucky he has 2010.

    Exchange 2012 will be awesome.  I am waiting to upgrade tthree sites for 2012.  W eneed advanced workflow and Sharepoint.


    ¯\_(ツ)_/¯

    Sunday, April 29, 2012 12:41 AM
  • Thanks all for your reply...

    First of all i have exchange 2010 here but i cannot use the desclaimer as managers and VIPs they want to see thier signature before sending the e-mail and as you know signature exchange trasport rule will not show it before sending the e-mail.

    secondly, please jrv if you have any links for such scripts for the outlook signature, paste it here...

    lastly, this script is working greate but the problem is the speed of this script to pull the information from the AD. Please check the below links:

    http://gallery.technet.microsoft.com/ScriptCenter/6f7eee4b-1f42-499e-ae59-1aceb26100de/

    http://blog.powershell.no/2010/01/09/outlook-signature-based-on-user-information-from-active-directory/

    Any advice??

    Sunday, April 29, 2012 9:01 AM
  • Thanks all for your reply...

    First of all i have exchange 2010 here but i cannot use the desclaimer as managers and VIPs they want to see thier signature before sending the e-mail and as you know signature exchange trasport rule will not show it before sending the e-mail.

    secondly, please jrv if you have any links for such scripts for the outlook signature, paste it here...

    lastly, this script is working greate but the problem is the speed of this script to pull the information from the AD. Please check the below links:

    http://gallery.technet.microsoft.com/ScriptCenter/6f7eee4b-1f42-499e-ae59-1aceb26100de/

    http://blog.powershell.no/2010/01/09/outlook-signature-based-on-user-information-from-active-directory/

    Any advice??

    Sunday, April 29, 2012 9:06 AM
  • Mr-Hussam

    Yes - I agree that you have an issue.  The script is one that appears would work however I stick with my earlier post on why it will be a problem in a logon script.

    I would place a test at the beginning of the script to see if the folder LastWriteTime has changed since the current one.  If it is then regenerate the signature.  That way it would only get generated if it doesn't exist or if the template has changed.

    You should also implement Richards suggestion as it will speed things a bit however avoiding constant regeneration would be the best thing. Also placing the code into the Outlook  program would also be better. You could distribute i via an MSI installer deployed by Group Policy.

    Another approach that I have used is to schedule a process to generate the signature remotely.  If you have a very large network this might need to be done incrementally. 

    The extension to Outlook is probably the best, fastest and least impacting.

    Here is a bit of code that you can place just before the active directory access and it will cause the script to exit if the files in the template have not changed.

    # check if update needed
    if(Test-Path $RemoteSignaturePathFull){
        $RemoteSigTime=(gci $RemoteSignaturePathFull).LastWriteTime
        $LocalSigTime=(gci $LocalSignaturePath).LastWriteTime
        if($RemoteSigTime -gt $LocalSigTime){ return}
    }
     

    Test it at the command line before deploying.  I have not tested it as I do not have your setup and I don't feel like synthesizing it.

    There are a couple of other signatures in the repository.  Just search for 'outlook signature'


    ¯\_(ツ)_/¯

    Sunday, April 29, 2012 10:16 AM
  • I looked more closely at the code.  It has some errors in it as downloaded from the repository.  I suspect that they are errros cause byt the forum code when it copies the code to the clipboard.  Be sure to test the code very carefull.  I found that single quotes had been chaned to backquptes shoich cause very strange behavior in teh code.  It appears to work but does not work well.  It may be getting hung.

    I would remove all end-of-line comments.   I would laos update the logic as it is a bit odd which may lead to issues.

    Here is a tool you might be interested in.

    http://www.smart-x.com/products/tools/signature-one/

    It does everything you want and it does not do it every time or at logon. It is an Outlook add-in.  It provides for a centrally managed template.

    I have not used it but it looks pretty good.


    ¯\_(ツ)_/¯

    Sunday, April 29, 2012 10:28 AM
  • Here is a patch for the AD bits that will run somewhat faster.  I eliminate a second trip to AD and only loads the properties reqiuired.

    #Get Active Directory information for current user
    # in this sectionproperty names (in quotes) are case sensitive
    $props=@(
        'displayname',
        'mail',
        'title',
        'telephonenumber'
    )
    $UserName = $env:username
    $searcher=[adsisearcher]“samAccountName=$($env:username)”
    $searcher.PropertiesToLoad.AddRange($props)
    $ADUser = $searcher.FindOne()
    $ADDisplayName = $ADUser.Properties['displayname']
    $ADEmailAddress = $ADUser.Properties['mail']
    $ADTitle = $ADUser.Properties['title']
    $ADTelePhoneNumber = $ADUser.Properties['telephonenumber']


    ¯\_(ツ)_/¯

    Sunday, April 29, 2012 10:46 AM
  • I just saw another bit that will cause many delays.  When the word document is updated it is done by using a find and replace technique.  This is very slow.

    Use a dot file or dotx file and load that.  The template should use properties.  If you use properties to set the values you will have a much faster document update,

    Again - instantiating MSWord during login ill cause a huge delay.  On some systems it can be a minute or more and if it occurs at the wrong point during logon you could get exceptions so look at the registry carefully.


    ¯\_(ツ)_/¯

    Sunday, April 29, 2012 10:55 AM
  • What I do not understand is why the code is using word to generate a signature butit is not using word to generte the signature.

    If we create a template and load it in word then tell word it is a signature Word will do all of teh rest. Word woll update the registry and generate all of the file types; text, rtf, html.  It does all of this automatically.  Why do it manually in code?

    This link has a better example of how this should be done.

    http://gallery.technet.microsoft.com/scriptcenter/b6dfc6d1-5354-4ed0-9856-9547d19ef670

    Of course thisis in VBscript but it is pretty much the same but generates withot using any file.  I prefer using a template file and named fields.

    The specific code of iterst that does all of the file generation and registry updates is this bit:

    Set objSelection = objDoc.Range() 
    objSignatureEntries.Add "Email Signature", objSelection  objSignatureObject.NewMessageSignature = "Email Signature" 
    objSignatureObject.ReplyMessageSignature = "Email Signature" 
     

    That little bit says to take the contents of the updated document which only exists in memory and generate all email signature file.  These two  lines do all of that:

    Set objSelection = objDoc.Range() 
    objSignatureEntries.Add "Email Signature", objSelection 

    These two lines do all of the registry bits:

    objSignatureObject.NewMessageSignature = "Email Signature" 
    objSignatureObject.ReplyMessageSignature = "Email Signature" 

    This version is much faster because it does not generate any files and it does not load any files. It is the version that most peoplehave been using

    VBScript is also a bit faster as PowerShell has to load Net files and it does take quite a bit longer to startup.


    ¯\_(ツ)_/¯

    Sunday, April 29, 2012 11:41 AM
  • Remove flags the force signature.  The code is creating three copies of word.  This is a formula for disaster.

    Go into the code and count this lines:

    $MSWord = New-Object -com word.application

    I think you ned to test that code under a lot more conditions.  I keep finding more bugs.

    If you open a document in powershell and you don't out-null or viod the return it willspew out all of teh properies on the object.  The default behavior of powershell is to enumerate objects.

    Change this line:

    $MSWord.Documents.Open($fullPath)

    to this:

    [void]$MSWord.Documents.Open($fullPath)

    That will prevent delays caused by the enumeration which is unnecessary.

    Other delays are caused by the repeated saving of files.


    ¯\_(ツ)_/¯

    • Marked as answer by Mr-Hussam Tuesday, May 01, 2012 9:17 AM
    Sunday, April 29, 2012 12:25 PM
  • Another very bad thing is that th code opens a common word document on a network share in write mode.

    If all users try to open this in write mode the code will fail.  If a users code fails the document will be marked as potentially corrupt in Word 2007 and later which will cause a prompt and cause failures to update. 

    I know this because I just had to debug a process that was trying to create a new document in the same way. After an hour of failed updates I decided to open the master document and it was flagged as potentially corrupt. 

    I fixed the document and made read-only.  Now the app claerly fails. I then went into the app code and set the open for read-shared. Now all is well. 

    In both cases the document should be a template and added to the session. This way it is never really openable and never stays open. The document template is just used to create a document with specific formatting and initial content.

    In one of my environments we have a corporate shared templates folder which contains, among other thing, a signature template.  The users are jsut set up to create a signature from the is template.  There is a script in the same folder that, when clicked, will refresh the signature.


    ¯\_(ツ)_/¯

    Sunday, April 29, 2012 2:57 PM
  • Amaaaaazing jrv... i did two things to solve this issue as suggested by you...

    i replaced this line:

    $MSWord.Documents.Open($fullPath)

    by this line:

    [void]$MSWord.Documents.Open($fullPath)

    and this solved my problem as a magic... the old version of the script was taking 3-4 min to run for the first time the user login only... after i did the above change the script is taking less than 10 seconds...

    also i want to thank Richard Mueller as i did what he suggest as well, the the AD information start comming after any change very fast.

    Thanks all guys.. deeply appreciate it.

    Tuesday, May 01, 2012 9:22 AM
  • It should NOT take 10 seconds to run.  That is becuse it is still constantly opening and closing word documents that it does not need to open/create/save.

    You can still have issues if two users try to generate a signature at the same time.  The second one will get locked out   Ther is also a great danger of MSWord corruping the document on teh network becuaseit is opening it for writing. Once it gets corrupted then very bad things will happen.

    1.  Set network document share to read only.
    2.  Alter MSWord open statement to open for reading.


    ¯\_(ツ)_/¯

    Tuesday, May 01, 2012 10:29 AM
  • You might want to consider database driver email signatures?

    Fast, flexible, scalable and include many advanced features developed since 2003.

    Based on MS SQL database and a management console.

    No installation on clients and servers. Management can be assigned to non-technical employees.

    www.emailsignature.com


    </Jesper Frier> | www.emailsignature.com

    Thursday, May 03, 2012 6:21 AM
  • Hi, this is script works fine in most of the cases, but for some users it the script fails to create the rtf, htm, txt and the folder with the xml and jpg file.

    I have found out that the process winword.exe gets locked.

    Also if i run the script manually instead of in a logon script it works.

    I have tried to delay the script at logon but it has the same issues.

    And the weird thing is that it works for most of the users.

    Any ideas?

    Wednesday, July 04, 2012 3:22 PM
  • YOu sshould not run Mocrosoft Outlook / WOrd scripts during logon.  It will never be reliable.

    The signature does not need to tbe generated every time.  It can be run by the user as needed.  It is best when run as an add-on to Outlook using a signed project file.

    This question was closed a very log time ago.  If you need to pursue this further you will need to start your own question.


    ¯\_(ツ)_/¯

    Wednesday, July 04, 2012 3:53 PM