<# .SYNOPSIS Sends a reminder on or before a date in a sharepoint list date field .DESCRIPTION Sends a reminding message to a user and some cc recipients on or before a specific date. Recipient and date must be field in the same sharepoint list. .PARAMETER WebUri Specifies the full URI of the (sub)site. .PARAMETER ListName Specifies the list's name. .PARAMETER DateFieldName Specifies the name of the field containing the desired due date. No space chars. Special characters must be escaped, example: "Datum-zurück" becomes "Datum_x002d_zur_x00fc_ck" .PARAMETER UserFieldName Specifies the name of the field containing the user name. Must be a sharepoint user lookup field. Special characters must be escaped, see DateFieldName. .PARAMETER ActiveFieldName Specifies the name of the field which will be used to decide if the current item is active. If the field is empty, non- existent or contains the letters [Nn] the item will be assumed as non-active. Special characters must be escaped. .PARAMETER DaysBefore Specifies how many days before the due date this reminder will fire. .PARAMETER EmailTemplate Specifies either a path to a email template or the template as string. The template is a notmal text file. You can use the notation {item:fieldname} for looking up values from the list item. Two special items ca be used: {LookedUpName} and {DueDate}. .PARAMETER EmailSubject Specifies the email subject line .PARAMETER EmailFrom Specifies the sender's email address .PARAMETER AlwaysSendCC Specifies an email address which will be used as cc address for every message .PARAMETER WhatIf If set, a dry run will be performed .PARAMETER EventLog If set the error messages are written to the event log. Event id 666 are script errors, id 667 are template engine errors. .NOTES Author: kurator | lagerhaus128.ch Changelog: Revision 3: Code optimization, added some explict type casts. Revision 2: Added event log write functionality. Revision 1: ActiveFieldName has been added, minor code changes. Revision 0: Initial revision .EXAMPLE SP-SendReminder -WebUri "https://sps-dev/oks/testlists" -ListName "List01" -DateFieldName "DateField" -UserFieldName "UserNameField" -DaysBefore "0" -EmailTemplate "C:\temp\sps-dev\test01.templ" -EmailSubject "Due date is coming" -EmailFrom "noreply@domain.tld" -AlwaysSendCC "ccaddress@domain.tld" -WhatIf:$true -EventLog #> #Requires -Version 4.0 #Requires -PSSnapin Microsoft.Sharepoint.Powershell -Version 1.0 param( [Parameter(Mandatory=$true)][string]$WebUri, [Parameter(Mandatory=$true)][string]$ListName, [Parameter(Mandatory=$true)][string]$DateFieldName, [Parameter(Mandatory=$true)][string]$UserFieldName, [Parameter(Mandatory=$false)][string]$ActiveFieldName, [Parameter(Mandatory=$true)][int]$DaysBefore, [Parameter(Mandatory=$true)][string]$EmailTemplate, [Parameter(Mandatory=$true)][string]$EmailSubject, [Parameter(Mandatory=$true)][string]$EmailFrom, [Parameter(Mandatory=$false)][string]$AlwaysSendCC, [Parameter(Mandatory=$false)][bool]$WhatIf=$false, [switch]$EventLog ) Add-PSSnapin Microsoft.Sharepoint.Powershell -ErrorAction SilentlyContinue Try { $SPWeb = Get-SPWeb $WebUri $SPWeb.Lists[$ListName].Items | ForEach-Object { $item = $_ if(([datetime]::Today).AddDays(-1*$DaysBefore) -eq $item[$DateFieldName]) { $ItemActive = $true if($ActiveFieldName.Length -ne 0) { if(($item[$ActiveFieldName].Length -eq 0) -or ([string]($item[$ActiveFieldName].toString()) -match '[Nn]')) { $ItemActive = $false } } if(($ItemActive) -and ($item[$UserFieldName])) { $user = New-Object Microsoft.SharePoint.SPFieldUserValue($SPWeb, $item[$UserFieldName].ToString()) if(Test-Path $EmailTemplate -ErrorAction SilentlyContinue) { $EmailBody = [IO.File]::ReadAllText($EmailTemplate) } else { $EmailBody = $EmailTemplate } ($EmailBody | Select-String -Pattern '(\{[a-zA-Z0-9_\:]+\})' -AllMatches).Matches.Value | ForEach-Object { try{ switch -Regex ($_) { '\{LookedUpName\}' { $EmailBody = $EmailBody.Replace($_,[string]$user.LookupValue) } '\{DueDate\}' { $EmailBody = $EmailBody.Replace($_,[string](Get-Date -Date $item[$DateFieldName] -UFormat '%d.%m.%Y')) } '\{item\:.*\}' { if($item[($_ -creplace '\{item:(.*)\}','$1')]) { $EmailBody = $EmailBody.Replace($_,[string]$item[($_ -creplace '\{item:(.*)\}','$1')]) } else { $EmailBody = $EmailBody.Replace($_,"!!List does not contain field ""{0}""" -f $_) } } default { $EmailBody = $EmailBody.Replace($_,"!!Reference ""{0}"" not found" -f $_) } } if(Get-Command "LookupCCUser" -ErrorAction SilentlyContinue) { $CCUser = LookUpCCUser $SPWeb,$item } } catch { if ($EventLog) { Write-EventLog -LogName 'Windows PowerShell' -Source 'PowerShell' -EntryType 'Error' -EventId 667 -Message ('The script engine of{0} whith the following exception: {1}' -f $MyInvocation.MyCommand.Name, $_.Exception.Message) -Category 667 } else { Write-Error $_.Exception.Message } } } if(! $WhatIf) { $EmailHeader = New-Object System.Collections.Specialized.StringDictionary @{"to"=$user.User.Email; "from"=$EmailFrom; "subject"=$EmailSubject; "content-type"="text/html"}.GetEnumerator() | ForEach-Object { $EmailHeader.Add($_.Name, $_.Value) } if($AlwaysSendCC) {$EmailHeader.Add("Cc", $AlwaysSendCC)} [Microsoft.SharePoint.Utilities.SPUtility]::SendEmail($SPWeb, $EmailHeader, $EmailBody) Remove-Variable EmailHeader } else { if ($EventLog) { Write-EventLog -LogName 'Windows PowerShell' -Source 'PowerShell' -EntryType 'Information' -EventId 666 -Message ("Would send the following lines to {0}, {1}`n`nSUBJECT: {2}`n`n{3}" -f $user.User.Email, $AlwaysSendCC, $EmailSubject, $EmailBody) -Category 666 } else { Write-Host ("Would send the following lines to {0}, {1}`n`nSUBJECT: {2}`n`n{3}" -f $user.User.Email, $AlwaysSendCC, $EmailSubject, $EmailBody) } } Remove-Variable EmailBody } Remove-Variable ItemActive } Remove-Variable item } Remove-Variable SPWeb } Catch { if ($EventLog) { Write-EventLog -LogName 'Windows PowerShell' -Source 'PowerShell' -EntryType 'Error' -EventId 666 -Message ('{0} failed on line {1} whith the following exception: {2}' -f $MyInvocation.MyCommand.Name, $_.InvocationInfo.ScriptLineNumber, $_.Exception.Message) -Category 666 } else { Write-Error $_.Exception.Message } exit 1 }