2

I'm trying to get all items of a shared calendar (I've followed EWS - Access All Shared Calendars from Glen Scales), but it only lists Folders under "Shared Calendars" ("Calendriers partagés" as it's in French, I can't find if "Common Views" should is localized either, I don't think so).

A coworker created a calendar with a few appointments, shared it with me and gave me maximum permissions (ownership) for testing.

How do you access the Items/Appointments within this shared calendar (in C#/PowerShell)?

More info: It's recommended to use Folder.Bind, but the call generates an exception:

        ExchangeService service = new ExchangeService(ExchangeVersion.ExchangeVersion);
        service.Credentials = new WebCredentials("login", "****");
        service.Url = new Uri("https://.../ews/exchange.asmx");

        try {
        FolderId cfolderid = new FolderId(WellKnownFolderName.Calendar, "coworker@domain.com");
        Folder TargetFolder = Folder.Bind(service, cfolderid);     

        Console.WriteLine("target folder = " + TargetFolder);
        } catch (Exception ex){
            Console.WriteLine(ex.ToString());
        }  

Microsoft.Exchange.WebServices.Data.ServiceResponseException: Le dossier spécifié est introuvable dans la banque  d'informations.                                          
  à Microsoft.Exchange.WebServices.Data.ServiceResponse.InternalThrowIfNecessary()                                                                                       
  à Microsoft.Exchange.WebServices.Data.MultiResponseServiceRequest`1.Execute()                                                                                          
  à Microsoft.Exchange.WebServices.Data.ExchangeService.BindToFolder(FolderId folderId, PropertySet propertySet)                                                         
  à Microsoft.Exchange.WebServices.Data.ExchangeService.BindToFolder[TFolder](FolderId folderId, PropertySet propertySet)                                                
  à Microsoft.Exchange.WebServices.Data.Folder.Bind(ExchangeService service, FolderId id)                                                                                
 à ConsoleApplication.Program.Main(String[] args)

Addendum: I restarted with Glen's code, traces shown as comments. WlinkAddressBookEIDA is null.

 static Dictionary<string, Folder> GetSharedCalendarFoldersA(ExchangeService service, String mbMailboxname)
{
    Dictionary<String, Folder> rtList = new System.Collections.Generic.Dictionary<string, Folder>();

    FolderId rfRootFolderid = new FolderId(WellKnownFolderName.Root, mbMailboxname);
    FolderView fvFolderView = new FolderView(1000);
    SearchFilter sfSearchFilter = new SearchFilter.IsEqualTo(FolderSchema.DisplayName, "Common Views");
    FindFoldersResults ffoldres = service.FindFolders(rfRootFolderid, sfSearchFilter, fvFolderView);
    if (ffoldres.Folders.Count == 1)
    {

        PropertySet psPropset = new PropertySet(BasePropertySet.FirstClassProperties);
        ExtendedPropertyDefinition PidTagWlinkAddressBookEID = new ExtendedPropertyDefinition(0x6854, MapiPropertyType.Binary);
        ExtendedPropertyDefinition PidTagWlinkFolderType = new ExtendedPropertyDefinition(0x684F, MapiPropertyType.Binary);
        ExtendedPropertyDefinition PidTagWlinkGroupName = new ExtendedPropertyDefinition(0x6851, MapiPropertyType.String);

        psPropset.Add(PidTagWlinkAddressBookEID);
        psPropset.Add(PidTagWlinkFolderType);
        ItemView iv = new ItemView(1000);
        iv.PropertySet = psPropset;
        iv.Traversal = ItemTraversal.Associated;

        SearchFilter cntSearch = new SearchFilter.IsEqualTo(PidTagWlinkGroupName, "Calendriers partagés"); // localized
        FindItemsResults<Item> fiResults = ffoldres.Folders[0].FindItems(cntSearch, iv);
        Console.WriteLine("fiResults TotalCount = " + fiResults.TotalCount) ; // OK -> 1
        foreach (Item itItem in fiResults.Items)
        {
            Console.WriteLine("itItem Subject = " + itItem.Subject);  // OK, my coworker shared calendar
            Console.WriteLine("itItem Id = " + itItem.Id); // Id but not the one expected!

                object WlinkAddressBookEIDA = null;
                itItem.TryGetProperty(PidTagWlinkAddressBookEID, out WlinkAddressBookEIDA);
                Console.WriteLine("WlinkAddressBookEIDA = " + WlinkAddressBookEIDA + " is null ? " + (WlinkAddressBookEIDA == null)); // KO -> WlinkAddressBookEIDA =  is null ? True

            try{[...]
Community
  • 1
  • 1
jgran
  • 1,111
  • 2
  • 11
  • 21

1 Answers1

4

I can't find if "Common Views" should is localized either, I don't think so)

It shouldn't need to be you can use the EWSEditor to browse the Non_IPM Subfolders which will tell you either way

A coworker created a calendar with a few appointments, shared it with me and gave me maximum permissions (ownership) for testing. How do you access the Items/Appointments within this shared calendar (in C#/PowerShell)?

If you know the EmailAddress of the person who has shared their calendar then just use the FolderId overload for Mailbox and bind to it directly eg

        FolderId cfolderid = new FolderId(WellKnownFolderName.Calendar, "Mailbox@domain.com");
        Folder TargetFolder = Folder.Bind(service, cfolderid);
Glen Scales
  • 20,495
  • 1
  • 20
  • 23
  • Thanks Glen for everything related to EWS and http://gsexdev.blogspot.fr/ and taking time to respond. I tried to adapt https://github.com/gscales/Powershell-Scripts/blob/master/ScriptArchive/AccessSharedContacts.zip. I always end up with an exception as from Folder.Bind Microsoft.Exchange.WebServices.Data.ServiceResponseException: Le dossier spécifié est introuvable dans la banque d'informations. Sorry, it's localized and hard for me to translate. I think it's roughly "cannot find folder in Information Store". But I see it in Outlook under "Calendriers partagés" ("Shared calendars"). – jgran Oct 10 '16 at 08:29
  • That sounds like a permission issue to me can you just bind to the folder directly ? Maybe try using the EWSeditor that would allow you also to do a test bind using EWS to ensure the permissions are correct – Glen Scales Oct 11 '16 at 01:14
  • Thanks! I had asked my coworker the folderId from his workstation ("AAMkA...AH0fOoAAA="). I could connect to his shared calendar with EWSeditor. Then I retried in PowerShell with success. Good! $folderId = new-object FolderId("AAMkA...AH0fOoAAA="); $folder = [calendarFolder]::Bind($service, $folderId); $iv = new-object ItemView(1000); $calendarView = new-object CalendarView( $from, $to); $folder.FindAppointments( $calendarView );. So permissions were correct. Still, how could I get calendar Id from above C# code? – jgran Oct 11 '16 at 09:54
  • Is it the default calendar folder your trying to connect to or is it a secondary calendar folder they have created and then shared ? The code I created only works on the primary calendar folder as it uses a distinguished folder bind. – Glen Scales Oct 12 '16 at 01:27
  • Thanks so much once again. Your comments open my eyes! The original situation is: my colleague creates a brand new calendar "someCal" and shares it with a group I'm a member of. I create a calendar group "foo". I drag'n drop someCal from "Shared Calendars" onto "foo" (should I?) in "WunderBar". My colleague gives me full access on someCal. I do reporting from it by querying through EWS. I don't have any special rights (not delegates, and AFAIK, impersonation is excluded as of now) . Hope "someCal" folder Id is queryable in some way (Exchange-2013, EWS-2.2) – jgran Oct 12 '16 at 12:27
  • A precision: when I say "no special rights", I mean, I'm not admin but access authorization can be adjusted up to ownership. Isn't this requirement doable with EWS-2+? I still cannot find how... – jgran Oct 13 '16 at 14:14
  • If you get the WunderBar shortcut for that folder and get the PR_WLINK_ENTRYID convert from a HexId to EWSId using EWS and then bind to that it should work okay. You can test it without writing any code using a MAPI editor and EWSEditor – Glen Scales Oct 14 '16 at 00:09
  • Thanks deeply Glen. Still not there though. I installed mfcmapi-15.0. On first trials couldn't find my shared folders, but some time later, I could find them under "shared data" (localized): Open Store > root > 'shared data' > cal creator > shared cal. Unfortunately, no 'PR_WLINK_ENTRYID' (or PidTagWlinkEntryId) whereever I looked for it. I'm puzzled. I could find it in your code: [...]foreach($Item in $fiItems.Items){ $id = $null; $Item.TryGetProperty($PidTagWlinkEntryId, [ref]$id);[...]. $id is '0 0 0 0 79 190 85 89 145 17'... but cannot convert it to EWSid (which should be 120 char long?). – jgran Oct 15 '16 at 12:38
  • ... Then I found out I could add properties in mfcmap, thanks to https://blogs.msdn.microsoft.com/dvespa/2014/01/16/how-to-configure-an-outlook-profile-using-mfcmapi-for-exchange-2013/ : Property > Additional Properties... > Add (PR_WLINK_ENTRYID) just to be a step further disappointed as displaid value is null (value column -> "cb: 0Ipb: NULL") or on another shared calendar: "Error: Code: MAPI_E_NOT_FOUND == 0x8004010F". – jgran Oct 15 '16 at 17:17
  • ... Then I found this link http://www.networksteve.com/exchange/topic.php/Where_are_Outlook_Favorites_stored/?TopicId=72816&Posts=0. From this insight, I looked up "Common Views" (localized in "Affichages communs" that I hadn't taken enough attention to). Right click to "Open associated contents table" where I can see every top level folder I guess. My colleague's shared calendar is there with the "PR_WLINK_ENTRYID". I could take the binary string value in the Property editor. – jgran Oct 16 '16 at 17:06
  • ... Then I searched the ewsId $PR_WLINK_ENTRYID = "0002F6...";<# from mfcmapi #> $colleagueMailBox = "colleague@domain"; $aiItem = New-Object Microsoft.Exchange.WebServices.Data.AlternateId $aiItem.Mailbox = $colleagueMailBox;$aiItem.Format = [Microsoft.Exchange.WebServices.Data.IdFormat]::HexEntryId;$aiItem.UniqueId = $PR_WLINK_ENTRYID; $ewsId = $service.ConvertId($aiItem, [Microsoft.Exchange.WebServices.Data.IdFormat]::EWSId). I could connect with EWSEditor > Add Root Folder > Folder Id = $ewsId. Should now do it from begin to end programmatically. Many thanks to Glen and GrayscaleRu. – jgran Oct 16 '16 at 17:22