Author: Tony Redmond
How to Replace Group Owners When They Leave the Organization
Replace Group Owners to Avoid Ownerless Groups
An ownerless group is not a thing of beauty, but it can happen when someone leaves an organization and the remobal of their Entra ID user account results in some groups becoming ownerless. The Microsoft 365 group ownership policy helps, but it’s better to avoid the problem in the first place by proactively replacing the to-be-deleted account with a new group owner.
Writing PowerShell to Replace Group Owners
Which brings me to a PowerShell snippet posted in LinkedIn to address the problem. Here’s the code:
$OldOwnerUPN = "user@domain.com" $NewOwnerUPN = "user1@domain.com" $Groups = Get-UnifiedGroup -ResultSize Unlimited foreach ($Group in $Groups) { $Owners = Get-UnifiedGroupLinks -Identity $Group.Identity -LinkType Owners if ($Owners.PrimarySmtpAddress -contains $OldOwnerUPN) { Remove-UnifiedGroupLinks -Identity $Group.Identity -LinkType Owners -Links $OldOwnerUPN -Confirm:$false Add-UnifiedGroupLinks -Identity $Group.Identity -LinkType Members -Links $NewOwnerUPN -Confirm:$false Add-UnifiedGroupLinks -Identity $Group.Identity -LinkType Owners -Links $NewOwnerUPN -Confirm:$false Write-Output "$($Group.DisplayName): Replaced $OldOwnerUPN with $NewOwnerUPN as owner" } }#
This is a great example of proof-of-concept code that runs superbly in a small tenant where there are fewer than a hundred or so groups but rapidly runs out of steam rapidly as the number of objects to process escalates. The big performance sink is running the Get-UnifiedGroup cmdlet to fetch every Microsoft 365 group in the tenant. Because of the number of properties it retrieves, Get-UnifiedGroup is not a fast cmdlet. It’s a cmdlet that should be used judiciously rather than being the default method to fetch details of Microsoft 365 groups.
Use the Graph for Best Performance
The Get-MgUserOwnedObject cmdlet from the Microsoft Graph PowerShell SDK is faster and more scalable. Get-MgUserOwnedObject is based on the Graph list OwnedObjects API. Its purpose is to find the set of Entra ID directory objects owned by a user account and requires consent for the Directory.Read.All permission to find those objects.
This example fetches the set of Microsoft 365 Groups owned by a user account. Unfortunately, it’s not possible to use a server-side filter to extract the Microsoft 365 groups from the set of directory objects fetched by the cmdlet. The set of owned objects can include other group types such security groups and distribution lists and other objects like applications and service principals. Using a client-side filter isn’t a huge issue here because most of the fetched objects are likely to be Microsoft 365 groups.
[array]$Groups = Get-MgUserOwnedObject -UserId Kim.Akers@office365itpros.com -All | Where-Object {$_.additionalProperties.groupTypes -eq "unified"}
Like many Graph SDK cmdlets, the output for a group is determined by the underlying Graph request. If you look at the information returned for an object in the output array, you’ll see something like this:
$Groups[0] | Format-List DeletedDateTime : Id : f9b6dcb7-609d-48ca-83c1-5afbfe888fe0 AdditionalProperties : {[@odata.type, #microsoft.graph.group], [createdDateTime, 2020-06-08T16:59:06Z], [creationOptions, System.Object[]], [description, Sunny Days]…}
If you examine the details of the additionalProperties property for a group, you’ll see the “normal” properties that a cmdlet like Get-MgGroup returns for a group.
$Groups[0].additionalProperties @odata.type #microsoft.graph.group createdDateTime 2020-06-08T16:59:06Z creationOptions {SPSiteLanguage:1033, HubSiteId:00000000-0000-0000-0000-000000000000, SensitivityLabel:00000000-0000-0000-0000-000000000000, ProvisionGro… description Sunny Days displayName Sunny Days groupTypes {Unified} mail SunnyDays@office365itpros.com mailEnabled True mailNickname SunnyDays proxyAddresses {SMTP:SunnyDays@office365itpros.com, SPO:SPO_c5365af4-7636-4bca-a9d2-e1eb9bbfe9f6@SPO_b… renewedDateTime 2020-06-08T16:59:06Z resourceBehaviorOptions {} resourceProvisioningOptions {} securityEnabled False securityIdentifier S-1-12-1-4189510839-1221222557-4217028995-3767503102 visibility Private onPremisesProvisioningErrors {} serviceProvisioningErrors {}
The most important property is the group identifier because it’s needed to update group membership. The other group properties can be accessed by prefixing them with additionalProperties (which is case sensitive). For example:
$Groups[0].additionalProperties.displayName Office 365 Planner Tips
Rewriting the Original Code to Replace Group Owners
The original code can be adjusted to replace Get-UnifiedGroup with Get-MgUserOwnedObject. Apart from the performance boost gained by only finding the set of Microsoft 365 groups owned by the user instead of all groups, eliminating the need to run the Get-UnifiedGroupLinks cmdlet to check the ownership of each group improves code execution further:
[array]$Groups = Get-MgUserOwnedObject -UserId $OldOwnerUPN -All | Where-Object {$_.additionalProperties.groupTypes -eq "unified ForEach ($Group in $Groups) { Remove-UnifiedGroupLinks -Identity $Group.Id -LinkType Owners -Links $OldOwnerUPN -Confirm:$false Add-UnifiedGroupLinks -Identity $Group.Id -LinkType Members -Links $NewOwnerUPN -Confirm:$false Add-UnifiedGroupLinks -Identity $Group.Id -LinkType Owners -Links $NewOwnerUPN -Confirm:$false Write-Output "$($Group.additionalPropertiesDisplayName): Replaced $OldOwnerUPN with $NewOwnerUPN as owner" }
The lesson here is that you can mix and match cmdlets from different Microsoft 365 PowerShell modules to solve problems. In this case, Get-MgUserOwnedObject finds groups to process before the group memberships are updated using the Remove-UnifiedGroupLinks and Add-UnifiedGroupLinks cmdlets.
Running a Pure Microsoft Graph PowerShell SDK Version
You might want to write a script based solely on the Microsoft Graph PowerShell SDK instead of combining Exchange Online and Graph SDK cmdlets. To do this, we replace the Exchange cmdlets with the following SDK cmdlets:
- New-MgGroupMember: Add the new owner as a member of the group.
- New-MgGroupOwnerByRef: Add the new owner as a group owner. This should be done before removing the original owner to avoid the risk of failure because Entra ID won’t allow cmdlets to remove the last owner of a group
- Remove-MgGroupOwnerDirectoryObjectByRef: Remove the old owner as a group owner. This also removes the account from group membership.

To see how to use these cmdlets, check out this script, available from the Office 365 for IT Pros GitHub Repository. You’ll notice that I include calls to Get-MgGroupMember and Get-MgGroupOwner to avoid attempting to add the new owner as a group member and owner if they already hold these roles. The best thing of all is that the script (Figure 1) is extremely fast.
To complete the job, you should update any security groups, distribution lists, and dynamic distribution lists owned by the soon-to-depart account. The required code isn’t difficult, so I shall leave it to the reader to write.
Need some assistance to write and manage PowerShell scripts for Microsoft 365? Get a copy of the Automating Microsoft 365 with PowerShell eBook, available standalone or as part of the Office 365 for IT Pros eBook bundle.
Microsoft 365 User Profile Card Gets Name Pronunciation
Name Pronunciation Recordings Helps People Get Names Right
Message center notification MC917748 (last update 13 November 2024, Microsoft 365 roadmap item 420329) marks the latest update for the Microsoft 365 user profile card. This time round, users get the opportunity to add a recording of up to ten seconds to help colleagues understand how to pronounce their name correctly (Figure 1).

Microsoft says that the “new feature helps promote diversity by giving working colleagues relevant information about each other. Names are a crucial part of a person’s identity. The incorrect pronunciation of a person’s name can lead to anxiety and offense in some cases. Correctly pronouncing a person’s name helps to create an inclusive environment.” Having the proven ability to make a mess of many peoples’ names in my career, I should find this feature useful.
Once a name pronunciation is available, people can play the recording back by clicking the playback button beside the user’s name (Figure 2).

General availability is scheduled for mid-January 2025, so the update is currently rolling out. The roadmap item tags the feature for Teams, but MC917748 correctly notes that it’s also available in OWA and the new Outlook for Windows (but not yet in Outlook classic). Over time, I assume that name pronunciation recording will show up everywhere that the Microsoft 365 profile card is visible.
Where Name Pronunciation Recordings are Stored
MC917748 says “Pronunciation data is stored in each user’s mailbox until the user deletes the recording.” Keeping the data in user mailboxes means that pronunciation recordings are available across all clients across all workstations and avoid the kind of problems encountered with Outlook classic where settings are usually held in the system registry.
The non-IPM folders of a mailbox are not visible to normal email clients like Outlook. Applications often use folders in this section to store configuration and other data. The new Outlook for Windows and OWA store many mailbox settings in sub-folders of ApplicationDataRoot, and browsing through those folders with the MFCMAPI utility reveals a folder called ApplicationDataRoot8c22b648-ee54-4ece-a4ca-3015b6d24f8esource_sourcenamepronunciation.
The folder holds a single message item containing the pronunciation recording. Figure 3 shows how the item appears in MFCMAPI. In my case, the recording takes 440,728 bytes (approximately 430 KB), which seems about right for a six-second recording.

Enabling Name Pronunciation Recordings
According to MC917748, the feature is off by default, meaning that you don’t see the icons to record and play back name pronunciation recordings in the user profile card. However, the feature is enabled in every tenant that I checked, possibly because Microsoft decided to enable it when the feature was in preview or first deployed to targeted release tenants late last year.
Control over name pronunciation recordings is via the Graph namePronunciationSettings resource type with APIs available to Get and Update the setting controlling whether users see the record and playback buttons. For instance, to get the current setting with the Microsoft Graph PowerShell SDK, run these commands:
$Uri = "https://graph.microsoft.com/beta/admin/people/namePronunciation" Invoke-MgGraphRequest -Uri $Uri -Method Get Name Value ---- ----- isEnabledInOrganization True @odata.context https://graph.microsoft.com/beta/$metadata#admin/people/namepronunciation/$entity
To update the setting to disable name pronunciation recordings, construct a hash table containing the new value and update (patch) the resource:
$Settings = @{} $Settings.Add("isEnabledInOrganization", $false) Invoke-MgGraphRequest -Uri $Uri -Method Patch -Body $Settings
The setting is on or off for a complete tenant. You cannot enable name pronunciation recording and playback for some mailboxes and not for others. This is very similar to the way that the setting controlling the display of personal pronouns (introduced in March 2023) is managed:
Uri = "https://graph.microsoft.com/V1.0/admin/people/pronouns" Invoke-MgGraphRequest -Uri $Uri -Method Get Name Value ---- ----- isEnabledInOrganization True @odata.context https://graph.microsoft.com/beta/$metadata#admin/people/pronouns/$entity
Unfortunately, the API requests to control the name pronunciation settings currently fail with a 404 not found error. I’m sure that this is a transient problem that Microsoft will sort out soon.
Up to Organizations to Decide
Some consider this kind of addition to the user profile to be so much woke fluff. Others consider getting pronouncing names correctly is an essential part of business discourse. Both are entitled to their opinion. It’s good to have the choice within a world where dealing with different cultures and names is a reality for most.
Learn how to exploit the data available to Microsoft 365 tenant administrators through the Office 365 for IT Pros eBook. We love figuring out how things work.
Microsoft Launches Copilot for All Initiative
New Agent Capabilities for the Free Microsoft 365 Copilot Chat App
Infused with the zealotry of true believers, Microsoft announced Copilot for All on January 15, 2025 to reveal the details of the complicated Copilot renaming they previewed in December. And the new logo, of course.
In a nutshell, Microsoft is creating an “on-ramp” to give Microsoft 365 tenants that haven’t invested in expensive Microsoft 365 Copilot licenses the chance to use agent technology “grounded in Microsoft Graph data.” The idea here is to encourage commercial customers to run a mix of Copilot with some having the full-blown licensed version while others experience with the free-to-use version. Figure 1 shows the relative capabilities of the two Copilot options.

.Lots of Functionality in Microsoft 365 Copilot Chat
The free-to-use Microsoft 365 Copilot Chat app includes a lot of functionality in terms of its ability process user prompts against information available on web sites (providing those sites are indexed by Bing). Recently, Microsoft added features like Copilot pages and the image generator (Figure 2). Microsoft says that limitations exist on the number of images that can be generated daily. I guess I don’t create many images as I haven’t experienced any problems.

The Chat client has enterprise data protection, so data is secure, protected, and actions are audited and captured in compliance records.
Pay-as-you-go Agents
The big news is that customers will be able to create and run custom agents grounded against “work data” on a pay-as-you-go (PAYG) metered basis. PAYG means the tenant must sign up for an Azure subscription with a valid credit card before the agent will run. Agent activity will be charged against the subscription. Grounding against work data means that the agents can interrogate information available in the Microsoft Graph. This includes data stored in Exchange, Teams, SharePoint, and OneDrive plus anything imported into the Graph through a third-party connector. This is where the magic lies because if an organization can import its data into the Graph, agents can reason over that data to create responses to user prompts, providing PAYG is set up for the tenant.
The custom agents are developed with Copilot Studio. I have spent some time working with Copilot Studio to build simple agents over the last few weeks. It’s not a terribly difficult task, but organizations do need to take the time to chart out how they plan to develop, deploy, and manage agents rather than rushing headlong into the brand-new world. Like any software, agents work best when some structure is in place.
The Big Differences between Microsoft 365 Copilot Chat and Microsoft 365 Copilot
Paying for agents to use Graph data does not deliver the full suite of capabilities enjoyed by those who invest in Microsoft 365 Copilot licenses. Figure 1 shows that Microsoft 365 Copilot includes a bunch of personal assistants where Copilot is built into Microsoft 365 apps like Teams, Word, Outlook, PowerPoint, and Excel. Sometimes, as in the case of the automatic document summary generated by Copilot in Word, the help is unwanted, but the personal assistants are very good at helping with other tasks, like summarizing long email threads or recapping Teams meetings.
Microsoft 365 Copilot also includes SharePoint Advanced Management (SAM). However, although Microsoft announced at Ignite 2024 that tenants with Microsoft 365 Copilot licenses would get SAM in early 2025, there’s no trace of these licenses turning up in any tenant that I have access to. License management can be complex and I’m sure that SAM will turn up soon.
Finally, PAYG access to Graph data does not include the semantic index. The index is generated automatically from Graph data in tenants with Microsoft 365 Copilot licenses to create a vector-based index of the relationships of items in the Graph. It’s an untrue urban legend that Microsoft 365 Copilot needs the semantic index to function. The semantic index enhances search results, but it’s not required for the chat app or agents to work.
In Simple Terms, Two Copilot Products
It’s easy to become confused by the naming of different elements within the Microsoft 365 Copilot ecosystem. It boils down to Microsoft offering free (with PAYG capabilities) and expensive Copilot products to Microsoft 365 customers. Microsoft obviously hopes that the free version will act as the on-ramp to full-fledged Copilot. It’s a reasonable tactic. Time will tell if it’s successful.
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 the Microsoft 365 ecosystem.
Final Days for the MSOnline and AzureAD PowerShell Modules
Time Ebbing Away Before AzureAD and MSOnline Module Retirement
On January 13, 2025 Microsoft posted what I am sure they hope will be the last notification about retirement details for the MSOnline and AzureAD PowerShell modules. This has been a long-running saga that’s taken almost as long as the effort to eradicate basic authentication for Exchange Online connection protocols.
The original August 2021 announcement that Microsoft intended to retire the two modules set a date of June 30, 2022. Following customer feedback that the date was too aggressive, Microsoft pushed the date out by a year and then by another nine months. The transition to a new Microsoft 365 licensing platform in mid-2024 forced people to take notice when PowerShell cmdlets stopped being able to assign or update licenses. Microsoft has now set what they say is the final schedule for the retirement (Figure 1).

Final Red Flags for MSOnline Module Retirement
The end of support for both modules is March 30, 2025, just eleven weeks away. But the really interesting note here is the temporary outage tests Microsoft plans for the MSOnline module cmdlets starting on January 20, 2025. What this means is that the MSOnline cmdlets will stop working at least twice between January 20 and February 28. The outages will last between three and eight hours and happen at different times during the day.
The two short outages will be followed in March 2025 by a longer outage. Microsoft hasn’t said how long the longer outage will last. What they have said is that the outages are “To ensure that customers are ready for this retirement of MSOnline PowerShell.”
Customers might view the outages in a different light, especially if the outages stop production scripts running. But to be fair to Microsoft, they have been up front and patient as the process for the retirement of the MSOnline and AzureAD modules unfolded since August 2021. The outages are no more than a final red flag warning to tenants. If you ignore the warnings, be prepared for disruption when the MSOnline module retirement finally completes sometime in April 2025. At that point, all the MSOnline cmdlets will stop working permanently.
AzureAD Module Retirement Follows in Third Quarter
To allow customers to focus on upgrading scripts from the older MSOnline module, Microsoft is targeting the third quarter of 2025 for the final retirement of the AzureAD module. Remember, its cmdlets have already lost their license management capability, so scripts used for other purposes such as reporting accounts and groups need to be upgraded now.
Upgrade to Entra PowerShell or the Microsoft Graph PowerShell SDK
Two upgrade options are available:
- The Entra PowerShell module (still in preview).
- The Microsoft Graph PowerShell SDK.
Microsoft built the Entra module from Graph SDK components wrapped up with some tweaks to make it slightly easier to migrate from MSOnline or AzureAD. Although I respect the opinion of those who advocate for the Entra module as the best migration target, I think this approach is a very short-term tactical step. You might end up being able to migrate scripts, but in doing so you’ll miss the opportunity to master the Graph SDK (and also be able to migrate your scripts).
Missing out on the Graph SDK might not sound like such a big deal, especially when the Entra module is available to handle the immediate need to migrate scripts before the old modules stop working. However, mastering the Graph SDK opens up the opportunity to use PowerShell to interact with many other forms of Microsoft 365 data instead of “just Entra ID.” The same techniques learned to interact with users, groups, and devices can be applied to teams, SharePoint Online sites, OneDrive for Business accounts, Exchange mailboxes, Planner plans and tasks, and so on. Understanding how the Microsoft Graph works is the better strategic choice for the longer term.
Whatever choice you make, time is ebbing away. If you need help to migrate, consider investing in a copy of the Office 365 for IT Pros eBook, which includes the Automating Microsoft 365 with PowerShell eBook (also available separately as an eBook or paperback). The hundreds of practical examples contained in these eBooks include many worked-out solutions for applying the Microsoft Graph PowerShell SDK to solve problems.
Using the SharePoint Pages Graph API
Create and Publish SharePoint Pages API with the Microsoft Graph PowerShell SDK
In April 2024, Microsoft announced the General availability for the Graph API for SharePoint Pages (also in message center notification MC789609 and Microsoft 365 roadmap item 101166). Despite Microsoft proclaiming that they were thrilled with the new API, I never got around to looking at it, largely because other work got in the way.
Given the period since general availability, it is no surprise that cmdlets for the SharePoint Pages API are available in the Microsoft Graph PowerShell SDK. However, some functionality is missing, and the Get- cmdlet to fetch pages for a site doesn’t work very well. Let’s discuss.
Get SharePoint Pages for a Site
The Get-MgSitePageAsSitePage cmdlet retrieves details of the pages for a site. You’ll need to fetch the site identifier for the target site first. The site identifier is not the site URL. A full site identifier looks something like this:
office365itpros.sharepoint.com,8e0a5589-b91d-496e-a5be-3473a75f2fe2,22d7a59d-d93c-498e-a806-6c9475717c88
If you know the URL for a site, you can compute a form of the site identifier that SharePoint will accept to lookup a site like this:
$Uri = "https://office365itpros.sharepoint.com/sites/BlogsAndProjects" $SiteId = $Uri.Split('//')[1].split("/")[0] + ":/sites/" + $Uri.Split('//')[1].split("/")[2] $Site = Get-MgSite -SiteId $SiteId
With the site identifier, you can run Get-MgSitePageAsSitePage. Here’s how to return the set of site pages sorted in date created order:
[array]$Posts = Get-MgSitePageAsSitePage -SiteId $Site.Id -All | Sort-Object {$_.CreatedDateTime -as [datetime]} -Descending
Unfortunately, the cmdlet doesn’t return values for many interesting properties, such as createdByUser. Better results are obtained by using the Graph API request:
$Uri = ("https://graph.microsoft.com/V1.0/sites/{0}/pages/microsoft.graph.sitepage" -f $Site.Id) $Data = Invoke-MgGraphRequest -Uri $Uri -Method Get $Pages = $Data.Value
Create a Page (a News Post) with the SharePoint Pages API
The example of creating a SharePoint page features see a large JSON structure composed of many properties. I wanted to simplify things to create a simple News Post page by running the New-MgSitePage cmdlet.
In PowerShell terms, the JSON structure is represented by a set of hash tables and arrays. It’s usually easier to manipulate the contents of hash tables and arrays programmatically, so that’s what I do here to create a page with a news item about a recent Office 365 for IT Pros article featuring the top five SharePoint features shipped in 2024.
$PostTitle = 'Microsoft Describes Top Five SharePoint Features Shipped in 2024' $PostName = ("News Post {0}.aspx" -f (Get-Date -format 'MMddyyy-HHmm')) $PostImage = "https://i0.wp.com/office365itpros.com/wp-content/uploads/2025/01/Top-Five-SharePoint-Features.png" $PostContent = '<p> An interesting article by Mark Kashman, a Microsoft marketing manager, lists his top five SharePoint features shipped in 2024. Four of the five features involve extra cost. Is the trend of Microsoft charging extra for most new features likely to continue in 2025? The need to generate additional revenues from the Microsoft 365 installed base probably means that this is the new normal.</p><a href="https://office365itpros.com/2025/01/07/top-five-sharepoint-features-2024" target="_blank">Read full article</a>' # The title area $TitleArea = @{} $TitleArea.Add("enableGradientEffect", $true) $TitleArea.Add("imageWebUrl", $PostImage) $TitleArea.Add("layout", "imageAndTitle") $TitleArea.Add("showAuthor",$true) $TitleArea.Add("showPublishedDate", $true) $TitleArea.Add("showTextBlockAboveTitle", $true) $TitleArea.Add("textAboveTitle", $PostTitle) $TitleArea.Add("textAlignment", "center") $TitleArea.Add("imageSourceType", $null) $TitleArea.Add.("title", "News Post") # A news item only needs one web part to publish the content $WebPart1 = @{} $WebPart1.Add("id", "6f9230af-2a98-4952-b205-9ede4f9ef548") $WebPart1.Add("innerHtml", $PostContent) $WebParts = @($WebPart1) # The webpart is in a single column $Column1 = @{} $Column1.Add("id", "1") $Column1.Add("width", "12") $Column1.Add("webparts", $webparts) $Columns = @($Column1) $Section1 = @{} $Section1.Add("layout", "oneColumn") $Section1.Add("id", "1") $Section1.Add("emphasis", "none") $Section1.Add("columns", $Columns) $HorizontalSections = @($Section1) $CanvasLayout = @{} $CanvasLayout.Add("horizontalSections", $HorizontalSections) # Bringing all the creation parameters together $Params = @{} $Params.Add("@odata.type", "#microsoft.graph.sitePage") $Params.Add("name", $PostName) $Params.Add("title", $PostTitle) $Params.Add("pagelayout", "article") $Params.Add("showComments", $true) $Params.Add("showRecommendedPages", $false) $Params.Add("titlearea", $TitleArea) $Params.Add("canvasLayout", $CanvasLayout) $Post = New-MgSitePage -SiteId $site.Id -BodyParameter $Params If ($Post) { Write-Host ("Post {0} successful" -f $PostTitle) }
Update (Promote) a SharePoint Page to be a News Post
After creating a page, we might need to update it. In this case, I update the page to promote it to be a news post so that it will appear in the News section of the site. I also add a description to appear under the title in the card shown for the item in the News section.
The Update-MgSitePage cmdlet reported an “API not found” error, so I used the Graph API request:
$UpdateBody = ‘{ "@odata.type": "#microsoft.graph.sitePage", "promotionKind": "newsPost", "description": "Microsoft Lists Top Five SharePoint Online features shipped in 2024" }’ $Uri = ("https://graph.microsoft.com/V1.0/sites/{0}/pages/{1}/microsoft.graph.sitePage" -f $Site.Id, $Post.Id) $Status = Invoke-MgGraphRequest -Uri $Uri -Method Patch -Body $UpdateBody If ($Status) { Write-Host 'Post Updated'}
Publish the News with the SharePoint Pages API
The news item that’s created is in a draft state. It must be published to make it visible to other site members. I couldn’t find a cmdlet to publish a news item, so I used the Graph API request:
$Uri = ("https://graph.microsoft.com/V1.0/sites/{0}/pages/{1}/microsoft.graph.sitePage/publish" -f $Site.Id, $Post.Id) Invoke-MgGraphRequest -Uri $Uri -Method Post
If an error isn’t reported, we can assume that SharePoint has published the page. Figure 1 shows how the page appears as a news item. I still have some bugs to figure out because the image I selected isn’t visible. There’s always something to do!

Acceptable SharePoint Pages API but Problematic Cmdlets
As far as I can tell, the SharePoint Pages Graph API works pretty well but the Microsoft Graph PowerShell SDK cmdlets generated from the API isn’t in great shape. I admit that some of the issues might be due to my lack of experience with SharePoint pages, but you do expect to be successful when you follow the documentation. I expect things to improve over time. At least, I hope improvement comes…
Need more help to write and manage PowerShell scripts for Microsoft 365? Get a copy of the Automating Microsoft 365 with PowerShell eBook, available standalone or as part of the Office 365 for IT Pros eBook bundle.
How to Post Video Clips in Teams Channel Posts and Replies
One-Minute Video Clips to Liven Up Channel Conversations
In September 2022, Microsoft launched the ability to record and send one-minute video clips in Teams chats. Message center notification MC947832 (3 December 2024, Microsoft 365 roadmap item 383740) reports that users will be able to post the same kind of video clips to channel posts and replies. Targeted release tenants should have this capability now while general availability is due from mid-January with full worldwide deployment to complete by late January 2025.
The new capability is available in Teams desktop (Windows and Mac) and browser clients. The feature is also available in Teams mobile clients, albeit with a slightly different implementation.
Basics of Video Clip for Teams Channel Conversations
The idea behind supporting video clips is that sometimes a brief message delivered in person is a better way to communicate. To record and post a video clip, open the + menu (where options like schedule message and delivery options are found) and select Record video clip to reveal the video capture screen (Figure 1).

Apart from not having a 3-2-1 countdown before recording a video, the implementation for Teams channels is similar to the video capture screen used to record and send a video message with Outlook. I noticed that Teams allows the user to upload a custom background (which is what I use in Figure 1) whereas Outlook is restricted to a set of standard backgrounds. Apart from that, the same options are available to add a script and apply various screen effects to make the video stand out (or distract the viewer).
Once posted, the video clip looks like any other embedded content in a Teams channel conversation (Figure 2).

Although it seems that Teams and Outlook use the same component for video capture, the difference in implementations is interesting. Outlook uses a Loop component to hold the captured video while Teams embeds the video clip like anything else you might paste into a Teams channel conversation. I guess that Teams already has its own way of handling graphic objects posted in channels and Outlook needed some form of container to hold video clips.
For more information about sending video clips with Teams, see the Microsoft documentation.
Controlling Video Clips
Microsoft enables the ability to record and send video clips by default. To disable the feature, update the Teams messaging policies assigned to the user accounts that you want to block and make sure that the AllowVideoMessages setting is $False:
Set-CsTeamsMessagingPolicy -Identity Global -AllowVideoMessages:$False
Where Teams Stores Video Clips
Where Teams stores video clips depends on the client used and the target location:
- Clips posted to channels with the Teams mobile client are stored in the SharePoint Online folder for the channel.
- Clips posted to channels with the Teams desktop and browser clients are stored in a Microsoft video service.
- Clips posted to chats are stored in the same Microsoft video service as used for clips posted to channels.
The storage location for video clips is revealed by using the MFCMAPI utility to examine the compliance records generated for channel posts and replies that contain video clips. You’ll see that the content of the message includes items like this:
<video src="https://eu-api.asm.skype.com/v1/objects/0-neu-d9-37aeb24ad5a76108f93a90b93ef50f88/views/video" itemscope="" itemtype="http://schema.skype.com/AMSVideo" data-duration="PT6.276S" width="1280" height="720"> Video-Clip</video>
The difference in how the clients store clips is likely explained by the reuse of code to send video clips to chats and channel messages by the desktop and browser clients. The mobile clients likely use the Graph APIs to upload the clips they generate to SharePoint Online. The other clients could do the same, but sometimes it’s just simpler to have the same code running for both chats and channel messaging.
If retention policies are in force for Teams channels and chats, the video clips are removed upon the expiration of the message they are embedded.
New Function Likely to be Popular
Given the huge popularity of video messaging popularized in other apps, video clips are likely to be a popular addition for Teams channels. This assertion is idle speculation on my part. Microsoft doesn’t provide any data for the kind of content posted to Teams, but it should be possible to use the Graph APIs to extract some statistics about how many video clips exist.
So much change, all the time. It’s a challenge to stay abreast of all the updates Microsoft makes across the Microsoft 365 ecosystem. Subscribe to the Office 365 for IT Pros eBook to receive monthly insights into what happens, why it happens, and what new features and capabilities mean for your tenant.