I don’t normally write about a new version of the Microsoft Teams PowerShell module and confine myself to updating the post covering recent module updates. However, the release of a major version is worth comment, which is the case with V5.0 of the Teams module, now available from the PowerShell Gallery (Figure 1).
Figure 1: V5.0 of the Microsoft Teams PowerShell module
Over the past few releases, Microsoft concentrated on “modernizing” the policy management cmdlets that Teams inherited from the Skype for Business connector. Modernization is a term to describe updating the cmdlets to recent standards to make them more reliable and robust. The Get-CsOnlineUser cmdlet is the focus for the V5.0 release.
The Use of Get-CsOnlineUser
Get-CsOnlineUser fetches details of user accounts enabled for Teams. I only use this cmdlet when I need to view details of the Teams policies assigned to accounts as I prefer using the Get-MgUser cmdlet to retrieve information about user accounts. The Get-CsOnlineUser cmdlet can return details of the Teams service plans assigned to an account (like the MCO_VIRTUAL_APPT and TEAMS_WEBINAR service plans assigned to accounts with the Teams Premium license), but these are also retrievable with Get-MgUser.
In the past, Get-CsOnlineUser hasn’t been very performant or flexible when retrieving accounts. Microsoft says that they’ve improved performance, especially when using filters to find accounts. In addition, a set of new filterable properties are available (Alias, City, CompanyName, CompanyName, HostingProvider, UserValidationErrors, OnPremEnterpriseVoiceEnabled, OnPremHostingProvider, OnPremLineURI, OnPremSIPEnabled, SipAddress, SoftDeletionTimestamp, State, Street, TeamsOwnersPolicy, WhenChanged, WhenCreated, FeatureTypes, PreferredDataLocation, andLastName).
Changes to Filtering
Another improvement is in the support of filtering operators to bring the cmdlet in line with other cmdlets that fetch user information like Get-ExoMailbox. This is server-side filtering, meaning that the server only returns items that match the filter. It’s faster to retrieve data with a server-side filter than it is to fetch items and then apply a filter on the workstation (client-side filtering).
For instance, this use of the like operator now works:
Get-CsOnlineUser -Filter {City -like "*York*"} | Format-Table DisplayName, City
DisplayName City
----------- ----
Terry Hegarty New York
Previous versions of the module generate the error: Get-CsOnlineUser : The filter attribute ‘city’ is not supported.
Get-CsOnlineUser now supports use of the gt (greater than), lt (less than), and le (less than or equal to) operators to filter against string properties. For instance, this works:
Get-CsOnlineUser -Filter {DisplayName -gt "James"} | Sort-Object DisplayName | Format-Table DisplayName, City
DisplayName City
----------- ----
James Abrahams Foxrock
James Ryan Foxrock
Jane Sixsmith Dublin
The contains operator now supports properties that contain arrays. For instance, this command returns the set of accounts enabled for Teams:
My attempts to use the cmdlet to filter against the Teams Channel policy failed. I also saw inconsistent results when filtering against other policies. For instance, this returns no accounts:
Adding wildcards generates some results, but it’s hard to accept that a policy called “Advanced” has a name greater or equal to “B”:
Get-CsOnlineUser -Filter {TeamsMessagingPolicy -ge "*B*"} | Format-Table DisplayName, TeamsMessagingPolicy
DisplayName TeamsMessagingPolicy
----------- --------------------
Jane Sixsmith Advanced
Marc Vigneau Advanced
Interestingly, a client-side filter has problems too:
$Users = Get-CsOnlineUser | Where-Object {$_.TeamsMessagingPolicy -ge "B"} | Format-Table DisplayName
Where-Object : Cannot compare "Advanced" because it is not IComparable.
At line:1 char:29
I might be doing things in a way unanticipated by the Teams PowerShell developers, but I have been around PowerShell long enough to know when things don’t work quite the way they should. Some tweaks might still be necessary to make sure that filters work against all Teams policies in the same way.
Soft Deleted Users
Apart from the filtering changes, Get-CsOnlineUser now returns details of unlicensed users for 30 days after license removal and indicates soft-deleted users (accounts in the Azure AD recycle bin awaiting permanent removal) by showing the date and time of deletion in the SoftDeletionTimestamp property. You can find the soft-deleted users with:
Get-CsOnlineUser -Filter {SoftDeletionTimestamp -ne $Null} | Format-Table DisplayName, SoftDeletionTimestamp
DisplayName SoftDeletionTimestamp
----------- ---------------------
Ben James 04/03/2023 23:11:41
Work Still to Do
Get-CsOnlineUser is an important cmdlet used in many scripts to automate administrative processes. It’s good that Microsoft invested effort to make the Get-CsOnlineUser cmdlet work better, even if some issues still exist. Crack out the update procedure you use to refresh Microsoft 365 modules (or use my script, which handles Exchange Online, SharePoint Online, and the Microsoft Graph PowerShell SDK too) and upgrade to V5.0 of the Microsoft Teams module.
Support the work of the Office 365 for IT Pros team by subscribing to the Office 365 for IT Pros eBook. Your support pays for the time we need to track, analyze, and document the changing world of Microsoft 365 and Office 365.
{"id":null,"mode":"button","open_style":"in_modal","currency_code":"EUR","currency_symbol":"\u20ac","currency_type":"decimal","blank_flag_url":"https:\/\/office365itpros.com\/wp-content\/plugins\/tip-jar-wp\/\/assets\/images\/flags\/blank.gif","flag_sprite_url":"https:\/\/office365itpros.com\/wp-content\/plugins\/tip-jar-wp\/\/assets\/images\/flags\/flags.png","default_amount":100,"top_media_type":"featured_image","featured_image_url":"https:\/\/office365itpros.com\/wp-content\/uploads\/2022\/11\/cover-141x200.jpg","featured_embed":"","header_media":null,"file_download_attachment_data":null,"recurring_options_enabled":true,"recurring_options":{"never":{"selected":true,"after_output":"One time only"},"weekly":{"selected":false,"after_output":"Every week"},"monthly":{"selected":false,"after_output":"Every month"},"yearly":{"selected":false,"after_output":"Every year"}},"strings":{"current_user_email":"","current_user_name":"","link_text":"Virtual Tip Jar","complete_payment_button_error_text":"Check info and try again","payment_verb":"Pay","payment_request_label":"Office 365 for IT Pros","form_has_an_error":"Please check and fix the errors above","general_server_error":"Something isn't working right at the moment. Please try again.","form_title":"Office 365 for IT Pros","form_subtitle":null,"currency_search_text":"Country or Currency here","other_payment_option":"Other payment option","manage_payments_button_text":"Manage your payments","thank_you_message":"Thank you for supporting the work of Office 365 for IT Pros!","payment_confirmation_title":"Office 365 for IT Pros","receipt_title":"Your Receipt","print_receipt":"Print Receipt","email_receipt":"Email Receipt","email_receipt_sending":"Sending receipt...","email_receipt_success":"Email receipt successfully sent","email_receipt_failed":"Email receipt failed to send. Please try again.","receipt_payee":"Paid to","receipt_statement_descriptor":"This will show up on your statement as","receipt_date":"Date","receipt_transaction_id":"Transaction ID","receipt_transaction_amount":"Amount","refund_payer":"Refund from","login":"Log in to manage your payments","manage_payments":"Manage Payments","transactions_title":"Your Transactions","transaction_title":"Transaction Receipt","transaction_period":"Plan Period","arrangements_title":"Your Plans","arrangement_title":"Manage Plan","arrangement_details":"Plan Details","arrangement_id_title":"Plan ID","arrangement_payment_method_title":"Payment Method","arrangement_amount_title":"Plan Amount","arrangement_renewal_title":"Next renewal date","arrangement_action_cancel":"Cancel Plan","arrangement_action_cant_cancel":"Cancelling is currently not available.","arrangement_action_cancel_double":"Are you sure you'd like to cancel?","arrangement_cancelling":"Cancelling Plan...","arrangement_cancelled":"Plan Cancelled","arrangement_failed_to_cancel":"Failed to cancel plan","back_to_plans":"\u2190 Back to Plans","update_payment_method_verb":"Update","sca_auth_description":"Your have a pending renewal payment which requires authorization.","sca_auth_verb":"Authorize renewal payment","sca_authing_verb":"Authorizing payment","sca_authed_verb":"Payment successfully authorized!","sca_auth_failed":"Unable to authorize! Please try again.","login_button_text":"Log in","login_form_has_an_error":"Please check and fix the errors above","uppercase_search":"Search","lowercase_search":"search","uppercase_page":"Page","lowercase_page":"page","uppercase_items":"Items","lowercase_items":"items","uppercase_per":"Per","lowercase_per":"per","uppercase_of":"Of","lowercase_of":"of","back":"Back to plans","zip_code_placeholder":"Zip\/Postal Code","download_file_button_text":"Download File","input_field_instructions":{"tip_amount":{"placeholder_text":"How much would you like to tip?","initial":{"instruction_type":"normal","instruction_message":"How much would you like to tip? Choose any currency."},"empty":{"instruction_type":"error","instruction_message":"How much would you like to tip? Choose any currency."},"invalid_curency":{"instruction_type":"error","instruction_message":"Please choose a valid currency."}},"recurring":{"placeholder_text":"Recurring","initial":{"instruction_type":"normal","instruction_message":"How often would you like to give this?"},"success":{"instruction_type":"success","instruction_message":"How often would you like to give this?"},"empty":{"instruction_type":"error","instruction_message":"How often would you like to give this?"}},"name":{"placeholder_text":"Name on Credit Card","initial":{"instruction_type":"normal","instruction_message":"Enter the name on your card."},"success":{"instruction_type":"success","instruction_message":"Enter the name on your card."},"empty":{"instruction_type":"error","instruction_message":"Please enter the name on your card."}},"privacy_policy":{"terms_title":"Terms and conditions","terms_body":null,"terms_show_text":"View Terms","terms_hide_text":"Hide Terms","initial":{"instruction_type":"normal","instruction_message":"I agree to the terms."},"unchecked":{"instruction_type":"error","instruction_message":"Please agree to the terms."},"checked":{"instruction_type":"success","instruction_message":"I agree to the terms."}},"email":{"placeholder_text":"Your email address","initial":{"instruction_type":"normal","instruction_message":"Enter your email address"},"success":{"instruction_type":"success","instruction_message":"Enter your email address"},"blank":{"instruction_type":"error","instruction_message":"Enter your email address"},"not_an_email_address":{"instruction_type":"error","instruction_message":"Make sure you have entered a valid email address"}},"note_with_tip":{"placeholder_text":"Your note here...","initial":{"instruction_type":"normal","instruction_message":"Attach a note to your tip (optional)"},"empty":{"instruction_type":"normal","instruction_message":"Attach a note to your tip (optional)"},"not_empty_initial":{"instruction_type":"normal","instruction_message":"Attach a note to your tip (optional)"},"saving":{"instruction_type":"normal","instruction_message":"Saving note..."},"success":{"instruction_type":"success","instruction_message":"Note successfully saved!"},"error":{"instruction_type":"error","instruction_message":"Unable to save note note at this time. Please try again."}},"email_for_login_code":{"placeholder_text":"Your email address","initial":{"instruction_type":"normal","instruction_message":"Enter your email to log in."},"success":{"instruction_type":"success","instruction_message":"Enter your email to log in."},"blank":{"instruction_type":"error","instruction_message":"Enter your email to log in."},"empty":{"instruction_type":"error","instruction_message":"Enter your email to log in."}},"login_code":{"initial":{"instruction_type":"normal","instruction_message":"Check your email and enter the login code."},"success":{"instruction_type":"success","instruction_message":"Check your email and enter the login code."},"blank":{"instruction_type":"error","instruction_message":"Check your email and enter the login code."},"empty":{"instruction_type":"error","instruction_message":"Check your email and enter the login code."}},"stripe_all_in_one":{"initial":{"instruction_type":"normal","instruction_message":"Enter your credit card details here."},"empty":{"instruction_type":"error","instruction_message":"Enter your credit card details here."},"success":{"instruction_type":"normal","instruction_message":"Enter your credit card details here."},"invalid_number":{"instruction_type":"error","instruction_message":"The card number is not a valid credit card number."},"invalid_expiry_month":{"instruction_type":"error","instruction_message":"The card's expiration month is invalid."},"invalid_expiry_year":{"instruction_type":"error","instruction_message":"The card's expiration year is invalid."},"invalid_cvc":{"instruction_type":"error","instruction_message":"The card's security code is invalid."},"incorrect_number":{"instruction_type":"error","instruction_message":"The card number is incorrect."},"incomplete_number":{"instruction_type":"error","instruction_message":"The card number is incomplete."},"incomplete_cvc":{"instruction_type":"error","instruction_message":"The card's security code is incomplete."},"incomplete_expiry":{"instruction_type":"error","instruction_message":"The card's expiration date is incomplete."},"incomplete_zip":{"instruction_type":"error","instruction_message":"The card's zip code is incomplete."},"expired_card":{"instruction_type":"error","instruction_message":"The card has expired."},"incorrect_cvc":{"instruction_type":"error","instruction_message":"The card's security code is incorrect."},"incorrect_zip":{"instruction_type":"error","instruction_message":"The card's zip code failed validation."},"invalid_expiry_year_past":{"instruction_type":"error","instruction_message":"The card's expiration year is in the past"},"card_declined":{"instruction_type":"error","instruction_message":"The card was declined."},"missing":{"instruction_type":"error","instruction_message":"There is no card on a customer that is being charged."},"processing_error":{"instruction_type":"error","instruction_message":"An error occurred while processing the card."},"invalid_request_error":{"instruction_type":"error","instruction_message":"Unable to process this payment, please try again or use alternative method."},"invalid_sofort_country":{"instruction_type":"error","instruction_message":"The billing country is not accepted by SOFORT. Please try another country."}}}},"fetched_oembed_html":false}