Message Center notification MC521457 (Microsoft 365 roadmap item 106102) might have passed you buy on February 27 when Microsoft announced a new PowerShell cmdlet for disposition review. Relatively few people are concerned with Microsoft Purview Data Lifecycle Management to care that a new cmdlet is available to export (not just “to support”) disposition review items, so it’s entirely natural that you might have gone on to read about other announcements occurring around the same time, like Exchange Online’s improved message recall feature.
Roll-out of the new Get-ReviewItems cmdlet is now complete. The cmdlet is available after loading the latest version of the Exchange Online management module.
Disposition Items
Microsoft 365 retention labels often result in the deletion of items after the lapse of their retention periods. This is enough for most organizations, but those that want oversight over the final processing of selected items can configure retention labels to invoke a disposition review, part of the Microsoft Purview records management solution. Disposition reviews are often used to retain messages and documentations such as those for project documentation until the organization is absolutely sure that it’s safe to remove individual items.
Using a disposition review with retention labels requires advanced licenses, like Office 365 E5. An organization can put items through a single-stage or multi-stage review (Figure1) leading to final deletion, retention for another period, or assignment of a new retention label. The reviewers who decide on the disposition of content are selected by the organization because they have the expertise and experience to know if items are still needed or can progress to final disposition. It’s also possible to configure a custom automated disposition process using Power Automate.
Figure 1: Viewing disposition review items for a retention label
Exporting Disposition Review Items
The Get-ReviewItems cmdlet doesn’t affect disposition outcomes. It’s a utility cmdlet to export details of disposition review items for a specific retention label in a pending or disposed (processed) state. The reason why the cmdlet exists is that the Purview GUI (Figure 1) supports export of up to 50,000 items. Although it’s unlikely that an organization will have more than 50,000 items awaiting disposition review, it is possible that they might have more than 50,000 disposed (processed) items. The Get-ReviewItems cmdlet can export details of all those items.
Microsoft’s documentation for Get-ReviewItems includes examples of using the cmdlet. One in particular is noteworthy because it explains how to fetch pages of review items until all items have been recovered. Fetching pages of data is common practice in the Graph API world and it’s done to reduce the strain on the service imposed if administrators requested very large numbers of items at one time.
I expanded the example to create a report of all disposition review items for a tenant (all items for all retention labels with a disposition review). Here’s the code:
Connect-IPPSSession
[array]$ReviewTags = Get-ComplianceTag | Where-Object {$_.IsReviewTag -eq $True} | Sort-Object Name
If (!($ReviewTags)) { Write-Host "No retention tags with manual disposition found - exiting"; break }
Write-Host ("Looking for Review Items for {0} retention tags: {1}" -f $ReviewTags.count, ($ReviewTags.Name -join ", "))
$Report = [System.Collections.Generic.List[Object]]::new()
[array]$ItemsForReport = $Null
ForEach ($ReviewTag in $ReviewTags) {
Write-Host ("Processing disposition items for the {0} label" -f $ReviewTag.Name)
[array]$ItemDetails = $Null; [array]$ItemDetailsExport = $Null
# Fetch first page of review items for the tag and extract the items to an array
[array]$ReviewItems = Get-ReviewItems -TargetLabelId $ReviewTag.ImmutableId -IncludeHeaders $True -Disposed $False
$ItemDetails += $ReviewItems.ExportItems
# If more pages of data are available, fetch them and add to the Item details array
While (![string]::IsNullOrEmpty($ReviewItems.PaginationCookie))
{
$ReviewItems = Get-ReviewItems -TargetLabelId $ReviewTag.ImmutableId -IncludeHeaders $True -PagingCookie $ReviewItems.PaginationCookie
$ItemDetails += $ReviewItems.ExportItems
}
# Convert data from CSV
If ($ItemDetails) {
[array]$ItemDetailsExport = $ItemDetails | ConvertFrom-Csv -Header $ReviewItems.Headers
ForEach ($Item in $ItemDetailsExport) {
# Sometimes the data doesn't include the label name, so we add the label name to be sure
$Item | Add-Member -NotePropertyName Label -NotePropertyValue $ReviewTag.Name }
$ItemsForReport += $ItemDetailsExport
}
}
ForEach ($Record in $ItemsForReport) {
If ($Record.ItemCreationTime) {
$RecordCreationDate = Get-Date($Record.ItemCreationTime) -format g
} Else {
$RecordCreationDate = "Unknown" }
$DataLine = [PSCustomObject] @{
TimeStamp = $RecordCreationDate
Subject = $Record.Subject
Label = $Record.Label
AppliedBy = $Record.LabelAppliedBy
RecordType = $Record.RecordType
'Last Reviewed' = Get-Date($Record.ItemLastModifiedTime) -format g
'Review Action' = $Record.ReviewAction
Comment = $Record.Comment
'Deleted Date' = $Record.DeletedDate
Author = $Record.Author
Link = $Record.InternetMessageId
Location = $Record.Location
}
$Report.Add($DataLine)
}
Everything works – until you meet an item with a comma in its subject or the comment captured when a reviewer decides upon a disposition outcome. After discussing the issue with Microsoft, its root cause is that the export is in CSV format and the comma in these fields causes problems when converting from CSV format. Microsoft is working on a fix which might be present as you read this.
The Lesson of Export
The Get-ReviewItems cmdlet will be a useful tool for those involved in disposition processing. They can extract details of items and report that information in whatever way they wish. The comma issue proves that documentation is not always perfect. It’s important to test examples to make sure that they work as they should.
Insight like this doesn’t come easily. You’ve got to know the technology and understand how to look behind the scenes. Benefit from the knowledge and experience of the Office 365 for IT Pros team by subscribing to the best eBook covering Office 365 and the wider Microsoft 365 ecosystem.
{"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}