Reading ALL custom properties on Exchange Server with EWS - exchange-server

I would like to read all "Custom properties" from EWS-Items. I do have the names of the properties (e.g. "duration" oder "distance") but I did not create them (my clients did).
I guess I will have to use "ExtendedProperties" of the "Item" class. But when I use Item.Bind() with a Property-set I need to know a GUID which I don't have! Microsoft says (http://msdn.microsoft.com/en-us/library/exchange/dd633697%28v=exchg.80%29.aspx):
"Create a GUID identifier from the GUID that was used when the extended property was created."
I don't have these GUIDs because I did not create the properties.
I guess the only chance is to use Item.Bind() without a specific property set. Would that slow down the process (I need to call this for every item in the mailbox)?
I basically would like to iterate with a clause like this:
if (extendedProperty.PropertyDefinition.Name == "duration")
Any ideas how to do this?
Thanks
Martin

try to recover it by name using the PropertyDefinition and property type (MapiPropertyType):
//Search for "duration" property
Microsoft.Exchange.WebServices.Data.ExtendedPropertyDefinition extendedPropertyDefinition =
new Microsoft.Exchange.WebServices.Data.ExtendedPropertyDefinition
(DefaultExtendedPropertySet.Common, "duration", MapiPropertyType.String);
EmailMessage msgMod = EmailMessage.Bind(service, msgComplete.Id,
new PropertySet(extendedPropertyDefinition));
ExtendedPropertyCollection colProp = msgMod.ExtendedProperties;
foreach (ExtendedProperty prop in colProp)
{
//Iterate properties
}

Related

How to transfer Activities (mails, notes, etc) from one contact to another in Dynamics 365

Due to some bad practices from one of our internal users. We need to transfer all activities (mails, notes, etc) from one contact to another contact. I was trying to achieve this via UI and I could not find a way to do this.
Is this possible? I'm looking for any way to achieve this, wether is CRMTool, SSIS, UI or any other way. Only admins will do this so we do not need anything fancy as it will be done maybe 4 times a year to clean up some data.
Thanks a lot :)
Tried using UI but no success.
I can think of two ways to do these updates.
The first method is selecting a view on an activity where the owner is listed (i.e. All Phone Calls) and exporting to Excel. This downloads a XLSX with some hidden columns at the start where IDs for the records are kept. You then update the owner column with the new owner (take care of copying the exact fullname), and then importing the Excel spreadsheet again. You would need to repeat this export/import steps for each activity type (phone calls, email, etc.). So this might be impractical if you have a large volume of date, because of the need to repeat and because there are max numbers of records that you can export.
The other way to do this is using some .NET code. Of course, to do this you will need to use Visual Studio 2019.
If that's the case, this will do the trick:
using System;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using Microsoft.Xrm.Tooling.Connector;
namespace ChangeActivitiesOwner
{
class Program
{
static void Main(string[] args)
{
string connectionString = "AuthType=Office365;Url=<TODO:URL>;Username=<TODO:User>;Password=<TODO:Pass>;";
string oldUserFullname = ""; // TODO: place here fullname for the user you want to overwrite
string newUserFullname = ""; // TODO: place here fullname for the user you want to overwrite with
CrmServiceClient client = new CrmServiceClient(connectionString);
IOrganizationService service = client.OrganizationWebProxyClient != null ? client.OrganizationWebProxyClient : (IOrganizationService)client.OrganizationServiceProxy;
QueryByAttribute qbyaOldUser = new QueryByAttribute("systemuser");
qbyaOldUser.AddAttributeValue("fullname", oldUserFullname);
Guid olduserid = (Guid)service.RetrieveMultiple(qbyaOldUser)[0].Attributes["systemuserid"];
QueryByAttribute qbyaNewUser = new QueryByAttribute("systemuser");
qbyaNewUser.AddAttributeValue("fullname", newUserFullname);
Guid newuserid = (Guid)service.RetrieveMultiple(qbyaNewUser)[0].Attributes["systemuserid"];
foreach (string activity in new string[]{ "task", "phonecall", "email", "fax", "appointment", "letter", "campaignresponse", "campaignactivity" }) // TODO: Add other activities as needed!!!
{
QueryExpression query = new QueryExpression(activity)
{
ColumnSet = new ColumnSet("activityid", "ownerid")
};
query.Criteria.AddCondition(new ConditionExpression("ownerid", ConditionOperator.Equal, olduserid));
foreach (Entity e in service.RetrieveMultiple(query).Entities)
{
e.Attributes["ownerid"] = new EntityReference("systemuser", newuserid);
service.Update(e);
}
}
}
}
}
Please complete the lines marked with "TODO" with your info.
You will need to add the packages Microsoft.CrmSdk.CoreAssemblies, Microsoft.CrmSdk.Deployment, Microsoft.CrmSdk.Workflow, Microsoft.CrmSdk.XrmTooling.CoreAssembly, Microsoft.IdentityModel.Clients.ActiveDIrectory and Newtonsoft.Json to your solution, and use .NET Framework 4.6.2.
Hope this helps.

Uniquely identify Mailitem

I need to store a model for every used MailItem. For this I've written following Method
private readonly static Dictionary<string, PermitCustomPaneViewmodel> ViewmodelLookup = new Dictionary<string, PermitCustomPaneViewmodel>();
public static PermitCustomPaneViewmodel CreateOrGet(MailItem c)
{
if (c.EntryID == null)
c.Save();
if (!ViewmodelLookup.ContainsKey(c.EntryID))
{
var vm = new PermitCustomPaneViewmodel(c);
c.Unload += () => ViewmodelLookup.Remove(c.EntryID);
ViewmodelLookup.Add(c.EntryID, vm);
}
return ViewmodelLookup[c.EntryID];
}
When the Model already exists, I look it up and return it. If it was not created, I create it and remove the entry after the MailItem will be unloaded.
However I have observed that the MailItem object will not be vailid all the time untill unload is called. In order to reliable identify the MailItem I used the EntryID. The problem now is this only works if the Item is saved.
So currently I save the Item if no EntryID was found. But this automaticly saves the item under draft.
Is there a way to distingush MailItem's that is not saved in a way so it can be used in a Dictionary<,>.
New created items don't have the EntryID property set. Get the ID assigned by the store provider you must save it. If you need to identify a new MailItem object you may consider adding a user property to the item by using the UserProperties.Add method which reates a new user property in the UserProperties collection. For example:
Sub AddUserProperty()
Dim myItem As Outlook.ContactItem
Dim myUserProperty As Outlook.UserProperty
Set myItem = Application.CreateItem(olContactItem)
Set myUserProperty = myItem.UserProperties _
.Add("LastDateSpokenWith", olDateTime)
myItem.Display
End Sub
Be aware, the Entry ID changes when an item is moved into another store, for example, from your Inbox to a Microsoft Exchange Server public folder, or from one Personal Folders (.pst) file to another .pst file. Solutions should not depend on the EntryID property to be unique unless items will not be moved. Basically it works fine as long as the message is staying in its parent folder or it may be changed if the Outlook item is moved to a different folder (depends on the store provider).
You may also consider using the message id from the message MIME header (PR_INTERNET_MESSAGE_ID and PR_TRANSPORT_MESSAGE_HEADERS). But they are not set on newly created items. These properties are available on the message received from an SMTP server or through the SMTP connector.

CRM do not support direct update of Entity Reference properties, Use Navigation properties instead

I am using Ms Dynamic Web Api with Simple OData. I need to add new record for link entities.
I am using the below code snip and refer the documentation on
https://github.com/object/Simple.OData.Client/wiki/Adding-entries-with-links
var newContactData = await _oDataClient
.For<Contacts>()
.Set(new
{
firstname = contactData.ContatDetails.firstname,
lastname = contactData.ContatDetails.lastname,
emailaddress1 = contactData.ContatDetails.emailaddress1
})
.InsertEntryAsync(true);
var newContactLink = await _oDataClient.For<New_project_contactses>()
.Set(new
{
_new_contact_project_name_new_value = contactData.ContatDetailsLink._new_contact_project_name_new_value,
new_project_contactsid = new Guid("0eb46b24-21a2-e611-80eb-c4346bc5b2d4"),
new_contact_type = contactData.ContatDetailsLink.new_contact_type,
})
.InsertEntryAsync(resultRequired: true);
i am getting exception
CRM do not support direct update of Entity Reference properties, Use
Navigation properties insteadS
Well, it is possible, but you need to use the special "#odata.bind" syntax to update your single-navigation properties.
For example, to update an account so that it references an existing primarycontactid, you can use a PATCH operation to the /api/data/v8.2/accounts endpoint with the following body:
{
"name":"Sample Account",
"primarycontactid#odata.bind":"/contacts(00000000-0000-0000-0000-000000000001)"
}
See https://msdn.microsoft.com/en-us/library/gg328090.aspx#Anchor_3 (it is discussed in terms of creating an entity, but it works for updating as well).
I figure out the issue With Dynamc CRM you cannot directly update reference entities Field. You can identify reference entity properties start with "_".

EWS Managed API 2.2 Read\Write extended properties of attachments

Currently I'm working on migration of one big project from MAPI CDO to EWS (Managed API 2.2) to support Ex2016. All things were migrated well except one: I can't find the way how to read\write Attachments Extended Properties. Does anybody know how to do that or may be some workaround? This is very critical for me and I would be very appreciate for any help.
---Update:
Also tried to use native EWS to get property of attachment but without success too:
var ret = esb.GetAttachment(new GetAttachmentType()
{
AttachmentIds = new []{new AttachmentIdType()
{
Id = "AAMkADVhNjUzMzMyLTRiMDYtNDc4OS1hYjJjLWI1ZDA4ZWFhYTJkZQBGAAAAAADqFaOFYZSeQI5UObwGbjIJBwAOgaos6ORVS5+o5bQovn/kAAAAeN2cAAAOgaos6ORVS5+o5bQovn/kAAAeCoIuAAABEgAQAJPAuRg2gipPmEKfgW26mFU=",
}},
AttachmentShape = new AttachmentResponseShapeType()
{
BodyType = BodyTypeResponseType.Best,
BodyTypeSpecified = true,
IncludeMimeContent = false,
IncludeMimeContentSpecified = true,
AdditionalProperties = new []
{
new PathToExtendedFieldType() { PropertyType = MapiPropertyTypeType.Integer, PropertyTag = "0x3705"},
new PathToExtendedFieldType() { PropertyType = MapiPropertyTypeType.Integer, PropertyTag = "0x0E21"},
}
}
});
The response doesn't contain any of requested properties.
--- Update 2:
In project we use next properties of attachments:
PR_RECORD_KEY, PR_DISPLAY_NAME, PR_RENDERING_POSITION
PR_ATTACH_ENCODING, PR_ATTACH_NUM, PR_ATTACH_METHOD, PR_ATTACH_LONG_FILENAME, PR_ATTACHMENT_HIDDEN, PR_ATTACH_CONTENT_ID, PR_ATTACH_FLAGS, PR_ATTACH_MIME_TAG, PR_ATTACH_CONTENT_LOCATION, PR_ATTACH_SIZE
Also we create a couple of Custom Extended Properties with custom Property Set and tag some attachments with that props.
Some of Properties can be found in object model of EWS/ManagedApi like PR_ATTACH_SIZE but the problem with others and with custom props.
So we need to read/write standard attachment properties as well as custom.
In project we mark attachment itself, not embedded Item.
You can't access extended properties on Attachments or the Recipients collection in EWS outside of those properties that are made accessible as strongly typed properties by the API. The only place you can use Extended properties are at the message level.
That said can you explain more as to how your using Extended properties eg are these extended properties on embeded items. If that is the case then you could access those extended properties via the Item Attachment.
Looking at your code 0x3705 is the PR_ATTACH_METHOD property on an attachment there is no equivalent to this in EWS, rather EWS will return a different Attachment Class based on the Attachment type. Eg ItemAttachment, FileAttachment or ReferanceAttachment (eg for OneDrive Attachments). 0x0E21 is that Attachment number EWS is going to return the Attachments in the order of that number in GetItem request so you can compute that yourself. But the property is useless in EWS because to get an Attachment you need the EWSId unlike MAPI.
Cheers
Glen

How to set ContentTypeID in CreateTaskWithContentType activity using VS 2013

When I create a task with activity "CreateTaskWithContentType", I can't bind a custom ContentType with the list "Tasks".
I created a new content type and select the "Task" as parent, then added this content type to my task list.
Then I get my content type id and set the "ContentTypeID" property of "CreateTaskWithContentType" activity in the vs 2013 by this ID, and after that click on taskid property and click "bind to new member" and then "create field" inorder ro create taskid property. I also created a taskProperties for my activity.
I determine a method for invoking this activity :
createTaskWithContentType1_TaskId1 = Guid.NewGuid();
createTaskWithContentType1.ContentTypeId = "0x010800FEAA30385A36B042BF804D643DBC9EEF";
createTaskWithContentType1_TaskProperties1.Title = "Approve document";
createTaskWithContentType1_TaskProperties1.AssignedTo = #"sps2013\Modrek";
createTaskWithContentType1_TaskProperties1.DueDate = DateTime.Now.AddDays(1.0);
But it doesn't work and after I started workflow the workflow accrued an error.
Do you have any idea how I can do this ?
thanks in advance.
Here is a real useful link for creating task with content type.
Click Here

Resources