Bulk update e-mail whitelist (Set-MailboxJunkEmailConfiguration)

A request came in from a client to develop an easier way to populating the e-mail whitelist for all new starters, or anyone that wants a new list.

My colleague had tried exporting the current whitelist from a user with

Get-MailboxJunkEmailConfiguration "Surname, FirstName" | select-object @{name='WhiteList';Expression={[string]::Join(',', ($_.TrustedSendersAndDomains))}} | export-CSV c:\temp\whitelist.csv

This outputs the entries and comma separates, looks great but when attempting to import back in to another user it fails with an error about it being a string. You can’t export to a variable very well becuase it’s a Microsoft.Exchange.Data.MultiValuedProperty (you can use Get-Member to discover this). I believe my colleague had followed the article here in order to export the multivalued properties.

So the request came to me to “simply populate the trusted senders and domains either with a full overwrite from text file, or using += or @{add=’$list}”, easy hey? 🙂

Instead of trying to alter the data in any way when exporting I used a simple script to export to a text file, it lists the e-mail addresses and domains line by line.

Output script:

$file = New-Item -type file "C:\Temp\Test.txt" -Force
$user = "Surname, FirstName"
$dc = 'domaincontroller.domain.com'
$Mailbox = Get-MailboxJunkEmailConfiguration $user -domaincontroller $dc
$mailbox.TrustedSendersAndDomains | out-file $file

Turns out that get-content will automatically create an array from an input, so there was no need to export to a CSV or similar. Then I could just run a foreach to iterate through the entries. Now you can have a text file with all safe senders / domains list, or just the sender you wish to add, the script will then append to the list.

Input script:

$addresses = Get-Content c:\temp\test.txt 
$mailbox = '[email protected]'
$dc = 'domaincontroller.domain.com'
Foreach ($address in $addresses)
{
Set-MailboxJunkEmailConfiguration -Identity $mailbox -TrustedSendersAndDomains @{Add=$address} -domaincontroller $dc
}

Check out Get-Content on TechNet.

Posted in Guides Tagged with: , ,

Alert when oldest Inbox mail item reaches a certain age

This script was created after a business requirement to ensure an important shared mailbox be regularly checked. The requester wanted to be sure that someone manually checked the mailbox for new mail at least every quarter of an hour, and an e-mail be sent to a distribution group if this did not happen. After a lot of searching I was unable to find a script that performed the task, I therefore decided to whip one up.

PowerShell doesn’t have the most advanced mailbox querying features, and you can’t check for aspects such as whether the e-mail has been read. The user had to change their manual processes somewhat in order to be sure that once the e-mail had been read that it was moved to a subfolder.

I broke the process down into 6 steps, these are:

1. Retrieve the current date, set it into a manageable format and store this info as a variable.
2. Provide some variables which you can amend around e-mail delivery and message text.
3. Query mailbox to retrieve date of oldest item in Inbox.
4. Create a variable with oldest item value in same format as the current date variable
5. Compare the time of the oldest mail in the Inbox to current time.
6. Send a mail if more than 10 minutes has elapsed.

The main issue I had with this script was comparing the current date with the date returned by the Get-MailBoxFolderStatistics command.

Running get-date returns the date in the FullDateTimePattern format.

get-date

get-date

Whereas the Get-MailboxFolderStatistics command returns the date in the General format.

Get-MailboxFolderStatistics -Identity mailbox -FolderScope Inbox -IncludeOldestAndNewestItems | where-object {$_.FolderPath  -eq "/Inbox"} | Select-Object -Property OldestItemReceivedDate

get-mailboxfolderstatistics

The fix for this is to change the value returned from get-date to a General type with the code

(get-date).ToString('G')

It may sound look like I am a compendium of knowledge around time formats, but the information actually came from the extremely handy article on Technet.

The other issue I had was around the filtering of the Get-MailboxFolderStatistics command, so that only the Inbox (and no subfolders) were queried. After a bit of trial and error I isolated that the filter | where-object {$_.FolderPath -eq “/Inbox”} did the trick.

The complete script is below, let me know if you find it useful.

#######################################################################
# Author  : Tom Anderson   
# Date    : 18-03-2013   
# Comment : This script checks the Oldest Item Receive Date for mails
#         : in the specified Mailbox. If a mail older than 10 minutes 
#         : is present an e-mail notification is sent.
# History :
#######################################################################

#### Add Exchange PowerShell Snap-In
Add-PSSnapin Microsoft.Exchange.Management.PowerShell.E2010

#### Set current date and correct format 
$date = (get-date).ToString('G')

### Set Mailbox identity
$mailbox = "yourmailbox"

#### E-mail variables
$smtpServer = "smtp.yourcompany.com"
$recipient = "[email protected]"
$sender = "[email protected]"
$Subject = "The process has fallen over"
$Body = "There is an e-mail older than 10 minutes in your $mailbox inbox."

#### Query Inbox of mailbox to retrieve date of oldest item
$OIRD = Get-MailboxFolderStatistics -Identity $mailbox -FolderScope Inbox -IncludeOldestAndNewestItems | where-object {$_.FolderPath  -eq "/Inbox"}

#### Create variable with above value in same format as the $date variable
$OIRDInfo = $OIRD.oldestitemreceiveddate

#### Compare the time of the oldest mail in the Inbox to current time.
#### A mail is sent if more than 10 minutes has elapsed.
$compare = new-timespan -start $OIRDInfo -end $date
if ($compare.TotalMinutes -gt 10) {Send-MailMessage -From "$sender" -To "$recipient" -Subject "$Subject" -Body "$body" -smtpserver "$smtpServer"}

This script is also listed on the Technet Script Repository.

Posted in Guides Tagged with: , ,

E-mail disk space info for Exchange servers

The PowerShell script below:

1. Queries the environment for a list of Exchange servers.
2. Creates a file with information about total and remaining disk space.
3. E-mails the file.

################################################## 
# Script  : DiskSpace.ps1 
# Author  : Tom Anderson - http://tomandersonpro.net   
# Date    : 13-03-2013    
# Purpose : This script checks the disk size and free space in Gigabytes for each 
#         : Exchange server in your environment that runs Exchange 2007 or newer   
#         : A report is created and sent out via email to address specified.  
# History : 
################################################## 
 
#### Set parameters for output filename  
$date = ( get-date ).ToString('yyyyMMdd') 
$file = New-Item -type file "C:\Temp\ExchangeDailyChecksHistory\$date-ExchangeFreeDiskSpace.txt" -Force 
 
#### E-mail variables 
$smtpServer = "EXSVR" 
$recipient = "[email protected]" 
$sender = "[email protected]" 
$Subject = "Daily Exchange Server disk space report" 
$Body = "Please find report attached." 
 
#### Poll Exchange environment to retrieve any servers newer than 2007  
#### (I used this filter as for some reason an Exchange 2003 box was reporting as being in the environment, despite having been removed some time ago) 
$servers=Get-ExchangeServer |where-object {$_.isExchange2007OrLater -eq $True} 
 
#### Set values for progress counter 
$serverscount = $servers.count;$i=0  
 
#### Loop through each server retrieved 
foreach ($server in $servers) {   
 
#### Get disk space 
'Get Disk Space ' +  $server |out-file $file -append 
get-wmiobject -computer $server -query ` 
"Select * from win32_logicaldisk ` 
where DriveType=3" | sort DeviceId | format-table DeviceId, VolumeName, @{Label="Size in GB"; Expression={[math]::round(($_.Size/1GB),2)}}, @{Label="Free space in GB"; Expression={[math]::round(($_.FreeSpace/1GB),2)}} -auto | out-file $file –append 
} 
 
#### Send message 
Send-MailMessage -From "$sender" -To "$recipient" -Subject "$Subject" -Body "$body" -Attachments "$file" -smtpserver "$smtpServer"

This has been listed on TechNet Script Center at http://gallery.technet.microsoft.com/scriptcenter/E-mail-disk-space-info-for-8ef4ed29

Posted in Guides Tagged with: ,

Interrogate SMTP Logs

This guide assumes you are running Exchange 2010, although should work with other versions. The Excel specific information assumes you have Excel 2010 on your workstation.

The first step is retrieving the SMTP logs. They are stored on your Hub Transports servers, and by default they are located at C:\Program Files\Microsoft\Exchange Server\V14\TransportRoles\Logs\ProtocolLog\SmtpReceive\

I usually copy the logs to a workstation so as not to affect anything on the server. The next step is to interrogate the logs to find devices that are using your servers as open relay. To do so:

1. Open Excel.

2. File > Open > Select File > Open

3. Change type to All Files (*.*)

4. Delimited > Next

5. Then Chose options as below

SMTPLogs

6. Hit Finish.

7. Add a filter on the 5th row. (Home > Sort & Filter > Filter)

8. On Context (Column I) change filter so only EHLO and HELO entries show up. Sort column A to Z.

The IP of relaying device can be viewed from remote-endpoint column (F)

Posted in Guides Tagged with:

Links and growing

When I started this site last year it was as a vehicle to pass on a few bits I have picked up over the years. Also perhaps cheekily to potential employers so I can demonstrate my documentation skills.

I think going forward I will be using it more and more as a resource for myself (hence some of the scripts that have gone up in the last few days, more to come!) as well as a link to other sites, and articles that I have found beneficial.

Do if you have found anything on this site to be beneficial.

Cheers,

Tom

Posted in Blog

Script to move a machine in AD after adding it to the domain

This is probably the script of which I’m most proud. Although I haven’t used it at many employers, it took a lot of testing to get it working.

This script checks the Computers container in Active Directory for machines that have recently been joined to the domain. It then prompts the user to decide whether the machine should be moved, if the response is yes then the machine is moved into the correct Organisational Unit.

You will need to edit line 20 to ensure you have entered the required information for your domain, as well as 40 and 45 to include the correct OUs for your machines.

This script was created on a domain which contained Windows XP and Vista machines, it can easily be extended to include other operating systems. You will need sufficient permission on the domain for the account you run this script from.

'**************************************************************************************************
'*Script Name: MoveMachine.vbs
'*Created on:  23/02/2009
'*Author:      Tom Anderson
'*Purpose:     This script checks the Computers container in Active Directory for machines that 
'*             have recently been joined to the domain. It then prompts the user to decide whether
'*             the machine should be moved, if the response is yes then the machine is moved
'*             into the correct Organisation Unit.
'*History:     27/02/2009 - Performed check for OS, removing user input.
'*             02/03/2009 - Added option to cancel script.
'**************************************************************************************************
 
'*****Search Computers container of AD for any machines with a name which begins "yourcompany"
'*****Returns name and Operating System information.
 
Set objConnection = CreateObject("ADODB.Connection")
objConnection.Open "Provider=ADsDSOObject;"
Set objCommand = CreateObject("ADODB.Command")
objCommand.ActiveConnection = objConnection
objCommand.CommandText = "<LDAP://cn=computers,dc=contoso,dc=com>;(&(objectCategory=computer)(cn=yourcompany*))" & ";name,operatingsystem;subtree"
Set objRecordSet = objCommand.Execute
 
'**************************************************************************************************
 
'*****Create array from yourcompany machines in Computers container. Then iterate through array, for each
'*****item prompt user to decide if machine should be moved. If answer is yes then machine is moved
'*****to correct OU.
 
Dim arrComputers : arrComputers = Array()
Dim intElem : intElem = 0
Set objShell = WScript.CreateObject("WScript.Shell")
Const TIMEOUT = 7
While Not objRecordSet.EOF
   ReDim Preserve arrComputers(intElem)
   arrComputers(intElem) = objRecordSet.Fields("name")
 OSVal = objShell.Popup("Do you want to move machine " & arrComputers(intElem) & "?" ,TIMEOUT,"More Info?",vbYesNoCancel + vbQuestion)
  Select Case OSVal
   Case vbYes
    If objRecordset.Fields("OperatingSystem") = "Windows Vista Enterprise" Then
     Set objOU = GetObject("LDAP://ou=Vista,ou=Workstations,ou=yourcompany,dc=contoso,dc=com")
     ObjLoc = "LDAP://cn=" & arrComputers(intElem) & ",cn=Computers,dc=contoso,dc=com"
     objOU.MoveHere objLoc, vbNullString
     wscript.echo "Machine has been moved to the Vista OU"
    Else
     Set objOU = GetObject("LDAP://ou=Production,ou=Workstations,ou=yourcompany,dc=contoso,dc=com")
      ObjLoc = "LDAP://cn=" & arrComputers(intElem) & ",cn=Computers,dc=contoso,dc=com"
      objOU.MoveHere objLoc, vbNullString
      wscript.echo "Machine has been moved to the Production OU"
     End If
   Case vbNo
    wscript.echo "Machine has not been moved."
   Case VbCancel
    wscript.Echo "Script has been cancelled."
    Wscript.Quit  
   End Select
     intElem = intElem + 1
   objRecordSet.MoveNext
Wend
 
'**************************************************************************************************
Posted in Guides Tagged with: ,

Script to defrag C: drive

Windows operating systems prior to Vist and Server 2008 didn’t have the functionality of easily scheduling a defrag job from the GUI. Using the script below you can create a scheduled task to regularly defragment your disks.

I recommend using it to accompany the

'***************************************************************************************************
'*Script Name:	Defrag.vbs
'*Created on:	16/03/2012
'*Author:	Tom Anderson
'*Purpose:	This script defragments the C: drive. Ammend the text if other drives are required.
'*History:	
'**************************************************************************************************

Set objShell = CreateObject("WScript.Shell")
objShell.Run "cmd.exe /c defrag.exe C:"
Posted in Guides Tagged with: ,

Script to clear temporary files

This is a script I put together a few years ago, but have ended up using at some point at every employer since.

Installing an application (or even just running one) can create lots of temporary files. It’s not unusual to see hundreds of megabytes, or even gigabytes of data in your temp folder. This is wasted space which slows your machines down! I have used this script on workstations and servers, it’s a very quick way to get a big speed increase, especially for older boxes.

The script below will clear out C:\Windows\Temp as well as any %USERPROFILE%\Local Settings\Temp\ folders that it has access to. It can be run on any Windows machine newer than XP or Server 2003. For especially troublesome machines I recommend creating a scheduled task. Several times I have created a task that runs 30 minutes before the Defrag script, this helps to keen your hard disk clear and optimised.

You can easily expand the script to include additional directories, such as C:\Windows\SoftwareDistribution\Download\ if you want to clear up WSUS files.

'**************************************************************************************************
'*Script Name: ClearTempFiles.vbs
'*Created on:  02/03/2009
'*Author:      Tom Anderson
'*Purpose:     This script clears all temp files from C:\%PROFILEFOLDER%\%USER%\Local
'*             Settings\Temp and C:\Windows\Temp\.
'*History:
'**************************************************************************************************

'*****First the script checks to see if C:\Users\ exists. If so then the machine is running
'*****Vista or 7, otherwise it runs XP.

Set Filesys = CreateObject("Scripting.FileSystemObject")
If Filesys.FolderExists ("C:\Users\") Then
path = "C:\Users\"
Else
path = "C:\Documents and settings\"
End If

'*****Checks all profile folders and deletes all files from %USERPROFILE%\Local Settings\Temp\

Set objShell = CreateObject("WScript.Shell")
Set fso = CreateObject("Scripting.FileSystemObject")
Set folder = fso.GetFolder(path)
Set subFolders = folder.SubFolders

For Each folderObject in SubFolders
If fso.FolderExists(path &amp; folderObject.Name &amp; "\Local Settings\Temp\") Then
objShell.currentdirectory = path &amp; folderObject.Name &amp; "\Local Settings\Temp\"
objShell.Run "cmd.exe /c rd ..\temp\ /s /q"
End If
Next

'*****Clears the C:\WINDOWS\Temp\ directory

objShell.currentdirectory = "C:\WINDOWS\Temp\"
objShell.Run "cmd.exe /c rd ..\temp\ /s /q"

Posted in Guides Tagged with: , ,

Return

Finally the website is back up and running! After an unwelcome experience attempting to increase the security of the site I had to trash it and start again.

Thankfully the database was backed up! FULL site backups from now on.

I have been working on lots of new content, some of which I hope to get up this weekend. I also plan to include some older (but very useful) scripts.

Tom

Posted in Blog

Exchange 2007 to 2010

Part of a merger required free/busy sharing with other business units. These units previously had no visibility or communications possibilities (outside of Internet relayed e-mail) so this presented an interesting challenge.

Prior to Exchange 2010 a one or two way interdomain trust would have had to have been created. Thankfully I managed to circumvent this task with the assitance of Microsoft Federation Gateway (MFG). For the sake of clarity and complete understanding for anyone attempting to complete this task (I could find no end-to-end documentation online for our scenario) I have included all steps taken.

Microsoft Federated Gateway allows you to securely share information with other e-mail organizations across the Internet.

The domain consisted of Mailbox, CAS and Client Access servers, all running Exchange 2007 SP1.

The process can be broadly broken down into 3 steps:

1. Updating all Exchange 2007 boxes to Exchange 2007 SP3 (SP2 will also work). This is to facilititate the installation of an Exchange 2010 CAS.

2. Install Exchange 2010 Client Access Server.

3. Autodiscover / certificates / federation creation.

Posted in Guides Tagged with: