# encoding: ascii
# api: powershell
# title: Set Outlook Signatures
# description: This is a script I wrote to automatically update email signatures. Reference this script in group policy.
# version: 1.80.4
# type: script
# author: darkscrypt
# license: CC0
# function: Check-LocalLogging
# x-poshcode-id: 6275
# x-archived: 2016-11-18T01:01:36
# x-published: 2016-03-31T17:35:00
#
#
param ([Switch]$force = $false)
$SignatureEnforcing = $true
$AppData=(Get-Item env:appdata).value
$SigPath = '\Microsoft\Signatures'
$SignatureName = 'Siggy Standard' 
$DomainName = 'siggy.com' 
$SigSource = "\\siggy1\Signatures\$SignatureName" 
$LocalLogFile = "C:\Siggy\Siggy\siggy_" + $ENV:Username + ".txt"
$LocalSignaturePath = $AppData+$SigPath
$RemoteSignaturePathFull = $SigSource+'\'+$SignatureName+'.docx'
$CompanyRegPath = "HKCU:\Siggy\"
$SignatureRegPath = $CompanyRegPath+'\'+$SignatureName
$SiggyVersion = "1.80.4"
$SiggySystemLog = [System.Collections.ArrayList]@()
$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
$ADDescription = $ADUser.description
$ADTelePhoneNumber = $ADUser.TelephoneNumber
$ADFax = $ADUser.facsimileTelephoneNumber
$ADMobile = $ADUser.mobile
$ADStreetAddress = $ADUser.streetaddress
$ADCity = $ADUser.l
$ADPOBox = $ADUser.postofficebox
$ADCustomAttribute1 = $ADUser.extensionAttribute1
$ADModify = $ADUser.whenChanged
$ADFirst = $ADUser.givenName
$ADLast = $ADUser.sn
$ADInitials = $ADUser.Initials
$ADPostal = $ADUser.postalcode
$ADDepartment = $ADUser.physicalDeliveryOfficeName
$ADState = $ADUser.st
$ADSignatureQuote = $ADUser.signatureQuote
$ADProfessionalCredentials = $ADUser.professionalCredentials
function Check-LocalLogging{
	if (!(Test-Path -path "C:\Siggy\Siggy")) {
		New-Item "C:\Siggy\Siggy" -Type Directory
	}
}
function Local-Log($message){
	Check-LocalLogging
	$stream = New-Object System.IO.StreamWriter $LocalLogFile, "Append"
	$output = "[" + (Get-Date).toString() + "]: " + $message
	$stream.WriteLine($output)
	$stream.close()
}
function Write-Log($message){
	Local-Log($message)
	if($SiggySystemLog.count -eq 0){
		$LocalScopedUser = $ENV:username
		$SiggySystemLog.Add("---------------------------") | Out-Null
		Local-Log("---------------------------")
		$SiggySystemLog.Add("Starting Siggy $SiggyVersion ") | Out-Null
		Local-Log("Starting Siggy $SiggyVersion ") 
		$SiggySystemLog.Add,("Siggy Evaluating $LocalScopedUser for signature") | Out-Null
		Local-Log("Siggy Evaluating $LocalScopedUser for signature") 
	}
	$output = "[" + (Get-Date).toString() + "]: " + $message
	Write-Host($output)
	$SiggySystemLog.Add($output) | Out-Null
}
function Finalize-Log{
	$LogFile = "\\SC1\Reporting\Siggy\$ENV:COMPUTERNAME.txt" 
	$stream = New-Object System.IO.StreamWriter $LogFile, "Append"
	foreach($message in $SiggySystemLog){
		Write-Output $message
		$stream.WriteLine($message)
	}
	$stream.close()
}
function Check-ValidMAPIAddress{
	$UserName = $env:username
	$Filter = "(&(objectCategory=User)(samAccountName=$UserName))"
	$Searcher = New-Object System.DirectoryServices.DirectorySearcher
	$Searcher.Filter = $Filter
	$ADUserPath = $Searcher.FindOne()
	$ADUser = $ADUserPath.GetDirectoryEntry()
	if(!$ADUser.mail -or $ADuser.mail -notmatch "yourdomain.com"){
		return $false
	}else{
		return $true
	}
}
function Check-ValidCompanyRegistry{
	#Return True if Valid, False if Invalid
	$Validations = $true
	if (Test-Path $SignatureRegPath) {
		Write-Log('Company Registry Valid')
	}else{
		New-Item -path "HKCU:\" -name "Siggy"
		New-Item -path $CompanyRegPath -name $SignatureName
		Write-Log('Company Registry Not Found.')
		$Validations = $false
	}

	if (Test-Path $SignatureRegPath'\Outlook Signature Settings') {
		Write-Log('Outlook Registry Settings Exist')
	}else{
		New-Item -path $SignatureRegPath -name "Outlook Signature Settings"
		Write-Log('Outlook Signature Settings Not Found.')
		$Validations = $false
	}
	return $Validations
}
function Synchronize-AD{
	Write-Log("Synchronizing Active Directory.")
	$ValidateProperties = [System.Collections.ArrayList]@()
	$ValidateProperties.Add("ADDisplayName") | Out-Null
	$ValidateProperties.Add("ADTitle")  | Out-Null
	$ValidateProperties.Add("ADEmailAddress") | Out-Null
	$ValidateProperties.Add("ADFirst") | Out-Null
	$ValidateProperties.Add("ADLast") | Out-Null
	$ValidateProperties.Add("ADInitials") | Out-Null
	$ValidateProperties.Add("ADPostal") | Out-Null
	$ValidateProperties.Add("ADState") | Out-Null
	$ValidateProperties.Add("ADDepartment") | Out-Null
	$ValidateProperties.Add("ADStreetAddress") | Out-Null
	$ValidateProperties.Add("ADCity") | Out-Null
	$ValidateProperties.Add("ADTelephoneNumber") | Out-Null
	$ValidateProperties.Add("ADMobile") | Out-Null
	$ValidateProperties.Add("ADFax") | Out-Null
	$ValidateProperties.Add("SiggyVersion") | Out-Null
	$ValidateProperties.Add("ADSignatureQuote") | Out-Null
	$ValidateProperties.Add("ADProfessionalCredentials") | Out-Null
	$key = Get-Item -Path $SignatureRegPath'\Outlook Signature Settings'
	foreach ($prop in $ValidateProperties){
		$CurrentValue = (Get-Variable $prop).Value
		if($key.GetValue($prop) -ne (Get-Variable $prop).Value){
			Write-Log("Updating Registry Item: $prop to $CurrentValue")
			Set-ItemProperty $SignatureRegPath'\Outlook Signature Settings' -Name $prop -Value $CurrentValue
		}
	}	
}
function Check-ADSync{
	#Returns False if Desynchronized, and True if Synchronized
	Write-Log("Checking AD Properties against Registry")
	$synchronized = $true 
	if((Check-ValidCompanyRegistry) -eq $false){
		$synchronized = $false
	}
	$ValidateProperties = [System.Collections.ArrayList]@()
	$ValidateProperties.Add("ADDisplayName") | Out-Null
	$ValidateProperties.Add("ADTitle")  | Out-Null
	$ValidateProperties.Add("ADEmailAddress") | Out-Null
	$ValidateProperties.Add("ADFirst") | Out-Null
	$ValidateProperties.Add("ADLast") | Out-Null
	$ValidateProperties.Add("ADInitials") | Out-Null
	$ValidateProperties.Add("ADPostal") | Out-Null
	$ValidateProperties.Add("ADState") | Out-Null
	$ValidateProperties.Add("ADDepartment") | Out-Null
	$ValidateProperties.Add("ADStreetAddress") | Out-Null
	$ValidateProperties.Add("ADCity") | Out-Null
	$ValidateProperties.Add("ADTelephoneNumber") | Out-Null
	$ValidateProperties.Add("ADMobile") | Out-Null
	$ValidateProperties.Add("ADFax") | Out-Null
	$ValidateProperties.Add("SiggyVersion") | Out-Null
	$ValidateProperties.Add("ADSignatureQuote") | Out-Null
	$ValidateProperties.Add("ADProfessionalCredentials") | Out-Null
	$key = Get-Item -Path $SignatureRegPath'\Outlook Signature Settings'
	foreach ($prop in $ValidateProperties){
		$CurrentValue = (Get-Variable $prop).Value
		if($key.GetValue($prop) -ne (Get-Variable $prop).Value){
			$synchronized = $false
			Write-Log("$prop is ne to $CurrentValue, setting synchronization status to false")
		}
	}
	if($synchronized){
		Write-Log "Active Directory information is Synchronized to local cache"
	}
	return $synchronized
	
	
}
function Check-SignatureSync{
	
	$LocalSignatureVersion = (Get-ItemProperty $SignatureRegPath'\Outlook Signature Settings').SignatureVersion
	$MasterSignatureVersion = (gci $RemoteSignaturePathFull).LastWriteTime.toString()
	if (!(Test-Path -path $LocalSignaturePath)) {
		New-Item $LocalSignaturePath -Type Directory
	}
	Copy-Item "$SigSource\*" $LocalSignaturePath -Recurse -Force
	if ($MasterSignatureVersion -eq $LocalSignatureVersion){
		Write-Log("Local Signature Version Matches Master Signature")
		return $true
	}else{
		Write-Log("Local Signature Mismatch.")
		Set-ItemProperty $SignatureRegPath'\Outlook Signature Settings' -name SignatureVersion -Value $MasterSignatureVersion
		return $false
	}
}
Function Get-OutlookProcess(){
	$process = Get-Process "Outlook" -ErrorAction SilentlyContinue
	if ($process -ne $null){
		$Application = [Runtime.InteropServices.Marshal]::GetActiveObject('Outlook.Application') 
		return $Application
	}else{
		Return $null
	}
}
Function WaitFor-Outlook(){
	$Application = $null
	while($true){
		if($force){
			Write-Log("Bypassing Outlook-Wait: Force Mode detected.")
			break
		}
		$Application = Get-OutlookProcess
		if($Application -ne $null){
			$profname = $Application.Application.DefaultProfileName
				Write-Log("Outlook Process Detected")
			if($profname -ne $null){
				Write-Log("Default Outlook Profile Detected")
				break
			}
		}
		Write-Log("No Outlook Profile Detected")
		start-sleep -s 120
	}
	Write-Log("Outlook Profile Detected")
}
function EndProgram{
	param([string]$Reason)
	Write-Log("Gracefully Ending Program: $Reason")
	Finalize-Log
}
function Set-OutlookDefaults{
	WaitFor-Outlook
	$MSWord = New-Object -com word.application
	$EmailOptions = $MSWord.EmailOptions
	$EmailSignature = $EmailOptions.EmailSignature
	$EmailSignatureEntries = $EmailSignature.EmailSignatureEntries
	if ($SignatureEnforcing -eq $false)
	{
		if ($EmailSignature.NewMessageSignature -eq "(none)")
		{
			Write-Log("New Message Signature Not Detected. Setting $SignatureName as Default.")
			$EmailSignature.NewMessageSignature = $SignatureName
		}
		if ($EmailSignature.ReplyMessageSignature -eq "(none)")
		{
			Write-Log("Reply Signature Not Detected. Setting $SignatureName as Default Reply.")
			$EmailSignature.ReplyMessageSignature = $SignatureName
		}
	}
	else
	{
		Write-Log ("SignatureEnforcing is `$true")
		Write-Log("Forcing $SignatureName as Default.")
		$EmailSignature.NewMessageSignature = $SignatureName
		Write-Log("Forcing $SignatureName as Default Reply.")
		$EmailSignature.ReplyMessageSignature = $SignatureName
	}
	$MSWord.Quit()
}
function Launch-Payload{

    Write-Log('Payload Triggered.')
	$Doctor = $false
	$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+'\'+$SignatureName+'.docx'
	$MSWord.Documents.Open($fullPath)
	
	#Begin Find and Replace
	#Check if Doctor
	if($ADDisplayName.ToString().substring(0,3) -match "Dr."){
		Write-Log "Display Name contains DR. In the first three characters. Switching to Doctor Mode."
		$Doctor = $true
	}
	
	#User Name 
	$FindText = "DisplayName" 
    $ReplaceText = $ADDisplayName.ToString() 

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

	#Title		
	$FindText = "Title"
	$ReplaceText = $ADTitle.ToString()
	$MSWord.Selection.Find.Execute($FindText, $MatchCase, $MatchWholeWord,	$MatchWildcards, $MatchSoundsLike, $MatchAllWordForms, $Forward, $Wrap,	$Format, $ReplaceText, $ReplaceAll	)
	
	#Email	
	$FindText = "harbmail"
	$ReplaceText = $ADEmailAddress.ToString()
	$MSWord.Selection.Find.Execute($FindText, $MatchCase, $MatchWholeWord,	$MatchWildcards, $MatchSoundsLike, $MatchAllWordForms, $Forward, $Wrap,	$Format, $ReplaceText, $ReplaceAll	)
	
	#FirstName
	$FindText = "FirstName"
	$ReplaceText = $ADFirst.ToString()
	$MSWord.Selection.Find.Execute($FindText, $MatchCase, $MatchWholeWord,	$MatchWildcards, $MatchSoundsLike, $MatchAllWordForms, $Forward, $Wrap,	$Format, $ReplaceText, $ReplaceAll	)
	
	#LastName
	$FindText = "LastName"
	$Unclean = $ADLast.ToString()
	$ReplaceText = $Unclean -replace "Dr. ", ""
	$MSWord.Selection.Find.Execute($FindText, $MatchCase, $MatchWholeWord,	$MatchWildcards, $MatchSoundsLike, $MatchAllWordForms, $Forward, $Wrap,	$Format, $ReplaceText, $ReplaceAll	)
	
	#Middle Initials
    If ($ADInitials -ne '') { 
	   	$FindText = "MiddleInitial"
	   	$ReplaceText = $ADInitials.ToString()
	}
	Else {
		$FindText = "MiddleInitial. "
	   	$ReplaceText = "".ToString()
	}
	$MSWord.Selection.Find.Execute($FindText, $MatchCase, $MatchWholeWord,	$MatchWildcards, $MatchSoundsLike, $MatchAllWordForms, $Forward, $Wrap,	$Format, $ReplaceText, $ReplaceAll	)
   	
	
	#Postal
	$FindText = "Postal"
	$ReplaceText = $ADPostal.ToString()
	$MSWord.Selection.Find.Execute($FindText, $MatchCase, $MatchWholeWord,	$MatchWildcards, $MatchSoundsLike, $MatchAllWordForms, $Forward, $Wrap,	$Format, $ReplaceText, $ReplaceAll	)
	
	#State
	$FindText = "State"
	$ReplaceText = $ADState.ToString()
	$MSWord.Selection.Find.Execute($FindText, $MatchCase, $MatchWholeWord,	$MatchWildcards, $MatchSoundsLike, $MatchAllWordForms, $Forward, $Wrap,	$Format, $ReplaceText, $ReplaceAll	)

	#Department
	$FindText = "Department"
	$ReplaceText = $ADDepartment.ToString()
	$MSWord.Selection.Find.Execute($FindText, $MatchCase, $MatchWholeWord,	$MatchWildcards, $MatchSoundsLike, $MatchAllWordForms, $Forward, $Wrap,	$Format, $ReplaceText, $ReplaceAll	)
	
	#Description
    If ($ADDescription -ne '') { 
	   	$FindText = "Description"
	   	$ReplaceText = $ADDescription.ToString()
	}
	Else {
		$FindText = " | Description "
	   	$ReplaceText = "".ToString()
	}
	$MSWord.Selection.Find.Execute($FindText, $MatchCase, $MatchWholeWord,	$MatchWildcards, $MatchSoundsLike, $MatchAllWordForms, $Forward, $Wrap,	$Format, $ReplaceText, $ReplaceAll	)
   	
	#Professional Credentials (Job titles)
    If ($ADProfessionalCredentials -ne '') { 
	   	$FindText = "ProfessionalCredentials"
	   	$ReplaceText = $ADProfessionalCredentials.ToString()
	}
	Else {
		$FindText = ", ProfessionalCredentials"
	   	$ReplaceText = "".ToString()
	}
	$MSWord.Selection.Find.Execute($FindText, $MatchCase, $MatchWholeWord,	$MatchWildcards, $MatchSoundsLike, $MatchAllWordForms, $Forward, $Wrap,	$Format, $ReplaceText, $ReplaceAll	)
	#Street Address
	If ($ADStreetAddress -ne '') { 
        $FindText = "StreetAddress"
	    $ReplaceText = $ADStreetAddress.ToString()
    }
    Else {
	    $FindText = "StreetAddress"
	    $ReplaceText = $DefaultAddress
    }
	$MSWord.Selection.Find.Execute($FindText, $MatchCase, $MatchWholeWord,	$MatchWildcards, $MatchSoundsLike, $MatchAllWordForms, $Forward, $Wrap,	$Format, $ReplaceText, $ReplaceAll	)
		
	#PostofficeBox
	If ($ADPOBox -ne '') { 
        $FindText = "PostofficeBox"
        $ReplaceText = $ADPOBox.ToString()
    }
    Else {
	    $FindText = "PostofficeBox"
	    $ReplaceText = $DefaultPOBox 
    }
	$MSWord.Selection.Find.Execute($FindText, $MatchCase, $MatchWholeWord,	$MatchWildcards, $MatchSoundsLike, $MatchAllWordForms, $Forward, $Wrap,	$Format, $ReplaceText, $ReplaceAll	)

	#City
	If ($ADCity -ne '') { 
	    $FindText = "City"
        $ReplaceText = $ADCity.ToString()
    }
    Else {
	    $FindText = "City"
	    $ReplaceText = $DefaultCity 
    }
	$MSWord.Selection.Find.Execute($FindText, $MatchCase, $MatchWholeWord,	$MatchWildcards, $MatchSoundsLike, $MatchAllWordForms, $Forward, $Wrap,	$Format, $ReplaceText, $ReplaceAll	)
	
	#Telephone
	If ($ADTelephoneNumber -ne "") { 
		$FindText = "TelephoneNumber"
		$Number = $ADTelephoneNumber.ToString() -replace "-", "."
		$ReplaceText = $Number
    }
	Else {
		$FindText = "Office TelephoneNumber"
	    $ReplaceText = "".ToString()
 	}
	$MSWord.Selection.Find.Execute($FindText, $MatchCase, $MatchWholeWord,	$MatchWildcards, $MatchSoundsLike, $MatchAllWordForms, $Forward, $Wrap,	$Format, $ReplaceText, $ReplaceAll	)
	
	#Mobile
	If ($ADMobile -ne "") { 
		$FindText = "MobileNumber"
		$Number = $ADMobile.ToString() -replace "-", "."
		$ReplaceText = $Number
    }
	Else {
		$FindText = "| Cell MobileNumber"
	    $ReplaceText = "".ToString()
 	}
	$MSWord.Selection.Find.Execute($FindText, $MatchCase, $MatchWholeWord,	$MatchWildcards, $MatchSoundsLike, $MatchAllWordForms, $Forward, $Wrap,	$Format, $ReplaceText, $ReplaceAll	)

	#Fax
    If ($ADFax -ne '') { 
    	$FindText = "FaxNumber"
		$Number = $ADFax.ToString() -replace "-", "."
        $ReplaceText = $Number 
    }
    Else {
	    $FindText = "| Fax FaxNumber"
        $ReplaceText = "".ToString() 
    }
	$MSWord.Selection.Find.Execute($FindText, $MatchCase, $MatchWholeWord,	$MatchWildcards, $MatchSoundsLike, $MatchAllWordForms, $Forward, $Wrap,	$Format, $ReplaceText, $ReplaceAll	)

	#END: Find And Replace
    #Save new message signature 
    Write-Log('Saving Signatures')
	#Save HTML
	$saveFormat = [Enum]::Parse([Microsoft.Office.Interop.Word.WdSaveFormat], "wdFormatHTML");
	$path = $LocalSignaturePath+'\'+$SignatureName+".htm"
	$MSWord.ActiveDocument.saveas([ref]$path, [ref]$saveFormat)
    
    #Save RTF 
	$saveFormat = [Enum]::Parse([Microsoft.Office.Interop.Word.WdSaveFormat], "wdFormatRTF");
	$path = $LocalSignaturePath+'\'+$SignatureName+".rtf"
	$MSWord.ActiveDocument.SaveAs([ref] $path, [ref]$saveFormat)
	
	#Save TXT    
    $saveFormat = [Enum]::Parse([Microsoft.Office.Interop.Word.WdSaveFormat], "wdFormatText");
	$path = $LocalSignaturePath+'\'+$SignatureName+".txt"
	$MSWord.ActiveDocument.SaveAs([ref] $path, [ref]$SaveFormat)
	$MSWord.ActiveDocument.Close()
	$MSWord.Quit()
	Write-Log('Signature Saved...')

} #End Payload
function Launch-Missile{
	WaitFor-Outlook
	Launch-Payload
}
Function Main{
	$payload = $false
	if($force){
		Write-Log("Force Mode!")
		$payload = $true
	}else{
		Write-Log("Initiating 3 Minute Sleep before continuing.")
		Start-Sleep -s 180
	}
	if((Check-ValidMapiAddress) -eq $false){
		EndProgram -Reason "Invalid MAPI Address for " + $ENV:Username
	}
	if((Check-ADSync) -eq $false){
		Write-Log("Active Directory is Not Synchronized. Missile Armed.")
		$payload = $true
	}
	if((Check-SignatureSync) -eq $false){
		Write-Log("Local Signature is Not Synchronized. Missile Armed.")
		$payload = $true
	}
	if($payload -eq $true){
		Write-Host "Launching Missile."
		Launch-Missile
		Set-OutlookDefaults
		Synchronize-AD
		EndProgram -Reason "Missile Launched"
	}else{
		EndProgram -Reason "Signature modification not needed. All Settings are Clear"
	}
}
Main
