Azure AD – Retrieving Group Members

Recently I needed to query Azure AD from a web api to retrieve members of an AD group, this was prototyped in a console app – C#.

Got the following packages from Nuget…

using Microsoft.Azure.ActiveDirectory.GraphClient;
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using Microsoft.Azure.ActiveDirectory.GraphClient.Extensions;

Declared my constants – I created a new application from within the Azure Management Portal (Active Directory Area), this allowed me to get a client ID and client Secret – required for authentication.

public class Constants
{
public const string auth = "https://login.windows.net/MYDOMAIN.onmicrosoft.com";
public const string clientID = "client ID GUID";
public const string clientSecret = "client SECRET GUID";
public const string azureGraphAPI = "https://graph.windows.net";
public const string serviceRoot = "https://graph.windows.net/MYDOMAIN.onmicrosoft.com";
}

Created a method to instantiate ActiveDirectoryClient – essentially creating a connection to Azure AD.

private static async Task<string> GetAzureAdToken()
{
AuthenticationContext authenticationContext = new AuthenticationContext(Constants.auth, true);
ClientCredential clientCred = new ClientCredential(Constants.clientID, Constants.clientSecret);
AuthenticationResult authenticationResult = await authenticationContext.AcquireTokenAsync(Constants.azureGraphAPI, clientCred);
return authenticationResult.AccessToken;
}

And wrote another two methods allowing me to get a single user by querying using a UPN, and another method to allow me to retrieve a group and its members based on the group name.

private static async Task<string> GetUser(ActiveDirectoryClient adClient, string Upn)
{
var userLookupTask = adClient.Users.Where(x => x.UserPrincipalName.Equals(Upn, StringComparison.CurrentCultureIgnoreCase)).ExecuteSingleAsync();

User me = (User)await userLookupTask;
Console.WriteLine(me.DisplayName);
return me.DisplayName;
}

private static async Task<string> GetGroup(ActiveDirectoryClient adClient, string GroupName)
{
var groupLookup = adClient.Groups.Where(x => x.DisplayName.Equals(GroupName, StringComparison.CurrentCultureIgnoreCase)).ExecuteSingleAsync();

Group grp = (Group)await groupLookup;
IGroupFetcher groupFetcher = (IGroupFetcher)grp;
IPagedCollection<IDirectoryObject> members = groupFetcher.Members.ExecuteAsync().Result;

do
{
List<IDirectoryObject> directoryObjects = members.CurrentPage.ToList();
foreach (IDirectoryObject member in directoryObjects)
{
if (member is User)
{
User usr = member as User;
Console.WriteLine("user: {0} : {1} : {2}", usr.DisplayName, usr.TelephoneNumber, usr.Mobile);
}
}
members = members.MorePagesAvailable ? members = members.GetNextPageAsync().Result : null;

} while (members != null);

return grp.DisplayName;
}

Within my Main method, it was a case of connecting to Azure AD, and calling the methods…

class Program
{
static void Main(string[] args)
{
try
{
Uri serviceRoot = new Uri(Constants.serviceRoot);
ActiveDirectoryClient adContext = new ActiveDirectoryClient(serviceRoot,async () => await GetAzureAdToken());

var user = GetUser(adClient, "david.hendry@MyDomain.com");
var group = GetGroup(adContext, "IT Solutions");

Console.ReadKey();
}
catch (AuthenticationException ex)
{
Console.ReadKey();
}
}
}
}

CRM Online – Retrieve all users

Being reasonably new to the CRM SDK I needed a method to retrieve all users from the system.  This was needed as I was doing a piece of work to replicate permissions between CRM business units and SharePoint.

Retrieving all users via a query expression turned out to be quite simple…

private static EntityCollection RetrieveAllUsers(IOrganizationService service)
        {
            QueryExpression query = new QueryExpression
            {
                EntityName = "systemuser",
                ColumnSet = new ColumnSet(true),
                Criteria =
                {
                    Conditions =
                    {
                        new ConditionExpression
                        {
                            AttributeName = "businessunitid",
                            Operator = ConditionOperator.NotNull
                        }
                    }
                }
            };
            return service.RetrieveMultiple(query);
        }

The EntityCollection returns a number of useful attributes, such as the users’ business unit, whether they have a valid licence, account status and so on.

Manually creating ICS files and sending from SharePoint

In a previous post I created Outlook appointments using Microsoft.Office.Interop, a limitation of using this method means MS Outlook is required to be installed on the server.

To avoid this limitation it’s possible to create an Outlook appointment manually and send as an attachment, you still have full control over the content and behaviour of the appointment file, known as a .ICS file.

There are various examples on the web of how to do this, but I struggled to find one that met my exact requirements, my requirements were:

  • Dynamically populate the ICS file with content from a custom webpart within SharePoint.
  • Send the email with attachment using the configuration stored within SharePoint (Outgoing SMTP Server, sender address).
  • Ability for the recipient to accept the invitation, to enable the employee calendar to be updated, with no meeting organiser.

What the code does… Creates a new instance of MailMessage, specifics the SMTP Server, Sender Address, and a couple of other properties.
P.S. I’m not managing garbage collection within this area of code..Also the variable ‘appointment’ is a class that I created to store the variables from the SharePoint webpart.

MailMessage messageContent = new MailMessage();
SPSite site = SPContext.Current.Site;
SPWeb web = site.OpenWeb();
string senderAddress = web.Site.WebApplication.OutboundMailSenderAddress;
string smtpServer = web.Site.WebApplication.OutboundMailServiceInstance.Server.Address;
messageContent.From = new MailAddress(web.Site.WebApplication.OutboundMailSenderAddress);
messageContent.To.Add(new MailAddress("appointment.recipient");
messageContent.Subject = appointment.Subject;
messageContent.Body = appointment.Body;

The next part builds the ICS file as a string. I found these properties by sending meeting invitations to my Gmail account and opening the appointment file in Notepad to understand what parameters I required.

StringBuilder icsBuilder = new StringBuilder();
            icsBuilder.AppendLine("BEGIN:VCALENDAR");
            icsBuilder.AppendLine("VERSION:2.0");
            icsBuilder.AppendLine("PRODID:-//Schedule a Meeting");
            icsBuilder.AppendLine("METHOD:REQUEST");
            icsBuilder.AppendLine("BEGIN:VEVENT");
            icsBuilder.AppendLine(string.Format("DTSAMP:{0:yyyyMMddTHHmmssZ}", DateTime.Now));
            icsBuilder.AppendLine(string.Format("DTSTART:{0:yyyyMMddTHHmmssZ}", appointment.StartDateTime));
            icsBuilder.AppendLine(string.Format("DTEND:{0:yyyyMMddTHHmmssZ}", appointment.EndDateTime));
            icsBuilder.AppendLine("LOCATION:None");
            icsBuilder.AppendLine(string.Format("UID:{0}", Guid.NewGuid()));
            icsBuilder.AppendLine(string.Format("DESCRIPTION", messageContent.Bcc));
            icsBuilder.AppendLine(string.Format("SUMMARY:{0}", messageContent.Subject));
            icsBuilder.AppendLine(string.Format("ORANIZER:MAILTO:{0}", messageContent.From.Address));
if(!string.IsNullOrEmpty(appointment.Body))
icsBuilder.AppendLine(string.Format("X-ALT-DESC:FMTTYPE=text/html:{0}", messageContent.Body));

I couldn’t use the send mail functionality available in SPUtility as I was unable to add attachments, there may be better ways of sending the actually email with the attachments.

Below, I’m using the standard System.Net.Mail functionality:

System.Net.Mail.SmtpClient smtpClient = new System.Net.Mail.SmtpClient();
smtpClient.Host = smtpServer;
smtpClient.UseDefaultCredentials = true;
System.Net.Mime.ContentType contentType = new System.Net.Mime.ContentType("text/calendar");
contentType.Parameters.Add("method", "REQUEST");
contentType.Parameters.Add("name", "MeetingAppointment.isc");
AlternateView view = AlternateView.CreateAlternateViewFromString(icsBuilder.ToString(), contentType);
messageContent.AlternateViews.Add(view);
smtpClient.Send(messageContent);

Programmatically creating Outlook appointments

Outlook Reference

Found myself needing to learn the basic of using the Microsoft Office API to programmatically creating appointments in Outlook.  The event will be initiated from SharePoint 2010, for various reasons I was unable to use the standard Outlook – SharePoint integration.

In this example I’ll demonstrate the basics of creating an Outlook Appointment…

First step is to add a reference into Visual Studio, Reference: Microsoft.Office.Interop.Outlook.

Once the reference is added you need to create a new Outlook Application, and then instantiate the object type you require, in this example…an Outlook appointment item.

Microsoft.Office.Interop.Outlook.Application outlookApp = new Microsoft.Office.Interop.Outlook.Application();

Microsoft.Office.Interop.Outlook.AppointmentItem appointmentItem =(Microsoft.Office.Interop.Outlook.AppointmentItem)outlookApp.
CreateItem(Microsoft.Office.Interop.
Outlook.OlItemType.olAppointmentItem);

As you’ve added the reference you get all the goodness of the intelliSense, obviously makes everything a lot easier.

Specify the Start and End date / time

appointmentItem.Start = DateTime.Now;
appointmentItem.End = DateTime.Now.AddHours(1);

Reminder settings

appointmentItem.ReminderSet = true;
appointmentItem.ReminderMinutesBeforeStart = 60;

Subject, location, and saving

appointmentItem.Subject = "Be Somewhere";
appointmentItem.Location = "Location 1";
appointmentItem.Body = "blah blah blah";
appointmentItem.Save();

Instead of calling ‘Save’ the appointment can be forwarded as a VCal attachment

protected void sendAsVcal(Microsoft.Office.Interop.Outlook.AppointmentItem appointmentItem)
{
Microsoft.Office.Interop.Outlook.MailItem mailItem = appointmentItem.ForwardAsVcal();
mailItem.SenderEmailAddress = "sysadmin@corp.net"
mailItem.To = "me@me.com";
mailItem.Send();
}

I initially built this as a console app to test the functionality, but can easily be moved to a standard web application project. Code above tested on Outlook 2007 / 2010.