Office

Streamdeck is now finally working with Teams

Screenshot of Elgato's Streamdeck buttons showing microphone, blur plugins and camera view

TLDR – set the api key whilst having a meeting with yourself

I was fortunate to get a Streamdeck for a birthday present back in March this year – the announcement that it was integrated into Teams was the final push to get one. I had been debating whether to get one or not and had been using TouchPortal as a software solution running on an old Kindle as test bed for quite some time to see how much I would use this functionality. The answer is a lot!

(Very) Shortly after getting the device and setting it up, the Teams plugin was pulled from the store but eventually re-released and it has never worked since. If I was lucky it would intermittently work for 5 minutes or even 20 if there was a blue moon, I was wearing my lucky jumper and there was a z in the day’s name.

Other people have also had the same problem and there has been a long thread on the elgato subreddit about the issue with various solutions provided but none of them have worked for me, at least on a consistent basis.

However a post yesterday on the Microsoft community forums had someone getting the plugin working with the new Teams version. I followed the steps and the issue was still not working for me – however it did give me a clue.

This morning I confirmed that the WebSocket was listening on port 8124 with netstat -aon | find “8124” and was fiddling around trying to get the plugin to work. I had already confirmed the api key (found from Settings/Privacy in Teams and pasted it into the plugin settings and was still getting the lock icons, but this morning I selected the calendar, “Meet now” option and started a meeting with myself. (It was very early and there was no one else to call!)

After the meeting was established, I opened the plugin and re-entered the api key in the button settings and this time the setting worked, all of my buttons had the padlock overlay removed.

Fearing the worst, I killed the meeting, restarted Teams and Stream Deck, and all the buttons are still working. Being the optimist, I then rebooted the computer, restarted Teams and Stream Deck and the buttons still work. 2 hours later and the buttons are *still* working.

For those interested, the TL, TR, BL, BR refer to the monitors attached to the desktop computer and enable me to quickly switch the OBS camera to the relevant monitor. Using the classic Teams app allows me to share a video feed from a camera so all I have to do is share the one video stream and let OBS and Streamdeck take care of everything else. Unfortunately, the New Teams does not have this functionality and the OBS output screen needs to be shared which requires way more key presses to setup and the OBS output running on one of the monitors, so until this shows up in the New Teams application, it’s Teams Classic for me.

Using Microsoft Graph Update-MgGroup with Certificate Based Authentication as a working alternative for Set-UnifiedGroup

Yesterday I had a fun time converting a PowerShell script that used the set-unifiedgroup powershell command that was originally running with basic authentication, to a script that would run using certificate based authentication so it can run against a tenant that uses Modern Authentication for office365.

There were quite a few hurdles to overcome so hopefully this helps other people.

Step 1 – Fix Office365 logins

Blank browser page that loads when attempting to log into Office365

The computer was initially generating a blank white page on the screen when attempting to log into the Office365 or Azure portal. This was resolved by resetting the browser settings in Control Panel / Internet Options. Clearing cookies and temporary internet files did not help for this step.

Step2 – Connect to Office365.

The ExchangeOnline module was already installed on the computer, but needed to be updated with

 update-Module -Name ExchangeOnlineManagement

The rest of this phase reduced the previous 5+ lines of code to log into Office365 to a one liner. There are quite a few steps involved in this, but App-only authentication in Exchange Online PowerShell and Security & Compliance PowerShell | Microsoft Learn is a good document to follow. Make sure that the SSL certificate is documented somewhere so that you get a reminder *before* the certificate expires. Once the certificate is uploaded to Azure and permissions are set it is possible to connect with

connect-exchangeonline -CertificateThumbprint "1a2b3c4d5e6f....." -appid "123abc-456def...." -organization "companyname.onmicrosoft.com"

Initially I thought that would be it, but after running the script I discovered the next big snag –

Step3 – Converting set-unifiedgroup to MS Graph module equivalent

The script gathered a list of Microsoft 365 distribution groups (or UnifiedGroups) in Office365 that had their access level not set to private and changed them to be private. The previous code was this

Get-UnifiedGroup -ResultSize Unlimited | Where-Object { $_.primarySmtpAddress -match 'companyname.onmicrosoft.com' -and $_.accesstype -ne 'Private' -and $_.HiddenFromAddressListsEnabled -ne 'true' } | Set-UnifiedGroup -AccessType Private -HiddenFromAddressListsEnabled $true -verbose

However, set-unifiedgroup is one of a few commands that cannot be used with Certificate Based Authentication and the msgraph module has to be used instead. The Microsoft documentation points this out but does not provide helpful information on how to actually get this accomplished. The linked information refers to api calls rather than using actual Microsoft Graph PowerShell commands and there were several gotchas in this process (hence this blog post).

First the Microsoft graph module needs to be installed on the computer with

Install-Module Microsoft.Graph

Step3a – Importing Microsoft.Graph.Groups

When importing the Microsoft.Graph module on the machine into PowerShell , not only did it take over 10 minutes to import, an error message is generated stating

Import-Module : Function Get-MgUserContactFolderChildFolderContactMultiValueExtendedProperty cannot be created because<br>function capacity 4096 has been exceeded for this scope.
Screenshot error stating Import-Module : Function Get-MgUserContactFolderChildFolderContactMultiValueExtendedProperty cannot be created because
function capacity 4096 has been exceeded for this scope.

This is due to the sheer number of commands available in the module and PowerShell 5.1 has a limit to the number of commands that can be used. Using PowerShell 7 is one way of fixing that issue but I was trying to reduce the amount of changes being made to this pc. By importing a subsection of the module with import-module microsoft.graph.groups the number of commands that are available is greatly reduced and the import is also a lot quicker. 10 seconds to run instead of over 10 minutes from above.

Step3b – Filter left

The original search returned all groups in Office365 and then filtered them locally. In this large organization, there are a significant number of groups returned and the lookup took several minutes to run. By passing a filter parameter I was able to reduce the number of groups significantly.

Unfortunately the filter parameter does not support accesstype or the primarysmtpaddress so these have to be filtered out by piping the groups to a select-object statement.

Get-UnifiedGroup -ResultSize Unlimited | Where-Object { $_.primarySmtpAddress -match 'companyname.onmicrosoft.com' -and $_.accesstype -ne 'Private' -and $_.HiddenFromAddressListsEnabled -ne 'true' }

becomes

$groups=get-unifiedgroup -filter {(hiddenfromaddresslistsenabled -ne $true)} | where-object {$_.primarysmtpaddress -match 'companyname.onmicrosoft.com' -and $_.accesstype -ne 'Private'} 

After making this change, the groups were returned in less than a minute.

Step3c – Changing from set-unifiedgroup to Update-MgGroup

The new command to modify the group is update-mggroup but the standard command does not have the ability to change the access type as per the documentation at Update-MgGroup (Microsoft.Graph.Groups) | Microsoft Learn

Screenshot for the update-MgGroup command that is missing the AccessType parameter

However, after switching the document to the Beta version of the api in the dropdown menu on the left, the accesstype parameter becomes available. The above screenshot shows AccessType is missing vs the screenshot below that includes this option.

Screenshot of the update-MgGroup beta command that includes the AccessType parameter

We therefore end up with the following commands to set the profile to Beta, load the Microsft.Graph.Groups subset of the module and then connect to Microsoft. Graph

Select-MgProfile -Name "beta"
import-module microsoft.graph.groups
connect-mggraph -clientid "1a2b3c4d5e-1234-1a2c3-a1aa-aa12b3456c7d" -tenantid companyname.onmicrosoft.com -certificatethumbprint "0a4f....fe"

I had issues with the next bit of code and ended up using my Exchange online connections to retrieve the groups that matched the criteria of not being hidden from the address list and where the access type was not private, and then using the ExternalDirectoryObjectID from those groups in the update-mggroup command from the graph module.

In theory I should have been able to search using the get-mggroup command but I was having issues getting the filters and search to work correctly. I could not get any results to come back for searches that included the companyname.onmicrosoft.com email address. As soon as I added that to the criteria the results came back empty. Due to time constraints I used the (admittedly) messy option of using Exchange to grab the groups and graph to update them.

$groups=get-unifiedgroup -filter {(hiddenfromaddresslistsenabled -ne $true)} | where-object {$_.primarysmtpaddress -match ‘companyname.onmicrosoft.com’ -and $_.accesstype -ne ‘Private’}

foreach ($group in $groups) {
update-mggroup -groupid $group.ExternalDirectoryObjectId -accesstype "Private" -HideFromAddressLists
}

Finally, the script was completed by disconnecting the Graph and the Exchange connections

get-pssession | Remove-PSSession
Disconnect-MgGraph
Stop-Transcript

Using the transcript option at the beginning of the script really helped in debugging this code as it’s meant to run from a scheduled task and viewing the transcript enabled me to see what the issue was and then decide to test further in an interactive session.

Fixed: NPS using Azure AD not prompting for 2 factor on phone

Screenshot of Yubico numbers for 2FA verification

We were recently came across an issue with configuring the NPS (Network Policy Server) to use Azure AD’s 2FA authorization to validate VPN access to one of our clients. The initial configuration was fairly straightforward with the instructions at https://docs.microsoft.com/en-us/azure/active-directory/authentication/howto-mfa-nps-extension but after connecting to the VPN server, we were not getting the push notification to our phone for the final verification steps.

Going through the Network Policy Server logs in event viewer we saw an error message as follows ” NPS Extension for Azure MFA: CID: 341b704d-03f1-4ba6-ae92-eb19ae2f2bf3 :Exception in Authentication Ext for User myusername :: ErrorCode:: CID :341b704d-03f1-4ba6-ae92-eb19ae2f2bf3 ESTS_TOKEN_ERROR Msg:: Verify the client certificate is properly enrolled in Azure against your tenant and the server can access URL in Registry STS_URL. Error authenticating to eSTS: ErrorCode:: ESTS_TOKEN_ERROR Msg:: Error in retreiving token details from request handle: -895352831 AADSTS7000112: Application ‘981f26a1-7f43-403b-a875-f8b09b8cd720′(Azure Multi-Factor Auth Client) is disabled. “

The key was the last line – Azure Multi Factor Auth Client is disabled. Despite the fact that 2FA was already in use to verify access to the Office365 portal and desktop apps, it seems that the client was not enabled in Office365.

This was fixed by running the following in a powershell window connected to Azure AD..

Set-MsolServicePrincipal -AppPrincipalId “981f26a1-7f43-403b-a875-f8b09b8cd720” -AccountEnabled $True
Set-MsolServicePrincipal -AppPrincipalId “1f5530b3-261a-47a9-b357-ded261e17918” -AccountEnabled $True

This then enabled 2FA to work with NPS. I put in a PR request to the official documentation to have this as an official troubleshooting step but the PR was closed. Hopefully this post and the PR will help others in their configuration as it did seem to be a fairly common problem.

Fixed: Failed_To_Auto_Discover_Domain error shows up when trying to administer Microsoft Teams in Office365

A week or so ago I was trying to administer a new Office365 Tenant in preparation for an Office365 migration. Part of the process is to configure the various services to reduce the security risk due to unauthorised sharing of files etc.

Attempting to log into the Teams admin interface gave me the worst error message of “Something has happened” when clicking on the Teams admin link as per the screenshot below. Not only is the Error devoid of anything useful but it’s inaccurate as actually *Nothing* has happened.Something has happened.  Failed_to_Auto_Discover_Domain. Error message when trying to administer Teams without a licence

The error code FAILED_TO_AUTO_DISCOVER_DOMAIN was misleading – it has nothing to do with the autodiscover record.

It turns out that the admin interface for Teams only works if you have at least one user with a Teams licence.  I didn’t have any as this was a new Tenant and the only users in the system are currently Global Admins that don’t have any licences assigned to them.  Once a licence was applied and 5 minutes had gone by (with a successful Teams login) I was then able to login and make the required settings.

 

Office365 Exchange Control Panel now has command logging for admins.

Help Button, Show command logging.One of my annoyances with Office365 administration tasks was that I could make changes to the interface but had no idea what commands were being run behind the scenes. This made creating scripts a frustrating trial and error attempt at finding the correct verbs to run.
However, this morning I stumbled under the Help/Show Command Logging option in the admin panel. This is similar to the Show command output that was available in the Exchange 2010 admin console that I used extensively in the good old on-premise days.

I have no idea how long this has been here but it really made my day.

Now if only the rest of the Office365 admin panels had the same functionality.

Retrieve Mailbox Migration errors for Office365

When you have a lot of mailboxes to migrate, Microsoft’s provided method of viewing the errors involves a tedious amount of clicking by logging into the portal, selecting Exchange, Migration, View details, scroll down to find a failure, select the user, click view details.

Viewing Migration status in Office365

 

Rather than use the tedious method of going into the details, selecting a user and then viewing details, run the following powershell script (once connected using the previous office365 connection script)

get-migrationuser -status failed  | get-migrationuserstatistics | select identity,emailaddress,recipienttype, error,bytestransferred |export-csv c:\temp\migrationstatus.csv

I also have a simple loop that gets me the status once an hour. Obviously change the email address’s appropriately.

while (1)
{
$a=(get-migrationuser | out-string)
send-mailmessage -to [email protected] -subject “Company Migration Stats” -from [email protected] -smtpserver my.mailserver.com  -body $a
start-sleep -seconds 3600
}

Fixed – Office365 journalling does not work for one user

I’ve been working on a case with Microsoft’s Office365 support for several weeks trying to find out why email sent *to* a particular user was not being journalled. All the other mail seemed to be journalled to the external recipient, email from the user was working, just not email to that user.

The experience was quite frustrating as Microsoft’s support were terrible at calling back and could not grasp the concept of email tracking. Their solution after making a change was to wait a day to see if it was fixed although it was quite apparent that the Microsoft servers were not even trying to send the email (by looking at the Trace Logs you can see what email was being sent and received).

After checking the connectors were setup, mail properly scoped, the user had no rules on their mailbox, Microsoft’s solution was to delete the mailbox and reset it up again.  Not so easy when the mailbox/user is federated with Active Directory and the user happens to be the owner of the company. That was not a conversation I was going to have with them!

The only thing that was different with this user was that in troubleshooting this issue we had set the user up to receive the journalling non delivery reports. I figured that if the emails were not being delivered, maybe sending him the errors would help. However no reports were being received either.  However, according to KB 2829319 this behaviour can be seen. Although I had removed the journal receipient in the web gui, the emails were still not being journalled until I added another external email address to the configuration using the powershell command set-transportconfig -JournalingReportNdrTo [email protected]

At this point, all the email started to be journalled.

Note that we only added the recipient into the mix when I was trying to work on the initial problem so it looks like this wasn’t the only fix.

The other thing we did was change the outboundconnector to be onpremises. Changing the setting in the GUI we then ran Set-OutboundConnector archivemymailconnector -routeAllmessagesviaonpremises $true.

 

These two combinations seemed to fix the issue.

One thing I also learnt was that it is really useful to send multiple emails between changes and keep the subject line starting the same. Use the date/time at the end of the email. That way you can sort the email logs by Subject and just pick out the ones you were working on. By having the subject start with zzz followed by Round X (ie zzz Round 1 – change connector – 1345pm and zzz Round 1 – change connector 1346pm ) then the results are likely to appear at the end of your mail logs if you sort by subject.  Sorting by Date was not always a good idea as mail flow could occur between mail coming into the server and mail leaving the server.

 

Fixed: Office 2010 installation with MAK key gives Error: Can’t decode PIDKey – Invalid digits! ErrorCode: 0(0x0)

After doing an administrative installation of Office Professional Plus 2010 for a client, I was trying to test the installation of office on a desktop machine but kept getting “Error: Can’t decode PIDKey – Invalid digits! ErrorCode: 0(0x0).” as the error message. I confirmed that the key was correct by doing a manual installation of the software and using the same product key that was successful. I was unable to find any useful pages on the internet with this error message so ended up logging a call with Microsoft Product Support to troubleshoot the installation.

Our troubleshooting steps were to remove the updates folder completely and try an installation – this worked so we knew the problem was in the updates directory. Recopying back the files from the extracted service pack 1 dvd worked successfully so the problem was either service pack 2 or the setup.msp file. I copied back the sp2 files and again the software installed successfully (note that having a virtual test pc makes these tests very easy. No uninstalling of office required!)  Again the installation was successful. I then copied the setup.msp file back into the updates directory and the installation failed again. As the configurations that are made in the setup.msp can either be set in the config.xml or group policy it was ok to proceed without using the setup.msp.

Full details of the log files and more information can also be found at the Microsoft forums where I posted the initial request for help.

Retrieve user friendly list of users who have full access to a particular mailbox in Office365

We had a request to provide a list of users who have Full access to a mailbox in Office 365. The get-mailboxpermission is pretty straightforward, but the results show the Windows username as opposed to the descriptive name for the user. The following script should provide the information needed. Note that the first 3 lines connect to Microsoft Online (you will be prompted for username and password) – the last two are the magic ones. Replace “User name” with the users first and last name ie “Andy Helsby” in my case

$LiveCred = Get-Credential
$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://ps.outlook.com/powershell/ -Credential $LiveCred -Authentication Basic -AllowRedirection
Import-PSSession $Session

$userlist = Get-Mailbox "user name" | Get-MailboxPermission | Where-Object { ($_.AccessRights -eq "Fullaccess") -and ($_.IsInherited -eq $false) -and -not ($_.User -like "*nt authorityself*") }
$userlist | foreach {get-mailbox $_.user}

If I can work it out, I’ll update the script later to provide a report for all mailboxes – in the meantime this works for 1 mailbox at a time.

Funnily enough, this report didn’t actually help the reason we were asked for the report – that was because the user had issues connecting to someone else’s mailbox. It turns out that the Microsoft Online password had been changed and outlook was using the cached credentials. By removing the stored passwords in the control panel, Outlook prompted for the password and everything started working.

Office 2010 almost here…

I’m running the Office2010 beta at home (mainly for Outlook and OneNote2010)  and would highly recommend it when it is finally released. If you are running Exchange2010 then there are even more reasons why you should be running Outlook2010. (Note that a lot of the extra features such as mailtips and access to the archive mailbox are already available with the outlook web access app). If you purchase and activate Office 2007 between now and Sept 30 2010, you will be able to upgrade to 2010 via a free download. You will need a LiveID, the receipt and to register your purchase. More details available at the Office2010 Technology guarantee website.