My background when it comes to scripting is rather weak. I have no programming skills. I never liked programming (took a class once in Turbo Pascal). Heck, I don’t even have a degree in Computer Science (History if you want to know…). However I have 18 years of practical IT experience and now about 8 years of PowerShell scripting (I started playing with Monad when it came out). Either way, I am still not a programmer, but have found a way to solve my Exchange issues with PowerShell using this methodology:
Methodology
STEP ONE – Either have an issue or come up with a problem to resolve
STEP TWO – Research the Internet (using my Google-Fu) to see if anyone else has a similar solution or at least part of the solution
STEP THREE – First Draft – Take prewritten code (mine or Internet sourced) and create the script.
STEP FOUR – Testing, testing, testing – My first large script took me weeks to create. Ninety percent of the time was testing.
STEP FIVE – Finalizing and posting – After testing has proven successful, I create my blog post with relevant screenshots and a basic description.
Process In Motion
STEP ONE
So, let’s say for argument’s sake let’s say I need a script to create a set of tasks in Outlook that I need to insert back into various mailboxes for a test environment. How they heck would I go about this? Well, in this case I’ve already worked on a similar process with Outlook Calendar Entries. I still use my ‘Google-Fu’ to find solutions, which leads us to:
STEP TWO
Searching the Internet has always been a challenge. Even with resources such as Google and Bing, finding a needle (your results) in the haystack otherwise known as the Internet, can be time-consuming. To find results quickly/efficiently, I try to reduce the number of search terms used in my searches. Sometimes I do what in math terms would be called iterations. This requires searching, reviewing what my results are, searching again with slightly or completely different terms, and then see what the results are. I may repeat this process a few times until I get results that look like what I need. In my example, I decided to use these search terms:
‘powershell create outlook tasks EWS’
A Google/Bing search with these terms leads to some interesting material:
- Working with Tasks using Exchange Web Services
- Creating a new Calendar,Contacts,Tasks or Notes Sub Folder in EWS with Powershell
- Use PowerShell to Import Appointments
- Learn to Use the Exchange Web Services with PowerShell
That’s the way the results showed up and in this case the way I read the articles. Key for me is relevance as well as recognizing good sources of information. In this case I know that Glen Scales is a great scripter, two other entries are from MSDN and the last article is from slipstick.com which is also a great resource.
At this point I read all four articles and then decide which article matches my particular issue as well as my personal skill level.
As I read through the articles I try to sift through and find code that would make sense and also do what I need it to do. In this search, the first result was the one I needed – the reasoning was that the properties of the Task item in Outlook were described. In combination with a previous article I had used (EWS Managed API) and (an MSDN article), I was able to create a script subset that would allow me to manipulate and add tasks to a mailbox in Exchange.
STEP THREE
My goal is to insert a list of tasks into Outlook. This means I will probably need a CSV file that contains the tasks to import in a format similar to:
Task,Date
“Go To Microsoft Store”,1/31/15
“Pick up dry cleaning”,1/24/15
Then I need to create a script that will import the CSV, run through each line of the CSV file and run the import task function. I’ll use code like this which gives you a choice between adding tasks to everyone or to random mailboxes. Because the code I am basing this section on was used for Exchange 2010 SP2, I need one adjustment that included changing the location of the “Microsoft.Exchange.WebServices.dll” or EWS DLL has been moved to the “\Program \Files\Microsoft\Exchange Server\V15\Bin\” with Exchange 2013. Also, the ExchangeVersion reference needs to be changed from “Exchange2010_SP2” to “Exchange2013_SP1” which can be referenced from here.
In the end, my code for importing a task looks like this:
# Import Tasks function Create-Tasks { $tasks = import-csv c:\scripts\tasks.csv $import = read-host "Do you want to import calendar events into all mailboxes or random mailboxes ['a' or 'r']" if ($import -eq "a") { foreach ($line in $events) { get-mailbox | new-task -subject $subject -date $date -impersonate } } else { $mbxcount = (get-mailbox).count $range = get-random -minimum 0 -maximum $mbxcount $counter = 0 while ($counter -lt $range) { $mailbox = (get-mailbox).alias get-mailbox $mailbox[$counter] | new-calendarevent -subject $subject -date $date -impersonate } } } # End Create Tasks Function
This then calls this function (a modified version of the holiday import function):
# Create Task Entries function new-task { [CmdletBinding(DefaultParametersetName='Identity')] param( [Parameter(Position=0, ParameterSetName='Identity')] $Identity, [Parameter(Position=1, Mandatory=$true)] $Subject, [Parameter(Position=2, Mandatory=$true)] $Date, [Parameter(Position=3)] [Switch]$Impersonate, [Parameter(Position=4)] # UPDATED to Exchange 2013 $ExchangeVersion = 'Exchange2013_SP1', [Parameter(Position=5, ParameterSetName='Pipeline', ValueFromPipelineByPropertyName=$true)] $PrimarySmtpAddress, [Parameter(Position=6)] [System.Management.Automation.PSCredential] $Credential, [Parameter(Position=7)] $EWSUrl ) begin { #Load the EWS Assembly - UPDATED to Exchange 2013 Add-Type -Path "C:\Program Files\Microsoft\Exchange\Web Services\1.2\Microsoft.Exchange.WebServices.dll" } process { #Is the identity coming from the pipeline? if($PsCmdlet.ParameterSetName -eq 'Pipeline') { $Identity = $PrimarySmtpAddress.ToString() } #Create the ExchangeService object $service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService -ArgumentList ([Microsoft.Exchange.WebServices.Data.ExchangeVersion]::$ExchangeVersion) #If Credential parameter used, set the credentials on the $service object if($Credential) { $service.Credentials = New-Object Microsoft.Exchange.WebServices.Data.WebCredentials -ArgumentList $Credential.UserName, $Credential.GetNetworkCredential().Password } #If EWSUrl parameter not used, locate the end-point using autoD if(!$EWSUrl) { $service.AutodiscoverUrl($Identity, {$true}) } else { $service.Url = New-Object System.Uri -ArgumentList $EWSUrl } #If Impersonation parameter used, impersonate the user if($Impersonate) { $ImpersonatedUserId = New-Object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId -ArgumentList ([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress),$Identity $service.ImpersonatedUserId = $ImpersonatedUserId } #Create and save the task $task = New-Object Microsoft.Exchange.WebServices.Data.Task -ArgumentList $service $task.Subject = $subject $task.StartDate = $start $task.DueDate = $end $task.Save } }
I wrote this in a function format so I could potentially use it in different scripts or different scenarios or just reuse the code to perform an entirely different function.
STEP FOUR
Once I’ve assembled code I think will work, I run through a series of tests to make sure that it will work as expected. I will not any errors that crop up and attempt to resolve the issue. My resolution process can include commenting out lines, removing loops, pre-populating variables instead of using a CSV file, putting in breaks (‘start-sleep 5’). Don’t forget to edit your code in the PowerShell ISE, this will help you see if you’re For or While loops are off or maybe you’re missing something important (quotes). For my first run through I received an error with the $subject field:
So, I have something wrong with either the source (the CSV file and its fields) or with the code (the $subject variable itself). While reviewing the code, I noticed that there was an incorrect variable in the ‘new-task’ on line 8 of the top section of code. Modified this to be $line.subject and $line.date
The next run of the code resulted in this:
Once I granted myself the rights I needed (impersonation), I was able to add the tasks to the various mailboxes.
Key thing was that this was done in a test lab because the changes or additions I made would potentially affect all mailboxes in an environment.
STEP FIVE
For my fifth and final step I usually write content to explain the intent of the script, a line by line explanation, and try to provide any background or other information I can to assist you readers in either using the script, making your own based off the code presented or even create code parts you can use for your own scripts (giving proper credit where due).
Other Notes
If I write a script and then publish, with content I’ve found on the Internet, I make sure I give people credit where it is due:
As an inside joke it states ‘Information Stolen From’ instead of Acknowledgements or something else.