Wednesday, December 22, 2010

Using Remote Powershell and EWS on Office365

A big leap forward on Office365 compared with the current BPOS offering is the ability to use remote powershell and a subset of the Exchange cmdlets that are available in Exchange 2010. This makes it pretty easy to migrate your current onpremise scripts that use make use of EMS and EWS into something that uses remote powershell and EWS. To demonstrate this I've converted on my old scripts the FreeBusy board to use Remote powershell, Office365 and the EWS Managed API 1.1.

I've put a download of the script here the code looks like

$UserName = "admin@domain.com"
$Password = "password1"
$secpassword = ConvertTo-SecureString $Password -AsPlainText -Force
$adminCredential = New-Object -TypeName System.Management.Automation.PSCredential -argumentlist $UserName,$secpassword

If(Get-PSSession | where-object {$_.ConfigurationName -eq "Microsoft.Exchange"}){
write-host "Session Exists"
}
else{
$rpRemotePowershell = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://ps.outlook.com/powershell -credential $adminCredential -Authentication Basic -AllowRedirection
$importresults = Import-PSSession $rpRemotePowershell
}


$dllpath = "C:\Program Files\Microsoft\Exchange\Web Services\1.1\Microsoft.Exchange.WebServices.dll"
[void][Reflection.Assembly]::LoadFile($dllpath)
$service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService([Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2010_SP1)

$windowsIdentity = [System.Security.Principal.WindowsIdentity]::GetCurrent()
$sidbind = "LDAP://<SID=" + $windowsIdentity.user.Value.ToString() + ">"
$aceuser = [ADSI]$sidbind
$service.Credentials = New-Object System.Net.NetworkCredential($username,$password)
$service.AutodiscoverUrl($UserName ,{$true})

$mbHash = @{ }

$tmValHash = @{ }
$tidx = 0
for($vsStartTime=[DateTime]::Parse([DateTime]::Now.ToString("yyyy-MM-dd 0:00"));$vsStartTime -lt [DateTime]::Parse([DateTime]::Now.ToString("yyyy-MM-dd 0:00")).AddDays(1);$vsStartTime = $vsStartTime.AddMinutes(30)){
$tmValHash.add($vsStartTime.ToString("HH:mm"),$tidx)
$tidx++
}

get-mailbox -ResultSize unlimited | foreach-object{
if ($mbHash.ContainsKey($_.WindowsEmailAddress.ToString()) -eq $false){
$mbHash.Add($_.WindowsEmailAddress.ToString(),$_.DisplayName)
}
}
$Attendeesbatch = [activator]::createinstance(([type]'System.Collections.Generic.List`1').makegenerictype([Microsoft.Exchange.WebServices.Data.AttendeeInfo]))

$StartTime = [DateTime]::Parse([DateTime]::Now.ToString("yyyy-MM-dd 0:00"))
$EndTime = $StartTime.AddDays(1)


$displayStartTime = [DateTime]::Parse([DateTime]::Now.ToString("yyyy-MM-dd 08:30"))
$displayEndTime = [DateTime]::Parse([DateTime]::Now.ToString("yyyy-MM-dd 17:30"))

$drDuration = new-object Microsoft.Exchange.WebServices.Data.TimeWindow($StartTime,$EndTime)
$AvailabilityOptions = new-object Microsoft.Exchange.WebServices.Data.AvailabilityOptions
$AvailabilityOptions.RequestedFreeBusyView = [Microsoft.Exchange.WebServices.Data.FreeBusyViewType]::DetailedMerged

$batchsize = 100
$bcount = 0
$bresult = @()
if ($mbHash.Count -ne 0){
$mbHash.GetEnumerator() | Sort Value | foreach-object {
if ($bcount -ne $batchsize){
$Attendee1 = new-object Microsoft.Exchange.WebServices.Data.AttendeeInfo($_.Key)
$Attendeesbatch.add($Attendee1)
$bcount++
}
else{
$availresponse = $service.GetUserAvailability($Attendeesbatch,$drDuration,[Microsoft.Exchange.WebServices.Data.AvailabilityData]::FreeBusy,$AvailabilityOptions)
foreach($avail in $availresponse.AttendeesAvailability.OverallResult){$bresult += $avail}
$Attendeesbatch = [activator]::createinstance(([type]'System.Collections.Generic.List`1').makegenerictype([Microsoft.Exchange.WebServices.Data.AttendeeInfo]))
$bcount = 0
$Attendee1 = new-object Microsoft.Exchange.WebServices.Data.AttendeeInfo($_.Key)
$Attendeesbatch.add($Attendee1)
$bcount++
}
}
}
$availresponse = $service.GetUserAvailability($Attendeesbatch,$drDuration,[Microsoft.Exchange.WebServices.Data.AvailabilityData]::FreeBusy,$AvailabilityOptions)
$usrIdx = 0
$frow = $true
foreach($res in $availresponse.AttendeesAvailability){
if ($frow -eq $true){
$fbBoard = $fbBoard + "<table><tr bgcolor=`"#95aedc`">" +"`r`n"
$fbBoard = $fbBoard + "<td align=`"center`" style=`"width=200;`" ><b>User</b></td>" +"`r`n"
for($stime = $displayStartTime;$stime -lt $displayEndTime;$stime = $stime.AddMinutes(30)){
$fbBoard = $fbBoard + "<td align=`"center`" style=`"width=50;`" ><b>" + $stime.ToString("HH:mm") + "</b></td>" +"`r`n"
}
$fbBoard = $fbBoard + "</tr>" + "`r`n"
$frow = $false
}
for($stime = $displayStartTime;$stime -lt $displayEndTime;$stime = $stime.AddMinutes(30)){
if ($stime -eq $displayStartTime){
$fbBoard = $fbBoard + "<td bgcolor=`"#CFECEC`"><b>" + $mbHash[$Attendeesbatch[$usrIdx].SmtpAddress] + "</b></td>" + "`r`n"
}
$title = "title="
if ($res.MergedFreeBusyStatus[$tmValHash[$stime.ToString("HH:mm")]] -ne $null){
$gdet = $false
$FbValu = $res.MergedFreeBusyStatus[$tmValHash[$stime.ToString("HH:mm")]]
switch($FbValu.ToString()){
"Free" {$bgColour = "bgcolor=`"#41A317`""}
"Tentative" {$bgColour = "bgcolor=`"#52F3FF`""
$gdet = $true
}
"Busy" {$bgColour = "bgcolor=`"#153E7E`""
$gdet = $true
}
"OOF" {$bgColour = "bgcolor=`"#4E387E`""
$gdet = $true
}
"NoData" {$bgColour = "bgcolor=`"#98AFC7`""}
"N/A" {$bgColour = "bgcolor=`"#98AFC7`""}
}
if ($gdet -eq $true){
if ($res.CalendarEvents.Count -ne 0){
for($ci=0;$ci -lt $res.CalendarEvents.Count;$ci++){
if ($res.CalendarEvents[$ci].StartTime -ge $stime -band $stime -le $res.CalendarEvents[$ci].EndTime){
if($res.CalendarEvents[$ci].Details.IsPrivate -eq $False){
$subject = ""
$location = ""
if ($res.CalendarEvents[$ci].Details.Subject -ne $null){
$subject = $res.CalendarEvents[$ci].Details.Subject.ToString()
}
if ($res.CalendarEvents[$ci].Details.Location -ne $null){
$location = $res.CalendarEvents[$ci].Details.Location.ToString()
}
$title = $title + "`"" + $subject + " " + $location + "`" "
}
}
}
}
}

}
else{
$bgColour = "bgcolor=`"#98AFC7`""
}
if($title -ne "title="){
$fbBoard = $fbBoard + "<td " + $bgColour + " " + $title + "></td>" + "`r`n"
}
else{
$fbBoard = $fbBoard + "<td " + $bgColour + "></td>" + "`r`n"
}

}
$fbBoard = $fbBoard + "</tr>" + "`r`n"
$usrIdx++
}
$fbBoard = $fbBoard + "</table>" + " "
$fbBoard | out-file "c:\fbboard.htm"

Wednesday, December 01, 2010

Simple Exchange Powershell Client V2

This has taken me a little longer then expected to update but I've finally created a version 2 of my simple powershell client script i posted here.

Firstly if you missed it the new version the EWS Managed API 1.1 has been released which allows you to access all the new 2010 SP1 functionality like archive mailboxes, dumpster v2 etc you can download this from here the new script requires this library.

The new features I've added to the script is firstly there is a Entry Point box that allows you to select what entry point you want.



The Non IPM Root is usefull if you want to look at the dumpster folders or other things in the Non_IPM_Root, Archive root takes you into the Archive mailbox if its exists for that user.

Another new edition is the ItemType box which allows you the select between being able to view the Normal Mailbox Items, FAI (Folder Associated Items) or Deleted Items (not really applicable for Dumpster v2).


Lastly because the new script is built for use with Windows 7.0 and Powershell V2 the right click menu for the datagird will now work okay so I've added the ability to once you select the Items in the datagrid you can rightclick and then Delete, Copy or Move the selected Items to another folder (the deletes are soft deletes).

I've put a download of the new script here