Can’t Join Teams Meeting Online? Try This.

Did you create a meeting either through Outlook 365 or directly in Microsoft Teams and can’t join teams meeting online? You used the Teams Meeting Button in Outlook, or you checked the “Online Meeting” Check box in Teams, but you still can’t join?
If you already tried signing in and signing out or deleting your Teams’ cache, here is a hack to get it back.
When you create a meeting in Teams directly it is supposed to automatically have the online option. The join button in the meeting should show up when it gets close to the meeting time. In fact, the only way at this point where it won’t be online is if you use a version of Outlook that doesn’t support the Microsoft Teams Meeting.
You Invite the others in the meeting, and they get the meeting info like this:

But the meeting you created in your calendar does not have the Join Button like what you see below:

If this happens to you there are two ways to Join Online.
Right Click on the Meeting
You can right click on the meeting and choose the “Join Online” option:

Still Can’t Join Teams Meeting Online? Refresh.
It is a hack, but it works.
- Open the meeting in Teams.
- Invite someone to the meeting.
- Remove them from the meeting.
Now, when you right click on the meeting. The “Join Online” Option is there. This refreshed the meeting details and brought the Join Online back!
The good news is at least you can fix the meeting and do not have to call the HelpDesk!
Happy IT’ing,
Dan
Adding a Number to a Teams User

So your organization has decided to do away with their phone system an go directly to Microsoft Teams Voice. Now all that is left to do is Adding a Number to a Teams User. The only prerequisite is that you have a block of DID assigned to you by your Telco.
If you don’t have many users to add telephone numbers to, you can manually enter them using some PowerShell commands. However, if you have a lot to do I can show you a way to automate them. Let’s add some numbers!!
You Only Have a Few Users To Do
This is also a good way for adding the odd number after the migration.
Connecting to the Teams Module
Connect-MicrosoftTeams
Add User Number
Set-CsPhoneNumberAssignment -Identity [email protected] -PhoneNumber ‘+1XXXXXXX’ -PhoneNumberType DirectRouting
Grant-CsOnlineVoiceRoutingPolicy -Identity [email protected] -PolicyName “Policy set up by you or Telco”
Set-CsOnlineVoiceMailUserSettings -Identity [email protected] -VoicemailEnabled $true
If you make a mistake you can easily remove the number and start again:
Remove User Number
Grant-CsOnlineVoiceRoutingPolicy -Identity [email protected] -PolicyName $null
Remove-CsPhoneNumberAssignment -Identity [email protected] -RemoveAll
But what if you have a lot of users to to???
You Have a Many Users To Do
You can run these commands in a batch but I would recommend testing it with a small block of users before you go ahead with the whole group. You could run a batch delete and start from scratch but that sounds like a headache….
You can use a for each loop going through each user in an import CSV you created. Create a CSV file with two field names: UPName and PNumber. Populate it with your users and then create this PowerShelScript:
$CSVPath = “<Path To File Goes Here>”
Connect-MicrosoftTeams
#MAIN
#Try import CSV file
try {
$Users = import-csv $CSVPath -ErrorAction stop
}
catch {
throw “Error importing CSV: $($_.Exception.Message)”
break
}
#Add Numbers
foreach ($User in $Users) {
Set-CsPhoneNumberAssignment -Identity $User.UPName -PhoneNumber $User.PNmuber -PhoneNumberType DirectRouting
Grant-CsOnlineVoiceRoutingPolicy -Identity $User.UPName -PolicyName “PolicyNameGoesHere”
Set-CsOnlineVoiceMailUserSettings -Identity $User.UPName -VoicemailEnabled $true
}
Write-Host User Numbers Added!
This should help you get your phone numbers added quickly.
Happy IT’ing
Dan
Delete Tap Scheduler Reservations With This One Trick
Don’t you wish you could Delete Tap Scheduler Reservations when a user makes them by mistake or realizes they don’t need the reservation anymore? It is fairly straight forward.
Making a Reservation Using The Logitech Tap Scheduler
The Logitech Tap Scheduler is a useful display board device that shows the status of a resource room in your organization. It has the ability to work with several calendaring systems (Teams, Zoom, Meetio and Robin). You can set up a system where a user can easily reserve a meeting room through a shared resource calendar or ad hoc right at the device. But what if you reserve a the room on the fly and realize you don’t need it?
How to Delete Tap Scheduler Reservations
Unfortunately there is no way to delete on the device itself. I researched high and low and even reached out to Logitech support. They agreed that the way I chose was the best way. For the future, they put a feature request with Microsoft Teams since that is the Calendar provider I use.
The best way is to make a member(s) of your support staff have at least Editor rights to the resource calendar that is connected to the Tap Scheduler. Have you users put in a request to delete it. Then your HelpDesk Staff can go to the calendar in question and delete the reservation and it frees up the room.
You can use PowerShell to quickly execute this task but it is just as easy to open the shared calendar and delete the reservation!
Happy IT’ing
Dan
Reclaim O365 Licenses From Deleted Users

O365 admin is funny. There a lot of things that you do a certain way if you came from an on premise environment. You don’t think about it (Like disabling a user). Well you have now moved into a hybrid environment and hopefully soon and all cloud environment. You need to Reclaim O365 Licenses.
Why do you need to start thinking about licensing when you disable / delete a user. If you don’t, you will need to reclaim O365 Licenses From Deleted Users. After awhile it might get expensive. Recycle the licenses as much as you can! Here I will show you how to quickly do this in a cloud environment and what steps you need to do differently in a Hybrid environment.
How to Reclaim O365 Licenses From Deleted Users in a Cloud Environment
This can be done very easily using power shell. A disabled used in strictly the cloud is deleted. You can go into the admin panel of O365 (now it’s called Entra??) and go into “Delete Users”. Pick the user with the license you want to recover and click “Restore User”. From there you can uncheck the license and then delete the user again….or…you can use PowerShell for if you need to reclaim more licenses.
Using PowerShell
Here is a great script that will help you with what I mentioned above especially if you have several users to go through (This is similar to the one I wrote on MFA):
#Connects to your Office365 tenant
#Connect-MsolService
#MAIN
$delUsers = Get-MsolUser -ReturnDeletedUsers | select UserPrincipalName,IsLicensed | Where-Object {$_.IsLicensed -eq $true} | export-csv c:\Temp\IsLisc.csv
$delUsers| foreach{
$UPN = $_.UserPrincipalName
Restore-MsolUser -UserPrincipalName $UPN
(get-MsolUser -UserPrincipalName $UPN).licenses.AccountSkuId |
foreach{
$License = $_
echo “Removing license: $License”
Set-MsolUserLicense -UserPrincipalName $UPN -RemoveLicenses $License -ErrorAction SilentlyContinue
}
Remove-MsolUser -UserPrincipalName $UPN -Force
}
#showing list again for verification
Write-Host Show list of deleted users so you can verify that there are no outstanding licenses. List should all be false
$delUsers = Get-MsolUser -ReturnDeletedUsers | select UserPrincipalName,IsLicensed | Where-Object {$_.IsLicensed -eq $false}
Return $delUsers
In a nutshell, this script connect to the MSOLservice, writes all delete users who are still licensed to a CSV file (located in C:\Temp – you can change this to whatever folder you want). Restores the user in the list, removes all the the licenses attributed to it and then deletes it again.
It is a little different in a hybrid situation.
How to Reclaim O365 Licenses From Deleted Users in a Hybrid Environment
You will need to go into AD and find all the disabled users and re-enabled them. Then either wait for an AD sync or perform a sync with a Start-ADSyncSyncCycle -PolicyType Delta on a domain controller. Then rerun the script minus the lines about deleting the users:
#Connects to your Office365 tenant
#Connect-MsolService
#MAIN
$delUsers = Get-MsolUser -ReturnDeletedUsers | select UserPrincipalName,IsLicensed | Where-Object {$_.IsLicensed -eq $true} | export-csv c:\Temp\IsLisc.csv
$delUsers| foreach{
$UPN = $_.UserPrincipalName
Restore-MsolUser -UserPrincipalName $UPN
(get-MsolUser -UserPrincipalName $UPN).licenses.AccountSkuId |
}
Go back to AD and disable the users again. That should do it.
Happy IT’ing
Dan
The Best Way To Automate and Email in PowerShell

PowerShell is great for automating many tasks. You might get the results of those tasks quickly or they could take awhile. Wouldn’t it be nice to run the script and walk away knowing that when it has finished it will notify you or send the results of the task by email (even with attachments).
The following is the best way to Automate and Email in PowerShell. You might want to read a newer article about this. It is more secure.
Automate and Email in PowerShell Using Send-MailMessage
The task could be anything. The point is that you can take the results and email them using the Send-MailMessage command. It is not recommend for use anymore as it is considered obsolete, however I am sure there are a lot of scripts out there that still use it. With Microsoft disabling the use of basic authentication for email it would make this command more difficult to use but it is not impossible.
If you are familiar with Microsoft Graph, it is possible to tweak your script to use modern authentication. My example will show you how to send out through an authorized network that makes use of a mail connector in O365 which helps legacy devices and applications that cannot send mail with Modern Authentication. I will circle back shortly in another article and show this example again using MS Graph to help send using modern auth. In the meantime if you can use another SMTP server (like Gmail) to send your mail in this script, that would be great.
Automate and Email in PowerShell Example
In this example I am taking screencaps at intervals I specify and then emailing them to myself when it is done:
#counter for Loop
$cnt = 1
#number of screenshots you want to take
$tot = 2
#number of seconds you want to wait between screenshots
$wait = 2
#Number of Attachments Left to Screen Cap
$left = 0
#Attachment List
$att = “”
#filepath array
$filepath = @()
While ($cnt-ne $tot+1)
{
#Capture Screenshot
$File = “C:\Temp\Screenshot”+$cnt+”.bmp”
Add-Type -AssemblyName System.Windows.Forms
Add-type -AssemblyName System.Drawing
#Gather Screen resolution information
$Screen = [System.Windows.Forms.SystemInformation]::VirtualScreen
$Width = $Screen.Width
$Height = $Screen.Height
$Left = $Screen.Left
$Top = $Screen.Top
#Create bitmap using the top-left and bottom-right bounds
$bitmap = New-Object System.Drawing.Bitmap $Width, $Height
#Create Graphics object
$graphic = [System.Drawing.Graphics]::FromImage($bitmap)
#Capture screen
$graphic.CopyFromScreen($Left, $Top, 0, 0, $bitmap.Size)
#Save to file
$bitmap.Save($File)
Write-Output “Screenshot saved to:”
Write-Output $File
$left = $tot – $cnt
$att = $File
$filepath += $att
Write-Host Will wait $wait seconds before next screenshot….
Write-Host There are $left to go…
Start-Sleep -seconds $wait
$cnt++
}
Write-Host $filepath
Send-MailMessage -From [email protected] -To [email protected] -Subject ‘Screenshots’ -Body ‘See Attached’ -Attachments $filepath -SmtpServer yoursmtpserver.com -Port 587
Write-Host All Done
Explanation Of The Script
First, the script sets all the counters at the users preference (the counter for the loop, how many screenshots you want to take and how many seconds between screenshots)
All that is left is to provide credentials for the SMTP Server , capture the screenshots and then send the email with the prescribed attachments. Automation at it’s best.
Happy IT’ing
Dan
Automatically Carbon Copy in EAC

I am sure your organization has a lot of automated process in place for its workflow. Most organizations have this set up to get things done more efficiently. However, some parts of this flow are still somewhat manual. For example, remembering to send an email after a process is completed. If it is not built in to the process, why not Automatically Carbon Copy in EAC?
A good option for an individual is to use Microsoft Flow for automation. But what if this process needs to be done by a department or the entire organization? If it is simple enough, it can be set at the server level using Exchange Online Mail Flow Rules. I will show you how…..
What Mail Flow Do You Need To Automate?
What process are you trying to automate? I will give an example. You have a department that either manually or through a system sends an email notification to [email protected]. They have been instructed to CC (Carbon Copy) [email protected] every time they do so. That’s fine but what if they forget? What if the system cannot accommodate this request. You can set up a Mail Flow Rule.
How to Set Up Automatically Carbon Copy in EAC
- First, go to your EAC (https://admin.exchange.microsoft.com/#/transportrules) and click add a rule / create a new rule.
- The Rule should look like the following:

When this rule is Saved and then Enabled (Don’t forget to enabled the rule after you have created it). Any email send to Company A will have Company B CC’ed on it. This is great for email addresses that serve one purpose like receiving reports. Maybe another company you work with closely with needs these reports too and you do not have to remember to CC them anymore. It is all done automatically!
Happy IT’ing
Dan
Trapping Errors in MS Graph

I was tasked with automating how Outlook contacts are written to a users profile using Microsoft Graph. I wrote about how to do it in my situation here. However, my last task was to accomplish this but with a much larger contact list. This required trapping errors in MS Graph. I will show you the behavior of the MS Graph Rest API when it writes many records.
Possible Errors You Will Get
Microsoft clearly outlines what errors you could get while writing / reading data. In my case the ones I came across were the following: 400, 401,503 and 429
400 – Bad Request – This will happen when the command your are sending or the data you are trying to write are malformed.
A “reading “example is when you have constructed a command in PowerShell that using the $ and ? characters together. It works find in Graph explorer but errors in PowerShell. Using an escape character between the two symbols remedies this ($`?).
A “writing example” is when you have data in a format (a cell in a CSV) that can not be read by the command so it errors out with a 400. When you are writing thousands of records it might be hard to check for format beforehand.
401 – Unauthorized – You would think a token for a session would last for the entire time your are issueing commands in a PowerShell session but it doesn’t. I have learned it lasts about 1 hour.
429 – Too Many Requests – if you issue too many reads or writes in an allotted period of time, Microsoft will throttle you. It is best to wait before you write again. If you keep trying , you will keep getting throttled. Even though I was issuing several writes in a 10 minute period, it wasn’t enough to trigger this error but it is still a consideration.
503 – Service Unavailable – This is mostly to do with network traffic. I am sure the service actually is not down. MS has built enough redundancy in their infrastructure to take care of this. It is like being in a very bad rain storm. Just pull over and wait a few minutes. Then you can start up again.
Trapping these errors will allow you to start up again. I will show you how.
Trapping the Errors
For this section it is good to download the sample script I provided in a previous article and tweak it as necessary.
How to you trap the errors? The part of your script that writes the records needs two things. One, a while loop that counts the records that goes through each record and knows exactly what record number it is (sorry, a for each x in x’s loop won’t do the trick here) and a try / catch block to handle the error.
$Results = “”
$Script:StatusCode = “”
While ($script:x-lt $tot) {
try {
$NewContact = ImportContact -Mailbox $mailbox -token $token -contact $contacts
$Script:StatusCode = $Results.StatusCode
} catch {
$Script:StatusCode = $_.Exception.Response.StatusCode.value__
$script:x = $script:x – 1
Write-Host Error processing contact. Backing up and trying again in 30 seconds…
Start-Sleep -seconds 30
#Login again
#Get Graph Token
Try {
$Token = GetGraphToken -ClientSecret $ClientSecret -ClientID $ClientID -TenantID $TenantID
}
catch {
throw “Error obtaining Token”
break
}
}
$script:x++
}
You can get a little more granular by specifying what to do with each exact error I mentioned about with an if statement inside the catch block but since I know exactly what errors I am going to get I left it general.
What this code accomplishes is it goes through each record and writes it to the users contact folder. If it encounters an error a long the way, it waits 30 seconds, tries the record that failed again and if successful, keeps writing records until it encounters an error again (hopefully not) and starts the process over again.
I have tested this several times with a contact list of thousands of records. and it works like a charm. One test showed three errors but every single record was written.
Happy IT’ing
Dan