powershell
2079 TopicsUPDATE: Create Office 365 Groups with team sites from SharePoint home moving beyond First Release
We recently completed the worldwide rollout for Office 365 Groups getting full-powered SharePoint team sites at the end of January 2017. Our next step is to now bring the ability to create SharePoint team sites connected to Office 365 Groups from SharePoint home beyond First Release. This next phase of rollout will begin today, and is expected to reach all customers worldwide over the next month. We also wanted to share some of the additional capabilities we’ve added to group-connected team sites since we first began roll out to First Release. No matter where you create an Office 365 Group from – whether SharePoint, Outlook, Microsoft Teams, Yammer, or elsewhere – you consistently get the full collaborative power of a connected SharePoint Online team site among the other services groups provides (shared inbox, shared calendar, Planner plan, team notebook, and more). This move beyond First Release includes the capabilities described in our November blog post: Fast creation of sites connected to Office 365 Groups from the SharePoint home page Editable team site home pages that look great at your desk and on your phone Modern creation panels for new libraries and lists In-place navigation editing Site settings panels for editing site information and site permissions Modern page creation in classic sites Admin controls for team site creation The site permissions panel listed above has been enhanced to include options for adding members to the site’s Office 365 Group or simply sharing only the team site without providing access to other group resources. The panel is intended to provide simple permissions management, but also includes a link to ‘Advanced permission settings’ for site owners that have a need to do things like add custom SharePoint permissions & mappings. Note this panel also allows you to add users or groups to the ‘Site Visitors’ permissions group, so it is easy to provide read-only access to the site. All you need to do is add a new person or group via the ‘Invite people’ button, and then change their permission level to ‘Read’. The user or group’s permission level determines which permission group they appear under – those with ‘Read’ permission will appear in the ‘Site Visitors’ category. Managing group-connected team sites Since new team sites are connected to Office 365 Groups, managing them involves possible interactions with Office 365 Group settings in addition to those provided by SharePoint. Examples include settings that apply to groups such as whether group creation is allowed in the tenant, which users are permitted to create groups, usage guidelines URL or group classification labels. Once the group-connected site is created, management of the site is likewise split between Azure Active Directory (AAD) PowerShell cmdlets and the SharePoint Online Management Shell. Anything dealing with creation, deletion, un-delete (restore) or membership happens through AAD. SharePoint-specific management, such as storage quota and link sharing policies, take place using the SharePoint management tools. For governing modern site creation, this support page details the administrative controls, but is useful to summarize the relationship between a group’s policy settings and how the SharePoint ‘Create site’ experience behaves. By default, if group creation is enabled in the tenant, the ‘Create site’ command will appear on SharePoint home, and if a user is permitted to create groups they will get the site creation experience. If the user is *not* permitted to create groups, they will get the classic self service provisioning experience that results in the creation of a subsite. The table below describes how the combination of group and site creation settings work together: * The current user is considered to have group creation permissions if the AAD property EnableGroupCreation is true, or it is false but the user is a member of the security group assigned to the GroupCreationAllowedId AAD property. ** Site creation is enabled via SharePoint Admin Center under Site creation settings: In addition to managing site creation, we are also enabling the SharePoint Online PowerShell cmdlets to administer modern, group-connected site collections. This means that modern team site collections can now be enumerated with the Get-SPOSite cmdlet with the following example: Get-SPOSite -Template GROUP#0 -IncludePersonalSite:$false Most parameters for these site collections can also be set using the Set-SPOSite cmdlet, with the exception of those that would result in breaking connection with their corresponding Office 365 Group (e.g. you cannot set the Owner property using this cmdlet – you would need to set the Group’s owners via AAD). Please refer to the respective documentation for each of the above cmdlets for additional details. For more information on using PowerShell to manage Office 365 Groups, this article may be helpful as well. What else is new? In addition to the above, this phase of the rollout includes a couple of previously unannounced capabilities. The first is a group membership management experience that lives in SharePoint itself. Now, when you click on the member count of the group in the site header, you will be presented with a new group membership panel that allows you to add members and change their roles between owners and members, or remove them outright. Users will no longer need to jump to Outlook to manage the group’s membership. The second is Content Type Hub syndication – modern sites can now consume content types that have been published from a central content type hub. We heard feedback that this is an important feature to enable, and we are including it in this rollout. As noted above, this rollout will take place over the course of a few weeks. We are very excited for you to take advantage of modern, connected team sites and look forward to any feedback or questions you may have. As always, please ask in a reply to this thread. Thanks, Tejas89KViews29likes76CommentsPowershell Script to list ALL videos in your 365 Stream environment
I hope this is useful to everyone. My goal was to get a list of all videos in my stream so that I could contact each video creator about the changes that are coming to stream. Also so I could figure out how much work there was to do in moving, and how much video is created and not used. My original solution (posted here 7 Oct 2020) I've retired, as thanks to Twan van Beers code here https://neroblanco.co.uk/2022/02/get-list-of-videos-from-microsoft-stream/ I've been able to build a single ps1 script that does all I need. I'll leave the the original code at the bottom of this post. Take a look a the comments I've put into the code for how to use this script. I found that my original script gave me information about the videos but it was hard to use AND didn't tell me which videos were in which channels. This new version of Twan van Beers script gives me both. Save the new code Oct 2022 as a PowerShell script e.g. get-stream-video-info.ps1 Then open a powershell screen, navigate to the folder get-stream-video-info.ps1 is in. To run it enter .\get-stream-video-info.ps1 "C:\Temp\streamanalysis\stream7Oct22-getnbstreamvideoinfo.csv" Follow the on screen prompts. >>> New Code Oct 2022 <<< using namespace System.Management.Automation.Host [CmdletBinding()] param ( [parameter(Position=0,Mandatory=$False)] [string]$OutputCsvFileName, [parameter(Position=1,Mandatory=$False)] [switch]$OpenFileWhenComplete = $False ) # ---------------------------------------- # How to use <#-- Open a powershell window then type in the following and click enter .\get-stream-video-info.ps1 "C:\Temp\streamanalysis\stream7Oct22-getnbstreamvideoinfo.csv" You'll then be prompted for 3 options [V] Videos [C] ChannelVideos [A] All [?] Help (default is "V"): V - videos, which will get a list of all the videos in your STREAM environment. NOTE you may need to alter the variables in the code if you have more than 1000s of videos C - ChannelVideos, will get a list of all the videos and the channels they are in. NOTE this returns a filtered view of all the videos associated with a channel A - All, returns both the Videos and the ChannelVideos. You'll then be prompted for a user to login to the STREAM portal with, this is so the script can get a security token to do it's work with. Choose/use an account with full access to STREAM. If you used a CSV file path after the script name, then this powershell script will export one or two CSV files based on the option chosen <your folder path, your filename>-videos<your file ending> and or <your folder path, your filename>-channelVideos<your file ending> If you don't want to export file names, this powershell creates objects you can use in other ways V or A - will create an object $ExtractData, which is a list of every video and key properties for each video. C or A - wil create an object $videosPerChannel, which lists key information about each video AND the channel they are part of. ---------------------------------------------------------------------------------------------- original source my script https://techcommunity.microsoft.com/t5/microsoft-stream-classic/powershell-script-to-list-all-videos-in-your-365-stream/m-p/1752149 which inspired Twan van Beers to write https://neroblanco.co.uk/2022/02/get-list-of-videos-from-microsoft-stream/ I've then taken Twan's script and modified it to do what I require in my environment. Namely - get the video information AND the channels they are part of. For my 1000 or so videos and 35 channels, it takes about 1 min to run using the All option. This meant I was able to setup an intranet video library with a channel metadata column, folders per channel (so i could give edit rights to channel owners, without opening up the entire library or having to use multiple libraries), and eventually download the videos, then upload them into the library using ShareGate to reinstate some of the key metadata, i.e. created date, person who created them etc --#> # ---------------------------------------------------------------------------------------------- function Show-OAuthWindowStream { param ( [string]$Url, [string]$WindowTitle ) $Source = ` @" [DllImport("wininet.dll", SetLastError = true)] public static extern bool InternetSetOption(IntPtr hInternet, int dwOption, IntPtr lpBuffer, int lpdwBufferLength); "@ $WebBrowser = Add-Type -memberDefinition $Source -passthru -name $('WebBrowser'+[guid]::newGuid().ToString('n')) $INTERNET_OPTION_END_BROWSER_SESSION = 42 # Clear the current session $WebBrowser::InternetSetOption([IntPtr]::Zero, $INTERNET_OPTION_END_BROWSER_SESSION, [IntPtr]::Zero, 0) | out-null Add-Type -AssemblyName System.Windows.Forms $Form = New-Object -TypeName System.Windows.Forms.Form -Property @{Width = 600; Height = 800 } $Script:web = New-Object -TypeName System.Windows.Forms.WebBrowser -Property @{Width = 580; Height = 780; Url = ($URL -f ($Scope -join "%20")) } $Web.ScriptErrorsSuppressed = $True $Form.Controls.Add($Web) $Featured = { $Head = $Web.Document.GetElementsByTagName("head")[0]; $ScriptEl = $Web.Document.CreateElement("script"); $Element = $ScriptEl.DomElement; # Javascript function to get the sessionInfo including the Token $Element.text = ` @' function CaptureToken() { if( typeof sessionInfo === undefined ) { return ''; } else { outputString = '{'; outputString += '"AccessToken":"' + sessionInfo.AccessToken + '",'; outputString += '"TenantId":"' + sessionInfo.UserClaim.TenantId + '",'; outputString += '"ApiGatewayUri":"' + sessionInfo.ApiGatewayUri + '",'; outputString += '"ApiGatewayVersion":"' + sessionInfo.ApiGatewayVersion + '"'; outputString += '}'; return outputString; } } '@; $Head.AppendChild($ScriptEl); $TenantInfoString = $Web.Document.InvokeScript("CaptureToken"); if( [string]::IsNullOrEmpty( $TenantInfoString ) -eq $False ) { $TenantInfo = ConvertFrom-Json $TenantInfoString if ($TenantInfo.AccessToken.length -ne 0 ) { $Script:tenantInfo = $TenantInfo; $Form.Controls[0].Dispose() $Form.Close() $Form.Dispose() } } } $Web.add_DocumentCompleted($Featured) $Form.AutoScaleMode = 'Dpi' $Form.ShowIcon = $False $Form.Text = $WindowTitle $Form.AutoSizeMode = 'GrowAndShrink' $Form.StartPosition = 'CenterScreen' $Form.Add_Shown( { $Form.Activate() }) $Form.ShowDialog() | Out-Null write-output $Script:tenantInfo } # ---------------------------------------------------------------------------------------------- function Get-RequestedAssets([PSCustomObject]$Token, [string]$Url, [string]$Label) { $Index = 0 $MainUrl = $Url $AllItems = @() do { $RestUrl = $MainUrl.Replace("`$skip=0", "`$skip=$Index") Write-Host " Fetching ... $($Index) to $($Index+100)" $Items = @((Invoke-RestMethod -Uri $RestUrl -Headers $Token.headers -Method Get).value) $AllItems += $Items $Index += 100 } until ($Items.Count -lt 100) Write-Host " Fetched $($AllItems.count) items" $Assets = $AllItems | Select-Object ` @{Name='Type';Expression={$Label}},` Id, Name,` @{Name='Size(MB)';Expression={$_.AssetSize/1MB}}, ` PrivacyMode, State, VideoMigrationStatus, Published, PublishedDate, ContentType, Created, Modified, ` @{name='Media.Duration';Expression={$_.Media.Duration}},` @{name='Media.Height';Expression={$_.Media.Height}},` @{name='Media.Width';Expression={$_.Media.Width}},` @{name='Media.isAudioOnly';Expression={$_.media.isAudioOnly}},` @{name='Metrics.Comments';Expression={$_.Metrics.Comments}},` @{name='Metrics.Likes';Expression={$_.Metrics.Likes}},` @{name='Metrics.Views';Expression={$_.Metrics.Views}}, ` @{name='ViewVideoUrl';Expression={("https://web.microsoftstream.com/video/" + $_.Id)}}, ` @{name='VideoCreatorName';Expression={$_.creator.name}}, ` @{name='VideoCreatorEmail';Expression={$_.creator.mail}}, ` @{name='VideoDescription';Expression={$_.description}} write-output $Assets } function Get-VideoChannels([PSCustomObject]$Token, [string]$Url, [string]$Label) { #this will get the list of channels $Index = 0 $MainUrl = $Url $AllItems = @() do { $RestUrl = $MainUrl.Replace("`$skip=0", "`$skip=$Index") Write-Host " Fetching ... $($Index) to $($Index+100)" $Items = @((Invoke-RestMethod -Uri $RestUrl -Headers $Token.headers -Method Get).value) $AllItems += $Items $Index += 100 } until ($Items.Count -lt 100) Write-Host " Fetched $($AllItems.count) items" #to add properties to this section look at https://aase-1.api.microsoftstream.com/api/channels?$skip=0&$top=100&adminmode=true&api-version=1.4-private $Channels = $AllItems | Select-Object ` @{Name='Type';Expression={$Label}},` Id, Name, Description,` @{Name='MetricsVideos';Expression={$_.metrics.videos}} #write-host $channels.count write-output $Channels } function Get-channelVideos([PSCustomObject]$Token, [PSCustomObject]$allChannels, [string]$Label) { #this will get the list of channels $MainUrl = "https://aase-1.api.microsoftstream.com/api/channels/ChannelIDToSwap/videos?`$top=50&`$skip=0&`$filter=published%20and%20(state%20eq%20%27completed%27%20or%20contentSource%20eq%20%27livestream%27)&`$expand=creator,events&adminmode=true&`$orderby=name%20asc&api-version=1.4-private" #for each channel URL go through all the videos, capture the channel name against the video id and name $allVideosPerChannel = @() foreach($chan in $allChannels) { $thisChannelid = $chan.id $chanUrl = @( $MainUrl.Replace("ChannelIDToSwap", $thisChannelid) ) $chanName = $chan.name $AllItems = "" $items = "" $thischanvideos = "" $Index = 0 #write-host $chanUrl #loop the index do { $RestUrl = $chanUrl.Replace("`$skip=0", "`$skip=$Index") #write-host $restUrl #Write-Host "$chanName | Fetching ... $($Index) to $($Index+50)" $Items = @((Invoke-RestMethod -Uri $RestUrl -Headers $Token.headers -Method Get).value) $allItems = $items | select id,name, @{Name='Channel';Expression={$chanName}},@{Name='Type';Expression={$Label}} #write-host $allItems.count #foreach($x in $items ) { # write-host $x.name #write-host $x.id #write-host $label #write-host $chanName #} $Index += 50 } until ($Items.Count -lt 100) #got videos into $items, now mist with $chan info and put into $allVideosPerChannel object $allVideosPerChannel += $AllItems $AllItems = "" $items = "" } Write-Host " Fetched $($allVideosPerChannel.count) videos in $($allChannels.count) channels" #to add properties to this section look at https://aase-1.api.microsoftstream.com/api/channels?$skip=0&$top=100&adminmode=true&api-version=1.4-private write-output $allVideosPerChannel } # ---------------------------------------------------------------------------------------------- function Get-StreamToken() { $TenantInfo = Show-OAuthWindowStream -url "https://web.microsoftstream.com/?noSignUpCheck=1" -WindowTitle "Please login to Microsoft Stream ..." $Token = $TenantInfo.AccessToken $Headers = @{ "Authorization" = ("Bearer " + $Token) "accept-encoding" = "gzip, deflate, br" } $UrlTenant = $TenantInfo.ApiGatewayUri $ApiVersion = $TenantInfo.ApiGatewayVersion $UrlBase = "$UrlTenant{0}?`$skip=0&`$top=100&adminmode=true&api-version=$ApiVersion" $RequestToken = [PSCustomObject]::new() $RequestToken | Add-Member -Name "token" -MemberType NoteProperty -Value $Token $RequestToken | Add-Member -Name "headers" -MemberType NoteProperty -Value $Headers $RequestToken | Add-Member -Name "tenantInfo" -MemberType NoteProperty -Value $TenantInfo $Urls = [PSCustomObject]::new() $RequestToken | Add-Member -Name "urls" -MemberType NoteProperty -Value $Urls $RequestToken.urls | Add-Member -Name "Videos" -MemberType NoteProperty -Value ($UrlBase -f "videos") $RequestToken.urls | Add-Member -Name "Channels" -MemberType NoteProperty -Value ($UrlBase -f "channels") $RequestToken.urls | Add-Member -Name "Groups" -MemberType NoteProperty -Value ($UrlBase -f "groups") $UrlBase = $UrlBase.replace("`$skip=0&", "") $RequestToken.urls | Add-Member -Name "Principals" -MemberType NoteProperty -Value ($UrlBase -f "principals") write-output $RequestToken } function New-Menu { [CmdletBinding()] param( [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string]$Title, [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string]$Question ) $videos = [ChoiceDescription]::new('&Videos', 'Videos') $channelvideos = [ChoiceDescription]::new('&ChannelVideos', 'All Videos by Channel') $all = [ChoiceDescription]::new('&All', 'All videos AND all videos by channel') $options = [ChoiceDescription[]]($videos, $channelvideos, $all) $result = $host.ui.PromptForChoice($Title, $Question, $options, 0) switch ($result) { 0 { 'Videos' } 1 { 'ChannelVideos' } 2 { 'All' } } } $menuoutome = New-Menu -title 'Stream videos' -question 'What do you want to output?' #write-host $menuoutome $StreamToken = Get-StreamToken $urlQueryToUse = $StreamToken.Urls.Videos #default $StreamToken.Urls.Videos is something like https://aase-1.api.microsoftstream.com/api/videos?$skip=900&$top=100&adminmode=true&api-version=1.4-private #To get creator and event details you need to add $expand=creator,events to the URL , not to do that you need to use &`$expand=creator,events with out the ` powershell thinks $expand is a variable. # e.g. use $urlQueryToUse = $StreamToken.Urls.Videos+"&`$expand=creator,events" #Other option # use the following if you want to only see files that have privacymode eq 'organization' i.e. video is visible to EVERYONE in the organisation # Thanks to Ryechz for this # # $urlQueryToUse = $StreamToken.Urls.Videos + "&orderby=publishedDate%20desc&`$expand=creator,events&`$filter=published%20and%20(state%20eq%20%27Completed%27%20or%20contentSource%20eq%20%27livestream%27)%20and%20privacymode%20eq%20%27organization%27%20" if($menuoutome -eq 'Videos' -Or $menuoutome -eq 'All'){ #modify the -URL submitted to get more data or filter data or order the output $ExtractData = Get-RequestedAssets -token $StreamToken -Url $urlQueryToUse -Label "Videos" write-host "" write-host "The `$ExtractData object contains all the details about each video. Use `$ExtractData[0] to see the first item in the object, and it's properties." if( $OutputCsvFileName ) { $thisOutputCsvFileName = $OutputCsvFileName.replace(".csv", '-'+$menuoutome+'-videos.csv') $ExtractData | Export-CSV $thisOutputCsvFileName -NoTypeInformation -Encoding UTF8 write-host "The following file has been created: $thisOutputCsvFileName" if( $OpenFileWhenComplete ) { Invoke-Item $thisOutputCsvFileName } } } if($menuoutome -eq 'ChannelVideos' -Or $menuoutome -eq 'All'){ #Get the list of channels , filter the result for the channel id and name $channelList = Get-VideoChannels -token $StreamToken -Url $StreamToken.Urls.Channels -Label "Channels" #for each channel get the videos that are in that channel, so that we can match them up to the ExtractData , which is the list of all videos) $videosPerChannel = get-channelvideos -token $StreamToken -allChannels $channelList -Label "ChannelVideos" write-host "" write-host "The `$videosPerChannel object contains key information about each video and the channel it is in. Use `$videosPerChannel[0] to see the first video, and it's properties." write-host "The `$channelList object contains a list of channel's and their properties." if( $OutputCsvFileName ) { $thisOutputCsvFileName = $OutputCsvFileName.replace(".csv", '-'+$menuoutome+'-channelVideos.csv') $videosPerChannel | Export-CSV $thisOutputCsvFileName -NoTypeInformation -Encoding UTF8 write-host "The following file has been created: $thisOutputCsvFileName" if( $OpenFileWhenComplete ) { Invoke-Item $thisOutputCsvFileName } } } >>> Original Code Oct 2020 <<< I've left this here in case it is useful to anyone. See the script above for a better solution. That said this solution relies on you knowing a bit about PowerShell, being a Stream Admin and being happy to manually save some files (I couldn't figure out how to do pass through windows authentication for the script) so you have to manually save each paged JSON file of 100 videos. It took me about 20minutes to export information about 591 videos (about 3 hours to make the script). To use the script update each variable marked with #<<<< Update this value in a normal (not admin) powershell window run the script (i copy and paste logical parts into the powershell window) you will be given several urls, to visit and save the JSON files from once you have the JSON files the final part of the script reads those, and exports a CSV file with a row per video in STREAM NOTE : as an admin you see all videos, so before you share the CSV with others be aware that there may be sensitive information in it that most users can't see due to STREAM's in built security. I don't have much time, hence I made this script so please don't expect quick answers to any questions. This script is rough, use it if it helps, but ... be professional and check it before you use it. ##>> Update 5 Aug 2021 <<## Thanks to everyone who has commented, I've updated the code below with your suggestions You still have to manually save the JSON browser tabs that show up as JSON files into a folder, but other than that I hope it is now easier for you to use 🙂 #reference https://techcommunity.microsoft.com/t5/microsoft-stream-forum/powershell-script-to-audit-and-export-channel-content-details-of/m-p/354832 # goal of this script #- get list of all videos in stream for analysis #- it takes about 20 minutes to do this for 500 stream videos. #First # find out what your api source is # go to the following URL in chrome as an admin of Stream https://web.microsoftstream.com/browse # using Developer tools look at the "console" search for .api.microsoftstream to find out what is between https:// and .api.microsoftstream in my case https://aase-1.api.microsoftstream.com/api/ [string]$rootAPIlocation = "aase-1" #<<<< Update this value to the one you find in the console view #[string]$rootAPIlocation = "uswe-1" # use this for Western US #[string]$rootAPIlocation = "euno-1" # use this for the Europe North region #enter where you on your computer you want the files to go [string]$PowerShellScriptFolder = "C:\Temp\streamanalysis" #<<<< Update this value #json files will be saved into "VideosJSON" folder [string]$streamJSONfolder = Join-Path -Path $PowerShellScriptFolder -ChildPath "VideosJSON" #<<<< Update this value if you want a different folder name #>>> REMOVES all exiisting JSON files <<<< #remove all JSON items in this folder Remove-Item -path $streamJSONfolder\* -include *.json -Force -Recurse #guess approx number of videos you think you have divide by 100 e.g. 9 = 900 videos [int]$Loopnumber = 9 #<<<< Update this value #put in your stream portal url [string]$StreamPortal = "https://web.microsoftstream.com/?NoSignUpCheck=1" #put in the url where you see all videos from in stream [string]$StreamPortalVideoRoot = "https://web.microsoftstream.com/browse/" #$StreamPortalChannelRootForFindingVideos [string]$StreamPortalVideoViewRoot= "https://web.microsoftstream.com/video/" # for watching a video #this builds from the info you've put in a URL which will give back the JSON info about all your videos. [string]$StreamAPIVideos100 = "https://$rootAPIlocation.api.microsoftstream.com/api/videos?NoSignUpCheck=1&`$top=100&`$orderby=publishedDate%20desc&`$expand=creator,events&`$filter=published%20and%20(state%20eq%20%27Completed%27%20or%20contentSource%20eq%20%27livestream%27)&adminmode=true&api-version=1.4-private&`$skip=0" #$StreamAPIVideos100 # use the following if you want to only see files that have privacymode eq 'organization' i.e. video is visible to EVERYONE in the organisation #Thanks to Ryechz for this # # [string]$StreamAPIVideos100 = "https://$rootAPIlocation.api.microsoftstream.com/api/videos?NoSignUpCheck=1&`$top=100&`$orderby=publishedDate%20desc&`$expand=creator,events&`$filter=published%20and%20(state%20eq%20%27Completed%27%20or%20contentSource%20eq%20%27livestream%27)%20and%20privacymode%20eq%20%27organization%27%20&adminmode=true&api-version=1.4-private&`$skip=0" [int]$skipCounter [int]$skipCounterNext = $skipCounter+100 [string]$fileName = "jsonfor-$skipCounter-to-$skipCounterNext.json" #next section creates the URLS you need to manually download the json from , it was too hard to figure out how to do this programatically with authentication. Write-Host " Starting Chrome Enter your credentials to load O365 Stream portal" -ForegroundColor Magenta #Thanks Conrad Murray for this tip Start-Process -FilePath 'chrome.exe' -ArgumentList $StreamPortal Read-Host -Prompt "Press Enter to continue ...." Write-host " -----------------------------------------" -ForegroundColor Green Write-host " --Copy and past each url into chrome-----" -ForegroundColor Green Write-host " --save JSON output into $streamJSONfolder" -ForegroundColor Green for($i=0;$i -lt $Loopnumber; $i++) { $skipCounter = $i*100 if($skipCounter -eq 0) { write-host $StreamAPIVideos100 Start-Process -FilePath 'chrome.exe' -ArgumentList $StreamAPIVideos100 } else { write-host $StreamAPIVideos100.replace("skip=0","skip=$skipCounter") #following code opens browser tabs for each of the jsonfiles #Thanks Conrad Murray for this tip Start-Process -FilePath 'chrome.exe' -ArgumentList $StreamAPIVideos100.replace("skip=0","skip=$skipCounter") } } Write-host " --save each browser window showing JSON output into $streamJSONfolder" -ForegroundColor Green Write-host " -----------------------------------------------------------------------------------" -ForegroundColor Green Write-host " -----------------------------------------" -ForegroundColor Green Read-Host -Prompt "Press Enter to continue ...." Write-host " -----------------------------------------" -ForegroundColor Green $JSONFiles = Get-ChildItem -Path $streamJSONfolder -Recurse -Include *.json [int]$videoscounter = 0 $VideosjsonAggregateddata=@() $data=@() foreach($fileItem in $JSONFiles) { Write-host " -----------------------------------------" -ForegroundColor Green Write-Host " =====>>>> getting content of JSON File:", $fileItem, "- Path:", $fileItem.FullName -ForegroundColor Yellow $Videosjsondata = Get-Content -Raw -Path $fileItem.FullName | ConvertFrom-Json $VideosjsonAggregateddata += $Videosjsondata Write-host " -----------------------------------------" -ForegroundColor Green #Write-Host " =====>>>> Channel JSON Raw data:", $Videosjsondata -ForegroundColor green #Read-Host -Prompt "Press Enter to continue ...." } write-host "You have " $VideosjsonAggregateddata.value.count " videos in Stream , using these selection criteria" foreach($myVideo in $VideosjsonAggregateddata.value) { $videoscounter += 1 $datum = New-Object -TypeName PSObject Write-host " -----------------------------------------" -ForegroundColor Green Write-Host " =====>>>> Video (N°", $videoscounter ,") ID:", $myVideo.id -ForegroundColor green Write-Host " =====>>>> Video Name:", $myVideo.name," created:", $myVideo.created,"- modified:", $myVideo.modified -ForegroundColor green Write-Host " =====>>>> Video Metrics views:", $myVideo.metrics.views, "- comments:", $myVideo.metrics.comments -ForegroundColor Magenta Write-Host " =====>>>> Video Creator Name: ", $myVideo.creator.name , " - Email:", $myVideo.creator.mail -ForegroundColor Magenta Write-Host " =====>>>> Video Description: ", $myVideo.description -ForegroundColor Magenta $datum | Add-Member -MemberType NoteProperty -Name VideoID -Value $myVideo.id $datum | Add-Member -MemberType NoteProperty -Name VideoName -Value $myVideo.name $datum | Add-Member -MemberType NoteProperty -Name VideoURL -Value $($StreamPortalVideoViewRoot + $myVideo.id) $datum | Add-Member -MemberType NoteProperty -Name VideoCreatorName -Value $myVideo.creator.name $datum | Add-Member -MemberType NoteProperty -Name VideoCreatorEmail -Value $myVideo.creator.mail $datum | Add-Member -MemberType NoteProperty -Name VideoCreationDate -Value $myVideo.created $datum | Add-Member -MemberType NoteProperty -Name VideoModificationDate -Value $myVideo.modified $datum | Add-Member -MemberType NoteProperty -Name VideoLikes -Value $myVideo.metrics.likes $datum | Add-Member -MemberType NoteProperty -Name VideoViews -Value $myVideo.metrics.views $datum | Add-Member -MemberType NoteProperty -Name VideoComments -Value $myVideo.metrics.comments #the userData value is for the user running the JSON query i.e. did that user view this video. It isn't for information about all users who may have seen this video. There seems to be no information about that other than, total views = metrics.views #$datum | Add-Member -MemberType NoteProperty -Name VideoComments -Value $myVideo.userData.isViewed $datum | Add-Member -MemberType NoteProperty -Name Videodescription -Value $myVideo.description #thanks Johnathan Ogden for these values $datum | Add-Member -MemberType NoteProperty -Name VideoDuration -Value $myVideo.media.duration $datum | Add-Member -MemberType NoteProperty -Name VideoHeight -Value $myVideo.media.height $datum | Add-Member -MemberType NoteProperty -Name VideoWidth -Value $myVideo.media.width $datum | Add-Member -MemberType NoteProperty -Name VideoIsAudioOnly -Value $myVideo.media.isAudioOnly $datum | Add-Member -MemberType NoteProperty -Name VideoContentType -Value $myVideo.contentType $data += $datum } $datestring = (get-date).ToString("yyyyMMdd-hhmm") $csvfileName = ($PowerShellScriptFolder + "\O365StreamVideoDetails_" + $datestring + ".csv") #<<<< Update this value if you want a different file name Write-host " -----------------------------------------" -ForegroundColor Green Write-Host (" >>> writing to file {0}" -f $csvfileName) -ForegroundColor Green $data | Export-csv $csvfileName -NoTypeInformation Write-host " ------------------ DONE -----------------------" -ForegroundColor Green Disclaimer : You can use that solution as you want and modify it depending of your case. Many thanks to Fromelard and his https://techcommunity.microsoft.com/t5/microsoft-stream-forum/powershell-script-to-audit-and-export-channel-content-details-of/m-p/354832 which gave me enough to figure out how to do this.SolvedHow to run a Windows 11 VM on Hyper-V
Happy new year everyone! Last month, before the holidays I wanted to run a Windows 11 VM on Hyper-V to run a few tests on Windows containers in a different environment than my local machine. However, it took me some time to get that VM up and running, simply because I forgot about the new hardware requirements for Windows 11 and that I had to get them configured before I installed the new OS in it. This blog post is my contribution so you don’t have to go through the same!223KViews16likes12CommentsAnnouncing General Availability of Terraform Azure Verified Modules for Platform Landing Zone (ALZ)
Azure Verified Modules ALZ ❤️ AVM. We are moving to a more modular approach to deploying your platform landing zones. In line with consistent feedback from you, we have now released a set of modules that together will deploy your platform landing zone architecture (ALZ). Azure Verified Modules for Platform Landing Zones (ALZ) is collection of Azure Verified Modules that are composed together to create your Platform Landing Zone. This replaces the existing CAF Enterprise Scale module that you may already be familiar with. The core Azure Verified Modules that are composed together are: Management Groups and Policy Pattern Module: avm-ptn-alz Management Resources Pattern Module: avm-ptn-management-alz Hub Virtual Networking Pattern Module: avm-ptn-hubnetworking Virtual Network Gateway Pattern Module: avm-ptn-vnetgateway Virtual WAN Networking Pattern Module: avm-ptn-virtualwan Private DNS Zone for Private Link Pattern Module: avm-ptn-network-private-link-private-dns-zones This means that you can now choose your own adventure by selecting only the modules that you need. It also means we can add new features faster and allows us the opportunity to do more rigorous testing of each module. To improve deployment reliability, we now use our own Terraform provider. The provider generates data for use by the module and does not directly deploy any resources. The move to a provider allows us to add many more features and checks to improve your deployment reliability. ALZ IaC Accelerator updates for Terraform The Azure Landing Zones IaC Accelerator is our recommended approach for deploying the Terraform Azure Verified Modules for Platform Landing Zone (ALZ). The Azure Verified Modules for Platform Landing Zone is now our default selection for the Terraform ALZ IaC Accelerator. This module will be the focus of our development and improvement efforts moving forward. The module implements best practices by default, including multi-region and availability zones for resiliency. The ALZ IaC Accelerator bootstrap continues to implement best practices, such as version control and Workload identity federation security. Along with supporting the Azure Verified Modules for Platform Landing Zone (ALZ) approach, we have also made many enhancements to the ALZ IaC Accelerator process. A summary of the improvements include: We now support HCL (HashiCorp Configuration language) tfvars file as the platform landing zone configuration file format We have introduced a Phase 0 to help you plan for your ALZ IaC Accelerator deployment We have introduced the concepts of Scenarios and Options to simplify the decisions you need to make Platform landing zone configuration file Before the introduction of the Azure Verified Modules for Platform Landing Zone (ALZ) starter module the platform landing zone configuration file was supplied in YAML format. Due to the lack of support for YAML in Terraform, we had to then convert this to JSON. Once converted to JSON the configuration file lost all it's ordering, formatting and comments. This made day 2 updates to the configuration very cumbersome. With the support for the tfvars file (in HashiCorp Configuration Language format), we are now able to pass the configuration file in its original format to the version control system repository. This makes for a much easier day 2 update process as the file retains it's ordering, comments and formatting as defined by you. Phase 0 Phase 0 is a new planning phase we have added to the documentation. This phase takes you through 3 sets of decisions you need to make about the ALZ IaC Accelerator deployment: Bootstrap decisions Platform Landing Zone Scenarios Platform Landing Zone Options In order to assist with this, we also provide a downloadable Excel checklist , which lists all the decisions so you can consider them up front prior to completing any configuration file updates. Phase 0 guides you through this process and provides explanations of the decisions. The Bootstrap decisions relate to the resources deployed to Azure and the configuration of your Version Control System required for the Continuous Delivery pipeline. These decisions are not new to the ALZ IaC Accelerator, but we now provide more structured guidance. Platform Landing Zone Scenarios The Scenarios are a new concept introduced for the Azure Verified Modules for Platform Landing Zone (ALZ) starter module. We aim to cover the most common Platform landing zone use cases we hear requested from partners and customers with the ALZ IaC Accelerator. These include: Multi-Region Hub and Spoke Virtual Network with Azure Firewall Multi-Region Virtual WAN with Azure Firewall Multi-Region Hub and Spoke Virtual Network with Network Virtual Appliance (NVA) Multi-Region Virtual WAN with Network Virtual Appliance (NVA) Management Groups, Policy and Management Resources Only Single-Region Hub and Spoke Virtual Network with Azure Firewall Single-Region Virtual WAN with Azure Firewall For each scenario we provide an example Platform landing zone configuration file that is ready to deploy immediately. We know that customers will want to modify some of the settings and that is where Options come in. NOTE: At the time this blog post was published, we support the 7 Scenarios listed above. We may update or add to these Scenarios based on feedback we hear from you, so keep an eye on our documentation. Platform Landing Zone Options The Options build on the Scenarios. For each Scenario, you can choose to customise it with one or more Options. Each Options includes detailed instructions of how to update the Platform landing zone configuration file or introduce library files to implement to the option. The Options are: Customise Resource Names Customize Management Group Names and IDs Turn off DDOS protection plan Turn off Bastion host Turn off Private DNS zones and Private DNS resolver Turn off Virtual Network Gateways Additional Regions IP Address Ranges Change a policy assignment enforcement mode Remove a policy assignment Turn off Azure Monitoring Agent Deploy Azure Monitoring Baseline Alerts (AMBA) Turn off Defender Plans Implement Zero Trust Networking NOTE: At the time this blog post was published, we support the 14 Options listed above. We may update or add to these Options based on feedback we hear from you, so keep an eye on our documentation. Azure Landing Zones Library Another new offering is the Azure Landing Zones Library. This is an evolution of the library concept in the caf-enterprise-scale module. Principally, the Library allows us to decouple the update cycle of the ALZ architecture, from the module and provider. We are separating the data from the deployment logic. This allows you to update the module to take advantage of a bug fix, without having to change the policies that are deployed. Something that wasn't easily possible before. Conversely, you are able to update to the latest policy refresh of Azure Landing Zones without updating the module itself. The Library has its own documentation site, which introduces the concepts. We plan to make the library the single source of truth for all Azure Landing Zones implementation options (e.g. Portal, Terraform and Bicep) in the future. Azure Landing Zones Documentation Site Furthermore, we have a new place to go for all technical documentation for Azure Verified Modules for Platform Landing Zones (ALZ). With the move to multiple modules, and the new accelerator all having multiple GitHub repositories, we felt the need to centralize the documentation to make it the one place to go to get technical details. We currently have documentation for the Accelerator and Terraform, with Bicep coming soon. The new vanity URL is: https://aka.ms/alz/tech-docs. Please let us know what you think! What about ALZ-Bicep? Finally, some of you may be wondering what the future for our Bicep implementation option (ALZ Bicep) for Azure Verified Modules for Platform Landing Zones (ALZ) may be with this evolution on the Terraform side. And we have good news to share! Work is underway to also build the next version of ALZ in Bicep, which will be known as “Bicep Azure Verified Modules for Platform Landing Zone (ALZ)”. This will also use the new Azure Landing Zones Library and be built from Azure Verified Modules (where appropriate). We are currently looking to complete this work before August 2025, if not a lot sooner than this; as we are making good progress as we speak! But for now, for Bicep you do not do anything and continue to use ALZ Bicep via the ALZ IaC Accelerator and we will provide more updates on the next version of Bicep ALZ in the coming months! Staying up-to-date We highly recommend joining, or watching back, our quarterly Azure Landing Zones Community Calls, to get all the latest and greatest from the ALZ team. Our next one is on the 29th January 2025 and you can find the link to sign up to attend or watch back previous ones at: aka.ms/ALZ/Community We look forward to seeing you all there soon!6.6KViews13likes0CommentsPowerShell Basics: How to Delete Microsoft Teams Cache for All Users
Sometimes there is a need to delete Microsoft Teams cache to quicken the adoption of an in-band policy change or simply troubleshoot an issue. The challenge here is that the cache for Microsoft Teams is in multiple directories. This can be done manually but would result in a slow and tedious process. Again, we turn to PowerShell to automate this process and this time it's a one-liner that addresses this opportunity.213KViews13likes33CommentsAzure Landing Zones Accelerators for Bicep and Terraform. Announcing General Availability!
Azure Landing Zones Accelerators are designed to simplify the process of onboarding your Infrastructure as Code into a robust CI / CD pipeline with Azure DevOps or GitHub. Learn more about what the Accelerator can do for you and why you should be using it.30KViews12likes4Comments