Teams Bulk Policy Assignment to Large Numbers of Accounts Using Background Jobs
In yesterday’s post about disabling chat for Teams users, the conclusion was that assigning a messaging policy to users is the best approach. As explained in the post, it’s easy to create a policy. All the pain comes in assigning the policy to users, especially when this must be done for hundreds or even thousands of users.
Assigning a messaging policy to a single user is easy. Select the user in the Teams admin center, edit the policies assigned to their account, and make sure that the assigned messaging policy is the one which disables chat (Figure 1).
Figure 1: Assigning a no-chat messaging policy to a Teams user
Using PowerShell to Assign a Messaging Policy
The same can be done with PowerShell using the Grant-CsTeamsMessagingPolicy cmdlet. This is loaded using the Skype for Business Online module (and soon, the Teams module). Here’s an example of assigning a messaging policy to a user:
Grant-CsTeamsMessagingPolicy -PolicyName "Restricted - No Chat" -Identity James.Joyce@office365itpros.com
Assigning Policies to Multiple Teams Users
The problem is how best to assign a policy to multiple Teams users. You could write a script to loop through a set of users and assign the policy with Grant-CsTeamsMessagingPolicy, but it’s easier to do this with a bulk (or batch) policy assignment, which runs a background job to assign a policy to multiple users.
Find the Target Users
The first thing to do is to determine the users we wish to assign the policy to. One way to approach the problem is to output a list of users to a CSV file, have someone edit the file to remove the accounts who should not be assigned the policy, and then use the edited CSV as the input for a bulk assignment of the messaging policy.
To create the CSV, run the Get-ExoMailbox cmdlet to fetch details of all mailboxes and then export the output to a CSV:
The CSV looks like the file shown in Figure 2. You should remove the entries for users who are not to be assigned the messaging policy and save the file.
Figure 2: Editing a CSV file to use as input for a Teams bulk policy assignment job
Up to 5,000 accounts can be processed in a bulk policy assignment job, so if you have more than this number, you’ll need to split the accounts across several files.
Submit a Teams Bulk Policy Assignment Job
To submit the job, we read the CSV file data into a list variable and process it to extract just the user principal names, which is what’s expected as input for a bulk assignment job.
Then call the New-CsBatchPolicyAssignmentOperation cmdlet to associate the policy we want to assign with the set of target users. Make sure that you’re signed into PowerShell with an account that has the Teams administrator role or global administrator role. A successful submission results in a GUID to identify the batch job.
It is normal that a little while elapses before the batch processor begins working on a job. Eventually, the job will start, and the policy assignments will happen. You can then find out what was done by running a command to fetch the status of each user:
Get-CsBatchPolicyAssignmentOperation -OperationId d9458f56-e03e-4f3d-9620-1d348547fb3b | Select -ExpandProperty UserState
Id Result State
-- ------ -----
Imran.Khan@Office365itpros.com Success Completed
Jeff.Guillet@office365itpros.com Success Completed
Marc.Vigneau@office365itpros.com Success Completed
Jane.Sixsmith@office365itpros.com Unknown error occurred. Completed
The error reported might be due to the account already being assigned the policy. This is easily checked by viewing the account through the Teams admin center to see what policy is assigned.
The Value of Teams Bulk Policy Assignment
Assigning Teams policies in background jobs is most advantageous when you have thousands of accounts to manage. But even if you have just a few hundred, you’ll still find that it’s easier to kick off a background job than to write some PowerShell to assign a policy to a bunch of users.
Struggling with the complexities of managing Microsoft Teams? Secure your copy of the Office 365 for IT Pros eBook and learn how to manage Teams effectively and efficiently.
12 Replies to “How to Bulk Assign Policies to Teams Users in Batch Jobs”
Hello Tony!
There seems to be a small error in the example script. In the New-CsBatchPolicyAssignmentOperation commandlet, you process $TargetUsers, that should be $PolicyUsers, no?
I also wonder why you do it this way and not Import-CSV users.CSV | Select -ExpandProperty UserPrincipalName
There is more than one ways to skin a cat and I am new to Powershell, so I am curious if there is a particular reason to go the explicit route for building the list.
You’re right. That was a cut and paste error on my part.
I wrote the code like that because I like sticking data into hash tables. It must have been automatic on my part. In any case, the important thing is that you provide a simple list of UPNs as input for the job, no matter how you generate it.
I take it there’s no way to cancel a Batch Policy Assignment yet? I’ve got an incorrect assignment in the activity log, that hasn’t started 4 hours later. I’d love to be able to cancel it but can’t find a way to.
Hi there i’m afraid i havea different problem all together… I get “An error occurred on a send” whenever i try to run the batch commands, non batch commands work without issue, I am failing to see where the problem is. Does anyone have any experience with this?
Hi Toby yes, it’s all the time, I run the script using a group managed service account but when I make the connection to Microsoft teams I’m using a cloud only account with teams administrator permissions – for other o365 services I use the same set up and it works fine. Is teams working differently?
Loading...
Who’s Toby?
In any case, are you saying that everything works OK when you run the command with one account and not when using a different one?
Loading...
Sorry Tony, auto correct, no I run my script as some account. if I connect to teams (by using my cloud only account which is a teams administrator) I am able to use commands like get-teamuser but the moment I try the batch assignments like in your examples, I receive an error that “an error occurred on a send” the error object contains no more information than this
{"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}
Hello Tony!
There seems to be a small error in the example script. In the New-CsBatchPolicyAssignmentOperation commandlet, you process $TargetUsers, that should be $PolicyUsers, no?
I also wonder why you do it this way and not Import-CSV users.CSV | Select -ExpandProperty UserPrincipalName
There is more than one ways to skin a cat and I am new to Powershell, so I am curious if there is a particular reason to go the explicit route for building the list.
Hi Martin,
You’re right. That was a cut and paste error on my part.
I wrote the code like that because I like sticking data into hash tables. It must have been automatic on my part. In any case, the important thing is that you provide a simple list of UPNs as input for the job, no matter how you generate it.
I take it there’s no way to cancel a Batch Policy Assignment yet? I’ve got an incorrect assignment in the activity log, that hasn’t started 4 hours later. I’d love to be able to cancel it but can’t find a way to.
Hi there i’m afraid i havea different problem all together… I get “An error occurred on a send” whenever i try to run the batch commands, non batch commands work without issue, I am failing to see where the problem is. Does anyone have any experience with this?
Does this happen all the time? Are you signed into PowerShell with an account that has Teams administrator permissions?
Hi Toby yes, it’s all the time, I run the script using a group managed service account but when I make the connection to Microsoft teams I’m using a cloud only account with teams administrator permissions – for other o365 services I use the same set up and it works fine. Is teams working differently?
Who’s Toby?
In any case, are you saying that everything works OK when you run the command with one account and not when using a different one?
Sorry Tony, auto correct, no I run my script as some account. if I connect to teams (by using my cloud only account which is a teams administrator) I am able to use commands like get-teamuser but the moment I try the batch assignments like in your examples, I receive an error that “an error occurred on a send” the error object contains no more information than this
Time to call Microsoft support. They can run a remote session to see exactly what you are doing and might be able to see where the problem lies.