Month: December 2018

Skype for Business & Teams Interoperation

Prior to August, when someone in Skype sent a message it showed up in my Teams client. And when I sent someone who had never used Teams a message, it showed up in their S4B client. Which was *exactly* the way I wanted it to work. And then Microsoft rolled some … enhancements. Now there’s an Island mode where messages are delivered to whatever platform originated them. Or a TeamsOnly mode when you’re done. Or a SkypeOnly mode when you’re not using Teams yet. And they’re working on some intermediary modes that will let you use Skype only but Teams for some limited subset of functions. I want what I had before their change!

And I finally figured out how to do it. It’s ugly. And eliminates the nice ad hoc “go try out Teams and use it whenever you want”. In addition to the tenant-level mode, there’s a user-level identity. If I set anyone who wants to be a teams user to UpgradeToTeams

PS O:\> Grant-CsTeamsUpgradePolicy -PolicyName UpgradeToTeams -Identity
WARNING: Users with this policy will become full Teams-only users. They will no longer be able to use Skype for Business clients, except to join Skype for Business meetings. For details, see

Messages sent from both Teams and Skype users to them will appear in their Teams client. Which is great; but, with the tenant in Island mode, they’ll still find themselves needing to log into Skype to talk to someone who is over there. You might be able to change the tenant to SkypeOnly (or the inverse, change the tenant to TeamsOnly and enumerate specific S4B users) but I don’t have a test tenant to, well, test that. But I can set anyone who isn’t
a dedicated Teams user to be a SkypeOnly user.

O:\> Grant-CsTeamsUpgradePolicy -PolicyName SfBOnly -Identity

And now T03826 will always get messages in Skype — even if e05826 sends them from Teams. And e05826 will always get messages in Teams — even if e03826 sends them from Skype. Amazing — I’ve managed to get back to where I was in July!

If the SkypeOnly user logs into Teams, they seem to be able to do anything they want … even sending messages to others in Teams. For the Teams recipient, there will be two listings for the SkypeOnly user. One with a Skype logo which will deliver messages to their Skype client (which also happens if you start a new chat and enter their name). Another, without the Skype logo, will deliver messages to their Teams client. Which they might miss if they’re not using Teams regularly.

Did you know … Microsoft Teams has a Twitter connector?

Microsoft publishes outage notifications several places –there’s a web portal that provides general status for major Office 365 outages,a customer-only portal that provides a LOT of details on every diminished service state, a Twitter feed with status on wide-spread outages. The common feature of all of these, though, is *checking* to see if there’s an outage –start seeing several calls for the same problem, check the outage site. It works, but it is not proactive.

Twitter could be proactive, but I don’t want to be diving for my phone every time a friend posts some random musing. But Microsoft Teams connects to Twitter, and it posts filtered content into a channel,so I only see pertinent information in our Teams channel. The connector can also search hash tags – useful for tracking brand mentions.

You can include Twitter posts into an existing channel or create a new one. I am creating a new channel to separate Twitter posts from other conversations.

Click the not-quite-a hamburger menu next to the channel into which you want Twitter posts to appear and select “Connectors”.

Locate “Twitter” and click “Configure”

You will need to configure a Twitter account before you can configure the connector. I recommend not using your personal account. Create a new account to be used by your Teams space. If ownership of the Teams space changes, the new owner can take over the Twitter account too. Click “Log in”

Click “Continue” to proceed with Twitter authentication

You are allowing the Twitter connector to use your account – read the access request and sign in if the usage is acceptable.

Once you have authenticated to Twitter, you will be able to configure the Teams connector. Enter accounts or tags to see Teams posts for relevant activity – do not put spaces after the commas!

Decide if you want Teams posts for replies, mentions, or re-tweets. Select the frequency with which you want the Teams connector to check for updates – our Microsoft outage notification connector is set to “Deliver individual messages as new tweets arrive”, but I configure most other connectors to create a digest every 1 or 6 hours. Once you have completed the connector configuration, click “Save”.

In your selected channel, you will find a post summarizing the connector configuration.

Did you know … you can share files in Microsoft Teams chats?

You can share files in both individual and group chats. In the chat, click on “Files”

Then click on “Share” and “Upload from my computer” to share a new file.

While it is uploading, you’ll see a status indicator.

And once the upload completes, you will get a desktop notification.

Voila – a shared file.

Where is that file? It’s been uploaded to your OneDrive for Business. Open the OneDrive web app and you’ll see a folder titled “Microsoft Teams Chat Files”.

In there, you’ll see all of the files you’ve shared in Teams. Click on “Shared”

And you can see with whom the file was shared.

If you shared a file in a group chat, everyone in the chat will be added to the file permission. If you shared a file in an individual chat, just that individual will be added.

If you want to share the same file with a second person, there’s no need to upload it again … doing so would remove the original permissions. When you see a warning that the file already exists, cancel.

Instead of uploading the file from your computer, select “OneDrive” from the “Share” menu.

Navigate into the “Microsoft Teams Chat Files” folder.

And select the file you wanted to share.

The new person with whom you want to share the file is added to the share list, and both individuals will see the file in the “Files” section of your Teams chat.

Be careful — deleting the file from your OneDrive space does not remove it from the Teams files list. The chat participants will get an error when they attempt to view the file.

Microsoft Graph — Application Registration

The application I am registering will pull report data from Graph for use within existing company systems. I will be assigning application-level permissions and no callback URL is needed.

To register an application, log into and select “Azure Active Directory” from the left-hand navigation column. Then select “App Registrations (preview)”.

Click on “New registration”

Provide a descriptive name for the application — tenant managers can see all of the registered applications and it’s a lot easier if you ask them to approve access for “Specific Application Name For Engineering” than “LJR Test”.

The application will be created and you will be brought to the app overview. Select “API permissions” then click the “Microsoft Graph” hyperlink.

Click on “Application permissions”

And find the permissions you need. For the script I want to run, I need Reports.Read.All. Click “Update permissions” to save your changes.

If you are a tenant admin, you can approve your own rights. Otherwise, you’ll need to contact a tenant admin and have them approve the permissions you have requested. Once the permissions have been acknowledged, you’re ready to go.

You will need the app ID and a secret for use within your code. The application ID is listed on the application “Overview”.

To create a secret, select “Certificates & secrets” then click “New client secret”. This is displayed one time, so copy it into your code now.

Splunk Teams Connector – Followup

We managed to use the stock Teams webhook app in Splunk — just needed to modify the search being used. Adding “|table” and specific fields to be included in the table avoids having to filter the list data within the Python code

There still is a tweak to the code that I prefer — Python lists aren’t in any particular order. I’d like to be able to look the same place in the Teams post to see a particular field. Adding a sort when the facts array is put into the post body ensures the fields are in the same order each time.

            {"activityTitle": settings.get("search_name") + " was triggered"},
                "title": "Details",
                "facts": sorted(facts)

And I’ve got a Teams post from Splunk with a generic script — desired fields are specified within the search, so can be easily changed.

Splunk – Posting to Microsoft Teams via Webhooks

Using either the default webhook action or the Teams-specific webhook, Splunk searches can post data into Microsoft Teams. First, you need to get a webhook URL for your Teams channel. On the hamburger menu next to the channel, select “Connectors”. Select Webhook, provide a name for the webhook, and copy the webhook URL.

If you intend to use the generic webhook app, there is no need to install the Teams-specific one. The Teams-specific app gives you prettier output & a “view in splunk” button. Download the app tgz. To install the app, go into “Manage Apps” and select “Install app from file”.

Click ‘Browse…’ and find the tgz you downloaded. Click ‘Upload’ to install the app to Splunk.

Now create a search for which you want to post data into your Teams channel. Click “Save As” and select “Alert”

Provide a title for the alert — you can use real-time or scheduled alerts. Once you’ve got the alert sorted, select “Add Actions” and select the Teams webhook action (or the generic webhook action if you intend to use that one). Paste in the URL from your Teams channel webhook and click “Save”.

You”ll see a confirmation that the alert has been saved. Close this.

Now you would think you’d be ready to use it … but wait. Neither one works out of the box. In the Splunk log, you see error 400 “Bad data” reported.

For the default webhook app, edit the Python script (/opt/splunk/etc/apps/alert_webhook/bin/ in my case). Find the section where the JSON body is built. Teams requires a summary or title within the POST data. I just added a static summary, but you could do something fancier.

        body = OrderedDict(

For the Teams-specific webhook, edit the Python script (/opt/splunk/etc/apps/alert_msteams/bin/ in my case) and find the section where the facts list is populated. There’s too much data being sent through. There’s probably a way to filter it out in Splunk, but I don’t know how 🙂

The right way to do it is select the most important items from settings.get(‘result’).items that you want to be displayed within Teams and populate facts with those elements. I used a new list, strWantedKeys, to determine which keys should be added to the facts list. The quick/ugly way is to just take the first n items from the result items (settings.get(‘results’).items()[:7] gets seven … 8 produced a ‘bad payload received by generic incoming webhook’ error from Teams.

settings = json.loads(
print >> sys.stderr, "DEBUG Settings: %s" % settings
url = settings['configuration'].get('url')
facts = []
strWantedKeys = ['sourcetype', '_raw', 'host', 'source']
for key,value in settings.get('result').items():
if key in strWantedKeys:
facts.append({"name":key, "value":value})
body = OrderedDict(

For reference, the original facts list was:

    "facts": [{
        "name": "index",
        "value": "history"
    }, {
        "name": "_raw",
        "value": "Test push to teams 555"
    }, {
        "name": "_eventtype_color",
        "value": ""
    }, {
        "name": "host",
        "value": ""
    }, {
        "name": "source",
        "value": "http:Sendmail testing"
    }, {
        "name": "_si",
        "value": ["49cgc3e5e52e", "history"]
    }, {
        "name": "sourcetype",
        "value": "mysourcetype"
    }, {
        "name": "_indextime",
        "value": "1544554125"
    }, {
        "name": "punct",
        "value": "___"
    }, {
        "name": "linecount",
        "value": ""
    }, {
        "name": "_time",
        "value": "1544554125"
    }, {
        "name": "eventtype",
        "value": ""
    }, {
        "name": "_sourcetype",
        "value": "mysourcetype"
    }, {
        "name": "_kv",
        "value": "1"
    }, {
        "name": "_serial",
        "value": "15"
    }, {
        "name": "_confstr",
        "value": "source::http:Sendmail testing|host::|mysourcetype"
    }, {
        "name": "splunk_server",
        "value": ""

Now generate a message that matches your search — you’ll see a post created in your Teams channel.

Did you know … you can record Microsoft Teams meetings (and add a transcription)?

Once you have started a Microsoft Teams meeting, click the not-quite-a-hamburger menu in the meeting control and select “Start recording.

You will see a confirmation that your meeting is recording – and, as the message mentions, make sure everyone knows they are being recorded.

If you are attending the meeting using a web browser, the browser tab will have a little red circle indicating that recording is active.

If you no longer wish to record the meeting, click the not-quite-a-hamburger-menu button again and select “Stop recording.

Now where is that recording?? Open the meeting chat

And you’ll see a post indicating that the recording is saving. Once the recording has been saved, a link to the recording will appear in the conversation. You can get a link to share with others.

If you would like a transcription to be created for your meeting, select “Open in Microsoft Stream”. This will open the recording in a web browser. Under the meeting information, click the not-quite-a-hamburger menu and select “Edit”

On the edit page, select the video language. Ensure “Captions” is checked.

Scroll up to the top of the page and click “Apply”.

Wait for it – the transcription process can take a loooong time. Once the transcription is done, you can click the gear icon in the video information and select “Show transcript” (if the transcript isn’t done yet, this option is still available. But the transcript pane will just tell you to come back later)

Read through the transcript – an AI engine is used to perform the natural language processing, and the transcription accuracy *should* improve as you use the service. Click on “Edit”, make any corrections

Click “Done” to save your changes.

When your video is played, there is now a button to display closed captioning.

And the transcript will be displayed as the video progresses.

When you view the transcript, you can copy the entire thing & paste the transcript into OneNote or the meeting chat to have computer-generated meeting notes. I usually edit the transcript to remove the timestamps (and remove any tangential discussions).

Did you know … Microsoft Teams saves your un-sent chat messages?

While cognitive research says we focus best if we’re not switching topics every few minutes,sometimes I find myself needing to switch to a new channel in the middle of a thought. Desktop notifications, important content flags … but Teams will save what you’ve already typed even if you leave the channel or chat session.

I’ve switched over to the channel with that important activity – I can even send a new message here.

And when I return to my original channel, everything I’ve typed is still in there. Teams even saves the un-sent post if you close the client (I still copy my post to notepad just in case if I’m doing anything more than re-launching the browser to apply updates, but I haven’t needed the saved post content yet)

I can continue writing my post and send it.

Did you know … you can schedule meetings through Microsoft Teams?

You can! From the Teams side-bar, select Meetings.

At the bottom of your screen, along the left-hand side click “Schedule a meeting”.

Add the usual stuff – a title, time, agenda. Click under “Invite people” and type in some names to add people to the invitation. They don’t all have to work here – you can type in SMTP addresses as well.

Once you’ve added your attendees, click on “Scheduling assistant” to view attendee availability.

You will see each person’s published availability to the left of their name, and text under their name will indicate if they are free during the selected time interval.

Select a time and click “Schedule”.

A meeting summary is displayed. You can edit the meeting if needed or click close.

As attendees accept your invitation, you will see their acceptance within your meeting.

To attend the meeting, click the “Join” button.

If you’ve invited individuals who work outside of Windstream, they can still use the “Join Microsoft Teams Meeting” link to join the meeting. They’ll be joining anonymously, and someone will have to let them join the meeting … but they’ll get there too.

Active Directory – Prevent Renaming and Moving OU

On my home domain, I’ve always added an access control entry to prevent this from happening … it’s really easy to double-click and be in rename mode or drag and drop an OU into a new location. I’ve always considered this to be a bit of paranoia on my part — not like anyone’s routinely screwing up entire OU’s.

Until they are. We’ve had significant two outages at work caused by unintentional changes to Active Directory organizational unit names. Partially to avoid wide-spread outages due to something that’s fundamentally silly and partially because any widespread outage requires a root cause analysis that includes some action you’ve taken to prevent whatever from happening again we’re going to implement the same permission tweak at work now.

Since it’s not just me who has wanted/needed this permission, figured I would publish how I’ve got the permissions set:

No idea why the GUI shows name and Name instead of rdn and CN respectively. But I’ve denied write for adminDisplayName, rdn, and cn.

Just like the “prevent accidental deletion” checkbox is a bit of a pain when you want to delete an OU, this is inconvenient if you want to rename or move OUs. The first step is to remove the permission, then you can make your change, and then you’ve got to re-apply the permission. Slight inconvenience, but having the entire company failing LDAP authentications (where the base DN no longer finds the users) is a massive inconvenience too.