Tuesday 29 January 2013

Sending SMTP Emails with Powershell using Authentication

The following script can be used to send an email message using SMTP. This method is slightly different to my previous post about sending email messages in Powershell as this method uses the smtpClient method rather than mailmessage in order to allow for authentication to occur.

$From = "fromaddress@domain.com"
$To = "toaddress@domain.com"
$SMTPServer = "smtp.gmail.com"
$SMTPPort = "587"
$Username = "username@gmail.com"
$Password = "gmailpassword"
$subject = "Email Subject"
$body = "Insert body text here"

$smtp = New-Object System.Net.Mail.SmtpClient($SMTPServer, $SMTPPort);

$smtp.EnableSSL = $true
$smtp.Credentials = New-Object System.Net.NetworkCredential($Username, $Password);
$smtp.Send($From, $To, $subject, $body);

You will need to update the values of the first 8 variables to match what is required for the email account/domain you are sending from.

The SMTP Server and Port number will vary for different email providers - I can confirm the server and port specified above for Gmail are correct though.

UPDATE - 29/11/13

You can also use the System.Net.Mail.MailMessage class to give you the additional option to add CC, BCC, attachments etc, as per the below script. Simply update the first 9 variables below to configure your email message.

$SMTPServer = "smtp.gmail.com"
$SMTPPort = "587"
$Username = "username@gmail.com"
$Password = ""

$to = "user1@domain.com"
$cc = "user2@domain.com"
$subject = "Email Subject"
$body = "Insert body text here"
$attachment = "C:\test.txt"

$message = New-Object System.Net.Mail.MailMessage
$message.subject = $subject
$message.body = $body
$message.to.add($to)
$message.cc.add($cc)
$message.from = $username
$message.attachments.add($attachment)

$smtp = New-Object System.Net.Mail.SmtpClient($SMTPServer, $SMTPPort);
$smtp.EnableSSL = $true
$smtp.Credentials = New-Object System.Net.NetworkCredential($Username, $Password);
$smtp.send($message)
write-host "Mail Sent"

File Locked After Sending SMTP Email with Powershell

In my previous blog post about sending emails with Powershell, I mentioned a problem where files that you attach to an email become locked until the instance of Powershell you are running has exited completely. So if you run a script through Powershell ISE that attaches a file to an email, that file will remain locked until you exit Powershell ISE.

If the file is locked by Powershell, you will get an error/warning message similar to the following if you try to modify it in any way;

The process cannot access the file 'c:\filename.txt' because it is being used by another process

By using the following command, you can ensure that Powershell 'disposes' of the email message once it has been sent and does not continue to 'lock' any files you attach and send via email;

$mailmessage.dispose()

Note: this is assuming that $MailMessage = New-Object system.net.mail.mailmessage 

Friday 25 January 2013

Sending Email Messages with Powershell

A lot of the scripts I use generate reports or .csv files that I need to reference or send to other users who have requested them. One of the easiest ways to accomplish this is to configure your script to automatically email yourself (or anyone else) with the results and/or any files that were created in your script. This saves you time by not having to manually copy the files to another location or attach them to a new email message. You can simply receive the email message and forward it on, or include all recipients in the original email sent by the script.

The following lines of code can be used to create and send an email message with Windows Powershell:


$SmtpClient = new-object system.net.mail.smtpClient 
$MailMessage = New-Object system.net.mail.mailmessage 
$SmtpClient.Host = "your.smtp.server" 
$mailmessage.from = ("fromaddress@yourdomain.com") 

$mailmessage.Subject = “Subject”
$mailmessage.Body = "body text"
$mailmessage.IsBodyHtml = $true
$mailmessage.ReplyTo = "replytoaddress@yourdomain.com"
$mailmessage.Attachments.Add("C:\Path\yourfile.txt")
$smtpclient.Send($mailmessage)
$mailmessage.dispose()

Notes:

You will need to replace the values in some of the variables above to allow it to work in your environment (ie. SmtpClient.Host, FromAddress, Subject, Body text, Reply to address, attachment path).

You will also need to ensure that whatever machine you are running this script on is "authorised" to send with the SMTP server you have configured.

The final line of code $mailmessage.dispose() is very important when sending emails with attachments. If this line is not included, Powershell 'locks' the file(s) you attached after the message has been sent and will not 'release' them until the Powershell instance you are running is closed.

Thursday 24 January 2013

Exporting Exchange Distribution Group Members with Powershell

Before making any major changes to distribution groups, I like to take a backup of the current membership lists prior to making any changes. Particularly in cases where membership lists are quite large, it's always better to be safe than sorry for when a user or distribution group owner wants to know who was a member prior to making the change.

Getting the list of members and exporting it to a simple .csv file can be achieved using the Powershell script below.

Note that you should change the first two (2) variables ($DLName and $ExportFilePath) accordingly.

#Script to get/export list of all distribution group members
#Date Created: 24th January, 2013
#Author: Peter Morrissey


#Enable Exchange cmdlets
add-pssnapin *exchange* -erroraction SilentlyContinue

$DLName = "DL_Example_List"
$ExportFilePath = "C:\Export\Export.csv"


$MemberList = get-distributiongroupmember -identity $DLName

ForEach ($Member in $MemberList){write-output "$($member.name)" | out-file -filepath "$exportfilepath" -append -noClobber}

Wednesday 23 January 2013

Creating a Graphical User Interface (GUI) with Powershell

One of the first things I wanted to do when I started learning Powershell was to create a simple graphical user interface (GUI) that I could use to automate some of my day to day tasks. One main task in particular that took up a lot of my time was creating new user accounts. The process involved creating an Active Directory account, attaching a new mailbox to the Active directory account, adding the new account to security and distribution groups, and also sending a notification email to the new account requester with all the information in it. Doing this process manually was incredibly time consuming, and I knew there had to be a better way.

By using Powershell, I created a script that prompts with several input boxes and list boxes where I can enter all the required details to create a user account. All these inputs are saved as variables, and can then be used to run a single command to perform all the necessary steps.

Here is a screenshot of one of the input boxes that is presented during the script:


By repeating this prompt for first name, last name, office, department, title, phone number, password etc, I was able to quickly and easily collect all the information I needed to create an Active Directory account using the dsadd command - which also runs as part of the script once all the information has been collected.

Once I had an Active Directory account created, I was then able to create a mailbox and attach it to the Active Directory account using the Enable-Mailbox cmdlet.

And finally, once the Active Directory account and mailbox were created,  I could add the user to any required security/distribution groups, and send all the new account information via email to the requester. (I will cover each these topics in more detail in future blog posts.)

One of the most valuable things you can teach yourself with Powershell is how to create input boxes and list boxes for the collecting of information you require to run a command. Some examples of such commands are creating user accounts (as I just discussed), enabling or disabling ActiveSync on a mailbox, or enabling/disabling email forwarding. The possibilities are endless, though most of mine focus around the Active Directory/Microsoft Exchange technologies.

This Technet Article is what I used to get started on input boxes and highly recommend it as a starting point as the article breaks down each line of code and explains what it does.

Once you learn how to create, modify and use input boxes, you can apply the same lines of code over and over again within all your scripts - invest the time to learn it and it will save you time in the end, and open up enormous possibilities/options for your Powershell scripting.

Monday 21 January 2013

Working with Forms Outside of Powershell ISE

Another issue I encountered when I was first starting out with Powershell scripting was a strange error that occurred when I loaded any of my scripts that used forms. (Forms are used to provide a graphical user interface (GUI) for the script - eg. input boxes, list boxes, pop up messages etc). The issue only occurred when I ran the script outside of the Powershell editor - Powershell ISE.

The following error would occur when the script started;

New-Object : Cannot find type [System.Windows.Forms.Form]: make sure the assembly containing this type is loaded

This error would occur hundreds of times, once for every line of code that referred to System forms that were being used.

After a little investigating, I discovered that you must load the .NET Framework classes being used at the beginning of the script. This is easily accomplished with the following lines of code;


[void]  [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[void]  [System.Reflection.Assembly]::LoadWithPartialName("system.net.mail")

This will load all the system form assembly's required to use custom windows forms in your script.

Note: The [void] text simply prevents any informational messages from being displayed on the screen when the classes are loaded.

Friday 18 January 2013

Powershell Execution Policies - Execution of Scripts is Disabled on this System

If you are attempting to run a powershell script file (.ps1) on a system for the first time, you will most likely encounter an error message similar to this;

File filename.ps1 cannot be loaded because the execution of scripts is disabled on this system.

This is related to what is known as the "execution policy" that is set for the particular user/computer you are attempting to run the scripts on.

You can view what the current execution policy is on your machine by opening a Windows Powershell prompt and running the command get-executionpolicy. There are four (4) different execution policies available:

  • Restricted - No scripts can be run. Windows PowerShell can be used only in interactive mode.
  • AllSigned - Only scripts signed by a trusted publisher can be run.
  • RemoteSigned - Downloaded scripts must be signed by a trusted publisher before they can be run.
  • Unrestricted - No restrictions; all Windows PowerShell scripts can be run.

You can modify what the current execution policy is by running the command set-executionpolicy setting where setting is one of the four (4) values specified above.

The following technet article contains further information on signing of scripts with Windows Powershell

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

Mozilla Firefox - The Proxy Server is Refusing Connections

Over the past few days I have encountered a number of users reporting issues with Firefox displaying the below error page:

The proxy server is refusing connections. Firefox is configured to use a proxy server that is refusing connections.



As at the time of this blog entry being written, the issue appears to be specifically related to version 18.0 of Mozilla Firefox. By installing a previous version of Mozilla Firefox (17.0.1), we were able to resolve the problem. Version 17.0.1 can be downloaded from here (Windows version)

In the specific environment that I discovered the issue, the proxy server involved was a Client Side Proxy (CSP) Squid server. The error page above was displayed intermittently on random pages/sites, most of which were using https.

Note: If you install a previous version of Mozilla Firefox, be sure to go into the Options and disable automatic updates for Firefox, otherwise it will simply update itself to 18.0 again automatically.

Powershell Scripts Slow to Load

One of the more unusual issues I have experienced is one where Powershell scripts take a significantly long time to load. After right clicking a .ps1 and selecting 'Run with Powershell', it can take several minutes of waiting on the black shell screen before anything actually happens.

The issue is caused by a setting within Internet Explorer that forces a Certificate Revocation check for the certificate used to sign the code in the Powershell script.

You can turn off this checking by following the steps below.
  1. Open Internet Explorer
  2. Go to Tools > Internet Options
  3. Select the Advanced tab
  4. Scroll down to the Security section. Uncheck the option to Check for publisher's certificate revocation
For security reasons it is not recommended to leave this setting unchecked, especially if the server has Internet access.

I have come across this problem on Windows Server 2003 and Windows Server 2008 R2 platforms.

Enabling Exchange Cmdlets in Powershell

In order to run Exchange Server commands within a Powershell script, the relevant cmdlets need to be 'called' within Powershell.

This is accomplished with the following line, which is found at the start of nearly all of my Powershell scripts.

#Enable Exchange cmdlets
add-pssnapin *exchange* -erroraction SilentlyContinue

If you attempt to run Exchange commands in Powershell (eg. Get-Mailbox) without loading the Exchange cmdlets first, you will get an error similar to the following;


The term 'get-mailbox' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
At line:1 char:12
+ get-mailbox <<<< 
    + CategoryInfo          : ObjectNotFound: (get-mailbox:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException


Exchange Global Address List Not Updating - Force Global Address List (GAL) Update

I have created this Powershell script to be able to force an update of the Global Address List within Exchange 2007. After making changes to recipients/distribution lists within Exchange, I sometimes required a way to make these changes quickly accessible to users, so when they next download the GAL through Outlook, they obtain the latest changes. Most environments do this automatically once or twice a day, which is fine, but this script can be used to force the process to run as required.

Before running this script, I manually force an update of the Default Offline Address Book (OAB) through the Exchange Management Console. I then run this script to force the latest version of the OAB to the Client Access Server's so it is available for download by end users.


#Enable Exchange cmdlets
add-pssnapin *exchange* -erroraction SilentlyContinue

#Force Update of OAB

Get-OfflineAddressBook | Update-OfflineAddressBook

#Get List of Current CAS Servers

$CASList = Get-ExchangeServer | where {$_.isClientAccessServer -eq $true}

#Force Deployment of GAL to CAS's

ForEach ($CAS in $CASList)
    {
    Update-FileDistributionService $($CAS.Name)
    }

Welcome

Welcome to my Blog!

I'm currently employed as an IT professional, and have decided to create this blog to share some of my ideas, thoughts, creations and findings with anyone who cares to look, as well as have a repository of sorts for some of my work/solutions.

I'm a big believer in automation - working smarter, not harder. I am a self taught Powershell "scripter" and have created a large number of scripts to help make my job much easier, and my time spent performing tasks much more efficient - in particular with Microsoft Exchange 2007 and Active Directory.

I plan to share alot of these creations on this very blog. Everything I've come to know and learn about Powershell scripting has been from other various blogs and sites around the Internet - it's always nice to give something back.

Feel free to comment - feedback/suggestions/questions are always welcome :-)

Cheers,
Peter.