Friday, April 24, 2015

Clutter Threshold and Probability Outlook form

Clutter is one of the new features in Exchange Online in Office365, while there is some really good info on how to use clutter the detailed info on how it works behind the scenes is a little harder to come by. There was a really good blog post recently http://blogs.technet.com/b/inside_microsoft_research/archive/2015/04/09/probabilistic-programming-goes-large-scale-from-reducing-email-clutter-to-any-machine-learning-task.aspx from one the Microsoft Research team that gives some good information on how it actually works using Infer.NET and Probabilistic Programming.

With new features in Exchange come new MAPI properties and clutter in no different so we have these two new properties that get set on items



Back in 2004 when SCL (SPAM confidence level) was introduced in Exchange 2003 Paul Bowden gave us this CFG trick to expose the SCL value in Outlook http://blogs.technet.com/b/exchange/archive/2004/05/26/142607.aspx . All these years later the same trick can be used to expose these Clutter properties in Outlook so when you do get a message in Outlook that you think should have been clutter you can see how close it was to being classified. eg in action


The details on the CFG file is we define 2 properties to show


[Properties]
Property01=ClutterProbability
Property02=ClutterThreshold

These properties are PT_Double so the Mapi property type is x0005 which is why the type=5, and both properties are Named Properties

[Property.ClutterProbability]
Type=5
NmidPropSet = {23239608-685D-4732-9C55-4C95CB4E8E33}
NmidString = ClutterProbability
DisplayName = Clutter Probability
[Property.ClutterThreshold]
Type=5
NmidPropSet = {23239608-685D-4732-9C55-4C95CB4E8E33}
NmidString = ClutterThreshold
DisplayName = Clutter Threshold

To use this CFG file you need to copy it into the same directory where the

IPML.ico
IPMS.ico

files are located on Outlook 2013 that will be in

C:\Program Files\Microsoft Office 15\root\office15\FORMS\1033

(or Program Files (x86) if you using the 32 bit version)

On 2010 it will be Microsoft Office 14

If you can't find the files just do a search of the hard disk for them (Sorry I don't have the rights to redistribute them).

Once you have the form in that directory you go through the same install procedure as http://blogs.technet.com/b/exchange/archive/2004/05/26/142607.aspx just replace SCL with Clutter Extension Form. SlipStick.com has also created a video on doing a CFG install https://www.youtube.com/watch?v=FfW6JknE_IQ which is quite good.

I've put a download of the file here the full file looks like

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
[Description]
MessageClass=IPM.Note
CLSID={00020D31-0000-0000-C000-000000000046}
DisplayName=Clutter Extension Form
Category=Standard
Subcategory=Form
Comment=This form is used to expose the Clutter settings
LargeIcon=IPML.ico
SmallIcon=IPMS.ico
Version=1.0
VersionMajor=1
VersionMinor=0
Locale=enu
Hidden=1
Owner=Clutter
ComposeInFolder=1

[Platforms]
Platform2=NTx86
Platform9=Win95

[Platform.NTx86]
CPU=ix86
OSVersion=WinNT3.5

[Platform.Win95]
CPU=ix86
OSVersion=Win95

[Properties]
Property01=ClutterProbability
Property02=ClutterThreshold

[Property.ClutterProbability]
Type=5
NmidPropSet = {23239608-685D-4732-9C55-4C95CB4E8E33}
NmidString = ClutterProbability
DisplayName = Clutter Probability

[Property.ClutterThreshold]
Type=5
NmidPropSet = {23239608-685D-4732-9C55-4C95CB4E8E33}
NmidString = ClutterThreshold
DisplayName = Clutter Threshold

[Verbs]
Verb1=1

[Verb.1]
DisplayName=&Open
Code=0
Flags=0
Attribs=2

[Extensions]
Extensions1=1

[Extension.1]
Type=30
NmidPropset={00020D0C-0000-0000-C000-000000000046}
NmidInteger=1
Value=1000000000000000

Monday, April 06, 2015

Configure the default calendar view in OWA in Exchange 2013 and Exchange Online using EWS and Powershell

If you are after a higher level of control over the default setting in OWA, EWS offers you the ability to configure many of the default setting by modifying the FAI (folder associated Item) configuration item that controls that setting. One example of a setting that you can modify is the default view of the calendar in OWA  eg  the following setting


When are user makes a change to this setting in OWA, the setting is stored in an FAI item with an Item Class of OWA.ViewStateConfiguration in a roaming dictionary property called CalendarViewTypeDesktop.

The values for each of the setting are

1 = Day
2 = Week
3 = Work week
4 = Month

The following script first checks to see if the OWA.ViewStateConfiguration config item exists (on a new mailbox if the user has never logged into OWA it probably wont exist).

To use this script you run it with the name of the Mailbox you want to run it against and the value for the enum you want to use eg to set the default as Work week use

./SetOWACalendarView.ps1 mailbox@domain.com 3

I've put a download of this script here

The code itself looks like

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
## Get the Mailbox to Access from the 1st commandline argument
$MailboxName = $args[0]

$CalendarSetting = $args[1]

## Load Managed API dll  
###CHECK FOR EWS MANAGED API, IF PRESENT IMPORT THE HIGHEST VERSION EWS DLL, ELSE EXIT
$EWSDLL = (($(Get-ItemProperty -ErrorAction SilentlyContinue -Path Registry::$(Get-ChildItem -ErrorAction SilentlyContinue -Path 'Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Exchange\Web Services'|Sort-Object Name -Descending| Select-Object -First 1 -ExpandProperty Name)).'Install Directory') + "Microsoft.Exchange.WebServices.dll")
if (Test-Path $EWSDLL)
    {
    Import-Module $EWSDLL
    }
else
    {
    "$(get-date -format yyyyMMddHHmmss):"
    "This script requires the EWS Managed API 1.2 or later."
    "Please download and install the current version of the EWS Managed API from"
    "http://go.microsoft.com/fwlink/?LinkId=255472"
    ""
    "Exiting Script."
    exit
    } 
  
## Set Exchange Version  
$ExchangeVersion = [Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2013  
  
## Create Exchange Service Object  
$service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService($ExchangeVersion)  
  
## Set Credentials to use two options are availible Option1 to use explict credentials or Option 2 use the Default (logged On) credentials  
  
#Credentials Option 1 using UPN for the windows Account  
$psCred = Get-Credential  
$creds = New-Object System.Net.NetworkCredential($psCred.UserName.ToString(),$psCred.GetNetworkCredential().password.ToString())  
$service.Credentials = $creds      
#$service.TraceEnabled = $true
#Credentials Option 2  
#service.UseDefaultCredentials = $true  
  
## Choose to ignore any SSL Warning issues caused by Self Signed Certificates  
  
## Code From http://poshcode.org/624
## Create a compilation environment
$Provider=New-Object Microsoft.CSharp.CSharpCodeProvider
$Compiler=$Provider.CreateCompiler()
$Params=New-Object System.CodeDom.Compiler.CompilerParameters
$Params.GenerateExecutable=$False
$Params.GenerateInMemory=$True
$Params.IncludeDebugInformation=$False
$Params.ReferencedAssemblies.Add("System.DLL") | Out-Null

$TASource=@'
  namespace Local.ToolkitExtensions.Net.CertificatePolicy{
    public class TrustAll : System.Net.ICertificatePolicy {
      public TrustAll() { 
      }
      public bool CheckValidationResult(System.Net.ServicePoint sp,
        System.Security.Cryptography.X509Certificates.X509Certificate cert, 
        System.Net.WebRequest req, int problem) {
        return true;
      }
    }
  }
'@ 
$TAResults=$Provider.CompileAssemblyFromSource($Params,$TASource)
$TAAssembly=$TAResults.CompiledAssembly

## We now create an instance of the TrustAll and attach it to the ServicePointManager
$TrustAll=$TAAssembly.CreateInstance("Local.ToolkitExtensions.Net.CertificatePolicy.TrustAll")
[System.Net.ServicePointManager]::CertificatePolicy=$TrustAll

## end code from http://poshcode.org/624
  
## Set the URL of the CAS (Client Access Server) to use two options are availbe to use Autodiscover to find the CAS URL or Hardcode the CAS to use  
  
#CAS URL Option 1 Autodiscover  
$service.AutodiscoverUrl($MailboxName,{$true})  
"Using CAS Server : " + $Service.url   
   
#CAS URL Option 2 Hardcoded  
  
#$uri=[system.URI] "https://casservername/ews/exchange.asmx"  
#$service.Url = $uri    
  
## Optional section for Exchange Impersonation  
  
#$service.ImpersonatedUserId = new-object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress, $MailboxName) 

#Check for existing Item  
$folderid= new-object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Root,$MailboxName)     
$SfSearchFilter = new-object Microsoft.Exchange.WebServices.Data.SearchFilter+IsEqualTo([Microsoft.Exchange.WebServices.Data.ItemSchema]::ItemClass,"IPM.Configuration.OWA.ViewStateConfiguration")  
$ivItemView =  New-Object Microsoft.Exchange.WebServices.Data.ItemView(1)  
$ivItemView.Traversal =  [Microsoft.Exchange.WebServices.Data.ItemTraversal]::Associated  
$fiResults = $service.FindItems($folderid,$SfSearchFilter,$ivItemView)  
if($fiResults.Items.Count -eq 0){  
    Write-Host ("No Config Item found, create new Item")  
    $UMConfig = New-Object Microsoft.Exchange.WebServices.Data.UserConfiguration -ArgumentList $service  
    $UMConfig.Save("OWA.ViewStateConfiguration",$folderid)  
}  
else{  
    Write-Host ("Existing Config Item Found");  
}  
#Specify the Root folder where the FAI Item is  
$UsrConfig = [Microsoft.Exchange.WebServices.Data.UserConfiguration]::Bind($service, "OWA.ViewStateConfiguration", $folderid, [Microsoft.Exchange.WebServices.Data.UserConfigurationProperties]::All)  
if($UsrConfig.Dictionary.ContainsKey("CalendarViewTypeDesktop")){  
    $UsrConfig.Dictionary["CalendarViewTypeDesktop"] = $CalendarSetting  
}  
else{  
    $UsrConfig.Dictionary.Add("CalendarViewTypeDesktop",$CalendarSetting)  
}
$UsrConfig.Update()  
"Mailbox Updated"

Downloading a shared file from Onedrive for business using Powershell

I thought I'd quickly share this script I came up with to download a file that was shared using One Drive for Business (which is SharePoint under the covers) with Powershell. The following script takes a OneDrive for business URL which would look like

https://mydom-my.sharepoint.com/personal/gscales_domain_com/Documents/Email%20attachments/filename.txt

This script is pretty simple it uses the SharePoint CSOM (Client side object Model) which it loads in the first line. It uses the URI object to separate the host and relative URL which the CSOM requires and also the SharePointOnlineCredentials object to handle the Office365 SharePoint online authentication.

The following script is a function that take the OneDrive URL, Credentials for Office365 and path you want to download the file to and downloads the file. eg to run the script you would use something like

./spdownload.ps1 'https://mydom-my.sharepoint.com/personal/gscales_domain_com/Documents/Email%20attachments/filename.txt'

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
$SharePointClientDll = (($(Get-ItemProperty -ErrorAction SilentlyContinue -Path Registry::$(Get-ChildItem -ErrorAction SilentlyContinue -Path 'Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\SharePoint Client Components\'|Sort-Object Name -Descending| Select-Object -First 1 -ExpandProperty Name)).'Location') + "ISAPI\Microsoft.SharePoint.Client.dll")
Add-Type -Path $SharePointClientDll 


function DownloadFileFromOneDrive{
 param (
         $DownloadURL = "$( throw 'DownloadURL is a mandatory Parameter' )",
   $PSCredentials = "$( throw 'credentials is a mandatory Parameter' )",
   $DownloadPath  = "$( throw 'DownloadPath is a mandatory Parameter' )"
    )
 process{
  $DownloadURI = New-Object System.Uri($DownloadURL);
  $SharepointHost = "https://" + $DownloadURI.Host
  $soCredentials =  New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($PSCredentials.UserName.ToString(),$PSCredentials.password) 
  $clientContext = New-Object Microsoft.SharePoint.Client.ClientContext($SharepointHost)
  $clientContext.Credentials = $soCredentials;
  $destFile = $DownloadPath + [System.IO.Path]::GetFileName($DownloadURI.LocalPath)
  $fileInfo = [Microsoft.SharePoint.Client.File]::OpenBinaryDirect($clientContext, $DownloadURI.LocalPath);
  $fstream = New-Object System.IO.FileStream($destFile, [System.IO.FileMode]::Create);
  $fileInfo.Stream.CopyTo($fstream)
  $fstream.Flush()
  $fstream.Close()
  Write-Host ("File downloaded to " + ($destFile))
 }
}

$cred = Get-Credential
#exmample use
DownloadFileFromOneDrive -DownloadURL $args[0] -PSCredentials $cred -DownloadPath 'c:\Temp\'