Outlook Calendar Tips for Remote Teams

As mentioned in my last blog post A New Role with Microsoft Graph Team, I mentioned I am joining the Microsoft Graph team. One of the nice aspects of our team is that we are diverse and globally dispersed. With the different time zones that our team all reside in I thought it would be helpful to review a few of my calendar settings in Outlook desktop and Outlook on the Web to help with scheduling meetings or calls.

Working / Meeting Hours

Set your working / meeting days and hours so that teammates will know when you are generally available for scheduled meetings or calls. Personally, I wake up early most days and hence my start of the day is likely earlier than some others.

Outlook desktop: File -> Options -> Calendar -> Work time

Outlook calendar settings for working hours

Outlook on the Web: Settings -> Calendar -> View -> Meeting hours

Outlook on the Web calendar settings for meeting hours

Time Zones

Since my team is all over the world, it is important to be aware of time zones for scheduling meetings. In Outlook desktop it is possible to set your primary time zone and display 2 additional time zones. In the following screenshot I have set Eastern Time (US & Canada) as my primary time zone with additional time zones for Pacific Time (US & Canada) and East Africa Time (Nairobi). I have purposely kept the labels short so that they fit easily in the display on calendar views.

Outlook desktop: File -> Options -> Calendar -> Time zones

I have only been able to add a single time zone in Outlook on the Web. If someone knows a way to add multiple please let me know in the comments or contact me.

Outlook on the Web: Settings -> Calendar -> Language and time

End Meetings Early

Whether you are hosting a meeting in-person or online there are many reasons you may want to end your meeting early including:

  • Allow attendees time to walk to their next meeting room
  • Encourage attendees to wrap up their meeting without overlapping the following time block
  • Give attendees time for a mental break / chance to use the restroom in between meetings
  • …and more

Outlook desktop: File -> Options -> Calendar -> Calendar options

Outlook on the Web: Settings -> Calendar -> Events and invitations -> End appointments and meetings early

Share Free / Busy Times

In addition to setting your working / meeting hours, you can also come to show your free / busy times (and more) with other people.

Outlook desktop: File -> Options -> Calendar -> Calendar options -> Free/Busy Options

By default you may see that all users in your organization are able to see your free / busy times. You can adjust permission levels to show more details or add / remove additional people to have access to view your calendar.

Outlook on the Web: Settings -> Calendar -> Shared calendars

Publish Calendar

Aside from showing your free / busy times to people internal to your organization, sometimes you may want to publish your calendar to people external to your organization. Currently I have found this easiest to do through Outlook on the Web.

Outlook on the Web: Settings -> Calendar Shared calendars -> Publish a calendar

After you publish your desired calendar you can provide people with either an HTML (render in browser) or ICS (universal calendar file format) link.

Conclusion

In this post I walked through a number of calendar settings and preferences on my Outlook desktop and Outlook on the Web client. I hope this helps you to think of the diverse and global audience that you may be working with currently or in the future. If you have any additional tips you recommend please share them in the comments.

-Frog Out

PowerShell Script to Create Office 365 Security and Compliance Center eDiscovery Case and Holds

This week my customer and a peer both asked for a sample PowerShell script to automate the creation of an Office 365 Security and Compliance Center eDisovery case, hold, and content search.  This post will share out that script and a few things to be aware of (ex. deprecating basic authentication) that are important.

Background

The below script accomplishes the following tasks:

  • Create a Security and Compliance Center eDiscovery case
  • Place an in-place hold on multiple users’ Exchange Online mailboxes
  • Create a content search within eDiscovery case for any folders named “Legal Hold” and the child folders under them

Important Note

As of the publish date (Mar 4th, 2020) the Security and Compliance Center remote PowerShell module relies on basic authentication.  The Exchange team has publicly shared that basic authentication for Exchange Online will be deprecated by Oct 2020.  As such that means the below script may not be usable in its current form in ~6 months.  When a replacement or update is available I will attempt to update this sample to reflect that.

Exchange Online deprecating Basic Authentication
https://support.microsoft.com/en-us/help/4521831/exchange-online-deprecating-basic-auth

In terms of the Exchange Online remote PowerShell module there is a v2 module being developed (active development, not ready for production) which you can find on the PowerShell Gallery.  This new module support OAuth authentication which resolves the issue of deprecated basic authentication.

ExchangeOnlineManagement module on PSGallery
https://www.powershellgallery.com/packages/ExchangeOnlineManagement

Solution

Before running this script, ensure that the account you log in with has the appropriate permissions to both Exchange Online as well as Security and Compliance Center.  My sample uses a single admin account but you may adapt the script to use separate accounts if needed.  See the following articles for more details.

Connect to Exchange Online PowerShell
https://docs.microsoft.com/en-us/powershell/exchange/exchange-online/connect-to-exchange-online-powershell/connect-to-exchange-online-powershell?view=exchange-ps

Connect to Office 365 Security & Compliance Center PowerShell
https://docs.microsoft.com/en-us/powershell/exchange/office-365-scc/connect-to-scc-powershell/connect-to-scc-powershell?view=exchange-ps

Note: If you do not see the below Gist please refer to code at this location: EXO_New-SCCeDiscoveryCaseAndHold.ps1

Conclusion

In this post I shared a sample script for automating the creation of an Office 365 Security and Compliance Center eDiscovery case, hold, and folder scoped content search.  The folder scoping was an interesting detour as I had to track down the way to gather folder IDs from a product group engineer sample (linked in the above sample).  I hope you find this useful and good luck scripting.

-Frog Out

Presenting at Collab365 SharePoint Summit 2019

I have the privilege of presenting “Getting Started with Microsoft Graph Development” at the upcoming Collab365 SharePoint Summit taking place Sept 10-12, 2019.  This is a free online conference with MVPs and experts from around the world presenting on developer, IT Pro, and adoption topics.

Title: Getting Started with Microsoft Graph Development

Abstract: “I hear that I need to use Microsoft Graph for developing against Office 365 but I have no clue where to start.” “I want to grant access to company data without throwing in the entire kitchen sink.” Fear not fellow developers and admins.

This session we will ramp you up to a 200 level knowledge on the pertinent parts of Microsoft Graph including endpoints available, syntax, authentication flows, and more. We will also cover useful examples of what can be accomplished using these APIs. Prior experience with Microsoft Graph is not required but can be helpful.

You can also purchase an all-access pass which includes lifetime access to the videos, additional e-books, and more.  Looking forward to participating in this great event.

Automate Creation of Azure AD Application with OAuth Permissions

<Update 2018-02-06>Updated with snippet to list out GUIDs for app roles that can be assigned.</Update>

In this post I will show how to automate the creation of an Azure AD Application and assign OAuth permissions to that application.  The latter part is tricky as there is not currently a PowerShell commandlet or Azure CLI command to assign OAuth permissions.  Instead we will leverage an authenticated call to the Microsoft Graph to assign the permissions.  For more in depth information about Azure AD apps, verifying the results, and more please see the following post which I am borrowing heavily from.  I had difficulty finding this information so this post is my attempt to spread the word and also add a few clarifications on the ADAL libraries used.

(Read this first!) Automating the creation of Azure AD Applications by Christer Ljung

http://www.redbaronofazure.com/?p=7197

Problem

Creating Azure AD apps typically involves logging into the Azure Portal (classic or “new” / Ibiza version) and manually clicking through multiple screens.  When developing a solution that needs to leverage Office 365 services (as is my case with a current project) it is helpful to automate the process of creating the Azure AD app and assigning the permissions.  If you happen to be assigning Admin permissions then additional steps will be required by an Azure AD domain administrator (see following screenshot).

AzureADApp1

Solution

Creating an Azure AD application can be accomplished in 2 lines of PowerShell.  Login to Azure then create the app.


Login-AzureRmAccount

$aadapp = New-AzureRmADApplication -DisplayName "Some amazing app" -HomePage https://localhost:8081/ -IdentifierUris https://localhost:8081/

***BONUS***

If you want to create an app that uses certificate based authentication you can use the following PowerShell commandlets.

Note: The commandlets for creating and exporting a certificate require Windows 8 or higher.  There are workarounds for Windows 7 or similar OS.  Feel free to reach out if you are in that scenario.


$pwd = Read-Host -AsSecureString -Prompt "Enter certificate password"

# process for Windows 8+ type OS
$ssc = New-SelfSignedCertificate -CertStoreLocation cert:\localmachine\my -Provider "Microsoft Enhanced RSA and AES Cryptographic Provider" `
                           -Subject "cn=MySuperSpecialCert" -KeyDescription "Used to access Azure Resources" `
                           -NotBefore (Get-Date).AddDays(-1) -NotAfter (Get-Date).AddYears(1)

# Export cert to PFX - uploaded to Azure App Service
Export-PfxCertificate -cert cert:\localMachine\my\$($ssc.Thumbprint) -FilePath ExportedSpecialCertFile.pfx -Password $pwd –Force
$KeyStorageFlags = [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::Exportable, [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::MachineKeySet, [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::PersistKeySet
$certFile = Get-ChildItem –Path <path to certificate file>
$x509 = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2
$x509.Import($certFile.FullName, $pwd, $KeyStorageFlags)
$certValue = [System.Convert]::ToBase64String($x509.GetRawCertData())

# should match our certificate entries above.
$validFrom = [System.DateTime]::Now.AddDays(-1)
$validTo = [System.DateTime]::Now.AddYears(1)

$aadapp = New-AzureRmADApplication –DisplayName "Some amazing app" -HomePage "https://localhost:8080/" `
                                   -IdentifierUris "https://localhost:8080/" -CertValue $certValue `
                                   -StartDate $validFrom -EndDate $validTo

The next step involves granting OAuth permissions to the recently created Azure AD app.  As of the writing of this blog (Feb 2, 2018) there is not a PowerShell commandlet nor Azure CLI command to assign those permissions.  There is however a way to use the Microsoft Graph to assign permissions.  This is an adapted version of Christer’s example that I referenced earlier and uses a local version of the Active Directory Authentication Library (ADAL) DLLs.  Currently these are at version 3.19.1.

ADAL NuGet package

https://www.nuget.org/packages/Microsoft.IdentityModel.Clients.ActiveDirectory/

Extract the following DLLs into the folder where you are executing other PowerShell commands:

  • Microsoft.IdentityModel.Clients.ActiveDirectory.dll
  • Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll

$Tenant = "<Office 365 tenant name, ex. Contoso>"
$aadTenant = "$Tenant.onmicrosoft.com"
$adminUser = "<admin account with access to authenticate against MS Graph>"

# load ADAL DLLs
$adal = ".\Microsoft.IdentityModel.Clients.ActiveDirectory.dll"
$adalforms = ".\Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll"

[System.Reflection.Assembly]::LoadFrom($adal) | Out-Null
[System.Reflection.Assembly]::LoadFrom($adalforms) | Out-Null

 $clientId = "1950a258-227b-4e31-a9cf-717495945fc2"  # Set well-known client ID for AzurePowerShell
  $redirectUri = "urn:ietf:wg:oauth:2.0:oob" # Set redirect URI for Azure PowerShell
  $resourceAppIdURI = "https://graph.windows.net/" # resource we want to use
  $adminUserId = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.UserIdentifier" -ArgumentList ($adminUser, "OptionalDisplayableId")

 # Create Authentication Context tied to Azure AD Tenant
  $authContext = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext" -ArgumentList $authority

  # Acquire token
  $authResult = $authContext.AcquireToken($resourceAppIdURI, $clientId, [Uri]$redirectUri, [Microsoft.IdentityModel.Clients.ActiveDirectory.PromptBehavior]::Always, $adminUserId)

 $authHeader = $authResult.CreateAuthorizationHeader()
  $headers = @{"Authorization" = $authHeader; "Content-Type"="application/json"}   

# make call against MS Graph to apply OAuth permissions
$url = "https://graph.windows.net/$aadTenant/applications/$($aadapp.ObjectID)?api-version=1.6"
$postData = "{'requiredResourceAccess':[
     {'resourceAppId':'00000003-0000-0ff1-ce00-000000000000','resourceAccess':[{'id':'fbcd29d2-fcca-4405-aded-518d457caae4','type':'Role'}]},
     {'resourceAppId':'00000002-0000-0000-c000-000000000000','resourceAccess':[{'id':'311a71cc-e848-46a1-bdf8-97ff7156d8e6','type':'Scope'}]}
     ]}";
$result = Invoke-RestMethod -Uri $url -Method "PATCH" -Headers $headers -Body $postData  

Note the use of specific resoureAppId and resourceAccess values above.  These two examples grant the “read and write all items in SharePoint Online” admin consent permission and the default “read user profile data” delegated permission respectively.  In order to find out the GUIDs you may need you’ll need to add the permissions through the Azure portal UI, check the manifest file, and extract the GUIDs.  See Christer’s post for more details.

<Update 2018-02-06>  I recently found out it is possible to list out the Application role permissions and GUIDs needed above by running the following PowerShell against the Azure AD module (I’m using Azure AD “V2” Preview module, haven’t verified against the existing V1 module).

Connect-AzureAD
# 00000003-0000-0ff1-ce00-000000000000 is the AppId for SharePoint Online, call Get-AzureADServicePrincipal by itself to find other AppIds
$SPOApi = Get-AzureADServicePrincipal -Filter "AppId eq '00000003-0000-0ff1-ce00-000000000000'"
$SPOApi.AppRoles

</Update>

If you happen to assign an admin consent permissions (such as the “read and write all items in SharePoint Online” permission) an Azure AD domain administrator will still need to consent to that permission by clicking “Grant permission” inside the Azure portal.  I’m not aware of a way to automate that process but if you do know please share in the comments below.

Conclusion

Originally I had hoped automating creation of an Azure AD app would be a simple process.  Creation of the Azure AD app is easy, but adding certificate authentication and / or assigning OAuth permissions adds extra work to be done.  As seen in this post though much of that can be automated.  Hopefully this post saves you time and effort.  Feel free to leave any feedback or questions in the comments below.

-Frog Out

SharePoint CSOM to Traverse All Sites in SharePoint Online

[Update 2018-07-31] Special thanks for my peer John Ferringer for pointing out an issue with my prior CSOM snippet. Updating CSOM code to handle large number of sites as previous sample would truncate results if large number of sites were traversed.[/Update]

In the past I’ve written posts for “PowerShell to Enumerate SharePoint 2010 or SharePoint 2013 Permissions” or “PowerShell Script To Traverse All Sites In SharePoint 2010 (or 2007) Farm” to assist with traversing through all sites within a SharePoint on-prem farm.  In this post I’ll share a snippet I recently used for traversing through all site collections and subsites within a SharePoint Online tenant.

 

Background

If you’ve worked with the SharePoint Online Management Shell you may know that originally it was not able to retrieve Personal Sites (also known as My Sites / OneDrive for Business sites) in SharePoint Online.  As far as I’m aware this was primarily a limitation of the underlying client side libraries (Microsoft.SharePoint.Client.*).  Fast forward to a recent release (I don’t have the specific one but I can confirm it is in the 16.1.6621.1200 release of the Microsoft.SharePointOnline.CSOM NuGet package) and now it is supported to retrieve Personal Sites.  In the management shell this is accomplished by calling the following:

 

Note: If you do not see the below Gist please refer to code at this location: PS-Get_All_Sites_SPO.ps1

 

The problem is that if you want to traverse all site collections in SharePoint Online in client side object model (CSOM) you would need to know how the SharePoint Online Management Shell implements that inclusion of Personal Sites with the rest of site collections.  In order to find this out I used a disassembler (ILSPY in my case, but there are many alternatives available as well) on the underlying libraries to recreate the process in my own code.

 

Solution

The resulting CSOM that I came up with is below.  Feel free to borrow this and use in your own code but note that it is provided as-is with no warranty.

Note: If you do not see the below Gist please refer to code at this location: CSOM_Traverse_All_Sites_SPO.txt

 

Conclusion

In this post I shared a snippet for traversing all site collections in SharePoint Online with C# CSOM code.  In my daily job I’ve been using this in combination with Azure Functions for a number of interesting interactions with a SharePoint Online tenant.  More to come on those scenarios in future weeks.  For now let me know in the comments if you have any questions or issues implementing the above snippet in your own code.  Happy coding!

 

-Frog Out

Controlling Office 365 Admin Access with Azure AD Privileged Identity Management (PIM)

   Controlling, monitoring, and revoking access to privileged accounts can be a difficult process.  Recently my coworker Ken Kilty shared with me a new service for Azure Active Directory called Privileged Identity Management (Azure AD PIM).  After spending some time with it I wanted to share with a broader audience since I had never heard of it previously.

image

 

Overview

   Please read the What is Azure AD Privileged Identity Management first for a good overview of implementation, example scenario, and additional links to resources.  Note that Azure AD PIM requires Azure AD Premium P2 licenses.  If you would like to test this out there is a free 30 day trial of Azure AD Premium P2 for up to 100 users.

   Granting administrator access, for any application or server, to users should always be done with caution.  Sometimes what starts out as a temporary elevation of permissions turns into a permanent assignment.  Azure AD PIM answers many of the tough questions for Azure AD, Office 365, and related services such as:

  • Who has admin access to <service X>?
  • How do I grant truly temporary access to <service Y>?
  • How can I review all current admins to see if they still need admin access?

   The goal with Azure AD PIM is to allow administrators to define either permanent or “eligible” assignment of specific elevated permissions within Azure and Office 365.  Currently there are 21 roles that can be managed such as Global Administrator, Password Administrator, SharePoint Service Administrator, Exchange Administrator, and more.  See Assigning administrator roles in Azure Active Directory for a more complete listing of roles.  Users who are defined as “eligible” will be able to elevate themselves to roles they have been assigned for a set number of hours (1-72) defined by a Azure AD PIM administrator.  During this role elevation process the “eligible” user will need to verify their identity through a text / call verification or multifactor authentication (MFA) mechanism.  One of the key advantages is that this entire interaction is tracked and auditable.  Administrators can even require an incident or service ticket number prior to elevation and receive alerts when elevation requests are processed.

 

Conclusion

   I have seen privileged role access handled in many different ways at customers over the years.  Having a consistent and auditable process ensures that changes can be tracked and users who no longer need elevated permissions can be removed.  In the time I’ve tested out Azure AD Privileged Identity Management I am very happy with the overall process and review options.  One word of advice for users elevating yourself.  You will need to log out and log back in in order to update your claim token with the new elevated role claims.  Give Azure Active Directory Privileged Identity Management a try and share any feedback in the comments below.

 

      -Frog Out

SharePoint 2013 Migration Assessment Tool Released To Web

   Microsoft quietly released the Release to Web (RTW) version of the SharePoint Migration Assessment Tool (SMAT) for SharePoint 2013 on Jan 20, 2017.  This is an update from the Release Candidate (RC) version that was released in Fall 2016.  I haven’t seen any announcements regarding this upgrade so I wanted to share here.

 

Background

  For those who are not familiar with SMAT it is a command line tool that will check a SharePoint farm for risks migrating to SharePoint Online.  Aside from that primary purpose it is also useful for an overview audit of the farm (name and size of content databases, name and size of site collections, site collection admins and owners, and more.   There is a backing configuration file (scandef.json) which can enable or disable various checks to be scanned against a SharePoint farm.  At the time of writing there is only a version compatible with SharePoint 2013 but there is potential for a SharePoint 2010 and / or 2016 compatible version in the future.

   In terms of the checks scanned for they include:

  • Large lists
  • Checked out files
  • Full trust solutions
  • Non-default master pages
  • Unsupported web templates
  • … and more

 

   SMAT will need to run on a server within the SharePoint farm and be run as the farm administrator.  Run time will vary depending on the size and configuration of the farm.  In a tiny lab farm I had created it took minutes to run but in sizable lab farm (multiple TBs of data and tens of thousands of site collections) it took over 24 hrs.  The output from the tool will be 1 summary CSV along with 1 detail CSV per check scanned (~30).

 

What’s New

  Comparing the documentation from the RC version to the RTW version I am seeing a few new risks that are scanned but I didn’t see them output in the CSV files.  I may need to be make changes to the config file in order to include the new checks.  Other than that the execution of the tool and general process is the same as the RC version.

 

Next Steps

   So what can you do with these CSV files?  By themselves the output CSV files can be difficult to read to get a good picture of the overall migration risks of a farm.  One option is to use these output files in conjunction with the Microsoft FastTrack Center and their SharePoint 2013 to SharePoint Online Migration Offer.  See this link for details on that offer and more.

   Another option is to analyze the CSV files on your own with tools such as Excel, SQL Server, or Power BI.  Personally I am very new to Power BI but with a little research and consulting with fellow PFEs I was able to generate a useful report that aggregated the risk data and filtered it into very usable visualizations.  I will write a follow up post about the process I followed to model and visualize these output files.

 

Conclusion

   If you are are hosting a SharePoint 2013 farm and looking to migrate to SharePoint Online or simply want to audit your farm for risks and general data I encourage you to take a look at the SharePoint Migration Assessment Tool.  Look for my next blog post where I’ll dig into interpreting the data with Power BI to find useful insights and more.

 

      -Frog Out