The Looming End for the Security and Compliance Center
A reader asked how to create a report of the membership of Microsoft 365 role groups. Although this sounds like a straightforward question, the answer is complex. Here’s why.
Originally, compliance functionality was workload-based. Exchange Online had its own features as did SharePoint Online. In 2016, Microsoft introduced the Office 365 Security and Compliance Center (SCC) to bring together functionality which applied across all workloads. Permissions for the SCC follow the Exchange Online Role-Based Access Control (RBAC) model. Users receive permissions to perform actions through membership of role groups. If your account is a member of the right role group, you can perform a compliance action, like running a content search or managing an eDiscovery case. If it’s not, you won’t see the options to perform those actions displayed in the SCC.
Here’s where the situation becomes complicated. We are in the middle of a transition from the SCC to the Microsoft 365 compliance center, which Microsoft launched in 2018. Three years and a lot of confusion later, an April 15 blog post warns that Microsoft will soon start to redirect users automatically from the SCC to the Microsoft 365 compliance center. Message center notification MC256030 posted on May 12 confirms that a new permissions management page in the Microsoft 365 compliance center will make role management easier (Microsoft 365 roadmap item 72239).
New Permissions Management Page
Figure 1: The new permissions page in the Microsoft 365 compliance center
The new permissions management page (Figure 1) allows management for both Azure AD roles and compliance center roles (more correctly, role groups). The differences between the two are:
Azure AD roles allow performance of directory-related tasks. The full set of Azure AD roles is visible by running the Get-AzureADDirectoryRole cmdlet or through the Roles and administrators section of the Azure AD admin center. Azure AD roles support advanced role management functionality like Privileged Identity Management to assign roles to users for limited periods.
Compliance center role groups allow performance of compliance tasks like eDiscovery. Each role group contains one or more roles, which is how accounts gain permission. The 43 compliance role groups (my tenant has 44 because I created a specific role group to handle certain processing) have no other function except to control access to different compliance features. The SCC was the previous location to manage these roles. To update the set of users who receive permissions through membership of a compliance role group, an account must be a global administrator or assigned the Role Management role (a role assigned only to the Organization Management role group).
The permission management page shows Azure AD roles used to performance compliance tasks. Currently, the page lists nine Azure AD roles like compliance administrator and compliance data administrator. Other Azure AD roles like Teams Administrator don’t appear because they are not associated with compliance management.
Reporting Who Holds Compliance Roles
Returning to the original question of how to generate a report about the holders of different compliance roles, the answer depends on if you want to report the membership of compliance role groups or Azure AD roles. Given that more functionality is governed by the latter type at present, the following code is a solution.
The steps to create the report are:
Uses the Connect-IPPSSession cmdlet (in the Exchange Online management module) to connect to the Compliance endpoint. You’ll need to use a tenant administrator account or one holding the compliance Organization Management role.
Fetches the list of known role groups.
Parses the set of members for each role group by converting the odd values used to represent members FFO.extest.microsoft.com/Microsoft Exchange Hosted Organizations/office365itpros.onmicrosoft.com/cad05ccf-a359-4ac7-89e0-1e33bf37579e into mailbox display names (the last part of the name is the Azure AD object identifier for the account).
Writes details out into a PowerShell list and displays the results using the Out-GridView cmdlet.
Figure 2 shows what the report looks like. A simple Export-CSV command will write the details out to a CSV file if you want to manipulate the data in Excel.
Figure 2: Reporting membership of compliance role groups
Simple questions often have complex answers. In this case, it’s a matter of deciding what kind of role holders you want to report. Once you know that, the PowerShell to generate the report is relatively straightforward.
Learn lots more about how different parts of Office 365 work by subscribing to the Office 365 for IT Pros eBook. We go where other writing teams don’t, and we keep our book refreshed with monthly updates.
the first script does not work fine , in the “$MemberName = (Get-ExoMailbox -Identity $Member.SubString(($Member.IndexOf(“onmicrosoft.com/”)+16),36) -Erroraction SilentlyContinue).DisplayName ” can’t make the subsrick
obviously something doesn’t work as well as it did in my environment when it’s in your environment, so it’s an opportunity to debug. Did you check what the $Member variable contained?
Stupid question, how can i connect both Connect-IPPSession and Connect-ExchangeOnline Cmdlets? Are you saying if run your script it will connect both of them at the same time? I have not had much luck getting Connect-IppSession to work in conjunction with any other modules.
Run Connect-ExchangeOnline to connect to the Exchange Online management endpoint, and then run Connect-IPPSsession to connect to the compliance endpoint. You’ll then be able to use the Exchange Online and compliance cmdlets.
Hey Tony, I will give that a try. But i swear i did that at least 3xs. Maybe just the wrong order.
Robert
Loading...
It ran successfully. But it doesnt report for example my admin user account which is part of the Compliance Administrator group (In the security and compliance center). I also tried using Get-ExoRecipient which seemed to work better but didnt quite get the job done.
A fair point. I was able to work around it by using Get-Recipient. That seemed to work better. It sometimes shows system.object[0] but when checking that seems only to occur for blank spaces in the repport line (For example, username1, , username2) shows the system object value.
but the data is correct.
Robert
Loading...
How do you list “Assigned Roles” to each “Role Group”?
Exception calling “Substring” with “2” argument(s): “startIndex cannot be larger than length of string.
Parameter name: startIndex”
I tried to change the values for the command $Member.IndexOf…. but I can’t get through.
I also changed the command into this below, not having the error but with useless results (empty Roles column and “SystemObject[]” in the Members column)
It’s PowerShell, so you will have to debug it based on what results you see from your tenant. It looks as if the $Member variable is not populated with a value. I’d start by checking there.
{"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}
the first script does not work fine , in the “$MemberName = (Get-ExoMailbox -Identity $Member.SubString(($Member.IndexOf(“onmicrosoft.com/”)+16),36) -Erroraction SilentlyContinue).DisplayName ” can’t make the subsrick
obviously something doesn’t work as well as it did in my environment when it’s in your environment, so it’s an opportunity to debug. Did you check what the $Member variable contained?
Hey Tony,
Stupid question, how can i connect both Connect-IPPSession and Connect-ExchangeOnline Cmdlets? Are you saying if run your script it will connect both of them at the same time? I have not had much luck getting Connect-IppSession to work in conjunction with any other modules.
Thanks,
Robert
Run Connect-ExchangeOnline to connect to the Exchange Online management endpoint, and then run Connect-IPPSsession to connect to the compliance endpoint. You’ll then be able to use the Exchange Online and compliance cmdlets.
Hey Tony, I will give that a try. But i swear i did that at least 3xs. Maybe just the wrong order.
Robert
It ran successfully. But it doesnt report for example my admin user account which is part of the Compliance Administrator group (In the security and compliance center). I also tried using Get-ExoRecipient which seemed to work better but didnt quite get the job done.
At this point, we say that it’s impossible to debug the problem without access to the tenant… and I don’t have it!
Hey Tony,
A fair point. I was able to work around it by using Get-Recipient. That seemed to work better. It sometimes shows system.object[0] but when checking that seems only to occur for blank spaces in the repport line (For example, username1, , username2) shows the system object value.
but the data is correct.
Robert
How do you list “Assigned Roles” to each “Role Group”?
For some reason the output does not seem to match the membership displayed in the Compliance center.
Which role? There have been some changes in the Compliance portal and it might require a Microsoft Graph PowerShell SDK cmdlet to get the information.
Hi, Tony, and thanks for the code.
It worked fine a couple of times, but now I’m facing an exception for the “SubString” method, at the command:
$MemberName = (Get-ExoMailbox -Identity $Member.SubString(($Member.IndexOf(“onmicrosoft.com/”)+16),36) -Erroraction SilentlyContinue).DisplayName
Error is:
Exception calling “Substring” with “2” argument(s): “startIndex cannot be larger than length of string.
Parameter name: startIndex”
I tried to change the values for the command $Member.IndexOf…. but I can’t get through.
I also changed the command into this below, not having the error but with useless results (empty Roles column and “SystemObject[]” in the Members column)
$MemberName = (Get-ExoMailbox -Identity $Member.SubString(0,($Member.lenght))).DisplayName
What can I do to solve this?
Thank you in advance.
It’s PowerShell, so you will have to debug it based on what results you see from your tenant. It looks as if the $Member variable is not populated with a value. I’d start by checking there.