tag:blogger.com,1999:blog-90573798465146795502024-03-13T05:38:34.204+01:00Thoughts on aspects within Microsoft 365 based Digital WorkplaceMy professional but personal ideas, thoughts, experiences and opinions wrt aspects in the Microsoft based Digital Workplace, including SharePoint, MS Teams, MS Stream, Microsoft Search, Power PlatformWilliam van Strienhttp://www.blogger.com/profile/02730614987048826403noreply@blogger.comBlogger369125tag:blogger.com,1999:blog-9057379846514679550.post-88509179539016394712023-08-20T22:31:00.000+02:002023-08-20T22:31:23.444+02:00Overcome JSON column formatting limitation that it does not support Rich Text Multiline<div>Inspired by the visualization of Microsoft 365 roadmap, I want to achieve similar for collecting and communicating the architecture vision and refined roadmap of our ART (<i><a href='https://scaledagileframework.com/agile-release-train/'>Agile Release Train</a></i>). As the purpose is mainly about communicating, I decide to just leverage a SharePoint list for it, no need to administrate in a planning tool (eg Jira Align). In the information architecture I add a column per aspect of the architectural roadmap topics: title, description, theme, year of delivery. And for the roadmap refinement a column per year in which to enumerate the steps I foresee in that year. The steps collected in a bulleted list, thus the column must be of type Multiline / Rich Text.</div><div style='margin-top:10px'>However, this decision results in a visualization challenge. Standard, SharePoint truncates in ListView the value of multiline columns to 4; and the roadmap does not display in entirety. List View / JSON formatting is not helpful to resolve: 1) ColumnFormatting does <a href='https://learn.microsoft.com/en-us/sharepoint/dev/declarative-customization/column-formatting'>not support Multiline / Rich Text</a>, and I don’t want to reduce to plain text (<a href='https://thechriskent.com/tag/multi-line-text/'><i>"It is NOT recommended to use Rich text fields in your formats"</i></a>); 2) RowFormatting requires to specify the <a href='https://learn.microsoft.com/en-us/sharepoint/dev/declarative-customization/view-formatting'>formatting for <b>full</b> view</a>, while I am satisfied with the standard formatting of all other columns.</div><div style='margin-top:10px'>As pragmatic resolution I decided to revert to old-skool approach of DOM formatting. In Modern SharePoint you cannot directly inject a custom style, but via <a href='https://sharepoint.handsontek.net/2023/03/15/use-script-editor-modern-sharepoint-sites/'>Modern Script Editor</a> this is easily possible: [[<a href='https://github.com/wvstrien/sharepoint/blob/master/FullShowMultilineListColumnsWithRichText'>Code<a>]].</div><div style='margin-top:10px'><i>
A risk of this approach is that Microsoft might change the standard formatting of list views: you cannot rely on DOM of standard SharePoint controls as “an interface contract”. But I can accept that risk: in unlikely case that Microsoft would make “breaking change”, all what would happen is that our roadmap visualization reduces to showing the multiline columns again truncated.
</i></div>William van Strienhttp://www.blogger.com/profile/02730614987048826403noreply@blogger.com0tag:blogger.com,1999:blog-9057379846514679550.post-5327761437078792042022-04-09T12:06:00.001+02:002022-04-09T12:09:20.418+02:00Too compulsive cleaning up PnPSearchResults SelectedProperties can destroy some of its behaviors<div>I utilize PnP Modern Search v4 for a business search solution on data that is administrated in a SharePoint list. In the business solution I display multiple list columns in the search results layout (<a href='https://microsoft-search.github.io/pnp-modern-search/usage/search-results/layouts/#details-list'><i>Details List</i></a>), and thus need to ensure that their mapped managed properties are included in 'selectedProperties' of the PnP Search Results webpart. Default already a lot of other properties are included in the configuration, some of which are not even present in the SharePoint list, and others that I do not intend to use. So as good citizen I limit the 'selectedProperties' to only "what you need / want to display":</div><div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEipkT5EvKt8hWvfaFQNVMyYkNxinQ-l-sdtldTbpfjakkIwKazC2w05LO7nDivlL8jJleMdnmR3BRvc054sFDFMtOenPgk_uXwYFbpxOruG3bdrUFvt3oFv7vSv56XiTUcI_G8vjYr9Jw8QpGmXor4IDPK9fTb4eXLo09S7988OWzoM_uFoceWosjKN9g/s549/PnPSearchResultsConfiguration.png" style="display: block; padding: 1em 0; text-align: left; "><img alt="" border="0" width="320" data-original-height="386" data-original-width="549" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEipkT5EvKt8hWvfaFQNVMyYkNxinQ-l-sdtldTbpfjakkIwKazC2w05LO7nDivlL8jJleMdnmR3BRvc054sFDFMtOenPgk_uXwYFbpxOruG3bdrUFvt3oFv7vSv56XiTUcI_G8vjYr9Jw8QpGmXor4IDPK9fTb4eXLo09S7988OWzoM_uFoceWosjKN9g/s320/PnPSearchResultsConfiguration.png"/></a></div><div style='margin-top:10px'>Well, this good citizenship resulted that some behavior was broken: it no longer worked to open a listitem from the PnP Search Results overview. Direct cause was the property 'PreviewUrl' was without a value in the mapped search results Slots, and this was result that I excluded 'Path' from the 'selectedProperties'. Lesson: although good to limit data retrieval to only what you need; you also must have understanding of 'for what purpose you may need'.</div><div style='margin-top:10px'>See for more details: <a href='https://microsoft-search.github.io/pnp-modern-search/usage/search-results/slots/'>PnP Modern Search - Slots</a></div>William van Strienhttp://www.blogger.com/profile/02730614987048826403noreply@blogger.com0tag:blogger.com,1999:blog-9057379846514679550.post-90213680407487199502022-03-20T13:41:00.002+01:002022-03-21T19:04:01.050+01:00How-to Join as external attendee an access-controlled Teams Live Event without explicit Teams Guest Access<div>MS Teams Live Event is current the only service in the Microsoft 365 landscape that enables audience outside the own organization. Teams Live Event supports both full public (anonymous) Live Events without any access control, as well as Live Events with the permission mode 'People and Groups'. In the last mode, also externals can on named base be allowed by applying the Azure AD B2B guest concept. Besides that (1) the external must be known in the identity system of the tenant in which the Teams Live Event is produced, another requirement (2) is that the external must switch in Teams first to that tenant aka 'Organization' before allowed to join the Teams Live Event. </div><div class="separator" style="clear: both;"><img alt="" border="0" width="95%" src="https://blogger.googleusercontent.com/img/a/AVvXsEgbR3Gz2WBdyRHI1esEv7tmYxanZ63L3j-aFnS35TxmEzm7edOhi4UGUnZ9TZwlaARczlFMYvE_1wffZLOfiZYvBT9UVipsExOQueo61ZETb3gpc5pwa1DDTkLiG1uOkdbPXSAvDMHUwhcHCPlsFKG-d70kJoi3rYdNErfF38NrKm8QE4N0GdBbVta_qQ=s1013"/></div>
<div style='margin-top:20px;padding:5px 5px 5px 5px;background-color:lightgrey;font-style:italic;font-size:9pt'>For reference, below the prerequisites to enable external to attend a Teams Live Event in your tenant.<div style='margin-top:10px'><b>On Organizing part</b><ul style='margin-top:2px;'><li>For each external that needs to be granted access, provision an Azure AD B2B guest account</li><li>Schedule in Teams a Live Event, with permission type: People and Groups</li><li>Authorize all the externals via their provisioned Azure AD B2B guest account for access to that Teams Live Event</li><li>Share the attendee link with the invited externals</li></ul></div><div style='margin-top:10px'><b>Per external</b><ul style='margin-top:2px;'><li>Redeem the provisioned Azure AD B2B guest account</li><li>Enroll for Azure MFA via MS Authenticator App; against the organizing tenant</li><li>In Teams context; first explicit switch to ‘<organizing> tenant’ ⇒ without this, Teams displays message that you are prohibited to access</li><li>Then click the attendee link ⇒ and the external will be allowed to access</li></ul></div></div>
<div style='margin-top:20px'>Externals that are authorized via Teams Guest Access concept in any arbitrary team in the organizing tenant, can do this 'tenant-switch' direct in the Teams App and web application, via so-called 'tenant-switcher': <div class="separator" style="clear: both;"><img alt="" border="0" width="320" src="https://blogger.googleusercontent.com/img/a/AVvXsEg6zhce3BiiKguKrGAgmVzYMIpcEJsynEglc2lsrytAmzBxn9wP7qEwMk1FY2-jz81P9TmLe3li6aVArK4oTtTb6sp6T-xPlD_ysZE-75AHeFZ9IOpkK1Xwoip1x4u5lqvNytNvkQng5_k-yq2ZRpozJfq8xFuG6EG6DpTQDUNjUf28FpijcbycOfS6aQ=s372"/></div>For externals that are not within any team, there is no reason for the Teams App and web application to list that tenant as organization within the 'tenant-switcher'. The easy way out is then to just add all the authorized externals to 'a' team in the organizing tenant. But for multiple reasons this is not always a preferred / good approach. For one, it doesn't "feel right" to add persons to a team with its full set of capabilities, only because they are invited to participate in a temporary digital event. Also as all members of a team instance can 'see' all the other members, and then contact each other; via teams chat, or via the discovered email addresses. For privacy and compliance reasons the event organization might not want this, or even not be allowed to do. Another reason has to do with timing aspect: in the Teams operational model it takes unpredictable yet significant time (can take up to 36 hours) after adding an external to a team instance, before the external sees the effect of this in the 'tenant-switcher' of the own local Teams App.
</div><div style='margin-top:10px'>Luckily there is an alternative approach in which the externals can do the 'tenant-switch'. Namely by visiting in the browser the link "<span style='background-color:lightblue;'>https://teams.microsoft.com/?tenantId=<<i>organizing tenant-id</i>></span>". The external must then sign-in via his/her Azure AD B2B guest account, and typical also answer on multi-factor authentication challenge (imposed by the organizing / inviting tenant), and if both successful the external is then allowed in the Teams context of the event organization. For the externals that are not member of any team, Teams will display the message "You’re currently not part of any teams…".
<div class="separator" style="clear: both;"><img alt="" border="0" width="320" data-original-height="346" data-original-width="359" src="https://blogger.googleusercontent.com/img/a/AVvXsEivXlLdpgKU8uspNuC-IgPmKQTtQpR50y_6MPdlAy4Ti_4zGl2UOKrHaPMIvzB-w-ZuNzKD9THW8Hty8JF6CeHLrfXxZzp4YCmFoHiqAATkeOlmrH3HjB1OaPOCGiI73pUKWlYuMsg3LDsP0miML9tGCDfdl5Od1hUXDCL14lUY9t_dOJ86hiLkuH4lIQ=s359"/></div>
And now from this context in Teams, the external can join via the attendee link the Teams Live Event. Be aware that this approach only works from the browser via Teams web application, the external can not watch the live event in the Teams App. But on user experience that makes no difference; Teams App and Teams web application have same behavior wrt Teams Live Event.</div><div style='margin-top:10px'><b><i>Update:</i></b>It is also possible to achieve both via <b><i>one single link</i></b>: making the attendee link of the Teams Live Event <i>tenant-switch enabled</i>. The trick is to insert "<span style='background-color:lightblue;'>/_?tenantId=<<i>organizing tenant-id</i>></span>" immediate after "https://teams.microsoft.com" and before the "/l/meetup-join/..." part. On navigating to this link, the browser (1) first switches in Teams Web Application to the referred tenant, and (2) next from that context it joins the Teams Live Event in that same tenant.</div>
William van Strienhttp://www.blogger.com/profile/02730614987048826403noreply@blogger.com0tag:blogger.com,1999:blog-9057379846514679550.post-19056076103437172402022-03-19T11:13:00.001+01:002022-03-19T11:13:16.249+01:00Best-practices for delivering webcast via Teams Meeting<div>Complementary to post <a href='https://williamvanstrien.blogspot.com/2022/03/bad-practice-include-presentation-video.html'>Bad-Practice: Include 'presentation / video production' as camera input in MS Teams Meeting + Teams Live Event</a>, here some best-practices to apply upon delivering a webcast / digital event via Teams Meeting.</div><div style='margin-top:10px'>Tips to practice / try-out:<ol style='margin-top:2px'><li>Ensure that the workstation on which you 'produce/present' the digital event, and are including camera, audio and likely also content, is qua CPU and memory sufficient equiped for it. And close all other applications, in particular CPU, memory and/or network intensive, on it during the period of the digital event production.</li><li>Be in particular careful with using OBS Studio on that same workstation. I love OBS for its webcast / digital events capabilities, but it puts extensive strain on the workstation. Together with Teams Meeting, this might become a bottleneck; and result that the production in Teams Meeting suffers. Better to have OBS on another workstation, and cast its output to the workstation on which presenting in Teams Meeting.</li><li>In the Teams Meeting where the webcast is produced, turn off 'incoming video' of the attendees aka audience.</li><li>If possible, connect to wired iso wifi; prevent potential disruption of WIFI signal, hotspots, others consumers.</li><li>Dedicate the 'presenter' role to only those persons that will actually present; avoid the role is assigned to everyone in the audience.</li><li>In case you need 'access-control' on who is allowed as audience, apply the lobby function (<a href='https://support.microsoft.com/en-us/office/change-participant-settings-for-a-teams-meeting-53261366-dbd5-45f9-aae9-a70e6354f88e'>Teams Meeting Options</a>). Note: in case you apply the lobby as manual access-control, there is an additional reason to assign 'presenter' to only event organization; <i><b>any</b></i> 'presenter' is namely empowered to allow people in from the lobby. Even external attendees with presenter role can do this, risking the 'access-control' via lobby.</li><li>Include 'production' from external device (mixer, encoder) as shared content, do not <i>misuse</i> the possibiliy to include it as 'attendee camera' (<i>see <a href='https://williamvanstrien.blogspot.com/2022/03/bad-practice-include-presentation-video.html'>Bad-Practice: Include 'presentation / video production' as camera input in MS Teams Meeting + Teams Live Event</a></i>).</li><li>In case producing without external device, then use PowerPoint Live to include PowerPoint presentation. And leverage Teams Meeeting 'presentation modes' (<a href='https://support.microsoft.com/en-us/office/engage-your-audience-with-presenter-modes-a3599bcb-bb35-4e9c-8dbb-72775eb91e04'>link</a>) to turn the layout of the digital event in a more professional / (televion) reporter look.</li></ol>
</div><div style='margin-top:10px'>See also <a href='https://techcommunity.microsoft.com/t5/microsoft-teams/improve-quality-of-a-teams-screen-shared-video/m-p/1244692'>Improve quality of a Teams screen-shared video?</a></div>William van Strienhttp://www.blogger.com/profile/02730614987048826403noreply@blogger.com0tag:blogger.com,1999:blog-9057379846514679550.post-69330727641779138012022-03-12T18:36:00.001+01:002022-03-19T11:19:05.122+01:00Bad-Practice: Include 'presentation / video production' as camera input in MS Teams Meeting + Teams Live Event<div>Via MS Teams Settings you have the option to configure an external camera as device. This can be used to include the video output signal from external mixer (e.g. vMix, OBS Studio) into a Teams Meeting or Teams Live Event, and then to spotlight it for all participants in the Meeting.</div><div style='margin-top:5px;'>But be aware of a serious caveat with such setup. From Teams perspective, that video signal is regarded as the camera display of 'face of a participant'. And Teams will continuous process it for optimal contrast of 'face' against the background. As long as in the video production there is indeed only a face, there will not be a real issue. But in situations where there is not (only) a face in the video production, e.g. slides are presented, the mismatch with Teams understanding results inevitable that the slides are on occassion not sharp rendered but blurry. The correct way to include the produced video signal into a Teams Meeting or Teams Live Event is via 'Share Content'; Teams Meeting prioritizes 'screen / content sharing' above the local 'camera'.</div><div style='margin-top:10px;'>Nice outline on this:
<iframe width="560" height="315" src="https://www.youtube.com/embed/2wwA0x8hVaA" title="YouTube video player" frameborder="0" allow="accelerometer; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
</div>William van Strienhttp://www.blogger.com/profile/02730614987048826403noreply@blogger.com0tag:blogger.com,1999:blog-9057379846514679550.post-7914546205640701832022-03-11T20:59:00.001+01:002022-03-11T20:59:51.469+01:00Tip: Reuse authentication of MFA secured account over multiple Connect-PnPOnline calls<div>A best security practice to connect into SharePoint Online is configure MultiFactor Authentication (MFA). When connecting from PowerShell to SharePoint Online this can give some challenges, as the default 'Credentials' based logon is not MFA aware. Resolution for this is to use either '-Interactive' or '-PnPO365ManagementShell' flag: both result that you are enabled to interactive address the MFA challenge.
</div>
<div style='margin-top:10px'>Need to address the MFA challenge is acceptable to do <b>one-time</b>. But in an administration context, it might be that you need to execute settings over a set of sitecollections. Then it is not a pleasant experience to everytime need to (re)logon including MFA challenge. Common way to address this is by piping the authenticated SPO connection into the subsequent PnP calls. But Connect-PnPOnline does not support the '-Connection' flag (other PnP cmdlets do support it; PnP is not consistent across all its cmdlets). But I found an alternative that works:
<ul style='margin-top:1px'>
<li>$connection = Connect-PnPOnline -Url $spoAdminUrl -PnPO365ManagementShell -ReturnCollection</li>
<li>Connect-PnPOnline -Url <<i>Url to other site collection</i>> -Interactive -ClientId $connection.ClientId</li>
</ul>
</div>
William van Strienhttp://www.blogger.com/profile/02730614987048826403noreply@blogger.com0tag:blogger.com,1999:blog-9057379846514679550.post-46601521027275363162022-01-08T20:30:00.001+01:002022-01-08T23:46:32.281+01:00Validate UDP communication in datacenter<div>When application setup is using UDP connection, and it is experiencing an issue on the UDP communication, as a first check you want to verify whether the UDP traffic is allowed over the network including the firewall(s). For TCP traffic you can use telnet as simple OS command tool, but telnet is not appropriate for UDP.</div><div style='margin-top:10px'>
On a client station one would then typically use a network sniffer as Wireshark to monitor that the UDP traffic can be delivered and received. On a server in the data center this is typical not allowed. And the Windows Server does not include itself a command to verify UDP communication. But you can easily create a validation setup yourself via Windows PowerShell.</div><div style='margin-top:10px'>A good example/inspiration is post <a href='https://cloudbrothers.info/en/test-udp-connection-powershell/'>Test UDP connection with PowerShell</a>.</div>
<div style='margin-top:20px;'>
<span style='font-style:italic;font-weight:bolder;font-size:8pt;'>PowerShell cmdlet running on both VMs / nodes in the datacenter</span>
<div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEiMReui69XB916AqoHNJEgE_7RdndNx4H7l78I8MYuRvAJxgiox4pU1GWxQV4G-GhbAyJuEcKU-H3yCLfl0aX-gS_-zayd2gLXWXoxe8UBW6SjgErfy3oEGqFUAtAGeGjFXFtihb1a96JPypo4G2iafgV2QRzf4CxhxHdL54_Jz_IAhDFDUWF3bgK0gOg=s923" style="display: block; padding: 1em 0; text-align: left; "><img alt="" border="1" height="400" data-original-height="923" data-original-width="922" src="https://blogger.googleusercontent.com/img/a/AVvXsEiMReui69XB916AqoHNJEgE_7RdndNx4H7l78I8MYuRvAJxgiox4pU1GWxQV4G-GhbAyJuEcKU-H3yCLfl0aX-gS_-zayd2gLXWXoxe8UBW6SjgErfy3oEGqFUAtAGeGjFXFtihb1a96JPypo4G2iafgV2QRzf4CxhxHdL54_Jz_IAhDFDUWF3bgK0gOg=s400"/></a></div>
<span style='font-style:italic;font-weight:bolder;font-size:8pt;'>Result of the UDP communication test: both VMs can communicate to each other over UDP <port></span>
<div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEh-E-eTXvuWj3-xMIYXoiKJgrSM71qnFuWRL1qk4D2wK4_LiZjjgwLsVQhrgy4g5NfD6IRrfkNUVpEOp3-TciN4mg4k9sDIAJsebDpJrtPN5Ot3RGlMdvaG64vXPGmXHh6Fdrbdt9L4Ux6JaEFep_nW5hMjOtuKyqvfQfs4grzhHNjvIy_reHWLmDYJIA=s1300" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="1" width="95%" src="https://blogger.googleusercontent.com/img/a/AVvXsEh-E-eTXvuWj3-xMIYXoiKJgrSM71qnFuWRL1qk4D2wK4_LiZjjgwLsVQhrgy4g5NfD6IRrfkNUVpEOp3-TciN4mg4k9sDIAJsebDpJrtPN5Ot3RGlMdvaG64vXPGmXHh6Fdrbdt9L4Ux6JaEFep_nW5hMjOtuKyqvfQfs4grzhHNjvIy_reHWLmDYJIA=s1300"/></a></div>
</div>William van Strienhttp://www.blogger.com/profile/02730614987048826403noreply@blogger.com0tag:blogger.com,1999:blog-9057379846514679550.post-32175443368843743762021-12-29T00:15:00.002+01:002021-12-29T00:15:28.053+01:00Beware: on site renaming, initial Url preserved as ReadOnly site collection<div>Last year Microsoft delivered the long-requested capability to change the address of a SharePoint Online site collection. One of the features is that any request to the original / initial site address, is seamless mapped to the renamed site address. An unexpected side-effect is that on SharePoint tenant level a placeholder site collection is created to deliver this site mapping / redirection.
</div>
<div style='margin-top:10px;font-style:italic;font-weight:bolder;'>Visualization of the effect: before + after
<table style='width:100%;border:1px solid blue;margin-top:10px;'>
<thead><tr style='font-weight:bold'><td style='width:50%'>Before Renaming</td><td>After Renaming</td></tr></thead>
<tbody>
<tr style='width:100%;border:1px solid lightblue'>
<td style='width:50%;border:1px solid lightblue;vertical-align:top;'><a href="https://blogger.googleusercontent.com/img/a/AVvXsEiuW7sKJCw5_0Lyfdzn8yva_eCuHWcPxovHn-kX468XyJ51KQhWE8k3nhnFNMXAFo9piJegbPzX5clUS7jlKlSlUnWP_7rYwggYdUWZVo5XeQ-WYjdbulZWg_2Z3htzj9LiR1cSzeASmjtMFxshpv-BkcmQ3ksjAGtOCTLL-HWNAYC6xcVF5g9Y3YRxBQ=s927" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" width="98%" data-original-height="102" data-original-width="927" src="https://blogger.googleusercontent.com/img/a/AVvXsEiuW7sKJCw5_0Lyfdzn8yva_eCuHWcPxovHn-kX468XyJ51KQhWE8k3nhnFNMXAFo9piJegbPzX5clUS7jlKlSlUnWP_7rYwggYdUWZVo5XeQ-WYjdbulZWg_2Z3htzj9LiR1cSzeASmjtMFxshpv-BkcmQ3ksjAGtOCTLL-HWNAYC6xcVF5g9Y3YRxBQ=s320"/></a>
</td>
<td style='width:50%;border:1px solid lightblue;vertical-align:top;'>
<a href="https://blogger.googleusercontent.com/img/a/AVvXsEjQ_fgghlommCTSRVJVde48fBv58-zYneCFJIefPVp4BWzHfViISPcxHTyDmksjDycjc7fusZOwTQ0q0IZSIIF71TCah0WvpKWbh3WR6ibXC93n5WYUTD3Zq48Qx8qUe_E2Upd4E0WQL6T5r9Svds5JViZAYQIz9Rgc1GFBy7il9S70baBO8ObiM3e40w=s914" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" width="98%" data-original-height="94" data-original-width="914" src="https://blogger.googleusercontent.com/img/a/AVvXsEjQ_fgghlommCTSRVJVde48fBv58-zYneCFJIefPVp4BWzHfViISPcxHTyDmksjDycjc7fusZOwTQ0q0IZSIIF71TCah0WvpKWbh3WR6ibXC93n5WYUTD3Zq48Qx8qUe_E2Upd4E0WQL6T5r9Svds5JViZAYQIz9Rgc1GFBy7il9S70baBO8ObiM3e40w=s320"/></a>
</td>
</tr>
<tr style='width:100%;border:1px solid lightblue'>
<td style='width:50%;border:1px solid lightblue;vertical-align:top;'>
<a href="https://blogger.googleusercontent.com/img/a/AVvXsEiaHkqChh1scBR81LJdtoKU__2TtXqGmDbZMfqEdHWsWTODtg0la1Q7SYHG3JhXbHE-mqrN9L3TwyzhNe9xB8NEpz1hsridooTxo-D1OJ-OFcdXSUkBeeV0AKmL2D0_T3LOdCkGKMEoyZsIFF6BdZbEKnfBjRK-azZqwMntkAmPa0Ugv4DEyoXd6IlUQQ=s554" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" width="98%" data-original-height="391" data-original-width="554" src="https://blogger.googleusercontent.com/img/a/AVvXsEiaHkqChh1scBR81LJdtoKU__2TtXqGmDbZMfqEdHWsWTODtg0la1Q7SYHG3JhXbHE-mqrN9L3TwyzhNe9xB8NEpz1hsridooTxo-D1OJ-OFcdXSUkBeeV0AKmL2D0_T3LOdCkGKMEoyZsIFF6BdZbEKnfBjRK-azZqwMntkAmPa0Ugv4DEyoXd6IlUQQ=s320"/></a>
</td>
<td style='width:50%;border:1px solid lightblue;vertical-align:top;'>
<a href="https://blogger.googleusercontent.com/img/a/AVvXsEgC-kql846DfD1v3Aiek5cUr8z0SbmxNJvu5Z0QZVs-k4ah6BQcWyYqE2vhvT-3ahzehJ1NKs2-Fy66YPyeTPbdRbZS8VQ5llsVIROXk6hOqCgd71bRybTBNjm9Okh4Q-8CeW-fdFrlWHk3A1CYZz1NMUD4EGkwp1GoY6sBoQOAOSbKME_eiABFZcSAhg=s661" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" width="98%" data-original-height="390" data-original-width="661" src="https://blogger.googleusercontent.com/img/a/AVvXsEgC-kql846DfD1v3Aiek5cUr8z0SbmxNJvu5Z0QZVs-k4ah6BQcWyYqE2vhvT-3ahzehJ1NKs2-Fy66YPyeTPbdRbZS8VQ5llsVIROXk6hOqCgd71bRybTBNjm9Okh4Q-8CeW-fdFrlWHk3A1CYZz1NMUD4EGkwp1GoY6sBoQOAOSbKME_eiABFZcSAhg=s320"/></a>
</td>
</tr>
<tr style='width:100%;border:1px solid lightblue'>
<td style='width:50%;border:1px solid lightblue;vertical-align:top;'>
<a href="https://blogger.googleusercontent.com/img/a/AVvXsEiJuePM5ZF8KH1uXR0ZXsIjHkHtwGiRTzD6PajgoRZ5USAIiWJ7zNyM-gJOiSveTrBFBYtXwHmMM9kuKw20_YmQcl08gftzaFWmAfYLl7EhwuGNhk_Zps8DKCxG-vmkpqhP11CyPsscmhdmb8T-iXPrPGp5vWHeIeZeBJsS7r_Zii55koGP0fgMsfi1Qg=s615" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" width="98%" data-original-height="99" data-original-width="615" src="https://blogger.googleusercontent.com/img/a/AVvXsEiJuePM5ZF8KH1uXR0ZXsIjHkHtwGiRTzD6PajgoRZ5USAIiWJ7zNyM-gJOiSveTrBFBYtXwHmMM9kuKw20_YmQcl08gftzaFWmAfYLl7EhwuGNhk_Zps8DKCxG-vmkpqhP11CyPsscmhdmb8T-iXPrPGp5vWHeIeZeBJsS7r_Zii55koGP0fgMsfi1Qg=s320"/></a>
</td>
<td style='width:50%;border:1px solid lightblue;vertical-align:top;'>
<a href="https://blogger.googleusercontent.com/img/a/AVvXsEjC7kPFQTcCjsbG3ZpIjfiAb2NFHc0ar6HfNNULHb0DbEO6WUZ2o7rXtj_Qj9QeoAGaF0rfSeh8xt3z5LTiJprDQ3YpfqmpHBSo8Soa-7yCZCNcbYU5lLv3_niiG7R33El-4O7KJ3clAqU483ZzkSKPfGqQB8g6pjAQ4tw3_Wf90uNlhL7cphyV_snRsw=s619" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" width="98%" data-original-height="139" data-original-width="619" src="https://blogger.googleusercontent.com/img/a/AVvXsEjC7kPFQTcCjsbG3ZpIjfiAb2NFHc0ar6HfNNULHb0DbEO6WUZ2o7rXtj_Qj9QeoAGaF0rfSeh8xt3z5LTiJprDQ3YpfqmpHBSo8Soa-7yCZCNcbYU5lLv3_niiG7R33El-4O7KJ3clAqU483ZzkSKPfGqQB8g6pjAQ4tw3_Wf90uNlhL7cphyV_snRsw=s320"/></a>
<a href="https://blogger.googleusercontent.com/img/a/AVvXsEjXNN5597KPAPAwgnCFFDAsCpl-5L7wHOLPq-Iu-nke3cRGwP2xOjm662hX1ee5NHjWbTb9BFWfNpeMgKMjkh-JCMjLOIiZpaFaZc5f5Y6xh3MQUx1XQ85p7zOXw8QI6mKepGiWCgAqA9h3LkzRbnb8nANOq_i9cyBMJdglaFshPe1R2jXchq_4VqWwQQ=s617" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" width="98%" data-original-height="95" data-original-width="617" src="https://blogger.googleusercontent.com/img/a/AVvXsEjXNN5597KPAPAwgnCFFDAsCpl-5L7wHOLPq-Iu-nke3cRGwP2xOjm662hX1ee5NHjWbTb9BFWfNpeMgKMjkh-JCMjLOIiZpaFaZc5f5Y6xh3MQUx1XQ85p7zOXw8QI6mKepGiWCgAqA9h3LkzRbnb8nANOq_i9cyBMJdglaFshPe1R2jXchq_4VqWwQQ=s320"/></a>
</td>
</tr>
</tbody>
</table>
</div>William van Strienhttp://www.blogger.com/profile/02730614987048826403noreply@blogger.com0tag:blogger.com,1999:blog-9057379846514679550.post-76254234778539988222021-12-24T17:52:00.001+01:002021-12-24T17:52:20.775+01:00Things to be aware of when embedding video play in Teams Meeting
<div>In the Microsoft Mechanics video <a href='https://www.youtube.com/watch?v=V9cHu_YwZg8'>how to present videos in microsoft teams meetings WITHOUT lag</a>,</div>
<div class="separator" style="clear: both;">
<iframe class="BLOG_video_class" allowfullscreen="" youtube-src-id="V9cHu_YwZg8" width="200" height="166" src="https://www.youtube.com/embed/V9cHu_YwZg8"></iframe>
the presenter clarifies the multiple hop issue that may result for the audience in non-optimal experience when embedding a video play in the Teams meetings.</div>
<div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEjD-r2Rs2eTDxkPdis4QqZ3Wxylj2Rzk4Oyh8ut76pPVg2Cc4xJcaQcvR-UrNCtT2NIULA4aK1nwJq3G7P__HT0wIrt-B3_k_WNHQfYNvr7bLk5fMh9yutgXYC1lkQngDFjW9VOYbqdzYWwOEEnVH9w0VXOWxPPhjpuv5Cgyv_aLnpjGdCj-Y9WE7LDEg=s999" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" width="95%" src="https://blogger.googleusercontent.com/img/a/AVvXsEjD-r2Rs2eTDxkPdis4QqZ3Wxylj2Rzk4Oyh8ut76pPVg2Cc4xJcaQcvR-UrNCtT2NIULA4aK1nwJq3G7P__HT0wIrt-B3_k_WNHQfYNvr7bLk5fMh9yutgXYC1lkQngDFjW9VOYbqdzYWwOEEnVH9w0VXOWxPPhjpuv5Cgyv_aLnpjGdCj-Y9WE7LDEg=s999"/></a></div>
<h2>Awareness 1: Recording misses the video if embedded via PowerPoint live</h2>
<div style='margin-top=10px'>In this video he also introduces the Microsoft recommendation how to resolve this; namely by uploading the video via PowerPoint already in the Microsoft cloud. With this approach the first 2 hops are avoided. This works like a charm for the people live in the meeting. But a caveat I noticed is that when you need a recording of the meeting for afterwards (re)watch, then the video play is missing.
</div>
<div style='margin-top:10px'><b>Include the video play via PowerPoint Live in the Teams Meeting presentation</b></div>
<div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEicsnjx40DvBGoFjsZpUTJ1HGENC6btb1cYbsRSxJ8ITFqxRY4juqhKeZmHTBj1Ww5q3QxYtkdRwHVQSWQnKK1PmZonFuXcBdwkmUhsEBcSm-_ZEzYF7zjGSpaLPtHEIIEuWSXaqb2Lq5-H_euFjNoqPx1Xn-LcVEX6tOqucivU9s-aNnEdZ48yFfNs9w=s1163" style="display: block; padding: 1em 0; text-align: left; "><img alt="" border="0" width="320" data-original-height="643" data-original-width="1163" src="https://blogger.googleusercontent.com/img/a/AVvXsEicsnjx40DvBGoFjsZpUTJ1HGENC6btb1cYbsRSxJ8ITFqxRY4juqhKeZmHTBj1Ww5q3QxYtkdRwHVQSWQnKK1PmZonFuXcBdwkmUhsEBcSm-_ZEzYF7zjGSpaLPtHEIIEuWSXaqb2Lq5-H_euFjNoqPx1Xn-LcVEX6tOqucivU9s-aNnEdZ48yFfNs9w=s320"/></a></div>
<div style='margin-top:10px'><b>Video is playing in the Teams Meeting, audience can live watch it</b></div>
<div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgjfDP1IPldBIS3VeuutnKRdy7_PM4jD_xYb8_4b6V0AqrMbYTW6SZd6CiTDiqUkGt5yaelhZ5hMCYOJVP2xIRWr0NQIn7raNlq6maHqUCy5GzxOpDC7KXiMOoKe0Opm9DUDJcNyI04afaOZhjnhZdncYVgRPmeTgQmv-wt8eENSsPGhgjTr9zqv2ANsg=s1915" style="display: block; padding: 1em 0; text-align: left; "><img alt="" border="0" width="400" data-original-height="1018" data-original-width="1915" src="https://blogger.googleusercontent.com/img/a/AVvXsEgjfDP1IPldBIS3VeuutnKRdy7_PM4jD_xYb8_4b6V0AqrMbYTW6SZd6CiTDiqUkGt5yaelhZ5hMCYOJVP2xIRWr0NQIn7raNlq6maHqUCy5GzxOpDC7KXiMOoKe0Opm9DUDJcNyI04afaOZhjnhZdncYVgRPmeTgQmv-wt8eENSsPGhgjTr9zqv2ANsg=s400"/></a></div>
<div style='margin-top=10px'><b>Video play is missing in the recording of the Teams Meeting</b></div>
<div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEhXI9WCfWQ6H-QuEZWDGuyvNVe1BJvH0aUHBrLtWIR7L-h00OnypWxbtlU2aOm5ZBWcxHM_h5Zk-tNYEVTEYOqbxfRCO7HxpEbJPNJvaNg2A9xnIzkGI5CNqDRtWv25nxMl6I2qCBLvs2tp9n84ReHkwNjld-5m1L7lpDqHO4VzID9_pGNvEKEx8VSt6A=s1916" style="display: block; padding: 1em 0; text-align: left; "><img alt="" border="0" width="320" data-original-height="922" data-original-width="1916" src="https://blogger.googleusercontent.com/img/a/AVvXsEhXI9WCfWQ6H-QuEZWDGuyvNVe1BJvH0aUHBrLtWIR7L-h00OnypWxbtlU2aOm5ZBWcxHM_h5Zk-tNYEVTEYOqbxfRCO7HxpEbJPNJvaNg2A9xnIzkGI5CNqDRtWv25nxMl6I2qCBLvs2tp9n84ReHkwNjld-5m1L7lpDqHO4VzID9_pGNvEKEx8VSt6A=s320"/></a></div>
<h2>Awareness 2: Embed the video as shared content - video play stops on ANY mouseclick</h2>
<div>If you need to meetings to be recorded; then you must share the video ‘as content’. The first of the 3 hops can be avoided by storing the video first local on your workstation, and play it from there on a 2nd monitor. Select this 2nd monitor on which playing for sharing in the Teams, and don’t forget to turn on ‘Include computer sound’ ! The video playing is then both visible for the audience 'live' in the meeting, and also included in the Teams meeting recording. Caveat with this setup is that during video play, you must take care not to click your mouse at all. If you do so, it doesn't matter whether in other screen or application; the video play immediate stops, resulting in disrupted experience. If you want to rule out this risk, then the trick is to play the video on another system then the one used for sharing in Teams Meeting (or Live Event). This setup is described in detail by Chris Stegh in his excellent article <a href='https://blog.enablingtechcorp.com/sharing-video-in-microsoft-teams-meetings'>Sharing Video in Microsoft Teams Meetings</a>.</div>
<div style='margin-top:10px'><b>Include the video play via shared content in the Teams Meeting presentation</b></div>
<div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEhsfNmKCuj9UH20px357czTLCI1WU41EmF0U49Kgs8d4gRkIUVY5OmGPkmo8t4GrzTywwBMrjbi9DdYqFFsg9MHeo33B8g2xML1SRgXDbVWqopLI4kzX2B99zmeLUgF9EDXk8IXd3FoPFKaCjtA-1_5SIFdOW6J-_buV1WOskBCwU8i7-uy_BnH_xeeDA=s1336" style="display: block; padding: 1em 0; text-align: left; "><img alt="" border="0" width="320" data-original-height="802" data-original-width="1336" src="https://blogger.googleusercontent.com/img/a/AVvXsEhsfNmKCuj9UH20px357czTLCI1WU41EmF0U49Kgs8d4gRkIUVY5OmGPkmo8t4GrzTywwBMrjbi9DdYqFFsg9MHeo33B8g2xML1SRgXDbVWqopLI4kzX2B99zmeLUgF9EDXk8IXd3FoPFKaCjtA-1_5SIFdOW6J-_buV1WOskBCwU8i7-uy_BnH_xeeDA=s320"/></a></div>
<div style='margin-top:10px'><b>Video play is included in the recording of the Teams Meeting</b></div>
<div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEg52-ntPcNKUoxlhUHrZ5JNvZROsU329dWcd17pq-a74U-HhhDmWoWNae4t-3oyYl4-9QgteSv7tjNA0gVJ3Y0vx_iaMzJCaWhE-lftpXtimZ0jsIktF66wkLU017wqPOHgOVVVJgdJ7a8K-tOuej1-qd6H2pKOwE9CUst93eEJ2P7GweJn-Y3HoPQADQ=s1922" style="display: block; padding: 1em 0; text-align: left; "><img alt="" border="0" width="320" data-original-height="928" data-original-width="1922" src="https://blogger.googleusercontent.com/img/a/AVvXsEg52-ntPcNKUoxlhUHrZ5JNvZROsU329dWcd17pq-a74U-HhhDmWoWNae4t-3oyYl4-9QgteSv7tjNA0gVJ3Y0vx_iaMzJCaWhE-lftpXtimZ0jsIktF66wkLU017wqPOHgOVVVJgdJ7a8K-tOuej1-qd6H2pKOwE9CUst93eEJ2P7GweJn-Y3HoPQADQ=s320"/></a></div>
<h2>Awareness 3: Reporter layout not propagated into recording</h2>
<div>A nice recent addition to Teams Meeting is <a href='https://support.microsoft.com/en-us/office/engage-your-audience-with-presenter-modes-a3599bcb-bb35-4e9c-8dbb-72775eb91e04'>multiple layout-options for the presenter</a>, contributing to more professional appearance to the audience. However, only the 'live' audience can enjoy it; in the recording the presenter mode is ignored and it always in side-by-side layout. This holds for both approaches: whether including the video via PowerPoint (but this is current a no-go if video AND need recording) and on including as shared content.</div>
<div style='margin-top:10px'><b>Reporter layout for the presenter in the 'live' meeting</b></div>
<div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEhF8FTUJ_dIs_03iOwp61JWZomxYSuff4SCHm2e4g9kWmEKisD8HJjRZjGTzoKU_1ObfYpZjhVtkiO2YnFG_81HpIQ9QUsNDuBplt4RILYIvhzWiCeASy6flDlkwh01pqUm9VZWUxTGkYPX7ntlexTompT95JTeszxwGMbhRCMatEd8EgSE44kPBQdszw=s1521" style="display: block; padding: 1em 0; text-align: center; clear: left; float: left;"><img alt="" border="0" width="320" data-original-height="1022" data-original-width="1521" src="https://blogger.googleusercontent.com/img/a/AVvXsEhF8FTUJ_dIs_03iOwp61JWZomxYSuff4SCHm2e4g9kWmEKisD8HJjRZjGTzoKU_1ObfYpZjhVtkiO2YnFG_81HpIQ9QUsNDuBplt4RILYIvhzWiCeASy6flDlkwh01pqUm9VZWUxTGkYPX7ntlexTompT95JTeszxwGMbhRCMatEd8EgSE44kPBQdszw=s320"/></a></div>
<div style='clear: both;margin-top:10px'><b>Side-by-Side layout for the presenter in the recording of meeting</b></div>
<div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgoC-jl3bJQXFILQ3rHjj9YFEG_ke8yz7-RRq69VzfVDY-iKyMG3AOB-TWh_xlEnKZaBLCyGMgVlFOdfNN-keQRSncNY9U-KgnTtmoSxPSG6hypfo819awqG0Hhm7UUE2uaxh5XKXprYTsjmoKLXG7rf9yg9JYauffDgMHylF8mphxPRkKCAOkJRYVkfg=s1926" style="display: block; padding: 1em 0; text-align: center; clear: left; float: left;"><img alt="" border="0" width="320" data-original-height="924" data-original-width="1926" src="https://blogger.googleusercontent.com/img/a/AVvXsEgoC-jl3bJQXFILQ3rHjj9YFEG_ke8yz7-RRq69VzfVDY-iKyMG3AOB-TWh_xlEnKZaBLCyGMgVlFOdfNN-keQRSncNY9U-KgnTtmoSxPSG6hypfo819awqG0Hhm7UUE2uaxh5XKXprYTsjmoKLXG7rf9yg9JYauffDgMHylF8mphxPRkKCAOkJRYVkfg=s320"/></a></div>
William van Strienhttp://www.blogger.com/profile/02730614987048826403noreply@blogger.com0tag:blogger.com,1999:blog-9057379846514679550.post-86054054158785827152021-10-13T20:45:00.005+02:002021-10-13T20:45:56.083+02:00Beware: Issues in Hybrid Search Crawling might not be flagged<div>We have a mixed SharePoint setup with parts still on-prem, while for others we moved to Microsoft cloud. We try as much as possible to abstract our end-users from this complexity in the SharePoint landscape. Therefore we utilize SharePoint Hybrid Search to allow the end-users finding from one single search entrance all SharePoint stored content, whether stored on-prem or online.</div><div style='margin-top:5px'>From time to time we encounter issues in this setup, most significant cause being that the required trust on the on-prem search crawlers to online index is lost due change of certificate on Microsoft Online side. We are automated flagged if such issue occurs, as we have an automated health monitoring + notification on the state of the crawl logs. Too bad, due a recent Microsoft change we can no longer trustworthy rely on the automated signalling. For (design) reasons so far only known to Microsoft development team, they decided to no longer flag in the crawl log in case an error occurs on propagating crawled content to the online index. We noticed as we started missing recent content in the search results; while on inspection of the crawl log it was reported to be successful crawled: full green. Yet by doing a query on 'k=isExternalContent:1' the most recent on-prem crawled items were not included in the search result, a clear deviation from the healthy report of the on-prem to online crawling.
</div>
<div class="separator" style="clear: both;"></div><div style='margin-top:10px;font-style:italic;'><img alt="" border="0" width="95%" src="https://1.bp.blogspot.com/-ke8ktWLAoI0/YWcka4YqCoI/AAAAAAAACKk/Ecz4utDfQZ8IGyGdp1DCe6BaYpD8cGnjQCNcBGAsYHQ/s0/Hybrid%2BSearch%2Bcrawling%2Bappears%2Bhealthy.png"/></div>
</div>
<div style='margin-top:20px;font-style:italic;'>Note: the actual rootcause of the missed crawled items in the online index was that in the user policy of the on-prem webapplication some accounts were configured, that in online world no longer had a match. This resulted in failing to index in SharePoint Online with error "Hybrid ACL Mapping: Deny ACE with unknown/unmappable hybrid claim", but it turns out that such error is no longer notified back to the on-prem crawler context. As Office 365 customer you do not have visibility on the Online index; we only came to know of this rootcause after we involved Microsoft Support. Once cause known, the problem was easily fixed: we removed the stale accounts also from the on-prem user policy.
</div>
<div>
William van Strienhttp://www.blogger.com/profile/02730614987048826403noreply@blogger.com0tag:blogger.com,1999:blog-9057379846514679550.post-81792957096118269792021-05-30T22:56:00.005+02:002021-05-30T23:04:28.141+02:00Prevent that Azure AD B2B guests are blocked due expired MFA<div>Azure AD B2B can also be used to authorized identified externals to digital events that your organization hosts, via Teams Live Event or via any streaming platform that is access-control protected via Azure AD. To increase security, enterprise organizations typical employ Multi-Factor Authentication via MS Authenticator App. A problem can be that re-visiting guests have their MFA status expired, but are unaware of that. And then face issue at the moment they want to join the digital event.</div><div style='margin-top:5px;'>To prevent this, better to explicit reset the MFA status <i>before</i> the event. But you should not do this blind for <i>all</i> invited guests, as there are likely also guests that still have and use an active MFA status; e.g. for regular external collaboration with your organization. The trick here is to inspect the latest logon of the guest, and in case this was longer ago then you can safely assume the person is not an heavy guest-user, and for safety sake reset the MFA.</div><div style='margin-top:5px;'>Azure AD does not direct reveal 'last logon' information, but you can utilize that access is granted via OAuth2.0 tokens: Azure AD stores per account 'RefreshTokensValidFromDateTime'; and this value can be interpreted as the datetime of 'last logon' (source: <a href='https://www.undocumented-features.com/2018/06/22/how-to-find-staleish-azure-b2b-guest-accounts/'>How to find Stale(ish) Azure B2B Guest Accounts</a>)
</div>
<div style='margin-top:10px'><b>Automation script</b> <a href='https://github.com/wvstrien/azure-ad/blob/main/ExecuteMFAResetForExpiredGuestsAccounts.ps1'>ExecuteMFAResetForExpiredGuestsAccounts.ps1</a>
</div>William van Strienhttp://www.blogger.com/profile/02730614987048826403noreply@blogger.com0tag:blogger.com,1999:blog-9057379846514679550.post-5437615389927910622021-05-22T20:14:00.004+02:002021-05-22T20:22:27.587+02:00Tip: How-To get non-persistent cookie (e.g ASP.NET_SessionId) within PowerShell<script src="https://google-code-prettify.googlecode.com/svn/loader/run_prettify.js"></script><div><u>Context of my need</u>: a COTS application deployed as Azure WebApp that is also used as REST Api by this webapplication, and the need to automate some of the provision capabilities in this application. The user-based authentication and access control on the Azure WebApp <i><u>as Api</u></i> is implemented by leveraging the SharePoint Add-In model, with the remote Azure App launched via AppRedirect.aspx. And next the Api endpoints check the 'SPAppToken' cookie included in Api request, plus the "ASP.NET_SessionId".</div><div style='margin-top:5px'>The first is rather simple to get hands on in PowerShell code, by 'Invoke_WebRequest' to AppRedirect.aspx with the proper launch parameters; and from the WebResponse object parse the SPAppToken value that is returned in body of the response. </div><div style='margin-top:5px'>However, the 2nd is more tricky: it is returned as <i>non-persistent cookie</i> in the response, and default not available within PowerShell automation context to read from the WebResponse object. I tried the approach described in <a href="https://social.technet.microsoft.com/Forums/ie/en-US/9f214ed6-66fc-43d1-b775-d841bddcbcfa/cannot-get-authentication-cookie-from-web-server-with-invokewebrequest">Cannot get authentication cookie from web server with Invoke-WebRequest</a>. Without success, but it did inspire me to an alternative approach; and that does work:</div>
<div class="highlight">
<pre class="prettyprint"><div style='font-size:95%;line-height:110%;border: 1px solid rgb(192, 192, 192);padding:5px;overflow:auto;color:#aaa;background-color:#FFFFFF'><pre class="code">
function GetAzureAppASPNetSessionId() {
$appLaunchCookies = "SPAppToken=$global:AzureSPAppToken&SPSiteUrl=$([System.Web.HttpUtility]::UrlEncode($global:targetSite))"
$url = "$azureAppLaunchUrl/?SPHostUrl=$([System.Web.HttpUtility]::UrlEncode($global:targetSite))";
<span style='background-color:yellow'>$WebSession = New-Object Microsoft.PowerShell.Commands.WebRequestSession;</span>
$wr1 = Invoke-WebRequest -Uri $url -Method Post -Body $akuminaCookie -WebSession $WebSession;
<span style='background-color:yellow'>$cookieCont = $WebSession.Cookies.GetCookies($appLaunchCookies);</span>
$aspNetSessionIdCookie = $cookieCont | Where {$_.Name -eq "ASP.NET_SessionId" };
if ($aspNetSessionIdCookie) {
return $aspNetSessionIdCookie.Value;
}
}
</pre></div>William van Strienhttp://www.blogger.com/profile/02730614987048826403noreply@blogger.com0tag:blogger.com,1999:blog-9057379846514679550.post-32102896561043126562021-04-30T23:24:00.005+02:002021-05-22T19:40:59.585+02:00Be aware: ''Check Permissions" does not report M365 Group authorizations until first access<div>The new and default permission model for Modern Team Sites is via the 'owning' Office 365 Group. I discovered a functional flaw in that: on accounts authorized for site access via the Office 365 group, the SharePoint 'Check Permissions' capability reports "None" <i>until</i> first site visit of an authorized account (<I>which on SharePoint level results that the account is administrated in the (hidden) site users list</I>). I reported this to Microsoft Support, and they reproduced + confirmed the behavior in an arbitrair tenant. Their first response was "this is expected behavior", but I strongly disagree. We use and rely on 'Check Permission' to assess whether a person has access <i><b>or not</b></i> to a SharePoint site. And the reliability of this access-check should not be dependent that the assessed person has actually already once visited the site.
</div>
<div style="margin-top:10px;"><i><b>Update:</b> in call with Microsoft Support they motivated the "this is expected behavior": it is expected from how it is <u>technically build</u> within SharePoint.... When I re-stated that on <u>functional view</u> this is not expected behavior, they agreed and asked me to submit as UserVoice <a href='https://sharepoint.uservoice.com/forums/329214-sites-and-collaboration/suggestions/43397184-spo-check-permissions-does-not-report-spo-permis'>suggestion</a>; so that the development team can triage it for product fix.</i></div>William van Strienhttp://www.blogger.com/profile/02730614987048826403noreply@blogger.com0tag:blogger.com,1999:blog-9057379846514679550.post-10522750822668824072021-02-07T00:00:00.003+01:002021-02-07T00:23:43.420+01:00Migrating away from SPD workflows: Power Automate is NOT the right direction for system processing<div>Like more O365 customers, we were in begin Q3 2020 unpleasant surprised by the Microsoft announcement that runtime execution of SharePoint Designer 2010 workflows would in few months time come to its end. In our tenant, business users are self-empowered for automation customizations, and in a significant number of site collections they have designed custom workflows. But as it quickly became clear that the stop-message of Microsoft this time was a final one (<i>note: on concrete stop-moment of InfoPath, the other 'old/classic' power-user customization tool is no Microsoft statement yet on</i>), we knew we had to act. We bought ourselves some time with Microsoft, as the initial message of stop in few months was both unrealistics as ridiculous / not consumer-friendly from Microsoft. And then together with business, as in our model they own their self-build customizations, started up a migration plan away from SharePoint 2010 workflows (and later on to include SPD 2013). The destination to be Power Automate, as that is what Microsoft itself is advising:
<div style='margin:10px 10px 10px 10px; width:97%;'><div style='margin-top:1px;margin-bottom:2px;border-width:1px;border-style:solid;border-color:#C0C0C0;background:lightblue;width:90%;font-style:italic;padding:10px;'><p>If you’re using SharePoint 2010 workflows, we recommend migrating to Power Automate or other supported solutions.</p><p>Source: <a href='https://support.microsoft.com/en-us/office/sharepoint-2010-workflow-retirement-1ca3fff8-9985-410a-85aa-8120f626965f'>SharePoint 2010 workflow retirement</a></p></div></div>
</div><div style='margin-top:10px;'>
While ongoing, this generic Microsoft advise turns out viable for the majority of the custom-build processing, as these are mostly on level of 'user-productivity'. But the Power Automate approach gets in a squeeze to migrate unattended system processing, with a bulk of actions. Power Automate on itself can handle that, but the license model restricts the flow owner from using it for bulk / large automated operation. You either are forced to buy a more extensive Power Automate license, but mind you: this buys additional capacity, but still with a defined limit. Or you must migrate to another 'supported solution'. In the Microsoft 365 domain this means to migrate to Logic Apps iso Power Automate. The design model of the both are similar, the operation model however very different: Power Automate runs under identity and license of Power Automate owner with a licensed capacity on level of flow actions; Logic Apps runs under system identity and with pricing model of 'pay what you use'. If you need more capacity, you will pay more; but Microsoft will not stop the system processing because you passed a capacity thresshold.
</div><div style='margin-top:10px;'>
Business users dislike the Logic Apps approach, as this reduces their self-empowerment. They are not capable to define + deploy Logic Apps flows themselves into the productive landscape, but must involve IT / administrators. But one must question on whether this loss of flexibility / business-agility is really a recurring problem: you do not expect critical system automation /processing to require the capability for business to continuously be able to change on the spot. A bit of control on such business critical processing is not per se a bad thing, neither for the owner business themselves...
</div>
<div style='margin-top:20px;'><b>Pointers:</b><ol><li><a href='https://flow.microsoft.com/en-us/pricing'>Power Automate pricing</a></li><li><a href='https://docs.microsoft.com/en-us/power-platform/admin/api-request-limits-allocations'>Power Platform: Requests limits and allocations</a><div style='margin-top:1px;margin-left:20px;font-style:italic;font-size:smaller'>For personal-productivity automation, licensed capacity of max 5000 actions per day is well beyond expected usage. But this does not apply ico automated system processing: max of only 5000 is not enough when bulkprocessing eg an HR process for all employees of a > 20.000 FTE organization.</div></li><li><a href='https://365bythijs.be/2020/11/12/why-you-should-use-logic-apps-instead-of-power-automate/'>Why you should use Logic Apps instead of Power Automate</a><div style='margin-top:1px;margin-left:20px;font-style:italic;font-size:smaller'>Power Automate is meant to automate certain workflows for productivity, Logic Apps are meant to automate certain tasks within your organization.</div></li><li><a href='https://econmdm.medium.com/why-you-need-power-automate-and-azure-logic-app-for-your-enterprise-c60a7fea1e66'>Why you need Power Automate and Azure Logic App for your enterprise</a><div style='margin-top:1px;margin-left:20px;font-style:italic;font-size:smaller'>If you create a custom workflow on Power Automate, it can be exported to a JSON file which can then be imported into Azure Logic App. This is a great way to migrate a custom workflow created by a Business user; for example, to be evolved into a more elaborate process and then shared with the team.</div><div style='margin-top:5px;margin-left:20px;font-style:italic;font-size:smaller'>Power Automate workflow is suitable for individual users who need their own custom processes. Azure Logic App is for workflow shared by multiple users or complex processes maintained by IT. This decision is also driven by their specific pricing model.</div><div style='margin-top:5px;margin-left:20px;font-style:italic;font-size:smaller'>Power Automate license by user: $15 USD per user per month.
Azure Logic App is charged by execution: $0.000025 USD per action, and $0.000125 USD per Standard Connector.</div></li><li><a href='https://www.thakkarworld.com/azure-logic-apps-vs-power-automate-detailed-comparison.html'>Azure logic apps vs Power automate – A detailed comparison</a></li></ol></div>William van Strienhttp://www.blogger.com/profile/02730614987048826403noreply@blogger.com0tag:blogger.com,1999:blog-9057379846514679550.post-57450377082531502252021-02-03T21:30:00.001+01:002021-02-03T21:31:44.034+01:00Leverage MS Stream eCDN investment with THEOplayer<div>Last year we selected <a href='https://www.rampecdn.com/'>Ramp eCDN</a> as <a href='https://docs.microsoft.com/en-us/stream/ecdn#acquire-and-set-up-your-ecdn-solution-outside-of-stream'>Microsoft-certified eCDN solution for Microsoft Stream</a>, and successful applied Ramp Multicast+ in multiple internal webcasts for control on the internal video delivery. For diverse reasons on another webcast Microsoft Stream is insufficient (<i>lack of customization options to provide a rich virtual event attendee experience, lack of guest access</i>). Business selected a product company with their own cloud-based streaming platform. The player used in that platform is <a href='https://www.theoplayer.com'>THEOplayer</a>, consuming HLS video traffic.</div><div style='margin-top:10px;'>An aspect that remained is that at IT / connectivity level, we must prevent network saturation on the internal network. So we explored whether possible to leverage Ramp Multicast+ also with this HLS-based THEOplayer. According to a <a href='https://www.theoplayer.com/blog/ramp-theoplayer-team-up-simplify-delivery-playback-video-press-release'>promotional</a> this should be possible, but it turned out that neither of the 2 involved vendors actually had it working. In a DevOps way of working with the 3 involved external parties (production company, Ramp, THEOplayer), we identified the code-pieces that are required to make the combination THEOplayer + Ramp an actual reality. With the required result: the global audience that was watching this webcast direct connected to the company LAN, all consumed the video traffic flawless as one shared multicast stream. Without negative effect of public internet connections at specific locations + countries.</div>
<div style='margin-top:10px;'><i>Proof of Concept code in plain JavaScript: <a href='https://github.com/wvstrien/sharepoint/blob/master/THEOPlayerAndRampPoC.js'>THEOPlayerAndRampPoC.js</a>. Based on successful PoC validation, this code-snippet was reused by vendor to include the Ramp Multicast+ optimized video consumption in their THEOplayer usage, via typescript THEOplayer hooks module.</i></div>
</div>William van Strienhttp://www.blogger.com/profile/02730614987048826403noreply@blogger.com0tag:blogger.com,1999:blog-9057379846514679550.post-81292044813846927132021-01-23T19:42:00.004+01:002021-01-24T12:36:27.178+01:00Understanding why you at least must consider to go isolated<script src="https://google-code-prettify.googlecode.com/svn/loader/run_prettify.js"></script><div>My trigger was actually a classsic 'admin' versus 'dev' mindset: I wanted to “play” with the new <a href='https://docs.microsoft.com/en-us/graph/toolkit/overview'>Microsoft Graph Toolkit 2.0</a>, and used <a href='https://docs.microsoft.com/en-us/graph/toolkit/components/person-card'>Mgt-PersonCard</a> in a custom SPFx webpart. Deployed it to a development/playground site in SharePoint production tenant, as only there is a filled User Profile store to fully experience all the capabilities delivered in the Person-Card component. Asked the Azure tenant admin to approve the <a href='https://docs.microsoft.com/en-us/graph/toolkit/components/person-card#microsoft-graph-apis-and-permissions'>API Permissions</a> that Mgt controls typical require, and in all the Microsoft provided code examples for simplicity sake are requested org-wide. And got the door slammed back in my face: sorry, not going to grant this [<i>are you insane for even dare to ask??</i>]</div>
<div style='margin-top:10px;'>
At first surprised and disappointed on this rejection, I again looked into API Permissions for understanding. I started with questioning some Microsoft contacts on what Microsoft recommended best-pracice in this is. Not suprising, the consultancy answer is on level of “<i>it depends</i>” and “<i>customers must consider and decide for themselves</i>”. So that is what I continued with: deep-dive to understand about how org-wide can be risky, and about the balance between strict security control/mitigation, versus developer convenience.
</div>
<div style='margin-top:10px;'><h2>The happy, unworried flow...</h2>I started with reading again the Microsoft Docs on <a href='https://docs.microsoft.com/en-us/sharepoint/dev/spfx/use-aadhttpclient'>Connect to Azure AD-secured APIs in SharePoint Framework solutions</a>. This is a typical example of Microsoft documentation in which simplicitly prevails above the more complex story. Yet some credits deserved, in the Considerations section there is some minor warning about <a href='https://docs.microsoft.com/en-us/sharepoint/dev/spfx/use-aadhttpclient#granted-permissions-apply-to-all-solutions'>Granted permissions apply to all solutions</a>.</div>
<div style='margin-top:10px;'><h2>Happy indeed, for malicious code...</h2>But what does this actually mean, how can 'any solution in tenant' (mis)use the Azure AD permissions granted to the webpart you deployed in AppCatalog? For understanding of this, another Microsoft Docs gives more insight: <a href='https://docs.microsoft.com/en-us/sharepoint/dev/spfx/web-parts/guidance/connect-to-api-secured-with-aad'>Connect to API secured with Azure Active Directory</a>; in the section '<a href='https://docs.microsoft.com/en-us/sharepoint/dev/spfx/web-parts/guidance/connect-to-api-secured-with-aad#azure-ad-authorization-flows'>Azure AD authorization flows</a>':<blockquote>"<i>Client-side web applications are implemented using JavaScript and run in the context of a browser. These applications are incapable of using a client secret without revealing it to users. Therefore these applications use an authorization flow named OAuth implicit flow to access resources secured with Azure AD. In this flow, <b>the contract between the application and Azure AD is established based on the publicly known client ID and the URL where the application is hosted</b></i>"</blockquote>In essence this means that all what is needed for arbitrary script code to reuse Azure AD permissions granted on org-wide level, is <b><i>the public client ID or name of an approved application</i></b>, and the script must be loaded in the browser on the <b><i>same domain as that approved application</i></b>. The clientside script code can then itself setup OAuth Implicit flow for the public client ID or name. The script does not have to be SPFx code itself, in the ultimate situation it can implement OAuth Implicit flow itself on raw OAuth protocol level. The lack of MSAL.js or even ADAL.js does not scare hackers away, they have rich toolkits to help them setup attacks. And the attack can even be simpler: in case the malicious code is included in the browser DOM where also at run and render time a SPFx control is loaded, then it can read/steal in the DOM the access token returned to that SPFx control loaded in the same domain. Awareness on this in <a href='https://docs.microsoft.com/en-us/sharepoint/dev/spfx/web-parts/guidance/connect-to-api-secured-with-aad#considerations-when-using-oauth-implicit-flow-in-client-side-web-parts'>Considerations when using OAuth implict flow in client-side webparts</a>: <blockquote>"<i>Web parts are a part of the page and, unlike SharePoint Add-ins, share DOM and resources with other elements on the page. Access tokens that grant access to resources secured with Azure AD, are retrieved through a callback to the same page where the web part is located. That callback can be processed by any element on the page. Also, after access tokens are processed from callbacks, they're stored in the browser's local storage or session storage from where they can be retrieved by any component on the page. A malicious web part could read the token and either expose the token or the data it retrieved using that token to an external service.</i>"</blockquote>
</div>
<div style='margin-top:10px;'><h2>Is there real risk?</h2>
A typical 'dev' response is that there is no real security risk of leaking unauthorized information. After all, the client side code can only access data and functions for which the logged-on user is allowed, thus is already entitled to access. Fair point, but the fundamental difference is in the <b><i>awareness</i></b> of the logged-on user that data is retrieved under his/her identity. For 'safe' code, the user is aware that data is retrieved; that is exact the business purpose why (s)he is using this trusted control. But consider malicious code that was downloaded by a business user from internet to deliver that one convenient capability (e.g. draw a nice looking graph). The business user is not aware in case that convenient library underwater misuses the OAuth accesstoken granted to e.g. invoke the Graph API for reading person data from User Profiles, and leak that data to social or even dungeon endpoints where you definitely don't want this company related data to land.
</div>
<div style='margin-top:10px;'><h2>Protection by isolation [<i>social distancing</i>]</h2>
How do SPFx isolated webparts protect against this global allowed access risk? In essence very simple: by isolating the Azure AD / API permissions approval to only the SPFx solution that requested it, and were approved / trusted by the Azure admin tenant. On browser operation level this isolation is delivered by each isolated SPFx webpart in its own unique solution-specific domain, hosted in an iframe. Other code cannot on browser nor DOM level be loaded into such iframe isolated domain, and thus cannot piggy-back on the contract of this approved SPFx solution. Loaded from different url, and the browser protects against reading the accesstoken from the iframe. </div>
<div style='margin-top:10px;'>And a nice additional advantage of SPFx isolated webparts is that in API Permissions administration is logged and thus visible per SPFx solution what permissions are requested. This visibility is lacking with org-wide permissions: an admin (Azure nor SharePoint) cannot tell which SPFx solutions requested the API permissions. And more dangerous: there is no indication on which code (SPFx webparts, other libraries) is using the org-wide approved permissions.
</div>
<div style='margin-top:20px;'><h2>Understanding summed up in bullets</h2>
<div style="font-size:95%;border: 1px solid rgb(192, 192, 192);padding:2px;color:#aaa;background-color:#F5F5F5">
<ul>
<li>Azure AD is used to for access-control to data (Microsoft 365) and applications (Microsoft 365 + other applications)</li>
<li>Azure API permissions (‘scopes’) are used to allow Azure AD authenticated clients, specific access to Azure AD protected resources</li>
<li>JavaScript code running in browser uses OAuth implicit flow to authenticate on-behalf of the logged-on user to Azure AD, and via approved Azure API permissions is permitted to do actions against the Azure AD protected resource</li>
<li>Org-Wide allowed API permissions are available for any JavaScript code that is executed in the runtime context of the ASML SharePoint domain, and that applies OAuth implicit flow against Azure AD (OAuth access token is returned within https://<tenant>.sharepoint.com global context)</li>
<li>There is no visibility in Azure AD of the usage-context for which org-wide API Permissions are required → identity of specific SPFx controls that request them at deployment time, is not administrated</li>
<li>On <u>Classic</u> Sites: via script injection, whatever library can be downloaded from internet by business users themselves, without IT involvement nor awareness. Malicious code is on Azure AD level enabled to misuse API permissions that are permitted on org-wide level. Without the logged-on user being aware, the downloaded JavaScript library can access the protected resource on behalf of the logged-on user, and “do malicious / bad things’ with the data that can be retrieved. E.g. send out the data to an extern location (social channels, business competitor, ...)</li>
<li>On <u>Modern</u> Sites: by default the business user are disallowed to insert / inject arbitrary code themselves. Code can only be uploaded as SPFx code in AppCatalog:<ul>
<li>Tenant AppCatalog: managed by IT</li>
<li>Site AppCatalog: managed by business self (SCA). IT controls whether a Site AppCatalog is delivered on a site, only on good business motivation; and knowledgeable + trusted developers are involved</li>
<li style='color:red'>Be considerable: PnP community (*) is delivering the <a href='https://github.com/pnp/sp-dev-fx-webparts/tree/master/samples/react-script-editor'>Modern Script Editor SPFx webpart</a>. A convenient webpart that enables fast delivery [rapid prototyping] of SharePoint Modern customization, without the need to immediate comply to all the 'SPFx development + deployment hashhle'. But be aware that once you allow this SPFx webpart in your tenant, you are opening also in your restricted Modern SharePoint context 'the box of pandora' that from then enables the business users to inject just any arbitrary script library for runtime execution in SharePoint pages.<ul style='list-style:none'><li style='color:#aaa'><i>(*) Initial version of Modern Script Editor WebPart is build and delivered by Mikael Svenson, and given as a gift to the SharePoint community. He build this <u>before</u> joining Microsoft; and it may <b><u>not in any way be regarded as a Microsoft supported + approved solution</u></b>.</i></li></ol></li>
</ul></li>
<li>Native SharePoint (Online) API is itself without Azure AD access-control, and can be invoked without need of approved API permissions. Thus also by code that is not running in context of SharePoint page; e.g. running from another webapplication platform, local running scripting, … <b>This is an inherent security leak / issue in SharePoint Online API, IT not in control to close / improve that</i></b></li>
<li>That the older SharePoint API does not provide the option to improve / control the usage, is not a reason to allow same freedom and flexibility on Azure AD protected APIs, of which Graph API is a significant one. Note: (exposure) scope of Graph API extends to much more then only SharePoint Online: also Mail, Teams, Groups, ….</li>
</ul>
</div></div>William van Strienhttp://www.blogger.com/profile/02730614987048826403noreply@blogger.com0tag:blogger.com,1999:blog-9057379846514679550.post-21375587713387469782020-12-28T15:18:00.003+01:002020-12-28T15:18:25.451+01:00In the dungeons of Azure AD B2B: prevented that external can have multiple active guest accounts on alternative email addresses<div>A charm of Azure AD B2B is that the responsibility for guests account management is federated to the external context of invited person. But with this charm inevitable also comes lesser direct control, as within the inviting tenant you have no insight on the federated account in the external Azure Active Directory. I wrote already on a negative effect that can result from this: <a href='https://williamvanstrien.blogspot.com/2019/09/in-dungeons-of-azure-ad-b2b-properties.html'>properties of external Azure AD account might block creation of guest account</a>.</div><div style='margin-top:10px;'>Recent I experienced a peculiar variant of this issue. An external was successful invited, and able to redeem the provisioned guest account and use that to access resources in the inviting tenant. At a later moment, the same external was reinvited via <a href='https://docs.microsoft.com/en-us/powershell/module/azuread/new-azureadmsinvitation?view=azureadps-2.0'>New-AzureADMSInvitation</a> cmdlet on an alternative email address as identity. This was also successful and resulted in a second guest account provisioned in the inviting tenant. But when trying to resend the redeem invitation from Azure Portal, this failed as the new guest account on deeper level is referring to the same federated external identity as the original provisioned guest account. Thus although it looked in the inviting tenant that the 2 guest accounts were isolated from each other, in the reality of the actual identity source of the invited external the 2 alternative emails are administrated as proxy addresses within the <i>same external Azure AD account</i>.</div><div style='margin-top:2px;'>I consider it as correct behavior by Azure AD B2B to recognize this, and prevent that <i>multiple guest accounts</i> can federate to the <i>same single external Azure AD account</i>.
</div>
<div style='margin-top:10px;font-size:8pt'><b>Same external invited with 2 separate guest accounts in inviting tenant</b></div>
<div class="separator" style="clear: both;"><img alt="" border="0" width="95%" src="https://1.bp.blogspot.com/-dCLxPmYuAN8/X-j_jT6OAcI/AAAAAAAACEU/rseQn8hY_V43RSR3U-xYIZhzfSTYCVkCwCNcBGAsYHQ/s620/ExternalInvitedWith2SeperateGuestAccounts.png"/></div>
<div style='margin-top:10px;font-size:8pt'><b>Initial guest account successful accepted and activated</b></div><div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-l0cUl2Vyi54/X-j_jYwMMKI/AAAAAAAACEQ/iat0hIH_pqQxY3JLrehQo_T0P4o6XtbswCNcBGAsYHQ/s850/InitialGuestAccountAccepted.png" style="display: block; padding: 1em 0; text-align: left; "><img alt="" border="0" width="95%" src="https://1.bp.blogspot.com/-l0cUl2Vyi54/X-j_jYwMMKI/AAAAAAAACEQ/iat0hIH_pqQxY3JLrehQo_T0P4o6XtbswCNcBGAsYHQ/s850/InitialGuestAccountAccepted.png"/></a></div><div style='margin-top:10px;font-size:8pt'><b>Later provisioned guest account cannot be accepted</b></div><div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-lOvNvl0MJrY/X-j_jWlYHzI/AAAAAAAACEY/eugA78YqDHIoI7h--4QWs_uJQbP5o-mfACNcBGAsYHQ/s900/LaterGuestAccountNotAccepted.png" style="display: block; padding: 1em 0; text-align: left; "><img alt="" border="0" width="95%" src="https://1.bp.blogspot.com/-lOvNvl0MJrY/X-j_jWlYHzI/AAAAAAAACEY/eugA78YqDHIoI7h--4QWs_uJQbP5o-mfACNcBGAsYHQ/s900/LaterGuestAccountNotAccepted.png"/></a></div><div style='margin-top:10px;font-size:8pt'><b>Reinvite via Azure Portal blocked as guest account is referring to same external Azure AD account</b></div><div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-PIweYmfqt94/X-j_jsLGARI/AAAAAAAACEc/l01E1v3Oxbsf2aWhLBLggmefxqDzZRejACNcBGAsYHQ/s453/ReinviteBlockedAsThe2AccountsPointToSameInExternalAzureAD.png" style="display: block; padding: 1em 0; text-align: left; "><img alt="" border="0" width="75%" src="https://1.bp.blogspot.com/-PIweYmfqt94/X-j_jsLGARI/AAAAAAAACEc/l01E1v3Oxbsf2aWhLBLggmefxqDzZRejACNcBGAsYHQ/s453/ReinviteBlockedAsThe2AccountsPointToSameInExternalAzureAD.png"/></a></div>William van Strienhttp://www.blogger.com/profile/02730614987048826403noreply@blogger.com0tag:blogger.com,1999:blog-9057379846514679550.post-68856116820967325692020-12-22T22:09:00.002+01:002020-12-28T20:06:21.850+01:00Developer inconvenience: Deploy Isolated WebPart with webApiPermissionRequests fails unless permission to create new Azure AD App Registration<div>In real-life enterprise context, it is advised to tag any SPFx webparts that will invoke an Azure AD protected API as isolated. This to prevent that other script running in same page, can abuse the OAuth access token assigned to the SPFx webpart and invoke any tenant-wide API permissions on behalf of current user.</div><div style="margin-top: 10px;">However, you need to be aware of some deployment implications with Isolated WebParts. The first one is that in the Microsoft design, you can only deploy Isolated WebParts via the tenant AppCatalog. It is not possible to deploy an Isolated WebPart (only) to the site App Catalog where it will actualy be used. I suspect this is due that each Isolated SPFx WebPart creates a new Azure AD App Registration on tenant level, and for consistency the SPFx WebPart must therefore also be installed on tenant level. Negative result is that every site-specific customization is visible on all others sites where it likely is unusable. Luckily this visibility is initial limited to only the site owners in "Add an App". Only after a site owner explicit adds the Isolated WebPart to the site, then it will be visible in page editing mode in the available WebParts.</div><div style="margin-top: 10px;">An even more significant inconvenience is that to successful deploy an Isolated WebPart, you need to have the authorization to create a new Azure AD App Registration. Without that permission, the deployment in tenant AppCatalog will fail with the generic error 'Deployment failed. Correlation Id ....'. Implication is that in effect the dependency on Ops is unnecessarily increased: a developer must reach out to a Global Admin for the deployment of SPFx solution containing Isolated WebPart. But the better option is that you request that Global Admin to assign your account the <a href='https://docs.microsoft.com/en-us/azure/active-directory/roles/permissions-reference#application-developer'>Application Developer</a> role, then you are empowered to do this 'Ops' part yourself.</div>William van Strienhttp://www.blogger.com/profile/02730614987048826403noreply@blogger.com0tag:blogger.com,1999:blog-9057379846514679550.post-78854222683968994732020-12-13T11:46:00.001+01:002020-12-13T11:54:31.753+01:00Simple pattern to ensure unique element ID inside SPFx React WebPart<div>When you build a SharePoint WebPart, you must take into account that the business user can add multiple instances of that webpart on a single page. So the operational execution must be robust for that. In case your webpart relies on HTML element ID, e.g. via 'getElementbyId', then you must ensure that the element ID of each instance is unique. A simple pattern I applied is to derive the ID of the inner React Component on that of the unique ID of the parent React WebPart.</div><div style='margin-top:10px;font-size:8pt'><b>Part 1: Extend the React WebPart Properties interface with a property for unique ID</b></div><div style='margin-top:2px;'><div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-EPorARfx4-A/X9XviM5Pt_I/AAAAAAAACDo/-F-YnQTcFN8Wrt7zzHbyVWpoD-oql8TpACNcBGAsYHQ/s439/ExtendSPFxReactWebPartPropsWithUniqueId.png" style="display: block; padding: 1em 0; text-align: left; "><img alt="" border="0" width="320" data-original-height="181" data-original-width="439" src="https://1.bp.blogspot.com/-EPorARfx4-A/X9XviM5Pt_I/AAAAAAAACDo/-F-YnQTcFN8Wrt7zzHbyVWpoD-oql8TpACNcBGAsYHQ/s320/ExtendSPFxReactWebPartPropsWithUniqueId.png"/></a></div>
</div>
<div style='margin-top:10px;;font-size:8pt'><b>Part 2: Parent React WebPart derives unique ID from its own, and pushes to the inner React Component</b></div><div style='margin-top:2px;'><div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-NR_-Z8BO7Nw/X9XvnFwEJfI/AAAAAAAACDs/geNeAmMQiyoPYJsUfVv3tDpKaw3fCK72QCNcBGAsYHQ/s1039/ExtendSPFxReactWebPartWithUniqueId.png" style="display: block; padding: 1em 0; text-align: left; "><img alt="" border="0" width="95%" src="https://1.bp.blogspot.com/-NR_-Z8BO7Nw/X9XvnFwEJfI/AAAAAAAACDs/geNeAmMQiyoPYJsUfVv3tDpKaw3fCK72QCNcBGAsYHQ/s1039/ExtendSPFxReactWebPartWithUniqueId.png"/></a></div>
</div>
<div style='margin-top:10px;;font-size:8pt'><b>Part 3: Inner React Control applies the received unique ID in its rendering + operation</b></div><div style='margin-top:2px;'><div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-Y752VeN9XCI/X9Xvsk0dpOI/AAAAAAAACDw/zBPW7DlLpEMeLhHsIJg_CqTs_q4Axc4QACNcBGAsYHQ/s871/ExtendSPFxReactComponentWithApplyingUniqueId.png" style="display: block; padding: 1em 0; text-align: left; "><img alt="" border="0" width="95%" src="https://1.bp.blogspot.com/-Y752VeN9XCI/X9Xvsk0dpOI/AAAAAAAACDw/zBPW7DlLpEMeLhHsIJg_CqTs_q4Axc4QACNcBGAsYHQ/s871/ExtendSPFxReactComponentWithApplyingUniqueId.png"/></a></div>
</div>William van Strienhttp://www.blogger.com/profile/02730614987048826403noreply@blogger.com0tag:blogger.com,1999:blog-9057379846514679550.post-3400977500969541992020-11-08T21:18:00.001+01:002020-11-22T22:10:17.836+01:00Office Graph and Microsoft Graph<div>Clear and consistent product naming remains a challenge, certain also in the Microsoft domain. An example is the reuse of phrase 'Graph' in Office Graph and Microsoft Graph aka Graph API. What do these names entail, and what if any is the relation?
</div><div style='margin-top:10px;'><h2>Office Graph</h2>Office Graph is the oldest name, and originates in 2014 as the foundation underlying Delve. "<i>The brains behind Delve is the Office Graph. The Office Graph <b>continuously collects and analyses signals</b> that you and your colleagues send when you work in Microsoft 365. For example, when you and a colleague modify or view the same document, it’s a signal that you’re likely to be working together. Other signals are who you communicate with through e-mail, and who you’ve shared documents with, who your manager is, and who has the same manager as you.</i>"
</div><div style='margin-top:10px;'><h2>Microsoft Graph aka Graph API</h2>Microsoft Graph is a giant proxy, it takes requests in, validates authentication token, optional does validation and transformation, and then passes / forwards to the specific inner layer in Microsoft 365 landscape; and returns the inner responses, optional after transformation to the Graph API caller.
Graph API provides consistency over all the different inner services, on level of authentication, property naming and casing, exception handling, singular shared object types (eg consolidate on one definition of ErrorDetails object type). Important to understand is that Microsoft Graph itself does not provide services, it simple delegates to the actual services in the Microsoft 365 landscape.
</div><div style='margin-top:10px;'><h2>Actual the same?</h2>
Microsoft: "<i>The Microsoft Graph models activity in Microsoft 365 services, including Exchange Online, SharePoint Online, Yammer, Skype for Business, Azure Active Directory, and more, and in external services, such as other Microsoft services or third-party services. Microsoft Graph components are used throughout Microsoft 365. The Microsoft Graph represents a collection of content and activity, and the relationships between them that happen across the entire Office suite. It uses sophisticated machine learning techniques to connect people to the relevant content, conversations and people around them. The Microsoft Graph contains information about enterprise objects, such as people and documents, as well as the relationships and interactions among these objects. The relationships and interactions are represented as edges.</i>"
</div>
<div style='margin-top:10px;'><h2>Office Graph renamed into Microsoft Graph</h2>The Office Graph has evolved to become exposible via the Microsoft Graph. Thus they have conceptual morphed into same offering, Office Graph as backend collects and analyses signals that you and your colleagues send when you work in Microsoft 365; and the Graph Api provides central gateway access to this collected information. And also to all other services within Microsoft 365 landscape.</div>
<div style='margin-top:10px;'><h2>Used resources</h2><ul><li><a href='https://office365itpros.com/2020/08/06/customizing-item-insights-privacy-graph-explorer/'>Customizing Privacy Controls for Microsoft Graph Insights with the Graph Explorer</a>, Tony Redmond</li><li><a href='https://support.microsoft.com/en-us/office/how-does-office-delve-know-what-s-relevant-to-me-048d502e-80a7-4f77-ac5c-f9d81733c385'>How does Office Delve know what's relevant to me?</a>, Microsoft</li><li><a href='https://techcommunity.microsoft.com/t5/microsoft-graph/what-is-the-office-graph/m-p/161?lightbox-message-images-161=56iAF58B3FF3D6AB7BF'>What is the Office Graph?</a>, Michael Holstee</li><li><a href='https://docs.microsoft.com/en-us/microsoft-365/enterprise/microsoft-365-isolation-in-graph-and-delve'>Microsoft 365 Tenant Isolation in the Microsoft Graph and Delve</a>, Microsoft</li><li><a href='https://blog.wbaer.net/2020/11/19/microsoft-search-101/'>Microsoft Search 101 - What’s the relationship between the Microsoft Graph and Office Graph?</a>, Bill Baer</li><li><a href='https://docs.microsoft.com/en-us/graph/overview'>Overview of Microsoft Graph</a>, Microsoft</li></ul></div>
<div style='margin-top:20px;'>
<div class="separator" style="clear: both;"><img alt="" border="0" width="95%" src="https://1.bp.blogspot.com/-crl89Y9j0_Y/X6hKQrzn62I/AAAAAAAACC4/86iKbFngAZoSeOXeghmV3pOhX4kaqEz7wCNcBGAsYHQ/s779/Graph%2BAPI%2Bon%2Btop%2Bof%2BMicrosoft%2BGraph%2Badministration%2Bof%2Bcollected%2Bsignals%2Bin%2BMicrosoft%2B365%2Blandscape%2Band%2Bservices.png"/></div>
<span style='font-size:7pt;font-weight:bolder;font-style:italic;'>Graph API on top of Microsoft Graph administration of collected signals in Microsoft 365 landscape and services</span>
</div>
<div class="separator" style="clear: both;">
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-vTqKQfY-HkQ/X7rQE_Ud7kI/AAAAAAAACDM/D8ML5vlRmH4khmFTofx-xnrgXIAr9A8fQCNcBGAsYHQ/s1434/microsoftgraphofficegraph.png" style="display: block; padding: 1em 0; text-align: center; "><img width="95%" src="https://1.bp.blogspot.com/-vTqKQfY-HkQ/X7rQE_Ud7kI/AAAAAAAACDM/D8ML5vlRmH4khmFTofx-xnrgXIAr9A8fQCNcBGAsYHQ/s1434/microsoftgraphofficegraph.png"/></a></div>
<span style='font-size:7pt;font-weight:bolder;font-style:italic;'>The Microsoft Graph Insight APIs expose relationships generated by Office Graph services (source: <a href='https://blog.wbaer.net/2020/11/19/microsoft-search-101/'>Microsoft Search 101 - What’s the relationship between the Microsoft Graph and Office Graph?</a>, Bill Baer)</span>
</div>
William van Strienhttp://www.blogger.com/profile/02730614987048826403noreply@blogger.com0tag:blogger.com,1999:blog-9057379846514679550.post-62662913215455992812020-10-16T20:32:00.002+02:002020-10-16T20:41:57.221+02:00Tip: how-to self-produce without external encoder into MS Stream Live Event<div>Webcast production for a Microsoft Stream Live Event is <a href='https://docs.microsoft.com/en-us/stream/live-encoder-setup'>default tied to external encoder</a>. Teams Live Event supports this also, but defaults to simple self-production via Teams App itself. In that case, the live event is not distributed via Stream; nor is the event recording stored within MS Stream. Instead Teams uses its internal Azure Media Services based streaming, and stores the recording <i>somewhere</i> for period of <a href="https://support.microsoft.com/en-us/office/schedule-a-teams-live-event-7a9ce97c-e1cd-470f-acaf-e6dfc179a0e2">max 180 days after the event is over</a>. Yammer Live Events takes a middle road, or the best of 2 worlds. It supports the same 2 production approaches as Teams - external encoder or via Teams. However, the difference is here within the Teams production handling. Even although produced as a simple Teams Live Event, under the hood this does use Microsoft Stream for the webcast distribution and processing, and after the live event is stopped for the storage of the recording for on-demand watch.</div><div style='margin-top:10px;'>This opens multiple advantages<ul style='margin-top:2px;'><li>It allows to use the simplicity of Teams production for a webcast, and still embed the video on an event portal (typical hosted via SharePoint Online);</li><li>It prevent the need for and availability of external encoder (e.g. Wirecast-S, TeraDeck, OBS Studio, ...);</li><li>Corporations that have employed <a href='https://www.rampecdn.com/enterprise-video-delivery/multicast/'>Ramp Multicast+</a> as eCDN solution to optimize and control the webcast traffic of <a href='https://www.rampecdn.com/enterprise/ramp-for-microsoft-stream/'>Stream</a> on the corporate network, can employ this also for webcasts produced via Teams</li></ul></div>
<div style='margin-top:10px;'>Way to apply this approach is by:<ol style='margin-top:2px;'><li>Schedule your webcast as a <b>Yammer</b> Live Event;</li><li>Produce your webcast as a <b>Teams</b> Live Event;</li><li>Consume / watch the webcast as a <b>Stream</b> Live Event.</li></ol></div>
<div style='margin-top:10px;font-size:smaller;'><b><i>Step 1: Schedule as Yammer Live Event</i></b></div>
<div class="separator" style="clear: both;"><img alt="" border="0" width="95%" src="https://1.bp.blogspot.com/-DgwvsHaKMbU/X4niBlIacaI/AAAAAAAACCA/CPrti6ogNVM_UcB6LG77CO7rVz2XjsMDgCNcBGAsYHQ/s1135/ScheduleAsYammerLiveEvent.png"/></div>
<div class="separator" style="clear: both;"><img alt="" border="0" style="max-width:95%;" src="https://1.bp.blogspot.com/-TUnG2SlisSE/X4niDGOgJoI/AAAAAAAACCE/fMcKWpphZs8s1843t9iNhHYAANlKCo09gCNcBGAsYHQ/s640/SelectYammerLiveEventProductionViaTeams.png"/></div>
<div style='margin-top:10px;font-size:smaller;'><b><i>Step 2: Produce as MS Teams Live Event</i></b></div>
<div class="separator" style="clear: both;"><img alt="" border="0" width="95%" data-original-height="642" data-original-width="1126" src="https://1.bp.blogspot.com/-m4-m_g2n0Rs/X4nkIOCkpDI/AAAAAAAACCU/V9KJgSW5vjQ6SsqTORs88K6QfVTq51lpgCNcBGAsYHQ/s1126/ProduceLiveEventInTeams.png"/></div>
<div style='margin-top:10px;font-size:smaller;'><b><i>Step 3: Consume as MS Stream Live Event, e.g. embedded on SharePoint Online page</i></b></div>
<div class="separator" style="clear: both;"><img alt="" border="0" width="95%" data-original-height="556" data-original-width="1184" src="https://1.bp.blogspot.com/-DEDMY3TtkVA/X4nko8nVxRI/AAAAAAAACCc/wkpRqEjbDBw4flPyBZgM-nVMmMq-OaQ-gCNcBGAsYHQ/s1184/ConsumeAttendLiveEventViaStreamOnSharePointPage.png"/></div>
<div style='margin-top:15px;'><b>Yammer channel determines who is allowed to watch the live event</b></div><div class="separator" style="clear: both;">
Something to be aware in case you would apply this approach, is that Yammer then controls who is allowed to watch the live webcast. Namely the members of the Yammer channel in which the Live Event is scheduled. So you must then make sure that all the accounts that are invited as webcast audience, are invited to the 'owning' Yammer channel. It is not possible to extend via Stream portal the permissions of the scheduled Yammer (= Stream) Live Event. After the event ended, then the video recording is 'released' for video management actions through Stream portal.</div>William van Strienhttp://www.blogger.com/profile/02730614987048826403noreply@blogger.com0tag:blogger.com,1999:blog-9057379846514679550.post-65910837801661752222020-10-15T22:50:00.005+02:002020-10-15T22:50:26.408+02:00Inconvenient authorization management in 'classic' MS Stream<div>In the corporate usage of Microsoft Stream as Enterprise Video Portal (EVP), authorization to watch videos is also applied on 'need-to-known' base. In current Stream, it turns out a bit inconvenient to execute effective permission management.
</div>
<div style='margin-top:10px;'><b>First issue</b> is that it is made complex to nearly impossible to efficient configure permission management on <i>a collection of videos</i>. The root cause of this is in how Microsoft Stream handles the <i>authorization</i> and <i>organization</i> of the video store: "<i>In Microsoft Stream, you can use channels and groups to organize and grant permission to your videos</i>" [Source: <a href='https://docs.microsoft.com/en-us/stream/groups-channels-overview'>https://docs.microsoft.com/en-us/stream/groups-channels-overview</a>]. This is actually not a valid statement. Indeed Stream (aka Azure AD) groups "<i>are both a way to organize videos and to control access to videos</i>", but channels merely "<i>are an organization method for videos, but not a permission method</i>". Limiting for efficient permission management is that Stream portal does not include a capability to logical associate video(s) within either a Group or Channel, this is only supported initial on the moment of adding / uploading video(s) into Microsoft Stream. Once already stored in Microsoft Stream, the only possible way to associate video(s) with additional groups or channels it to do this <i><b>per video</b></i>, via the manual <i>Add to group/channel</i> action in the video-edit menu. When this must be done for larger collection of videos, this is a cumbersome and time-consuming effort.</div>
<div style='margin-top:10px;'><b>Second issue</b> is that Stream suffers from a delay before the indirect authorization assignment via Stream groups is actual applied (becomes active). In situation that authorization to watch a certain video is managed by one or more Stream groups, authorizing another person for access by adding her/his Office 365 account to an authorized group (e.g. via Azure Portal), does not immediate grant the person allowed access to the video. In reality it can take up to even an hour before the group based authorization within Stream context is updated to incorporate the new added account. Until then, the person remains confronted with Stream access denial on the video.
</div><div style='margin-top:10px;'><img alt="" style="max-width:95%" border="0" src="https://1.bp.blogspot.com/-G4SxzAg4YYQ/X4i1MrPrshI/AAAAAAAACBw/RHM0EolraVUSCrAcv_aNTz4AO10APJ4pACNcBGAsYHQ/s0/StreamDeniesAccessToVideo.png"/>
</div><div style='margin-top:10px;'>Even worse, similar effect occurs when revoking the access by removing from Stream group. This is neither immediate effectuated. Luckily the elapse time period is in this situation shorter, max 1 to 2 minutes; not a full hour. Still, immediate access revocation on unjustified granted video is not possible.
</div><div style='margin-top:10px;'>Perhaps within <a href='https://docs.microsoft.com/en-us/stream/streamnew/new-stream'>new Stream</a>, in which the video storage moves to SharePoint Online, the authorization management improves. Not 100% confident yet, as Modern SharePoint also uses Azure AD groups for permission management. However, experiences within regular SharePoint Online usage are that any change in the Azure AD group(s) are almost immediate applied for access control, both on access assignment as revocation.
</div>William van Strienhttp://www.blogger.com/profile/02730614987048826403noreply@blogger.com0tag:blogger.com,1999:blog-9057379846514679550.post-67057346947279155022020-10-04T15:29:00.007+02:002020-10-04T15:44:37.794+02:00Tip: Teams NDI® only becomes active for capture when 2nd person joins the meeting<div>The new NDI® capability in Teams is interesting for webcast production, as it allows that you simultaneously combine the video signals of multiple persons in the stream. An use case is for a digital (panel)conversation between 2 or more presenters, which are physical at different places. This scenario is native already possible via Teams Meeting; however then you miss the flexibility in organizing the screen layout of the webcast production. E.g. display another background, display a PowerPoint presentation, switch between picture-in-picture vs full profile; display a ticker message and so on.</div><div style='margin-top:10px;'>As I acknowledge the usability of Teams NDI capability for productive company webcasts, I played around a bit with it: in Teams (MSDN development tenant) configured NDI capability on tenant level (<i><a href='https://docs.microsoft.com/en-us/MicrosoftTeams/use-ndi-in-meetings'>Use NDI® technology in Microsoft Teams</a></i>) + for own Teams account (<i><a href='https://support.microsoft.com/en-us/office/broadcasting-audio-and-video-from-teams-with-ndi%c2%ae-technology-e91a0adb-96b9-4dca-a2cd-07181276afa3?ui=en-us&rs=en-us&ad=us'>Broadcasting audio and video from Teams with NDI® technology</a></i>); webcam setup (<i>via <a href='https://www.e2esoft.com/ivcam/'>IVCam</a></i>) on home system; OBS Studio with <i><a href='https://obsproject.com/forum/resources/obs-ndi-newtek-ndi%E2%84%A2-integration-into-obs-studio.528/'>NDI plug-in</a></i>.</div><div style='margin-top:10px;'>While playing, I notice that the NDI signal only becomes active on the network once a second person joins in the Teams meeting. Implication of this is that as producer you cannot prepare a production setup with only you present yet in the Teams meeting. In reality this should not be an issue: the reason to use NDI for capturing is because you want to capture the video of <b><i>other person or persons</i></b>. Not that of yourself, that you can just as simple direct capture in OBS Studio (or other encoder) as 'video camera' input.</div>
<div style='margin-top:10px;'><h2>Screenshots of exploring Teams NDI capability</h2></div>
<div class="separator" style="clear: both;font-size:smaller"><b>Join as webcast producer / organiser the Teams Meeting, with NDI enabled for yourself</b></div><div class="separator" style="clear: both;"><img alt="" border="0" width="320" src="https://1.bp.blogspot.com/-d-HHMVRjJCw/X3m9urXKcTI/AAAAAAAACBA/sFpLjTZ2-Fs-aZW2CkMnAvAx0g8-CXaiACNcBGAsYHQ/s320/Join-Teams-Meeting-With-NDI-Enabled.png"/></div>
<div class="separator" style="clear: both;font-size:smaller"><b>Teams does not yet activate NDI broadcasting, while not actually a meeting of multiple persons</b><a href="https://1.bp.blogspot.com/-caNyDwmnfws/X3m96IIyfaI/AAAAAAAACBE/_94zHT_Eqo034ZkAHjJyrM-Wl5wFyiozACNcBGAsYHQ/s1135/OBS-NDI-Unable-To-Capture-Teams-NDI-signal.png" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" width="95%" src="https://1.bp.blogspot.com/-caNyDwmnfws/X3m96IIyfaI/AAAAAAAACBE/_94zHT_Eqo034ZkAHjJyrM-Wl5wFyiozACNcBGAsYHQ/s1135/OBS-NDI-Unable-To-Capture-Teams-NDI-signal.png"/></a></div><div class="separator" style="clear: both;font-size:smaller;"><b>Second person joins the Teams Meeting</b><img alt="" border="0" width="320" data-original-height="375" data-original-width="458" src="https://1.bp.blogspot.com/-ataiOWTtOrY/X3m98XWqoiI/AAAAAAAACBI/A8TYj1z6h2MxMtaxN_-A0Jzi0O2FHtK9wCNcBGAsYHQ/s320/Allow-Second-Person-in-Teams-Meeting.png"/></div><div class="separator" style="clear: both;font-size:smaller;"><b>Teams now activated NDI broadcasting, and can be captured in OBS Studio</b><img alt="" border="0" width="95%" src="https://1.bp.blogspot.com/-LcSZzsoRPzM/X3m9-HLVJBI/AAAAAAAACBM/ahqgPoVPLS4Zi7Gkxvjo0yje6Oe_7zcowCNcBGAsYHQ/s722/OBS-NDI-Able-To-Capture-Teams-NDI.png"/></div><div class="separator" style="clear: both;"><img alt="" border="0" width="95%" src="https://1.bp.blogspot.com/-pGUtSQpaONU/X3m-Dp04tOI/AAAAAAAACBQ/zxVwq6eQheIHmgfX_yqylqgva1zKNgvvQCNcBGAsYHQ/s890/OBS-NDI-Capture-in-Screen-layout.png"/></div><div class="separator" style="clear: both;font-size:smaller;"><b>Once 2nd attendee in the meeting, Teams displays the NDI broadcasting notification</b><img alt="" border="0" width="95%" src="https://1.bp.blogspot.com/-feWKKaUm7RI/X3m-F3LQhbI/AAAAAAAACBU/6re9v-HVRBUv-zA-mOA9WhiIBpj1KXS6ACNcBGAsYHQ/s1352/Teams-Displays-NDI-Notification.png"/></div>William van Strienhttp://www.blogger.com/profile/02730614987048826403noreply@blogger.com0tag:blogger.com,1999:blog-9057379846514679550.post-22626075770518211402020-09-05T20:19:00.000+02:002020-09-05T20:19:01.530+02:00How-to prevent download of video files stored in SharePoint Online site<div><b>Context</b><ul style='margin-top:2px;'><li>Event portal with both company internal as external audience</li><li>Teaser videos to prepare the audience for the event</li><li>Due the company information in the videos, not allowed that visitors download the videos for uncontrolled distribution.</li></ul></div>
<div style='margin-top:10px;'>An answer on the first aspect can be a SharePoint Online communication site, via Azure AD B2B external shared with known guest accounts. For the second aspect it would be preferred to use Microsoft Stream as secure Enterprise Video Platform. However, as Stream is still lacking the capability of external access; this would result that the external audience cannot watch the videos. Pragmatic alternative is then to fallback on using SharePoint Online itself as administration plus platform for the teaser videos. Remaining question is then whether possible, and if so how, to prevent that the external audience can easily download the video files.</div>
<div style='margin-top:10px;'><h2>Prevent download on SharePoint level</h2>First component in answerring is to prevent on SharePoint Level that site visitors can download content from the site. The standard 'Read' permission level grants the authorization to "Can view pages and list items and <b><i>download</i></b> documents". There required to create a restricted permission level that only allows to "View content", and assign that permission level to the 'Visitors' permission group.</div><div style='margin-top:5px;'>
<img alt="" border="1" width="95%" src="https://1.bp.blogspot.com/-zejG6fieYhA/X1NtB84pxHI/AAAAAAAAB_U/ZXPVGRtxLE8t864x0qVH13JaatO87Eg1gCNcBGAsYHQ/s0/RestrictedPermissionForVisitors.png"/></div>
<div class="separator" style="clear: both;"><img alt="" border="0" width="95%" src="https://1.bp.blogspot.com/-WYHUvGCxPeQ/X1Nvlp7JRLI/AAAAAAAAB_g/gz0_-XzKOXQOH6koMwvdhbtuCigKZ6m5QCNcBGAsYHQ/s0/VisitorCannotDownload.png"/>
</div>
<div style='margin-top:10px;'><h2>Prevent download on browser level</h2>
However, this does not prevent that visitors can download on <b><i>browser</i></b> level the SharePoint stored .mp4 videos, whether embedded in a SharePoint page, or the .mp4 video direct visited + played in the browser. All modern browsers native understand / recognize .mp4 as a video file, and then default to allow play, download and 'save as video' on browser level of that video file.
<img alt="" border="0" width="95%" src="https://1.bp.blogspot.com/-H6KVb4_Zszw/X1PIAbqAZxI/AAAAAAAAB_s/Jv5uPQqtqrY5JkI5R4QflTx_MbS7-kuRgCNcBGAsYHQ/s0/NativeBrowserVideoFileCapabilities.png"/>
</div>
<div style='margin-top:10px;'>Does this mean it is not possible to prevent download of video files? The honest answer is: <i>you can't stop downloading of html5 videos</i>. But you can make the action more complicate to do. Multiple options for that.
<h2><i>Option 1: Download as blob in video player</i></h2>
This suggestion is made in <a href='https://stackoverflow.com/questions/9756837/prevent-html5-video-from-being-downloaded-right-click-saved'>Prevent HTML5 video from being downloaded (right-click saved)?</a>
<div class="separator" style="clear: both;"><img alt="" border="0" width="95%" src="https://1.bp.blogspot.com/-es8IRM35w0Q/X1PUZmNJjKI/AAAAAAAACAQ/uafvbNNsdXAMa1X3mefY3wvDspQ0gxW6wCNcBGAsYHQ/s0/VideoDownloadAsBlobPlayer.png"/></div><br/>
<b>Result wrt default browser behavior:</b><br/>
As for the video player it is not .mp4, the default menu options for 'save as video' and 'download' are not triggered. However, on network level the video file is still initial downloaded as .mp4; and a knowledgeable person has no problem to simple direct navigate on browser level to the SharePoint address of the .mp4 videofile.<br/>
<div class="separator" style="clear: both;"><img alt="" border="1" width="95%" src="https://1.bp.blogspot.com/-XWYOOwprGsE/X1PVlJBAgXI/AAAAAAAACAc/cPvqUwrKIb4Sxvi5Nbfz7HmxWVraBC-ngCNcBGAsYHQ/s0/ToPlayAsBlobStillRequiredToFirstDownloadAsMP4.png"/></div>
<h2><i>Option 2: Play as 'renamed video extension' file, so that default browser behaviour is prevented</i></h2>
<b>Steps:</b><ol style='margin-top:2px'><li>Rename the file extension to something else than .mp4; example rename 'SampleVideo.<b>mp4</b>' into 'SampleVideo.<b>videofile</b>'</li>
<li>Upload the renamed file into SharePoint Assets library</li>
<li>Also upload an image to use as preview</li>
<li>Embed a videojs based videoplayer on SharePoint page, that is configured to understand how-to play '.videofile' as '.mp4'. Also customize the videoplayer to not render the standard contextmenu</li>
</ol>
<img alt="" border="0" width="95%" src="https://1.bp.blogspot.com/-OfEnUvT3eng/X1PMl6B3bBI/AAAAAAAAB_4/49HpsyrQ9vcEAp_gRygzve0Jj4oUIk20ACNcBGAsYHQ/s0/EmbedVideoJSPlayerRenamedMP4.png"/><br/>
<b>Result wrt default browser behavior:</b><br/>
As the file-extension is not a video format; neither SharePoint, nor browser recognize this as video file. And the default browser behavior to play the video-file address as video, is not fired; and thus the option from menus to ‘download’ + ‘save video as’ is not presented.<br/><br/>
However, when navigating in browser to the SharePoint address of the renamed videofile, it will then download as file (despite that SharePoint permission does not allow). It is downloaded with the renamed file extension, but a knowledgeable person can guess that it is actual a .mp4 file, fix the downloaded file, and then it is native playable again.
<h2><i>Option 3: Convert from single .mp4 into HLS; with division accross multiple files</i></h2>
<b>Steps:</b><ol style='margin-top:2px'><li>Convert .mp4 video file into .HLS video (manifest file + video fragments). An approach for this is via '<a href="https://ffmpeg.org/">FFmpeg</a>'.</li>
<li>Upload the manifest + video fragments into SharePoint Assets library</li>
<li>Also upload an image to use as preview</li>
<li>Embed a HLS videoplayer on SharePoint page.</li>
</ol>
<img alt="" border="0" width="95%" src="https://1.bp.blogspot.com/--WKG5oRQEgw/X1PPRzVZ2sI/AAAAAAAACAE/Wx232eRgHMcBKfOdjxlqwQ5XKlS3B2NVwCNcBGAsYHQ/s0/HLSVideoPlayer.png"/><br/>
<b>Result wrt default browser behavior:</b><br/>
Browser default do not handle HLS video files; this is handled via a HLS video player (JavaScript). To download the video, one must navigate in browser first to manifest file, and then all individual video fragments.
Doable, but manual labor for the person downloading.
</div>William van Strienhttp://www.blogger.com/profile/02730614987048826403noreply@blogger.com0tag:blogger.com,1999:blog-9057379846514679550.post-49050148497557352042020-07-25T15:51:00.002+02:002020-07-25T15:52:30.732+02:00Beware: Request SharePoint Root Certificate as administrator<div>On trying the Microsoft advised <a href='https://docs.microsoft.com/en-us/sharepoint/troubleshoot/sites/site-slowness-because-of-sts-certificate-crl-checking#workaround-1'>workaround 1</a> in situation in which in the SharePoint 2016 central admin server every hour a 'Critical Error' is logged on '<i>A certificate validation operation took milliseconds and has exceeded the execution time threshold</i>', I initial failed as <a href='https://docs.microsoft.com/en-us/powershell/module/sharepoint-server/get-spcertificateauthority'>Get-SPCertificateAuthority</a> returned Null for RootCertificate. The trick / requirement here is to invoke the cmdlet from PowerShell runas administrator:
</div>
<div style='margin-top:10px;'>
<a href="https://4.bp.blogspot.com/-HFst5VlJwW8/Xxw4XEkQ99I/AAAAAAAAB-g/D8Pxv7ZbztQgVfFnn0m2nn635vXws07SACNcBGAsYHQ/s1600/Get-SPCertificateAuthority-RequiresInvocationAsAdmin.png" imageanchor="1" ><img border="0" src="https://4.bp.blogspot.com/-HFst5VlJwW8/Xxw4XEkQ99I/AAAAAAAAB-g/D8Pxv7ZbztQgVfFnn0m2nn635vXws07SACNcBGAsYHQ/s1600/Get-SPCertificateAuthority-RequiresInvocationAsAdmin.png" width="95%" /></a>
</div>William van Strienhttp://www.blogger.com/profile/02730614987048826403noreply@blogger.com0