<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-7258322562721325894</id><updated>2026-01-03T14:55:29.536+02:00</updated><category term="SharePoint"/><category term="moss"/><category term="media center"/><category term="facebook"/><category term="twitter"/><category term="sharepoint 2010"/><category term="PowerShell"/><category term="Azure"/><category term="Office365"/><category term="error"/><category term="jQuery"/><category term="SPFx"/><category term="Teams"/><category term="mysite"/><category term="onet.xml"/><category term="CSOM"/><category term="central admin"/><category term="search"/><category term="site definition"/><category term="sql server"/><category term="PnP"/><category term="SQLServer"/><category term="Windows 8"/><category term="addin"/><category term="audience"/><category term="authentication"/><category term="feature"/><category term="stsadm"/><category term="tfs"/><category term="Flow"/><category term="OOS"/><category term="Office2013"/><category term="OneDrive"/><category term="Win8"/><category term="api"/><category term="auth0"/><category term="caml"/><category term="config wizard"/><category term="dfwp"/><category term="folders"/><category term="import"/><category term="language"/><category term="list"/><category term="master"/><category term="metadata"/><category term="organization"/><category term="outlook"/><category term="permissions"/><category term="runwithelevatedprivileges"/><category term="sharepoint designer"/><category term="site collection"/><category term="ubiquiti"/><category term="user"/><category term="user profile"/><category term="vista"/><category term="visual studio"/><category term="windows media center"/><category term="500"/><category term="AD"/><category term="ARM"/><category term="AutoSPInstaller"/><category term="AzureAD"/><category term="B2C"/><category term="EdgeRouter"/><category term="Excel"/><category term="FBA"/><category term="Graph"/><category term="Hyper-V"/><category term="IoT"/><category term="JSON"/><category term="LogParser"/><category term="MSI"/><category term="OneNote"/><category term="Planner"/><category term="PowerPoint"/><category term="REST"/><category term="Runbook"/><category term="SAML"/><category term="SPLimitedWebPartManager"/><category term="SPSecurityTrimmedControl"/><category term="SPtimerV3"/><category term="SSRS"/><category term="SharePoint; VSTS"/><category term="ULS"/><category term="VMware"/><category term="VPN"/><category term="VisualStudio"/><category term="WAC"/><category term="WCA"/><category term="WCF"/><category term="WMC"/><category term="Wazuh"/><category term="Windows"/><category term="Word"/><category term="XAML"/><category term="aam"/><category term="allowunsafeupdates"/><category term="amazon"/><category term="approval"/><category term="architecture"/><category term="backup"/><category term="blobcache"/><category term="breakroleinheritance"/><category term="cache"/><category term="chartjs"/><category term="claims"/><category term="collect feedback"/><category term="compress"/><category term="configuration"/><category term="cookie"/><category term="copyroleassignments"/><category term="core"/><category term="create site"/><category term="custom list"/><category term="debug"/><category term="delete site"/><category term="discussion"/><category term="diskpart"/><category term="domain"/><category term="e-mail"/><category term="edge"/><category term="errorwebpart"/><category term="exception"/><category term="export"/><category term="fbmce"/><category term="field"/><category term="forms server"/><category term="functions"/><category term="gac"/><category term="groups"/><category term="guide"/><category term="happyornot"/><category term="htpc"/><category term="iis"/><category term="infopath"/><category term="internet explorer"/><category term="invalid"/><category term="item"/><category term="layout"/><category term="li"/><category term="managed metadata"/><category term="managed paths"/><category term="memberships"/><category term="microsoft online"/><category term="microsoftband"/><category term="migration"/><category term="navigation"/><category term="nlb"/><category term="officeuifabric"/><category term="opensource"/><category term="password"/><category term="peoplepicker"/><category term="powerbi"/><category term="profile synchronization"/><category term="rar"/><category term="reference"/><category term="remote access"/><category term="require check out"/><category term="restore"/><category term="ribbon"/><category term="savechanges"/><category term="schema.xml"/><category term="security"/><category term="server"/><category term="service"/><category term="session"/><category term="setup"/><category term="silverlight"/><category term="site directory"/><category term="sitegroups"/><category term="smallsearchinputbox"/><category term="sorting"/><category term="spfield"/><category term="spweb"/><category term="ssl"/><category term="stack trace"/><category term="subsite"/><category term="term store management"/><category term="timer"/><category term="update"/><category term="upgrade"/><category term="validation"/><category term="view"/><category term="webhook"/><category term="wfetch"/><category term="whs"/><category term="windows 7"/><category term="wix"/><category term="workflow"/><category term="x64"/><category term="yammer"/><category term="zip"/><title type='text'>How To Code</title><subtitle type='html'>Exact answers to exact problems.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://blog.jussipalo.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7258322562721325894/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://blog.jussipalo.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/7258322562721325894/posts/default?start-index=26&amp;max-results=25&amp;redirect=false'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>233</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-7258322562721325894.post-2624802361290139216</id><published>2026-01-01T15:40:00.016+02:00</published><updated>2026-01-03T14:55:29.502+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="EdgeRouter"/><category scheme="http://www.blogger.com/atom/ns#" term="ubiquiti"/><category scheme="http://www.blogger.com/atom/ns#" term="Wazuh"/><title type='text'>Logging Ubiquiti EdgeRouter firewall events to Wazuh</title><content type='html'>&lt;h3 style=&quot;text-align: left;&quot;&gt;Problem&lt;/h3&gt;&lt;p&gt;Logging EdgeRouter firewall events to Wazuh needs custom decoder and rules.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3 style=&quot;text-align: left;&quot;&gt;Solution&lt;/h3&gt;&lt;p&gt;In&amp;nbsp;/var/ossec/etc/rules/edgerouter-fw_rules.xml:&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;lt;group name=&quot;local,edgerouter,&quot;&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;lt;rule id=&quot;900100&quot; level=&quot;3&quot;&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;decoded_as&amp;gt;edgerouter-fw-tcp&amp;lt;/decoded_as&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;description&amp;gt;EdgeRouter TCP packet: $(srcip):$(srcport) → $(dstip):$(dstport) via $(in_iface)&amp;lt;/description&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;group&amp;gt;edgerouter,tcp,firewall,&amp;lt;/group&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;lt;/rule&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;lt;rule id=&quot;900110&quot; level=&quot;3&quot;&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;decoded_as&amp;gt;edgerouter-fw-udp&amp;lt;/decoded_as&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;description&amp;gt;EdgeRouter UDP packet: $(srcip):$(srcport) → $(dstip):$(dstport) via $(in_iface), payload $(payload_len) bytes&amp;lt;/description&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;group&amp;gt;edgerouter,udp,firewall,&amp;lt;/group&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;lt;/rule&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;lt;rule id=&quot;900120&quot; level=&quot;3&quot;&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;decoded_as&amp;gt;edgerouter-fw-icmp&amp;lt;/decoded_as&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;description&amp;gt;EdgeRouter ICMP packet: $(srcip) → $(dstip), type $(icmp_type) code $(icmp_code)&amp;lt;/description&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;group&amp;gt;edgerouter,icmp,firewall,&amp;lt;/group&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;lt;/rule&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;lt;rule id=&quot;900200&quot; level=&quot;5&quot;&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;if_sid&amp;gt;900100&amp;lt;/if_sid&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;match&amp;gt;SYN&amp;lt;/match&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;description&amp;gt;TCP SYN from $(srcip):$(srcport) to $(dstip):$(dstport) blocked by $(chain)&amp;lt;/description&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;group&amp;gt;edgerouter,tcp,syn,&amp;lt;/group&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;lt;/rule&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;lt;rule id=&quot;900210&quot; level=&quot;10&quot; frequency=&quot;10&quot; timeframe=&quot;60&quot;&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;if_matched_sid&amp;gt;900200&amp;lt;/if_matched_sid&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;same_source_ip /&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;description&amp;gt;Possible TCP SYN scan: $(srcip) sent repeated SYN packets to multiple ports&amp;lt;/description&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;group&amp;gt;edgerouter,tcp,scan,&amp;lt;/group&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;lt;/rule&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;lt;rule id=&quot;900300&quot; level=&quot;4&quot;&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;if_sid&amp;gt;900110&amp;lt;/if_sid&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;description&amp;gt;UDP traffic: $(srcip):$(srcport) → $(dstip):$(dstport)&amp;lt;/description&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;group&amp;gt;edgerouter,udp,event,&amp;lt;/group&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;lt;/rule&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;lt;rule id=&quot;900310&quot; level=&quot;10&quot; frequency=&quot;20&quot; timeframe=&quot;30&quot;&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;if_matched_sid&amp;gt;900300&amp;lt;/if_matched_sid&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;same_source_ip /&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;description&amp;gt;Possible UDP flood: $(srcip) sent $(frequency) packets in $(timeframe)s&amp;lt;/description&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;group&amp;gt;edgerouter,udp,flood,&amp;lt;/group&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;lt;/rule&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;lt;rule id=&quot;900400&quot; level=&quot;4&quot;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;if_sid&amp;gt;900120&amp;lt;/if_sid&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;match&amp;gt;TYPE=8&amp;lt;/match&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;description&amp;gt;ICMP Echo Request (ping) from $(srcip) to $(dstip), seq $(icmp_seq)&amp;lt;/description&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;group&amp;gt;edgerouter,icmp,echo,&amp;lt;/group&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;lt;/rule&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;lt;rule id=&quot;900410&quot; level=&quot;10&quot; frequency=&quot;20&quot; timeframe=&quot;30&quot;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;if_matched_sid&amp;gt;900400&amp;lt;/if_matched_sid&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;same_source_ip /&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;description&amp;gt;Possible ICMP flood: $(srcip) sent $(frequency) echo requests in $(timeframe)s&amp;lt;/description&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;group&amp;gt;edgerouter,icmp,flood,&amp;lt;/group&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;lt;/rule&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;lt;rule id=&quot;900500&quot; level=&quot;3&quot;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;match&amp;gt;WAN_LOCAL&amp;lt;/match&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;description&amp;gt;EdgeRouter WAN_LOCAL rule matched: $(srcip) → $(dstip) on $(proto)&amp;lt;/description&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;group&amp;gt;edgerouter,wan_local,&amp;lt;/group&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;lt;/rule&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;lt;rule id=&quot;900600&quot; level=&quot;5&quot;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;match&amp;gt;WAN_LOCAL-default-D&amp;lt;/match&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;description&amp;gt;Inbound traffic blocked by WAN_LOCAL: $(srcip):$(srcport) → $(dstip):$(dstport) proto $(proto)&amp;lt;/description&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;group&amp;gt;edgerouter,blocked,wan_local,&amp;lt;/group&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;lt;/rule&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;lt;rule id=&quot;900700&quot; level=&quot;8&quot;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;if_sid&amp;gt;900200&amp;lt;/if_sid&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;match&amp;gt;WAN_LOCAL-default-D&amp;lt;/match&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;description&amp;gt;Blocked TCP SYN: $(srcip):$(srcport) → $(dstip):$(dstport) flags $(flags)&amp;lt;/description&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;group&amp;gt;edgerouter,tcp,blocked,scan,&amp;lt;/group&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;lt;/rule&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;lt;rule id=&quot;900710&quot; level=&quot;8&quot; frequency=&quot;15&quot; timeframe=&quot;60&quot;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;if_matched_group&amp;gt;blocked&amp;lt;/if_matched_group&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;same_source_ip /&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;description&amp;gt;Repeated blocked traffic from $(srcip): $(frequency) events in $(timeframe)s&amp;lt;/description&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;group&amp;gt;edgerouter,blocked,scan,&amp;lt;/group&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;lt;/rule&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;lt;/group&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;p&gt;In&amp;nbsp;/var/ossec/etc/decoders/edgerouter-fw.xml. Make sure there are no line breaks inside &amp;lt;regex&amp;gt; node:&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;lt;decoder name=&quot;edgerouter-fw-tcp&quot;&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;parent&amp;gt;kernel&amp;lt;/parent&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;regex type=&quot;pcre2&quot;&amp;gt;\[([^\]]+)\]IN=(\S*)\s+OUT=(\S*)\s+MAC=([0-9A-Fa-f:]+)\s+SRC=([0-9.]+)\s+DST=([0-9.]+)\s+LEN=(\d+)\s+TOS=(\S+)\s+PREC=(\S+)\s+TTL=(\d+)\s+ID=(\d+)(?:\s+DF)?\s+PROTO=TCP\s+&lt;/span&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;SPT=(\d+)\s+DPT=(\d+)\s+WINDOW=(\d+)\s+RES=(\S+)\s+(\S+)\s+URGP=(\d+)&amp;lt;/regex&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;order&amp;gt;chain,in_iface,out_iface,mac,srcip,dstip,len,tos,prec,ttl,id,srcport,dstport,window,res,flags,urgp&amp;lt;/order&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;lt;/decoder&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;lt;decoder name=&quot;edgerouter-fw-udp&quot;&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;parent&amp;gt;kernel&amp;lt;/parent&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;regex type=&quot;pcre2&quot;&amp;gt;\[([^\]]+)\]IN=(\S*)\s+OUT=(\S*)\s+MAC=([0-9A-Fa-f:]+)\s+SRC=([0-9.]+)\s+DST=([0-9.]+)\s+LEN=(\d+)\s+TOS=(\S+)\s+PREC=(\S+)\s+TTL=(\d+)\s+ID=(\d+)\s+PROTO=UDP\s+SPT=(\d+)\&lt;/span&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;s+DPT=(\d+)\s+LEN=(\d+)&amp;lt;/regex&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;order&amp;gt;chain,in_iface,out_iface,mac,srcip,dstip,len,tos,prec,ttl,id,srcport,dstport,payload_len&amp;lt;/order&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;lt;/decoder&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;lt;decoder name=&quot;edgerouter-fw-icmp&quot;&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;parent&amp;gt;kernel&amp;lt;/parent&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;regex type=&quot;pcre2&quot;&amp;gt;\[([^\]]+)\]IN=(\S*)\s+OUT=(\S*)\s+MAC=([0-9A-Fa-f:]+)\s+SRC=([0-9.]+)\s+DST=([0-9.]+)\s+LEN=(\d+)\s+TOS=(\S+)\s+PREC=(\S+)\s+TTL=(\d+)\s+ID=(\d+)(?:\s+DF)?\s+PROTO=ICMP\s&lt;/span&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;+TYPE=(\d+)\s+CODE=(\d+)\s+ID=(\d+)\s+SEQ=(\d+)&amp;lt;/regex&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;order&amp;gt;chain,in_iface,out_iface,mac,srcip,dstip,len,tos,prec,ttl,id,icmp_type,icmp_code,icmp_id,icmp_seq&amp;lt;/order&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;lt;/decoder&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.jussipalo.com/feeds/2624802361290139216/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.jussipalo.com/2026/01/logging-ubiquiti-edgerouter-firewall.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7258322562721325894/posts/default/2624802361290139216'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7258322562721325894/posts/default/2624802361290139216'/><link rel='alternate' type='text/html' href='http://blog.jussipalo.com/2026/01/logging-ubiquiti-edgerouter-firewall.html' title='Logging Ubiquiti EdgeRouter firewall events to Wazuh'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7258322562721325894.post-3893331546238131525</id><published>2025-09-11T10:36:00.005+03:00</published><updated>2025-09-11T10:36:37.900+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="PnP"/><category scheme="http://www.blogger.com/atom/ns#" term="PowerShell"/><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint"/><title type='text'>SharePoint: Connect using access tokens in PnP PowerShell</title><content type='html'>&lt;h3 style=&quot;text-align: left;&quot;&gt;Task&lt;/h3&gt;&lt;p&gt;I had an string array of SPO site collection URLs and I needed to execute PowerShell script that fetches comments and likes of app pages across all of these site collections. For getting actual page specific likes and comments, there is PnP PowerShell commands&amp;nbsp;&lt;i&gt;Get-PnPPageLikedByInformation&lt;/i&gt; and&amp;nbsp;&lt;i&gt;Get-PnPListItemComment&lt;/i&gt;, and you get nice object array including date, and even comment content. No problem there.&lt;/p&gt;&lt;p&gt;However, in my one-time executable script I didn&#39;t want to do interactive login for each of those site collections, so I needed a way to somehow persist the credentials and reuse them every time I called&amp;nbsp;&lt;i&gt;Connect-PnPOnline&lt;/i&gt; towards each site collection.&lt;/p&gt;&lt;p&gt;Back in the days, all they way in on-prem SharePoint, you could use &lt;i&gt;Get-Credential &lt;/i&gt;once and store the credentials in a variable and include that as the parameter in the connection PS command, whatever that was. It, however, hasn&#39;t worked in a long time when there are MFA and other requirements towards signing in to online services such as SharePoint Online.&lt;/p&gt;&lt;p&gt;Good thing there is a solution.&lt;/p&gt;&lt;h3 style=&quot;text-align: left;&quot;&gt;Solution&lt;/h3&gt;&lt;p&gt;Access tokens to the rescue!&amp;nbsp;&lt;br /&gt;&lt;/p&gt;&lt;div style=&quot;background-color: #1e1e1e; font-family: Consolas, &amp;quot;Courier New&amp;quot;, monospace; font-size: 14px; line-height: 19px; white-space: pre;&quot;&gt;&lt;div style=&quot;color: #d4d4d4;&quot;&gt;&lt;span style=&quot;color: #6a9955;&quot;&gt;# first connect normally to SPO, but remember to return the connection using ReturnConnection parameter&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;color: #d4d4d4;&quot;&gt;&lt;span style=&quot;color: #9cdcfe;&quot;&gt;$conn&lt;/span&gt; = &lt;span style=&quot;color: #dcdcaa;&quot;&gt;Connect-PnPOnline&lt;/span&gt; -ClientId [YOUR_CLIENT_ID] -Url &lt;span style=&quot;color: #9cdcfe;&quot;&gt;[YOUR_SPO_URL]&lt;/span&gt; -ReturnConnection&lt;/div&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;&lt;div style=&quot;background-color: #1e1e1e; font-family: Consolas, &amp;quot;Courier New&amp;quot;, monospace; font-size: 14px; line-height: 19px; white-space: pre;&quot;&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;/span&gt;&lt;span style=&quot;color: #6a9955;&quot;&gt;# magic is here, first get the access token, you only need to do this once (note that token will expire at some point)&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;div style=&quot;color: #d4d4d4;&quot;&gt;&lt;span style=&quot;color: #9cdcfe;&quot;&gt;$token&lt;/span&gt; = &lt;span style=&quot;color: #dcdcaa;&quot;&gt;Get-PnPAccessToken&lt;/span&gt; -Connection &lt;span style=&quot;color: #9cdcfe;&quot;&gt;$conn&lt;/span&gt; -ResourceTypeName SharePoint&lt;/div&gt;&lt;div style=&quot;color: #d4d4d4;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;color: #d4d4d4;&quot;&gt;&lt;div style=&quot;line-height: 19px;&quot;&gt;&lt;span style=&quot;color: #6a9955;&quot;&gt;# then whenever you want to connect to new site collection, use the token instead of ClientId&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div style=&quot;line-height: 19px;&quot;&gt;&lt;div style=&quot;line-height: 19px;&quot;&gt;&lt;span style=&quot;color: #9cdcfe;&quot;&gt;$newConn&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;color: #dcdcaa;&quot;&gt;Connect-PnPOnline&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt; -AccessToken &lt;/span&gt;&lt;span style=&quot;color: #9cdcfe;&quot;&gt;$token&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt; -Url &lt;/span&gt;&lt;span style=&quot;color: #9cdcfe;&quot;&gt;[NEW_SPO_URL]&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt; -ReturnConnection&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.jussipalo.com/feeds/3893331546238131525/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.jussipalo.com/2025/09/sharepoint-connect-using-access-tokens.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7258322562721325894/posts/default/3893331546238131525'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7258322562721325894/posts/default/3893331546238131525'/><link rel='alternate' type='text/html' href='http://blog.jussipalo.com/2025/09/sharepoint-connect-using-access-tokens.html' title='SharePoint: Connect using access tokens in PnP PowerShell'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7258322562721325894.post-384051905184578424</id><published>2025-01-17T11:43:00.004+02:00</published><updated>2025-01-17T11:44:51.341+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint"/><title type='text'>SharePoint: How to create direct link to list view including search query</title><content type='html'>&lt;h1 style=&quot;text-align: left;&quot;&gt;Problem&lt;/h1&gt;&lt;p&gt;While going back to basics, that is on-prem SharePoint, I needed to create list view search box to another page. Meaning that the other page (not the the list view page) needed to have search box and button. Typing in query and pressing the button would redirect to the list view and do the search like user would&#39;ve typed in the search in the list view search box.&lt;/p&gt;&lt;p&gt;I was certain there was some querystring parameter one could define for this to work, but couldn&#39;t find, so after some trial and error I found the correct one!&lt;/p&gt;&lt;h1 style=&quot;text-align: left;&quot;&gt;Solution&amp;nbsp;&lt;/h1&gt;&lt;p&gt;In your link that points to list view, use querystring parameters &lt;b&gt;View&lt;/b&gt; and&amp;nbsp;&lt;b&gt;InplaceSearchQuery&lt;/b&gt;. &lt;b&gt;View&lt;/b&gt; contains the GUID of the view you want to show, and&amp;nbsp;&lt;b&gt;InplaceSearchQuery&lt;/b&gt; contains the query that is executed towards that view.&lt;/p&gt;&lt;p&gt;So a simplest example of this is to add this to Script Editor Web Part:&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;input type=&quot;text&quot; id=&quot;inputBox&quot; placeholder=&quot;Enter search query...&quot; style=&quot;width:300px&quot;&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: courier; font-size: small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;button onclick=&quot;redirectToURL()&quot; type=&quot;button&quot;&amp;gt;Search&amp;lt;/button&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier; font-size: small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;script&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: courier; font-size: small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; function redirectToURL() {&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: courier; font-size: small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; var inputValue = document.getElementById(&#39;inputBox&#39;).value;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: courier; font-size: small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; var baseURL = &#39;http://intranet.company.com/Lists/RequestForOffer/AllItems.aspx?view={DD04F0F8-6441-4DD9-9515-29EE952C9306}&amp;amp;InplaceSearchQuery=&#39;;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: courier; font-size: small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; var fullURL = baseURL + encodeURIComponent(inputValue);&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: courier; font-size: small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; window.location.href = fullURL;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: courier; font-size: small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: courier; font-size: small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;/script&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Only downside here is that the list view search box doesn&#39;t show the query text, but that you could do by some JavaScript magic injected to the list view page.&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.jussipalo.com/feeds/384051905184578424/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.jussipalo.com/2025/01/sharepoint-how-to-create-direct-link-to.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7258322562721325894/posts/default/384051905184578424'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7258322562721325894/posts/default/384051905184578424'/><link rel='alternate' type='text/html' href='http://blog.jussipalo.com/2025/01/sharepoint-how-to-create-direct-link-to.html' title='SharePoint: How to create direct link to list view including search query'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7258322562721325894.post-2601937727406333416</id><published>2024-11-28T10:26:00.019+02:00</published><updated>2025-04-23T16:40:26.026+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="OneDrive"/><category scheme="http://www.blogger.com/atom/ns#" term="permissions"/><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint"/><title type='text'>How to use Files.SelectedOperations.Selected permission for SharePoint and OneDrive content</title><content type='html'>&lt;h1 style=&quot;text-align: left;&quot;&gt;Problem&lt;/h1&gt;&lt;p&gt;I needed to grant permission for an Entra Id application to access SharePoint Online and OneDrive folder. I didn&#39;t want to grant the broadest &lt;i&gt;Sites.ReadWrite.All&lt;/i&gt; permission to all site collections, nor the second broadest permission &lt;i&gt;Sites.Selected&lt;/i&gt; to specific site collection. Instead I needed to go very granular, so limit access to specific folder and use the &lt;i&gt;Files.SelectedOperations.Selected &lt;/i&gt;permission.&lt;/p&gt;&lt;h1 style=&quot;text-align: left;&quot;&gt;Backgound: Granting permission to whole site collection&lt;/h1&gt;&lt;div&gt;Before realizing &lt;i&gt;Sites.Selected&lt;/i&gt; was too broad, I tested using it, and it worked great. In order to use the following commands, I used Graph Explorer to which I granted&amp;nbsp;&lt;i&gt;Sites.FullControl.All&lt;/i&gt; permission so that it could modify the permissions for SPO items.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;h2 style=&quot;text-align: left;&quot;&gt;1. Get the site collection&lt;/h2&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;First I queried the site (collection) ID for my SharePoint site collection:&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;HTTP GET&amp;nbsp;https://graph.microsoft.com/v1.0/sites/xyz.sharepoint.com:/sites/jussi&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Then with the site ID (it looks something like this: &lt;span style=&quot;font-family: inherit;&quot;&gt;&quot;xyz.sharepoint.com,8e099463-6a83-48c3-9c0e-59c3ca071054,15a706b9-af56-49dd-97ad-51325cee3b66&quot;)&lt;/span&gt;, I queried current permissions for the site:&lt;/div&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;HTTP GET https://graph.microsoft.com/v1.0/sites/[SITE_ID]/permissions&lt;/span&gt;&lt;/p&gt;&lt;div&gt;No permissions were found, just as expected.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;h2 style=&quot;text-align: left;&quot;&gt;2. Add permissions&lt;/h2&gt;&lt;div&gt;To add permissions, you use the &lt;i&gt;permissions&lt;/i&gt; endpoint:&lt;/div&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;HTTP POST&amp;nbsp;https://graph.microsoft.com/v1.0/sites/&lt;/span&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;[SITE_ID]&lt;/span&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;/permissions&lt;/span&gt;&lt;/p&gt;&lt;p&gt;with the following payload in the body section of Graph Explorer:&lt;/p&gt;&lt;div style=&quot;background-color: #1e1e1e; color: #d4d4d4; font-family: Consolas, &amp;quot;Courier New&amp;quot;, monospace; font-size: 14px; line-height: 19px; white-space: pre;&quot;&gt;&lt;div&gt;&lt;span style=&quot;color: gainsboro;&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &lt;span style=&quot;color: #9cdcfe;&quot;&gt;&quot;roles&quot;&lt;/span&gt;&lt;span style=&quot;color: gainsboro;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: gainsboro;&quot;&gt;[&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #ce9178;&quot;&gt;&quot;write&quot;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &lt;span style=&quot;color: gainsboro;&quot;&gt;],&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &lt;span style=&quot;color: #9cdcfe;&quot;&gt;&quot;grantedToIdentities&quot;&lt;/span&gt;&lt;span style=&quot;color: gainsboro;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: gainsboro;&quot;&gt;[&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: gainsboro;&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #9cdcfe;&quot;&gt;&quot;application&quot;&lt;/span&gt;&lt;span style=&quot;color: gainsboro;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: gainsboro;&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #9cdcfe;&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span style=&quot;color: gainsboro;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #ce9178;&quot;&gt;&quot;10facd40-ec88-4c62-b5dc-8170a2ccaba1&quot;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: gainsboro;&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: gainsboro;&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &lt;span style=&quot;color: gainsboro;&quot;&gt;]&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;color: gainsboro;&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;h2 style=&quot;text-align: left;&quot;&gt;3. Removing permissions&lt;/h2&gt;&lt;p&gt;You can remove the permissions too, but for that you need the permission ID. You got the permission ID from the result of the query you used when you added the permission earlier, but in case you missed it, you can list the permissions:&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;HTTP GET https://graph.microsoft.com/v1.0/sites/[SITE_ID]/permissions&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Permission ID is the long non-GUID string like this:&lt;/p&gt;&lt;div style=&quot;background-color: #1e1e1e; color: #d4d4d4; font-family: Consolas, &amp;quot;Courier New&amp;quot;, monospace; font-size: 14px; line-height: 19px; white-space: pre;&quot;&gt;&lt;span style=&quot;color: #9cdcfe;&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span style=&quot;color: gainsboro;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #ce9178;&quot;&gt;&quot;aTowaS50fG1zLnNwLmV4dHwyMGZhY2Q0NC1lYzg4LTRjNjItYjVkYy04MTcwYTJjY2FiYTFAOTJlNTE2MTUtNDkwOS00OGUzLWJhMDYtMmE1ZmMyMzNiNGJi&quot;&lt;/span&gt;&lt;/div&gt;&lt;p&gt;So in order to remove the permission:&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;HTTP DELETE https://graph.microsoft.com/v1.0/sites/&lt;/span&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;[SITE_ID]&lt;/span&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;/permissions/[PERMISSION_ID]&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;h1 style=&quot;text-align: left;&quot;&gt;Granting permission to folder level&lt;/h1&gt;&lt;p&gt;Alright, I removed the site collection level permissions and started to grant folder level permissions.&amp;nbsp;&lt;/p&gt;&lt;h2 style=&quot;text-align: left;&quot;&gt;1. Get the drive ID for the library&lt;/h2&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;https://graph.microsoft.com/v1.0/sites/&lt;/span&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;[SITE_ID]&lt;/span&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;/drives&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Drive ID is the non-GUID string like:&lt;/p&gt;&lt;div style=&quot;background-color: #1e1e1e; color: #d4d4d4; font-family: Consolas, &amp;quot;Courier New&amp;quot;, monospace; font-size: 14px; line-height: 19px; white-space: pre;&quot;&gt;&lt;span style=&quot;color: #9cdcfe;&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span style=&quot;color: gainsboro;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #ce9178;&quot;&gt;&quot;b!Y6QJjoNqw0icDlnDygcQVLkGpxVWr91Jl61RMlzuO2a6mn6WqINZRLEDcG_BOOKl&quot;&lt;/span&gt;&lt;/div&gt;&lt;h2 style=&quot;text-align: left;&quot;&gt;2. Get the folder ID from the drive by querying all the children items of the folder&lt;/h2&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;HTTP GET https://graph.microsoft.com/v1.0/sites/&lt;/span&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;[SITE_ID]&lt;/span&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;/drives/[DRIVE_ID]/root/children&lt;/span&gt;&lt;/p&gt;&lt;p&gt;So, what I now got was the id &lt;i&gt;01QHBNZNLH6DKOS3GO3FHKHKIC6AGODYML&amp;nbsp;&lt;/i&gt;of the folder &lt;i&gt;MyTemplates&amp;nbsp;&lt;/i&gt;inside the library &lt;i&gt;Shared Documents&lt;/i&gt;, that&#39;s the one&lt;i&gt;.&lt;/i&gt;&lt;/p&gt;&lt;div style=&quot;background-color: #1e1e1e; color: #d4d4d4; font-family: Consolas, &amp;quot;Courier New&amp;quot;, monospace; font-size: 14px; line-height: 19px; white-space: pre;&quot;&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #9cdcfe;&quot;&gt;&quot;createdDateTime&quot;&lt;/span&gt;&lt;span style=&quot;color: gainsboro;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #ce9178;&quot;&gt;&quot;2024-11-27T07:26:15Z&quot;&lt;/span&gt;&lt;span style=&quot;color: gainsboro;&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #9cdcfe;&quot;&gt;&quot;eTag&quot;&lt;/span&gt;&lt;span style=&quot;color: gainsboro;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #ce9178;&quot;&gt;&quot;\&quot;{E9D4F067-CE6C-4ED9-A3A9-02F00CE1E18B},1\&quot;&quot;&lt;/span&gt;&lt;span style=&quot;color: gainsboro;&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #9cdcfe;&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span style=&quot;color: gainsboro;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #ce9178;&quot;&gt;&quot;01QHBNZNLH6DKOS3GO3FHKHKIC6AGODYML&quot;&lt;/span&gt;&lt;span style=&quot;color: gainsboro;&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #9cdcfe;&quot;&gt;&quot;lastModifiedDateTime&quot;&lt;/span&gt;&lt;span style=&quot;color: gainsboro;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #ce9178;&quot;&gt;&quot;2024-11-27T07:26:15Z&quot;&lt;/span&gt;&lt;span style=&quot;color: gainsboro;&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #9cdcfe;&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span style=&quot;color: gainsboro;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #ce9178;&quot;&gt;&quot;MyTemplates&quot;&lt;/span&gt;&lt;span style=&quot;color: gainsboro;&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #9cdcfe;&quot;&gt;&quot;webUrl&quot;&lt;/span&gt;&lt;span style=&quot;color: gainsboro;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #ce9178;&quot;&gt;&quot;https://xyz.sharepoint.com/sites/jussi/Shared%20Documents/MyTemplates&quot;&lt;/span&gt;&lt;span style=&quot;color: gainsboro;&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #9cdcfe;&quot;&gt;&quot;cTag&quot;&lt;/span&gt;&lt;span style=&quot;color: gainsboro;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #ce9178;&quot;&gt;&quot;\&quot;c:{E9D4F067-CE6C-4ED9-A3A9-02F00CE1E18B},0\&quot;&quot;&lt;/span&gt;&lt;span style=&quot;color: gainsboro;&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #9cdcfe;&quot;&gt;&quot;size&quot;&lt;/span&gt;&lt;span style=&quot;color: gainsboro;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #b5cea8;&quot;&gt;20558&lt;/span&gt;&lt;span style=&quot;color: gainsboro;&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #9cdcfe;&quot;&gt;&quot;createdBy&quot;&lt;/span&gt;&lt;span style=&quot;color: gainsboro;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: gainsboro;&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #9cdcfe;&quot;&gt;&quot;user&quot;&lt;/span&gt;&lt;span style=&quot;color: gainsboro;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: gainsboro;&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #9cdcfe;&quot;&gt;&quot;email&quot;&lt;/span&gt;&lt;span style=&quot;color: gainsboro;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #ce9178;&quot;&gt;&quot;admin@xyz.onmicrosoft.com&quot;&lt;/span&gt;&lt;span style=&quot;color: gainsboro;&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #9cdcfe;&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span style=&quot;color: gainsboro;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #ce9178;&quot;&gt;&quot;45a44407-f372-45f5-a69d-9f4dd4f704fa&quot;&lt;/span&gt;&lt;span style=&quot;color: gainsboro;&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #9cdcfe;&quot;&gt;&quot;displayName&quot;&lt;/span&gt;&lt;span style=&quot;color: gainsboro;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #ce9178;&quot;&gt;&quot;xyz Admin&quot;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: gainsboro;&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: gainsboro;&quot;&gt;},&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h2 style=&quot;text-align: left;&quot;&gt;3. Add permissions&lt;/h2&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div style=&quot;text-align: left;&quot;&gt;Following my earlier steps when granting permission to site level, I made call:&lt;/div&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;HTTP POST&amp;nbsp;https://graph.microsoft.com/v1.0/sites/&lt;/span&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;[SITE_ID]&lt;/span&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;/drives/[DRIVE_ID]/items/[FOLDER_ID]/permissions&lt;/span&gt;&lt;/p&gt;&lt;p&gt;using same payload as earlier&lt;/p&gt;&lt;div style=&quot;background-color: #1e1e1e; color: #d4d4d4; font-family: Consolas, &amp;quot;Courier New&amp;quot;, monospace; font-size: 14px; line-height: 19px; white-space: pre;&quot;&gt;&lt;div&gt;&lt;span style=&quot;color: gainsboro;&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &lt;span style=&quot;color: #9cdcfe;&quot;&gt;&quot;roles&quot;&lt;/span&gt;&lt;span style=&quot;color: gainsboro;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: gainsboro;&quot;&gt;[&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #ce9178;&quot;&gt;&quot;read&quot;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &lt;span style=&quot;color: gainsboro;&quot;&gt;],&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &lt;span style=&quot;color: #9cdcfe;&quot;&gt;&quot;grantedToIdentities&quot;&lt;/span&gt;&lt;span style=&quot;color: gainsboro;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: gainsboro;&quot;&gt;[&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: gainsboro;&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #9cdcfe;&quot;&gt;&quot;application&quot;&lt;/span&gt;&lt;span style=&quot;color: gainsboro;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: gainsboro;&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #9cdcfe;&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span style=&quot;color: gainsboro;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #ce9178;&quot;&gt;&quot;10facd40-ec88-4c62-b5dc-8170a2ccaba1&quot;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: gainsboro;&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: gainsboro;&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &lt;span style=&quot;color: gainsboro;&quot;&gt;]&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;color: gainsboro;&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;╯︿╰&amp;nbsp; &amp;nbsp;I get &quot;Invalid request&quot; error:&lt;/p&gt;&lt;div style=&quot;background-color: #1e1e1e; color: #d4d4d4; font-family: Consolas, &amp;quot;Courier New&amp;quot;, monospace; font-size: 14px; line-height: 19px; white-space: pre;&quot;&gt;&lt;div&gt;&lt;span style=&quot;color: gainsboro;&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #9cdcfe;&quot;&gt;&quot;error&quot;&lt;/span&gt;&lt;span style=&quot;color: gainsboro;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: gainsboro;&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #9cdcfe;&quot;&gt;&quot;code&quot;&lt;/span&gt;&lt;span style=&quot;color: gainsboro;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #ce9178;&quot;&gt;&quot;invalidRequest&quot;&lt;/span&gt;&lt;span style=&quot;color: gainsboro;&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #9cdcfe;&quot;&gt;&quot;message&quot;&lt;/span&gt;&lt;span style=&quot;color: gainsboro;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #ce9178;&quot;&gt;&quot;Invalid request&quot;&lt;/span&gt;&lt;span style=&quot;color: gainsboro;&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #9cdcfe;&quot;&gt;&quot;innerError&quot;&lt;/span&gt;&lt;span style=&quot;color: gainsboro;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: gainsboro;&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #9cdcfe;&quot;&gt;&quot;date&quot;&lt;/span&gt;&lt;span style=&quot;color: gainsboro;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #ce9178;&quot;&gt;&quot;2024-11-28T08:12:45&quot;&lt;/span&gt;&lt;span style=&quot;color: gainsboro;&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #9cdcfe;&quot;&gt;&quot;request-id&quot;&lt;/span&gt;&lt;span style=&quot;color: gainsboro;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #ce9178;&quot;&gt;&quot;62a82827-5c26-4883-934e-7eabeceead88&quot;&lt;/span&gt;&lt;span style=&quot;color: gainsboro;&quot;&gt;,&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #9cdcfe;&quot;&gt;&quot;client-request-id&quot;&lt;/span&gt;&lt;span style=&quot;color: gainsboro;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #ce9178;&quot;&gt;&quot;f6cd7714-2199-3a94-3a4b-5df804f1ec37&quot;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: gainsboro;&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: gainsboro;&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;color: gainsboro;&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;What is this? Documentation is rather brief. There was a &lt;a href=&quot;https://www.michev.info/blog/post/6074/granular-permissions-for-working-with-files-list-items-and-lists-added-to-the-graph-api&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;great article by Vasil&lt;/a&gt; that discusses permissions that indicated that this should (or at least was) possible, so I started testing further, and finally found a solution.&lt;/p&gt;&lt;h1 style=&quot;text-align: left;&quot;&gt;Solution&lt;/h1&gt;&lt;p&gt;When granting application permissions to &lt;i&gt;folder objects&lt;/i&gt; (probably same goes for files and lists), the payload you send is slightly different. You don&#39;t use &lt;i&gt;grantedToIdentities&lt;/i&gt; array, but instead &lt;i&gt;grantedTo&lt;/i&gt; object:&lt;/p&gt;&lt;div style=&quot;background-color: #1e1e1e; color: #d4d4d4; font-family: Consolas, &amp;quot;Courier New&amp;quot;, monospace; font-size: 14px; line-height: 19px; white-space: pre;&quot;&gt;&lt;div&gt;&lt;span style=&quot;color: gainsboro;&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &lt;span style=&quot;color: #9cdcfe;&quot;&gt;&quot;roles&quot;&lt;/span&gt;&lt;span style=&quot;color: gainsboro;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: gainsboro;&quot;&gt;[&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #ce9178;&quot;&gt;&quot;read&quot;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &lt;span style=&quot;color: gainsboro;&quot;&gt;],&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &lt;span style=&quot;color: #9cdcfe;&quot;&gt;&quot;grantedTo&quot;&lt;/span&gt;&lt;span style=&quot;color: gainsboro;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: gainsboro;&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #9cdcfe;&quot;&gt;&quot;application&quot;&lt;/span&gt;&lt;span style=&quot;color: gainsboro;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: gainsboro;&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #9cdcfe;&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span style=&quot;color: gainsboro;&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;color: #ce9178;&quot;&gt;&quot;10facd40-ec88-4c62-b5dc-8170a2ccaba1&quot;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: gainsboro;&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &lt;span style=&quot;color: gainsboro;&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;color: gainsboro;&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;b&gt;&lt;i&gt;NOTE!&lt;/i&gt;&lt;/b&gt; This payload doesn&#39;t work when granting permission on a site level.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.jussipalo.com/feeds/2601937727406333416/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.jussipalo.com/2024/11/how-to-use-filesselectedoperationsselec.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7258322562721325894/posts/default/2601937727406333416'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7258322562721325894/posts/default/2601937727406333416'/><link rel='alternate' type='text/html' href='http://blog.jussipalo.com/2024/11/how-to-use-filesselectedoperationsselec.html' title='How to use Files.SelectedOperations.Selected permission for SharePoint and OneDrive content'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7258322562721325894.post-2612112027293352023</id><published>2023-12-14T10:19:00.007+02:00</published><updated>2023-12-14T10:21:27.038+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint"/><title type='text'>SharePoint: How to find out if you have legacy add-ins that are affected by the SharePoint Add-in model retirement</title><content type='html'>&lt;h3 style=&quot;text-align: left;&quot;&gt;Question&lt;/h3&gt;&lt;p&gt;How to find out if my SharePoint Online tenant has legacy add-ins that stop working when the legacy add-in model is retiring?&lt;/p&gt;&lt;p&gt;Answer&lt;/p&gt;&lt;p&gt;In order to list add-ins, you can use few techniques:&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;ul style=&quot;text-align: left;&quot;&gt;&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/sharepoint/dev/sp-add-ins/get-to-know-the-sharepoint-rest-service&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;SharePoint REST API&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://www.nuget.org/packages/Microsoft.SharePointOnline.CSOM&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;PnP CSOM&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://aka.ms/sppnp-powershell&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;PnP PowerShell&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://pnp.github.io/cli-microsoft365?utm_source=msft_docs&amp;amp;utm_medium=page&amp;amp;utm_campaign=Use+SharePoint+Online+tenant+properties&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;CLI for Microsoft 365&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;Easiest in my opinion is the CLI for Microsoft 365, as it will give you the result in just a two commands.&amp;nbsp; If you wish to build further automation, you will want to pick the PnP PowerShell library to use in your PowerShell script or the PnP CSOM if you&#39;re using .NET.&lt;/p&gt;&lt;p&gt;To get a quick list or add-ins using the CLI for Microsoft 365, first login to your tenant with command:&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;m365 login&lt;/span&gt;&lt;/p&gt;&lt;p&gt;then list the add-ins with command:&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;m365 spo app list&lt;/span&gt;&lt;/p&gt;&lt;p&gt;in order to output the add-in JSON array to a file, use command:&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;m365 spo app list &amp;gt; add-ins.json&lt;/span&gt;&lt;/p&gt;The output will contain array of add-ins, and the property &lt;i&gt;IsClientSideSolution&lt;/i&gt; will tell you if the application is legacy and will be retiring.&amp;nbsp;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If &lt;i&gt;IsClientSideSolution&lt;/i&gt; is &lt;b&gt;false&lt;/b&gt;, it is legacy and will be retired.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If &lt;i&gt;IsClientSideSolution&lt;/i&gt; is &lt;b&gt;true&lt;/b&gt;, it is modern and will NOT be retired.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEgkMx4p-rU5RZ-rFznmw0fqaTfiW32p8PGE2vgQFWRgpwbe5pF0rMMzllyCqDEOSCKAd-MVnvmHfKdyHFU8GMxoEOlQbu3FZKvypWT3EuLikC7qHM6Yr3wuWnbgFaxQSb0HVIZef3XtE8VetI6qozd7Jsa4FFjtYTdAJauRxAjYjOvgzIf1ij_GnAH4h7Zh&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;433&quot; data-original-width=&quot;419&quot; height=&quot;240&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEgkMx4p-rU5RZ-rFznmw0fqaTfiW32p8PGE2vgQFWRgpwbe5pF0rMMzllyCqDEOSCKAd-MVnvmHfKdyHFU8GMxoEOlQbu3FZKvypWT3EuLikC7qHM6Yr3wuWnbgFaxQSb0HVIZef3XtE8VetI6qozd7Jsa4FFjtYTdAJauRxAjYjOvgzIf1ij_GnAH4h7Zh&quot; width=&quot;232&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.jussipalo.com/feeds/2612112027293352023/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.jussipalo.com/2023/12/sharepoint-how-to-find-out-if-you-have.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7258322562721325894/posts/default/2612112027293352023'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7258322562721325894/posts/default/2612112027293352023'/><link rel='alternate' type='text/html' href='http://blog.jussipalo.com/2023/12/sharepoint-how-to-find-out-if-you-have.html' title='SharePoint: How to find out if you have legacy add-ins that are affected by the SharePoint Add-in model retirement'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/a/AVvXsEgkMx4p-rU5RZ-rFznmw0fqaTfiW32p8PGE2vgQFWRgpwbe5pF0rMMzllyCqDEOSCKAd-MVnvmHfKdyHFU8GMxoEOlQbu3FZKvypWT3EuLikC7qHM6Yr3wuWnbgFaxQSb0HVIZef3XtE8VetI6qozd7Jsa4FFjtYTdAJauRxAjYjOvgzIf1ij_GnAH4h7Zh=s72-c" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7258322562721325894.post-6696057540252316760</id><published>2022-01-12T15:42:00.003+02:00</published><updated>2022-01-12T15:45:10.488+02:00</updated><title type='text'>Kuluttajariitalautakunnan päätös: Puutteet auton varusteissa</title><content type='html'>&lt;p&gt;Kuluttajariitalautakunta käsitteli tapaukseni kun tammikuussa 2020 ostamastani autosta puuttui varusteita, jotka tilaushetkellä oli varustelistauksessa. Lautakunta päätyi suosittamaan hyvitystä. Hyvitysvaateissanne voitte viitata Kuluttajariitalautakunnan julkiseen päätökseen Dnro 6279/33/2020.&lt;/p&gt;&lt;p&gt;Päätöksen PDF:n saa Kuluttajariitalautakunnalta tai allekirjoittaneelta pyydettäessä. Alla copy&amp;amp;paste julkisen päätöksen tekstisisällöstä.&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;KULUTTAJARIITALAUTAKUNTA PÄÄTÖS Dnro 6279/33/2020&lt;/p&gt;&lt;p&gt;Esitelty 28.10.2021&lt;/p&gt;&lt;p&gt;IVa jaosto&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Myyjän vastuu auton puuttuvista varusteista&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;Lautakunnan ratkaisu&amp;nbsp;&lt;/b&gt;&lt;/p&gt;&lt;p&gt;Kuluttajariitalautakunta suosittaa, että Autokeskus Oy maksaa N.Nlle 300 euroa.&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;Asiaselostus&amp;nbsp;&lt;/b&gt;&lt;/p&gt;&lt;p&gt;Kuluttaja osti 26.10.2019 myyjäliikkeeltä uuden Skoda Superb henkilöauton 53 136,95&amp;nbsp;&lt;/p&gt;&lt;p&gt;eurolla. Autolle annettiin kahden vuoden pituinen takuu. Auto toimitettiin kuluttajalle&amp;nbsp;&lt;/p&gt;&lt;p&gt;29.1.2020.&lt;/p&gt;&lt;p&gt;Kuluttajan mukaan autosta puuttuu sellaisia varusteita, joiden kuuluisi olla siinä kaupassa&amp;nbsp;&lt;/p&gt;&lt;p&gt;sovitun mukaisesti. Lisäksi Infotainment-järjestelmä toimii hitaasti. Osapuolet ovat eri mieltä&amp;nbsp;&lt;/p&gt;&lt;p&gt;siitä, onko kyseessä myyjän vastuulla oleva kaupan kohteen virhe, ja mikä on&amp;nbsp;&lt;/p&gt;&lt;p&gt;hinnanalennuksen määrä.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;Ostajan vaatimukset perusteluineen&lt;/b&gt;&lt;/p&gt;&lt;p&gt;Kuluttaja vaatii myyjäliikkeeltä hyvityksenä 3 000 euroa. Vaatimus perustuu kaupan&amp;nbsp;&lt;/p&gt;&lt;p&gt;kohteessa ilmenneeseen varusteiden ongelmiin ja siihen sisältyy 2 500 euroa puuttuvista&amp;nbsp;&lt;/p&gt;&lt;p&gt;varusteista, 400 euroa puutteellisesti toimivista varusteista ja 100 euroa puhelinkuluista ja&amp;nbsp;&lt;/p&gt;&lt;p&gt;huoltokäynneistä.&amp;nbsp;&lt;/p&gt;&lt;p&gt;Joitain varusteita puuttuu ja jotkin toimivat puutteellisesti. Kuluttaja totesi virheen keväällä&amp;nbsp;&lt;/p&gt;&lt;p&gt;2020 ja ilmoitti siitä 9.9.2020. Kuluttaja viittaa vastaukseen ja toteaa, että Personalisointi ei&amp;nbsp;&lt;/p&gt;&lt;p&gt;toimi eikä ole toiminut syyskuusta 2020 alkaen.&lt;/p&gt;&lt;p&gt;Kuluttaja on myöhemmin todennut, että mahdollisesti schuko-latausjohdon ongelma saatiin&amp;nbsp;&lt;/p&gt;&lt;p&gt;poistettua 28.12.2020 eli 11 kuukautta luovutuksesta. Kuluttaja ei pidä järkevinä ratkaisuna&amp;nbsp;&lt;/p&gt;&lt;p&gt;varusteiden ongelmiin korvata integroidut järjestelmät irrallisilla laitteilla tai manuaalisilla&amp;nbsp;&lt;/p&gt;&lt;p&gt;toiminnoilla. Muuten ongelmiin ei ole tarjottu ratkaisua. GPS-antenni uusittiin 12.1.2021,&amp;nbsp;&lt;/p&gt;&lt;p&gt;mikä ei poistanut ongelmia. Infotainment järjestelmälle on lupailtu päivitystä useita kertoja&amp;nbsp;&lt;/p&gt;&lt;p&gt;turhaan.&lt;/p&gt;&lt;p&gt;Ratkaisupyynnön liitteenä on ajoneuvon käyttöohjekirja.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;Myyjän vastaus perusteluineen&lt;/b&gt;&lt;/p&gt;&lt;p&gt;Myyjäliike ja maahantuoja ovat antaneet asiassa yhteisen vastauksen, ja toteavat voivansa&amp;nbsp;&lt;/p&gt;&lt;p&gt;maksaa 300 euroa hyvityksenä puuttuvista varusteista.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Maahantuojan toimittamaan myyntimateriaaliin oli jäänyt virheellisesti aiemman&lt;/p&gt;&lt;p&gt;Infotaiment järjestelmän tiedot. Puuttuvia varusteita ovat DVD-soitin 2 SD-korttipaikkaa In&amp;nbsp;&lt;/p&gt;&lt;p&gt;Car Commonication ja Personalisation 1.1.&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Autossa on uuden sukupolven Infotainment järjestelmä, jossa on lataushybridijärjestelmälle&amp;nbsp;&lt;/p&gt;&lt;p&gt;tärkeitä ominaisuuksia kuten akun lataukseen liittyvät toiminnot. Järjestelmässä&amp;nbsp;&lt;/p&gt;&lt;p&gt;karttapäivitykset tehdään internetyhteydellä. In Car Communication vahvistaa kuljettajan&amp;nbsp;&lt;/p&gt;&lt;p&gt;ääntä takapenkille ja on tarpeen etenkin seitsenpaikkaisessa autossa. Personalisointi 1.1&amp;nbsp;&lt;/p&gt;&lt;p&gt;tallentaa kuljettajan istuimen säädöt ym. avaimeen. Tässä autossa tallennus voidaan tehdä&amp;nbsp;&lt;/p&gt;&lt;p&gt;istuimen muistipaikkapainikkeisiin ja se on ollut käytettävissä Connect-palvelun kautta&amp;nbsp;&lt;/p&gt;&lt;p&gt;viimeistään syyskuusta 2020 alkaen.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Mode 2 -latausjohtoa varten on olemassa ohjelmistopäivitys veloituksetta. Sen jälkeen&amp;nbsp;&lt;/p&gt;&lt;p&gt;voidaan käyttää täyttä 8A latausvirtaa (n. 1,8 kW). Ennen päivitystä latausvirta oli enintään&amp;nbsp;&lt;/p&gt;&lt;p&gt;6A ja muut lataustavat olivat normaalisti käytettävissä. Asiakkaalle on lähetetty tästä tieto&amp;nbsp;&lt;/p&gt;&lt;p&gt;3.12.2020 ja 11.12.2020. Mahdollisten Infotainment-järjestelmän ongelmien vuoksi asiakasta&lt;/p&gt;&lt;p&gt;on pyydetty tuomaan auto huoltoon tarkistettavaksi 16.9. ja 3.12.2020 sekä myös&amp;nbsp;&lt;/p&gt;&lt;p&gt;11.12.2020. GPS-antenni on uusittu, koska Connect-yhteys oli pätkinyt. Infotainment järjestelmälle on tulossa päivitys viikkoon 29 mennessä vuonna 2021.&lt;/p&gt;&lt;p&gt;Vastauksen liitteenä on Autokeskuksen työmääräyksiä.&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;Ratkaisun perustelut&lt;/b&gt;&lt;/p&gt;&lt;p&gt;Virheellisyyden arviointi&amp;nbsp;&lt;/p&gt;&lt;p&gt;Virheen arvioinnin lähtökohta on osapuolten välisen sopimuksen sisältö. Uuden auton&amp;nbsp;&lt;/p&gt;&lt;p&gt;kaupassa virheen olemassa oloa arvioidaan kuluttajansuojalain 5 luvun 12 §:n mukaan.&amp;nbsp;&lt;/p&gt;&lt;p&gt;Virhearvioinnin perustana ovat ostajan aiheelliset odotukset.&lt;/p&gt;&lt;p&gt;Asiassa on riidatonta, että autosta on puuttunut siihen kuuluneita varusteita. Kuluttaja on&amp;nbsp;&lt;/p&gt;&lt;p&gt;perustellusti voinut edellyttää, että autossa on hänelle ilmoitetut varusteet, joten kaupassa&amp;nbsp;&lt;/p&gt;&lt;p&gt;on tällä perusteella kuluttajansuojalain 5 luvun 12 §:n mukainen virhe. Kauppa ei ole kaikilta&amp;nbsp;&lt;/p&gt;&lt;p&gt;osin vastannut sitä, mistä asiassa on sovittu.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Infotainment-järjestelmän osalta autoon on tehty päivityksiä, ja tältä osin asiassa ei ole&amp;nbsp;&lt;/p&gt;&lt;p&gt;tarkempaa tietoa siitä, mikä on järjestelmän tilanne päivitysten jälkeen. Asiassa ei ole&amp;nbsp;&lt;/p&gt;&lt;p&gt;esitetty ulkopuolista selvitystä siitä, voidaanko kuluttajan esiin nostama ongelma katsoa&amp;nbsp;&lt;/p&gt;&lt;p&gt;kuluttajansuojalain mukaiseksi virheeksi. Tältä osin asiassa ei esitetyn näytön valossa ole&amp;nbsp;&lt;/p&gt;&lt;p&gt;todettavissa virhettä.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;Virheen seuraamukset&lt;/b&gt;&lt;/p&gt;&lt;p&gt;Myyjäliike saa omalla kustannuksellaan korjata virheen, jos se tarjoutuu tekemään&lt;/p&gt;&lt;p&gt;korjauksen viipymättä saatuaan tietää virheestä. Myyjällä on oikeus osoittaa ostajalle myyjän&lt;/p&gt;&lt;p&gt;lukuun tehtävän korjauksen paikka. Ostaja saa kieltäytyä virheen korjaamisesta vain&lt;/p&gt;&lt;p&gt;erityisestä syystä, esimerkiksi, jos siitä aiheutuisi hänelle olennaista haittaa.&amp;nbsp;&lt;/p&gt;&lt;p&gt;Tässä tapauksessa virheen korjaaminen ei ole mahdollista, koska ajoneuvoon ei ole&lt;/p&gt;&lt;p&gt;asennettu puuttuvia varusteita, vaan ne on tarjottu käytettäviksi ulkoisina järjestelminä, joita&lt;/p&gt;&lt;p&gt;ei ole integroitu autoon. Näin ollen tarjottu korjaustapa ei ole asianmukainen, ja asiaa on&lt;/p&gt;&lt;p&gt;arvioitava hinnanalennukseen perustuen.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Hyvityksen määrän arviointi perustuu ilmenneen virheen laadun ja merkityksen ohella&lt;/p&gt;&lt;p&gt;kauppahintaan sekä ostajan aiheellisiin odotuksiin.&lt;/p&gt;&lt;p&gt;Nämä seikat huomioon otettuna lautakunta katsoo, että myyjäliikkeen tulee suorittaa&lt;/p&gt;&lt;p&gt;ostajalle hinnanalennuksena ja korvauksena tarpeellisista kuluista yhteensä 300 euroa.&lt;/p&gt;&lt;p&gt;Päätös oli yksimielinen.&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.jussipalo.com/feeds/6696057540252316760/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.jussipalo.com/2022/01/kuluttajariitalautakunnan-paatos.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7258322562721325894/posts/default/6696057540252316760'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7258322562721325894/posts/default/6696057540252316760'/><link rel='alternate' type='text/html' href='http://blog.jussipalo.com/2022/01/kuluttajariitalautakunnan-paatos.html' title='Kuluttajariitalautakunnan päätös: Puutteet auton varusteissa'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7258322562721325894.post-8409609165558713792</id><published>2021-11-02T10:26:00.006+02:00</published><updated>2021-11-02T10:26:41.524+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint"/><category scheme="http://www.blogger.com/atom/ns#" term="sql server"/><title type='text'>SharePoint: Transport-level error has occurred when receiving results from the server</title><content type='html'>&lt;h3 style=&quot;text-align: left;&quot;&gt;Problem&lt;/h3&gt;&lt;p&gt;SharePoint 2016 (on-prem) farm had weird issues on few application and WFE servers. Namely, the servers couldn&#39;t connect to SQL Server, but ULS logs showed error:&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;Unknown SQL Exception 64 occurred. Additional error information from SQL Server is included below.&amp;nbsp; A transport-level error has occurred when receiving results from the server. (provider: TCP Provider, error: 0 - The specified network name is no longer available.)&lt;/span&gt;&lt;/p&gt;&lt;p&gt;When testing the connection with UDL file, the behavior was also strange, i.e., when testing the connection to server without defining any specific database, the test succeeded:&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQbduS7IQIgxQAOB0LCF8eTjyKpR7j0nKXs-eTuMvlxMisH_VIvHdw4ojeQWJHYmj3F6ys6X0Wnr2d5wxdMTfl-5n7cf-eW88ZvkzPJvc3IaqvSpR033lTmqHD_po_9rJhyphenhyphenPzynfux8nqz/&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;463&quot; data-original-width=&quot;361&quot; height=&quot;400&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQbduS7IQIgxQAOB0LCF8eTjyKpR7j0nKXs-eTuMvlxMisH_VIvHdw4ojeQWJHYmj3F6ys6X0Wnr2d5wxdMTfl-5n7cf-eW88ZvkzPJvc3IaqvSpR033lTmqHD_po_9rJhyphenhyphenPzynfux8nqz/w312-h400/image.png&quot; width=&quot;312&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Also when defining a specific database, the test succeeded:&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgRWt1BfqGXoWvxpDs7IhO2qXDy34PoMrtmbHBfYg595g4Om2CL0atWUux3sGTR7rIO1B3PHdVns6Tmd8XnEI_rFbTriK5Hpe627OXdVxvhPvYkeJGYDrp6Gw0UD5buKVwaLXAR-PMsP2E6/&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;469&quot; data-original-width=&quot;390&quot; height=&quot;400&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgRWt1BfqGXoWvxpDs7IhO2qXDy34PoMrtmbHBfYg595g4Om2CL0atWUux3sGTR7rIO1B3PHdVns6Tmd8XnEI_rFbTriK5Hpe627OXdVxvhPvYkeJGYDrp6Gw0UD5buKVwaLXAR-PMsP2E6/w333-h400/image.png&quot; width=&quot;333&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;However, when attempting to list the databases by expanding the &quot;Select the database on the server&quot; dropdown, there was first &quot;Unspesified error&quot; error:&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh5B1LmCSigZJAm57Ub6I6SPLocn90HSkgG1G5BA9hewllmr84db8VFn7K6xwJOd1Cvq_PoMKSKnL2-GRBAFTqmcildqam9cZCoWK2DpeMpvcaBwQZrsFIAVSzCzO-C4aiaxjQn3GKpQJfy/&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;463&quot; data-original-width=&quot;361&quot; height=&quot;400&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh5B1LmCSigZJAm57Ub6I6SPLocn90HSkgG1G5BA9hewllmr84db8VFn7K6xwJOd1Cvq_PoMKSKnL2-GRBAFTqmcildqam9cZCoWK2DpeMpvcaBwQZrsFIAVSzCzO-C4aiaxjQn3GKpQJfy/w312-h400/image.png&quot; width=&quot;312&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Followed by error &quot;Microsoft Data Link &lt;br /&gt;Login failed. Catalog information cannot be retrieved.&quot;:&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEihP3u0IH9XbGSoHA-VFOiRKR1WKV3ehkjD2ItNtIupM912EvOun1fTAed573cvkw1_w3Wm8QEaT6ImePd0RMv9EoKXugExaSm9iXQ_VehG_UiuRllNeRvV0ANuzFckF5mDmwXzCLxhaA0y/&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;480&quot; data-original-width=&quot;429&quot; height=&quot;400&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEihP3u0IH9XbGSoHA-VFOiRKR1WKV3ehkjD2ItNtIupM912EvOun1fTAed573cvkw1_w3Wm8QEaT6ImePd0RMv9EoKXugExaSm9iXQ_VehG_UiuRllNeRvV0ANuzFckF5mDmwXzCLxhaA0y/w358-h400/image.png&quot; width=&quot;358&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;h3 style=&quot;text-align: left;&quot;&gt;Solution&lt;/h3&gt;&lt;div&gt;Solution was (eventually) to fix the Jumbo Packet setting on the servers having the issue. Other servers had value 1514, while the problematic servers had value 9014 and changing value to 1514 made all the SharePoint servers immediately connect to SQL Server, and also the UDL DB listing started working.&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhIbU9dWuwDJ2vZDVWAhIdYRFn5PuV7Pp6po6D8jj3gE0nHwjCjyFsgTcRVAejPxXAFYoxTVpCrsgklraid7W4N4Us-BslBGUnVmqNEVqkOlazV-LqOOhoKXAws7SKBB5hT8_hIACLphefi/&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;524&quot; data-original-width=&quot;569&quot; height=&quot;368&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhIbU9dWuwDJ2vZDVWAhIdYRFn5PuV7Pp6po6D8jj3gE0nHwjCjyFsgTcRVAejPxXAFYoxTVpCrsgklraid7W4N4Us-BslBGUnVmqNEVqkOlazV-LqOOhoKXAws7SKBB5hT8_hIACLphefi/w400-h368/image.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.jussipalo.com/feeds/8409609165558713792/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.jussipalo.com/2021/11/sharepoint-transport-level-error-has.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7258322562721325894/posts/default/8409609165558713792'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7258322562721325894/posts/default/8409609165558713792'/><link rel='alternate' type='text/html' href='http://blog.jussipalo.com/2021/11/sharepoint-transport-level-error-has.html' title='SharePoint: Transport-level error has occurred when receiving results from the server'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQbduS7IQIgxQAOB0LCF8eTjyKpR7j0nKXs-eTuMvlxMisH_VIvHdw4ojeQWJHYmj3F6ys6X0Wnr2d5wxdMTfl-5n7cf-eW88ZvkzPJvc3IaqvSpR033lTmqHD_po_9rJhyphenhyphenPzynfux8nqz/s72-w312-h400-c/image.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7258322562721325894.post-4641995511636342873</id><published>2021-09-29T09:52:00.007+03:00</published><updated>2024-01-16T14:39:45.662+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="authentication"/><category scheme="http://www.blogger.com/atom/ns#" term="edge"/><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint"/><title type='text'>Edge: Reverting to classic authentication dialog a.k.a disable Windows Hello for HTTP authentication</title><content type='html'>&lt;h3 style=&quot;text-align: left;&quot;&gt;Problem&lt;/h3&gt;&lt;p&gt;In recent Microsoft Edge browser versions 90+, the classic authentication dialog (or NTLM authentication dialog, or Windows authentication prompt) has been replaced by Windows Hello authentication prompt. It&#39;s all nice and secure, but at the moment at least, browser password vault extensions such as 1Password cannot fill in the credentials to that modern prompt. What it means is that you need to close the Windows Hello prompt, open password extension, copy username/password to notepad, refresh browser window, paste credentials from notepad to Windows Hello prompt. *yawn*&lt;/p&gt;&lt;p&gt;This is cumbersome in enterprise scenarios with various internal systems such as SharePoint that may require you to login with different credentials from the one you&#39;re currently logged into Windows.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgb9IxaS-a4KNWrGb8jk1kIB3QOqIeQ1Dr5Kzfunqh9xYMtlhUtfirDslYAyZecxCANOpS2ksTV5I_5lkGlpPSPkanmrsYxsizj1Y9lKS63GNJfO6xLZqrOr84aa2laqBTgCcFiyIQNCFrD/&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img data-original-height=&quot;488&quot; data-original-width=&quot;747&quot; height=&quot;261&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgb9IxaS-a4KNWrGb8jk1kIB3QOqIeQ1Dr5Kzfunqh9xYMtlhUtfirDslYAyZecxCANOpS2ksTV5I_5lkGlpPSPkanmrsYxsizj1Y9lKS63GNJfO6xLZqrOr84aa2laqBTgCcFiyIQNCFrD/w400-h261/image.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;h3 style=&quot;text-align: left;&quot;&gt;Solution&lt;/h3&gt;&lt;p&gt;For now the only solution is to disable the Windows Hello prompt in Edge. It will require using Group Policies either on AD level, or on individual machine. The following steps are for individual machine, but if you&#39;re an AD admin, you can pick the essential pieces from the instructions and do the same on AD level policy.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;ol style=&quot;text-align: left;&quot;&gt;&lt;li&gt;First download MS Edge policy file from&amp;nbsp;&lt;a href=&quot;https://aka.ms/EdgeEnterprise&quot; target=&quot;_blank&quot;&gt;https://aka.ms/EdgeEnterprise&lt;/a&gt;, from the drop-downs, select the version of your Edge, then press &lt;b&gt;GET POLICY FILES&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi7CvewMeWwmvDLZ-4iibqjJ9y_h0RE8Ma7WMEl1RDV2fRtBNkbfRx8YF9mKaw25j9T8AIVRs4NqKfKKyUb7EgnY__aqEnbfn805iQBY4zldju_wf7ZdTaqZzj3xQtNC1KV10lzzeN1pm7J/&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;270&quot; data-original-width=&quot;1258&quot; height=&quot;86&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi7CvewMeWwmvDLZ-4iibqjJ9y_h0RE8Ma7WMEl1RDV2fRtBNkbfRx8YF9mKaw25j9T8AIVRs4NqKfKKyUb7EgnY__aqEnbfn805iQBY4zldju_wf7ZdTaqZzj3xQtNC1KV10lzzeN1pm7J/w400-h86/image.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Extract the .cab, and .zip 🙄&lt;/li&gt;&lt;li&gt;Navigate to &lt;i&gt;.\MicrosoftEdgePolicyTemplates\windows\admx&lt;/i&gt; folder&lt;/li&gt;&lt;li&gt;Copy&amp;nbsp;&lt;i&gt;msedge.admx&lt;/i&gt; to&amp;nbsp;&lt;i&gt;C:\Windows\PolicyDefinitions&lt;/i&gt;&lt;/li&gt;&lt;li&gt;Navigate to &lt;i&gt;.\MicrosoftEdgePolicyTemplates\windows\admx\en-US&lt;/i&gt; folder (NOTE! or the language of your Windows installation, if not en-US)&lt;/li&gt;&lt;li&gt;Copy &lt;i&gt;msedge.adml&lt;/i&gt; to&amp;nbsp;&lt;i&gt;C:\Windows\PolicyDefinitions\en-US&lt;/i&gt;&lt;/li&gt;&lt;li&gt;Open Local Group Policy Editor, and navigate to &lt;i&gt;Computer Configuration / Administrative Templates / Microsoft Edge / HTTP Authentication&lt;/i&gt;&lt;/li&gt;&lt;li&gt;Edit &lt;i&gt;Windows Hello For HTTP Auth Enabled &lt;/i&gt;setting, and set it to &lt;i&gt;Disabled&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjgD30X3_QNembfrGLX1I5c-4HuJmr9WpCXUYp-zbmW82GTYUDwA6mOfbg2kdtw0WGD6cJ56LYN8HOe7J7bO1ik8ZpPH_Q7qYO7Q9tq1Pj8A_daTxEdV09ejZfZzupH63fyQpC2sqU63bcn/&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;560&quot; data-original-width=&quot;1017&quot; height=&quot;220&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjgD30X3_QNembfrGLX1I5c-4HuJmr9WpCXUYp-zbmW82GTYUDwA6mOfbg2kdtw0WGD6cJ56LYN8HOe7J7bO1ik8ZpPH_Q7qYO7Q9tq1Pj8A_daTxEdV09ejZfZzupH63fyQpC2sqU63bcn/w400-h220/image.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;/i&gt;&lt;/li&gt;&lt;li&gt;Click OK to confirm policy setting, and refresh page in Edge - no restart needed&lt;/li&gt;&lt;li&gt;Applauds! Classic authentication prompt is back and you can also access the browser extension&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEisODexZhzmjtxFzgsplej1NdaKCisUV79U9Bmk-Ox5awXV4Ev0FV8wj7whYdVei9PqwGSB9RUMwMILLI9wxZPRVQ-y8JfCrs6x5EWxhBSCNqbnG7N_W-SdKVg5fTGgUYUwC0b9oIBy00Ei/&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;268&quot; data-original-width=&quot;715&quot; height=&quot;150&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEisODexZhzmjtxFzgsplej1NdaKCisUV79U9Bmk-Ox5awXV4Ev0FV8wj7whYdVei9PqwGSB9RUMwMILLI9wxZPRVQ-y8JfCrs6x5EWxhBSCNqbnG7N_W-SdKVg5fTGgUYUwC0b9oIBy00Ei/w400-h150/image.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/li&gt;&lt;/ol&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.jussipalo.com/feeds/4641995511636342873/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.jussipalo.com/2021/09/edge-reverting-to-classic.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7258322562721325894/posts/default/4641995511636342873'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7258322562721325894/posts/default/4641995511636342873'/><link rel='alternate' type='text/html' href='http://blog.jussipalo.com/2021/09/edge-reverting-to-classic.html' title='Edge: Reverting to classic authentication dialog a.k.a disable Windows Hello for HTTP authentication'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgb9IxaS-a4KNWrGb8jk1kIB3QOqIeQ1Dr5Kzfunqh9xYMtlhUtfirDslYAyZecxCANOpS2ksTV5I_5lkGlpPSPkanmrsYxsizj1Y9lKS63GNJfO6xLZqrOr84aa2laqBTgCcFiyIQNCFrD/s72-w400-h261-c/image.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7258322562721325894.post-5085172188720659412</id><published>2021-09-20T10:43:00.005+03:00</published><updated>2021-09-21T11:05:02.367+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="auth0"/><category scheme="http://www.blogger.com/atom/ns#" term="authentication"/><title type='text'>Auth0: Invalid RSAES-OAEP padding</title><content type='html'>&lt;h3 style=&quot;text-align: left;&quot;&gt;Problem&lt;/h3&gt;&lt;p&gt;After configuring Auth0 with custom certificates via API, you get Access Denied error when attempting to login.&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;color: #2b2e2f; font-size: 14px;&quot;&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;{ &quot;error&quot;: &quot;access_denied&quot;, &quot;error_description&quot;: &quot;Invalid RSAES-OAEP padding.&quot; }&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3 style=&quot;text-align: left;&quot;&gt;Solution&lt;/h3&gt;&lt;p&gt;Add an additional &lt;span face=&quot;&amp;quot;Lucida Sans Unicode&amp;quot;, sans-serif&quot; style=&quot;color: #2b2e2f; font-size: 10.5pt;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;code style=&quot;white-space: pre-wrap;&quot;&gt;&lt;span style=&quot;background: rgb(248, 248, 248); border: 1pt solid rgb(234, 234, 234); color: #2b2e2f; font-family: Consolas; font-size: 10pt; mso-border-alt: solid #EAEAEA .75pt; padding: 0cm;&quot;&gt;decryptionKey&lt;/span&gt;&lt;/code&gt;&lt;span face=&quot;&amp;quot;Lucida Sans Unicode&amp;quot;, sans-serif&quot; style=&quot;color: #2b2e2f; font-size: 10.5pt;&quot;&gt;&amp;nbsp;&lt;/span&gt;to the connection&#39;s options with the following format.&lt;/p&gt;

&lt;div style=&quot;background: rgb(248, 248, 248); border: 1pt solid rgb(204, 204, 204); mso-border-alt: solid #CCCCCC .75pt; mso-element: para-border-div; padding: 5pt 8pt;&quot;&gt;&lt;pre style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-radius: 3px; border: none; line-height: 14.25pt; max-width: 100%; padding: 0cm;&quot;&gt;&lt;code style=&quot;border: transparent; max-width: 100%; white-space: pre-wrap;&quot;&gt;&lt;span style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #2b2e2f; font-family: Consolas;&quot;&gt;options: {&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border: none; line-height: 14.25pt; padding: 0cm;&quot;&gt;&lt;code&gt;&lt;span style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #2b2e2f; font-family: Consolas;&quot;&gt;&amp;nbsp;&amp;nbsp;//... other options&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border: none; line-height: 14.25pt; padding: 0cm;&quot;&gt;&lt;code&gt;&lt;span style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #2b2e2f; font-family: Consolas;&quot;&gt;&amp;nbsp; &quot;decryptionKey&quot; : {&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border: none; line-height: 14.25pt; padding: 0cm;&quot;&gt;&lt;code&gt;&lt;span style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #2b2e2f; font-family: Consolas;&quot;&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;/span&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&quot;key&quot;: &lt;/span&gt;&quot;-----BEGIN PRIVATE KEY-----\n...&quot;,&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border: none; line-height: 14.25pt; padding: 0cm;&quot;&gt;&lt;code&gt;&lt;span style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #2b2e2f; font-family: Consolas;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;span&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;/span&gt;&quot;cert&quot;: &quot;-----BEGIN CERTIFICATE-----\n...&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border: none; line-height: 14.25pt; padding: 0cm;&quot;&gt;&lt;code&gt;&lt;span style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #2b2e2f; font-family: Consolas;&quot;&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;/span&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border: none; line-height: 14.25pt; padding: 0cm;&quot;&gt;&lt;code&gt;&lt;span style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #2b2e2f; font-family: Consolas;&quot;&gt;}&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;span face=&quot;&amp;quot;Lucida Sans Unicode&amp;quot;,sans-serif&quot; style=&quot;color: #2b2e2f; font-size: 10.5pt; mso-ansi-language: FI; mso-bidi-language: AR-SA; mso-fareast-font-family: Calibri; mso-fareast-language: FI; mso-fareast-theme-font: minor-latin;&quot;&gt;&lt;div&gt;&lt;span face=&quot;&amp;quot;Lucida Sans Unicode&amp;quot;,sans-serif&quot; style=&quot;color: #2b2e2f; font-size: 10.5pt; mso-ansi-language: FI; mso-bidi-language: AR-SA; mso-fareast-font-family: Calibri; mso-fareast-language: FI; mso-fareast-theme-font: minor-latin;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;/span&gt;Keep in mind that options are replaced, not merged - so you&#39;ll need to send the whole options object to the PATCH call.</content><link rel='replies' type='application/atom+xml' href='http://blog.jussipalo.com/feeds/5085172188720659412/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.jussipalo.com/2021/09/auth0-invalid-rsaes-oaep-padding.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7258322562721325894/posts/default/5085172188720659412'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7258322562721325894/posts/default/5085172188720659412'/><link rel='alternate' type='text/html' href='http://blog.jussipalo.com/2021/09/auth0-invalid-rsaes-oaep-padding.html' title='Auth0: Invalid RSAES-OAEP padding'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7258322562721325894.post-3971916371380930532</id><published>2021-04-28T14:22:00.002+03:00</published><updated>2021-04-28T14:23:43.207+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Azure"/><category scheme="http://www.blogger.com/atom/ns#" term="B2C"/><title type='text'>Azure B2C: Adding missing translations on Page Layouts</title><content type='html'>&lt;h3 style=&quot;text-align: left;&quot;&gt;Problem&lt;/h3&gt;&lt;p&gt;After starting to use Azure B2C custom &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/active-directory-b2c/page-layout&quot; target=&quot;_blank&quot;&gt;Page Layout versions newer than 2.0.0&lt;/a&gt;, you will find translations are missing on many controls. Documentation is lacking behind, so it will take some trial and error to figure out some of the translation IDs. In the following pictures, you see missing translations marked with beautiful hand drawn red arrows.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg2LJAgW7j-6oWHPpFperQzqRGePf_Jmc4tvp0UPLxq2PVOzIQuTFZmHq0eacCOh8HsWVmf7YE3WF3GnovlFrMTme7YOme1bk0TqswATCMQ-MgaKg9HwVXkoZ6Z1VaA_-YM-Gj9ildcdcoH/&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;410&quot; data-original-width=&quot;446&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg2LJAgW7j-6oWHPpFperQzqRGePf_Jmc4tvp0UPLxq2PVOzIQuTFZmHq0eacCOh8HsWVmf7YE3WF3GnovlFrMTme7YOme1bk0TqswATCMQ-MgaKg9HwVXkoZ6Z1VaA_-YM-Gj9ildcdcoH/s16000/image.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-WsIN45oBiJpLtqQoaMoUAgLO-LNrPlUwFE80ij_jlVI736H82jLEb_EIx0LR2u7b9nPOBg3giP3XbJgj9K8yUD9eN0p3x640LG7ks-Re_Mn7mOL0brLeiXO3tyKqT3S_GxeNc9suHIcC/&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;475&quot; data-original-width=&quot;458&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-WsIN45oBiJpLtqQoaMoUAgLO-LNrPlUwFE80ij_jlVI736H82jLEb_EIx0LR2u7b9nPOBg3giP3XbJgj9K8yUD9eN0p3x640LG7ks-Re_Mn7mOL0brLeiXO3tyKqT3S_GxeNc9suHIcC/s16000/image.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;h3 style=&quot;text-align: left;&quot;&gt;Solution&lt;/h3&gt;&lt;p&gt;As B2C _should_ already include these translations, the only workaround currently is to manually provide the missing strings in your Custom Policy. The following will work for&amp;nbsp;&lt;i&gt;urn:com:microsoft:aad:b2c:elements:contract:unifiedssp:2.1.4&lt;/i&gt;&amp;nbsp;and&amp;nbsp;&lt;i&gt;urn:com:microsoft:aad:b2c:elements:contract:selfasserted:2.1.4&lt;/i&gt;.&lt;/p&gt;&lt;p&gt;So first of all, add &lt;i&gt;LocalizedResourceReference&lt;/i&gt;&amp;nbsp;elements in the &lt;i&gt;ContentDefinition&lt;/i&gt; elements.&lt;/p&gt;&lt;!--HTML generated using hilite.me--&gt;&lt;div style=&quot;background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;&quot;&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;pre style=&quot;line-height: 125%; margin: 0px;&quot;&gt; 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22&lt;/pre&gt;&lt;/td&gt;&lt;td&gt;&lt;pre style=&quot;line-height: 125%; margin: 0px;&quot;&gt;&lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;ContentDefinition&lt;/span&gt; &lt;span style=&quot;color: #0000cc;&quot;&gt;Id=&lt;/span&gt;&lt;span style=&quot;background-color: #fff0f0;&quot;&gt;&quot;api.signuporsignin&quot;&lt;/span&gt;&lt;span style=&quot;color: #007700;&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;LoadUri&amp;gt;&lt;/span&gt;https://xyz.blob.core.windows.net/customui/ocean_blue/unified.html&lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;/LoadUri&amp;gt;&lt;/span&gt;
  &lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;RecoveryUri&amp;gt;&lt;/span&gt;https://xyz.blob.core.windows.net/customui/ocean_blue/exception.html&lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;/RecoveryUri&amp;gt;&lt;/span&gt;
  &lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;DataUri&amp;gt;&lt;/span&gt;urn:com:microsoft:aad:b2c:elements:contract:unifiedssp:2.1.4&lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;/DataUri&amp;gt;&lt;/span&gt;
  &lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;Metadata&amp;gt;&lt;/span&gt;
    &lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;Item&lt;/span&gt; &lt;span style=&quot;color: #0000cc;&quot;&gt;Key=&lt;/span&gt;&lt;span style=&quot;background-color: #fff0f0;&quot;&gt;&quot;DisplayName&quot;&lt;/span&gt;&lt;span style=&quot;color: #007700;&quot;&gt;&amp;gt;&lt;/span&gt;Signin and Signup&lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;/Item&amp;gt;&lt;/span&gt;
  &lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;/Metadata&amp;gt;&lt;/span&gt;
  &lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;LocalizedResourcesReferences&lt;/span&gt; &lt;span style=&quot;color: #0000cc;&quot;&gt;MergeBehavior=&lt;/span&gt;&lt;span style=&quot;background-color: #fff0f0;&quot;&gt;&quot;Prepend&quot;&lt;/span&gt;&lt;span style=&quot;color: #007700;&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;LocalizedResourcesReference&lt;/span&gt; &lt;span style=&quot;color: #0000cc;&quot;&gt;Language=&lt;/span&gt;&lt;span style=&quot;background-color: #fff0f0;&quot;&gt;&quot;fi&quot;&lt;/span&gt; &lt;span style=&quot;color: #0000cc;&quot;&gt;LocalizedResourcesReferenceId=&lt;/span&gt;&lt;span style=&quot;background-color: #fff0f0;&quot;&gt;&quot;api.signuporsignin.fi&quot;&lt;/span&gt; &lt;span style=&quot;color: #007700;&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;/LocalizedResourcesReferences&amp;gt;&lt;/span&gt;
&lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;/ContentDefinition&amp;gt;&lt;/span&gt;
&lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;ContentDefinition&lt;/span&gt; &lt;span style=&quot;color: #0000cc;&quot;&gt;Id=&lt;/span&gt;&lt;span style=&quot;background-color: #fff0f0;&quot;&gt;&quot;api.selfasserted&quot;&lt;/span&gt;&lt;span style=&quot;color: #007700;&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;LoadUri&amp;gt;&lt;/span&gt;https://xyz.blob.core.windows.net/customui/ocean_blue/selfAsserted.html&lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;/LoadUri&amp;gt;&lt;/span&gt;
  &lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;RecoveryUri&amp;gt;&lt;/span&gt;https://xyz.blob.core.windows.net/customui/ocean_blue/exception.html&lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;/RecoveryUri&amp;gt;&lt;/span&gt;
  &lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;DataUri&amp;gt;&lt;/span&gt;urn:com:microsoft:aad:b2c:elements:contract:selfasserted:2.1.4&lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;/DataUri&amp;gt;&lt;/span&gt;
  &lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;Metadata&amp;gt;&lt;/span&gt;
    &lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;Item&lt;/span&gt; &lt;span style=&quot;color: #0000cc;&quot;&gt;Key=&lt;/span&gt;&lt;span style=&quot;background-color: #fff0f0;&quot;&gt;&quot;DisplayName&quot;&lt;/span&gt;&lt;span style=&quot;color: #007700;&quot;&gt;&amp;gt;&lt;/span&gt;Collect information from user page&lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;/Item&amp;gt;&lt;/span&gt;
  &lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;/Metadata&amp;gt;&lt;/span&gt;
  &lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;LocalizedResourcesReferences&lt;/span&gt; &lt;span style=&quot;color: #0000cc;&quot;&gt;MergeBehavior=&lt;/span&gt;&lt;span style=&quot;background-color: #fff0f0;&quot;&gt;&quot;Prepend&quot;&lt;/span&gt;&lt;span style=&quot;color: #007700;&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;LocalizedResourcesReference&lt;/span&gt; &lt;span style=&quot;color: #0000cc;&quot;&gt;Language=&lt;/span&gt;&lt;span style=&quot;background-color: #fff0f0;&quot;&gt;&quot;fi&quot;&lt;/span&gt; &lt;span style=&quot;color: #0000cc;&quot;&gt;LocalizedResourcesReferenceId=&lt;/span&gt;&lt;span style=&quot;background-color: #fff0f0;&quot;&gt;&quot;api.localaccountpasswordreset.fi&quot;&lt;/span&gt; &lt;span style=&quot;color: #007700;&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;/LocalizedResourcesReferences&amp;gt;&lt;/span&gt;
&lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;/ContentDefinition&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Then the actual strings you will add in the &lt;i&gt;Localization&lt;/i&gt; element.&lt;/p&gt;&lt;!--HTML generated using hilite.me--&gt;&lt;div style=&quot;background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;&quot;&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;pre style=&quot;line-height: 125%; margin: 0px;&quot;&gt; 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22&lt;/pre&gt;&lt;/td&gt;&lt;td&gt;&lt;pre style=&quot;line-height: 125%; margin: 0px;&quot;&gt;&lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;LocalizedResources&lt;/span&gt; &lt;span style=&quot;color: #0000cc;&quot;&gt;Id=&lt;/span&gt;&lt;span style=&quot;background-color: #fff0f0;&quot;&gt;&quot;api.signuporsignin.fi&quot;&lt;/span&gt;&lt;span style=&quot;color: #007700;&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;LocalizedStrings&amp;gt;&lt;/span&gt;
    &lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;LocalizedString&lt;/span&gt; &lt;span style=&quot;color: #0000cc;&quot;&gt;ElementType=&lt;/span&gt;&lt;span style=&quot;background-color: #fff0f0;&quot;&gt;&quot;ClaimType&quot;&lt;/span&gt; &lt;span style=&quot;color: #0000cc;&quot;&gt;ElementId=&lt;/span&gt;&lt;span style=&quot;background-color: #fff0f0;&quot;&gt;&quot;signInName&quot;&lt;/span&gt; &lt;span style=&quot;color: #0000cc;&quot;&gt;StringId=&lt;/span&gt;&lt;span style=&quot;background-color: #fff0f0;&quot;&gt;&quot;DisplayName&quot;&lt;/span&gt;&lt;span style=&quot;color: #007700;&quot;&gt;&amp;gt;&lt;/span&gt;Sähköpostiosoite&lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;/LocalizedString&amp;gt;&lt;/span&gt;
    &lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;LocalizedString&lt;/span&gt; &lt;span style=&quot;color: #0000cc;&quot;&gt;ElementType=&lt;/span&gt;&lt;span style=&quot;background-color: #fff0f0;&quot;&gt;&quot;ClaimType&quot;&lt;/span&gt; &lt;span style=&quot;color: #0000cc;&quot;&gt;ElementId=&lt;/span&gt;&lt;span style=&quot;background-color: #fff0f0;&quot;&gt;&quot;password&quot;&lt;/span&gt; &lt;span style=&quot;color: #0000cc;&quot;&gt;StringId=&lt;/span&gt;&lt;span style=&quot;background-color: #fff0f0;&quot;&gt;&quot;DisplayName&quot;&lt;/span&gt;&lt;span style=&quot;color: #007700;&quot;&gt;&amp;gt;&lt;/span&gt;Salasana&lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;/LocalizedString&amp;gt;&lt;/span&gt;
    &lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;LocalizedString&lt;/span&gt; &lt;span style=&quot;color: #0000cc;&quot;&gt;ElementType=&lt;/span&gt;&lt;span style=&quot;background-color: #fff0f0;&quot;&gt;&quot;UxElement&quot;&lt;/span&gt; &lt;span style=&quot;color: #0000cc;&quot;&gt;StringId=&lt;/span&gt;&lt;span style=&quot;background-color: #fff0f0;&quot;&gt;&quot;local_intro_generic&quot;&lt;/span&gt;&lt;span style=&quot;color: #007700;&quot;&gt;&amp;gt;&lt;/span&gt;Kirjaudu sisään aiemmin luodulla tililläsi&lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;/LocalizedString&amp;gt;&lt;/span&gt;
  &lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;/LocalizedStrings&amp;gt;&lt;/span&gt;
&lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;/LocalizedResources&amp;gt;&lt;/span&gt;
&lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;LocalizedResources&lt;/span&gt; &lt;span style=&quot;color: #0000cc;&quot;&gt;Id=&lt;/span&gt;&lt;span style=&quot;background-color: #fff0f0;&quot;&gt;&quot;api.localaccountpasswordreset.fi&quot;&lt;/span&gt;&lt;span style=&quot;color: #007700;&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;LocalizedStrings&amp;gt;&lt;/span&gt;
    &lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;LocalizedString&lt;/span&gt; &lt;span style=&quot;color: #0000cc;&quot;&gt;ElementType=&lt;/span&gt;&lt;span style=&quot;background-color: #fff0f0;&quot;&gt;&quot;ClaimType&quot;&lt;/span&gt; &lt;span style=&quot;color: #0000cc;&quot;&gt;ElementId=&lt;/span&gt;&lt;span style=&quot;background-color: #fff0f0;&quot;&gt;&quot;email&quot;&lt;/span&gt; &lt;span style=&quot;color: #0000cc;&quot;&gt;StringId=&lt;/span&gt;&lt;span style=&quot;background-color: #fff0f0;&quot;&gt;&quot;DisplayName&quot;&lt;/span&gt;&lt;span style=&quot;color: #007700;&quot;&gt;&amp;gt;&lt;/span&gt;Sähköpostiosoite&lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;/LocalizedString&amp;gt;&lt;/span&gt;
    &lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;LocalizedString&lt;/span&gt; &lt;span style=&quot;color: #0000cc;&quot;&gt;ElementType=&lt;/span&gt;&lt;span style=&quot;background-color: #fff0f0;&quot;&gt;&quot;ClaimType&quot;&lt;/span&gt; &lt;span style=&quot;color: #0000cc;&quot;&gt;ElementId=&lt;/span&gt;&lt;span style=&quot;background-color: #fff0f0;&quot;&gt;&quot;VerificationCode&quot;&lt;/span&gt; &lt;span style=&quot;color: #0000cc;&quot;&gt;StringId=&lt;/span&gt;&lt;span style=&quot;background-color: #fff0f0;&quot;&gt;&quot;DisplayName&quot;&lt;/span&gt;&lt;span style=&quot;color: #007700;&quot;&gt;&amp;gt;&lt;/span&gt;Vahvistuskoodi&lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;/LocalizedString&amp;gt;&lt;/span&gt;
    &lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;LocalizedString&lt;/span&gt; &lt;span style=&quot;color: #0000cc;&quot;&gt;ElementType=&lt;/span&gt;&lt;span style=&quot;background-color: #fff0f0;&quot;&gt;&quot;ClaimType&quot;&lt;/span&gt; &lt;span style=&quot;color: #0000cc;&quot;&gt;ElementId=&lt;/span&gt;&lt;span style=&quot;background-color: #fff0f0;&quot;&gt;&quot;signInNames.emailAddress&quot;&lt;/span&gt; &lt;span style=&quot;color: #0000cc;&quot;&gt;StringId=&lt;/span&gt;&lt;span style=&quot;background-color: #fff0f0;&quot;&gt;&quot;DisplayName&quot;&lt;/span&gt;&lt;span style=&quot;color: #007700;&quot;&gt;&amp;gt;&lt;/span&gt;Sähköpostiosoite&lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;/LocalizedString&amp;gt;&lt;/span&gt;
    &lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;LocalizedString&lt;/span&gt; &lt;span style=&quot;color: #0000cc;&quot;&gt;ElementType=&lt;/span&gt;&lt;span style=&quot;background-color: #fff0f0;&quot;&gt;&quot;DisplayControl&quot;&lt;/span&gt; &lt;span style=&quot;color: #0000cc;&quot;&gt;ElementId=&lt;/span&gt;&lt;span style=&quot;background-color: #fff0f0;&quot;&gt;&quot;emailVerificationSSPRControl&quot;&lt;/span&gt; &lt;span style=&quot;color: #0000cc;&quot;&gt;StringId=&lt;/span&gt;&lt;span style=&quot;background-color: #fff0f0;&quot;&gt;&quot;email&quot;&lt;/span&gt;&lt;span style=&quot;color: #007700;&quot;&gt;&amp;gt;&lt;/span&gt;Sähköpostiosoite&lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;/LocalizedString&amp;gt;&lt;/span&gt;
    &lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;LocalizedString&lt;/span&gt; &lt;span style=&quot;color: #0000cc;&quot;&gt;ElementType=&lt;/span&gt;&lt;span style=&quot;background-color: #fff0f0;&quot;&gt;&quot;DisplayControl&quot;&lt;/span&gt; &lt;span style=&quot;color: #0000cc;&quot;&gt;ElementId=&lt;/span&gt;&lt;span style=&quot;background-color: #fff0f0;&quot;&gt;&quot;emailVerificationSSPRControl&quot;&lt;/span&gt; &lt;span style=&quot;color: #0000cc;&quot;&gt;StringId=&lt;/span&gt;&lt;span style=&quot;background-color: #fff0f0;&quot;&gt;&quot;ver_input&quot;&lt;/span&gt;&lt;span style=&quot;color: #007700;&quot;&gt;&amp;gt;&lt;/span&gt;Vahvistuskoodi&lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;/LocalizedString&amp;gt;&lt;/span&gt;
    &lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;LocalizedString&lt;/span&gt; &lt;span style=&quot;color: #0000cc;&quot;&gt;ElementType=&lt;/span&gt;&lt;span style=&quot;background-color: #fff0f0;&quot;&gt;&quot;DisplayControl&quot;&lt;/span&gt; &lt;span style=&quot;color: #0000cc;&quot;&gt;ElementId=&lt;/span&gt;&lt;span style=&quot;background-color: #fff0f0;&quot;&gt;&quot;emailVerificationSSPRControl&quot;&lt;/span&gt; &lt;span style=&quot;color: #0000cc;&quot;&gt;StringId=&lt;/span&gt;&lt;span style=&quot;background-color: #fff0f0;&quot;&gt;&quot;verificationcode&quot;&lt;/span&gt;&lt;span style=&quot;color: #007700;&quot;&gt;&amp;gt;&lt;/span&gt;Vahvistuskoodi&lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;/LocalizedString&amp;gt;&lt;/span&gt;
    &lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;LocalizedString&lt;/span&gt; &lt;span style=&quot;color: #0000cc;&quot;&gt;ElementType=&lt;/span&gt;&lt;span style=&quot;background-color: #fff0f0;&quot;&gt;&quot;DisplayControl&quot;&lt;/span&gt; &lt;span style=&quot;color: #0000cc;&quot;&gt;ElementId=&lt;/span&gt;&lt;span style=&quot;background-color: #fff0f0;&quot;&gt;&quot;emailVerificationSSPRControl&quot;&lt;/span&gt; &lt;span style=&quot;color: #0000cc;&quot;&gt;StringId=&lt;/span&gt;&lt;span style=&quot;background-color: #fff0f0;&quot;&gt;&quot;intro_msg&quot;&lt;/span&gt;&lt;span style=&quot;color: #007700;&quot;&gt;&amp;gt;&lt;/span&gt;Syötä sähköpostiosoitteesi ja paina Lähetä vahvistuskoodi -painiketta.&lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;/LocalizedString&amp;gt;&lt;/span&gt;
    &lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;LocalizedString&lt;/span&gt; &lt;span style=&quot;color: #0000cc;&quot;&gt;ElementType=&lt;/span&gt;&lt;span style=&quot;background-color: #fff0f0;&quot;&gt;&quot;DisplayControl&quot;&lt;/span&gt; &lt;span style=&quot;color: #0000cc;&quot;&gt;ElementId=&lt;/span&gt;&lt;span style=&quot;background-color: #fff0f0;&quot;&gt;&quot;emailVerificationSSPRControl&quot;&lt;/span&gt; &lt;span style=&quot;color: #0000cc;&quot;&gt;StringId=&lt;/span&gt;&lt;span style=&quot;background-color: #fff0f0;&quot;&gt;&quot;but_send_code&quot;&lt;/span&gt;&lt;span style=&quot;color: #007700;&quot;&gt;&amp;gt;&lt;/span&gt;Lähetä vahvistuskoodi&lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;/LocalizedString&amp;gt;&lt;/span&gt;
    &lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;LocalizedString&lt;/span&gt; &lt;span style=&quot;color: #0000cc;&quot;&gt;ElementType=&lt;/span&gt;&lt;span style=&quot;background-color: #fff0f0;&quot;&gt;&quot;DisplayControl&quot;&lt;/span&gt; &lt;span style=&quot;color: #0000cc;&quot;&gt;ElementId=&lt;/span&gt;&lt;span style=&quot;background-color: #fff0f0;&quot;&gt;&quot;emailVerificationSSPRControl&quot;&lt;/span&gt; &lt;span style=&quot;color: #0000cc;&quot;&gt;StringId=&lt;/span&gt;&lt;span style=&quot;background-color: #fff0f0;&quot;&gt;&quot;but_verify_code&quot;&lt;/span&gt;&lt;span style=&quot;color: #007700;&quot;&gt;&amp;gt;&lt;/span&gt;Vahvista koodi&lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;/LocalizedString&amp;gt;&lt;/span&gt;
    &lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;LocalizedString&lt;/span&gt; &lt;span style=&quot;color: #0000cc;&quot;&gt;ElementType=&lt;/span&gt;&lt;span style=&quot;background-color: #fff0f0;&quot;&gt;&quot;DisplayControl&quot;&lt;/span&gt; &lt;span style=&quot;color: #0000cc;&quot;&gt;ElementId=&lt;/span&gt;&lt;span style=&quot;background-color: #fff0f0;&quot;&gt;&quot;emailVerificationSSPRControl&quot;&lt;/span&gt; &lt;span style=&quot;color: #0000cc;&quot;&gt;StringId=&lt;/span&gt;&lt;span style=&quot;background-color: #fff0f0;&quot;&gt;&quot;but_send_new_code&quot;&lt;/span&gt;&lt;span style=&quot;color: #007700;&quot;&gt;&amp;gt;&lt;/span&gt;Lähetä uusi koodi&lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;/LocalizedString&amp;gt;&lt;/span&gt;
    &lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;LocalizedString&lt;/span&gt; &lt;span style=&quot;color: #0000cc;&quot;&gt;ElementType=&lt;/span&gt;&lt;span style=&quot;background-color: #fff0f0;&quot;&gt;&quot;DisplayControl&quot;&lt;/span&gt; &lt;span style=&quot;color: #0000cc;&quot;&gt;ElementId=&lt;/span&gt;&lt;span style=&quot;background-color: #fff0f0;&quot;&gt;&quot;emailVerificationSSPRControl&quot;&lt;/span&gt; &lt;span style=&quot;color: #0000cc;&quot;&gt;StringId=&lt;/span&gt;&lt;span style=&quot;background-color: #fff0f0;&quot;&gt;&quot;success_send_code_msg&quot;&lt;/span&gt;&lt;span style=&quot;color: #007700;&quot;&gt;&amp;gt;&lt;/span&gt;Vahvistuskoodi on lähetetty sähköpostiisi. Kopioi se alla olevaan syöteruutuun ja paina Vahvista koodi -painiketta.&lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;/LocalizedString&amp;gt;&lt;/span&gt;
  &lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;/LocalizedStrings&amp;gt;&lt;/span&gt;
&lt;span style=&quot;color: #007700;&quot;&gt;&amp;lt;/LocalizedResources&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Please note that this is not a comprehensive list of missing translations, so feel free to comment below if you happen to have a full tested list of translations that will work with the new Page Layouts.&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.jussipalo.com/feeds/3971916371380930532/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.jussipalo.com/2021/04/azure-b2c-adding-missing-translations.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7258322562721325894/posts/default/3971916371380930532'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7258322562721325894/posts/default/3971916371380930532'/><link rel='alternate' type='text/html' href='http://blog.jussipalo.com/2021/04/azure-b2c-adding-missing-translations.html' title='Azure B2C: Adding missing translations on Page Layouts'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg2LJAgW7j-6oWHPpFperQzqRGePf_Jmc4tvp0UPLxq2PVOzIQuTFZmHq0eacCOh8HsWVmf7YE3WF3GnovlFrMTme7YOme1bk0TqswATCMQ-MgaKg9HwVXkoZ6Z1VaA_-YM-Gj9ildcdcoH/s72-c/image.png" height="72" width="72"/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7258322562721325894.post-8213004146327154788</id><published>2021-03-23T13:31:00.004+02:00</published><updated>2021-03-23T13:32:35.727+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="outlook"/><title type='text'>Office Add-In: Empty group label</title><content type='html'>&lt;h3 style=&quot;text-align: left;&quot;&gt;Problem&lt;/h3&gt;&lt;p&gt;I needed to create Outlook Add-In Ribbon button without Group label, like the Insights Add-In does.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi3N28b57Cnma7hlUU5WMoNlF5Qdcm0LRtuBPb3lwwlip-mtIqTlULi1p7M_E8FpaBNv8rnu8486KhYmI8zEZPyzXWUSTCqz1FLvwKMEDyoekHTHZTczwr8A4xTrlEi8LEi4UWidqm2xgFl/&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;99&quot; data-original-width=&quot;213&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi3N28b57Cnma7hlUU5WMoNlF5Qdcm0LRtuBPb3lwwlip-mtIqTlULi1p7M_E8FpaBNv8rnu8486KhYmI8zEZPyzXWUSTCqz1FLvwKMEDyoekHTHZTczwr8A4xTrlEi8LEi4UWidqm2xgFl/s16000/image.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;h3 style=&quot;text-align: left;&quot;&gt;Solution&lt;/h3&gt;&lt;p&gt;As the &lt;i&gt;Group&lt;/i&gt; element requires &lt;i&gt;Label&lt;/i&gt;, and the String of the Label requires &lt;i&gt;DefaultValue&lt;/i&gt; to have some value, the workaround was to set the &lt;i&gt;DefaultValue&lt;/i&gt; as one space character.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhV0IJlfRVIZ5cocWSMUGwupzVuqSS8gtFW4yK-BtCKO1zcgfdvG5zZhNRukBsRojfgOflHGE-PeYgCYcGDs1HhW8QyfVxt42vthNKOKsAaspqbznGBTHYLphUPrsOYlsZIRh-HIH4uc9GD/&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;93&quot; data-original-width=&quot;553&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhV0IJlfRVIZ5cocWSMUGwupzVuqSS8gtFW4yK-BtCKO1zcgfdvG5zZhNRukBsRojfgOflHGE-PeYgCYcGDs1HhW8QyfVxt42vthNKOKsAaspqbznGBTHYLphUPrsOYlsZIRh-HIH4uc9GD/s16000/image.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;clear: both; text-align: center;&quot;&gt;&lt;span style=&quot;font-size: x-large;&quot;&gt;&lt;b&gt;Ta-daa!&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgf3aW71C3l86lSUXOQV-L7mH9ldRHrGp_2pFZzWYUh5QvSF9uEW-13dkAvaCzBBL9wH8vkPGTnEat_G-ipZJwpAt8gLoZ5_5YJysmjYFXSY6c_BZnKVFjN7BimN1jdJyOojWeDDFb6UFwO/&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;109&quot; data-original-width=&quot;290&quot; height=&quot;120&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgf3aW71C3l86lSUXOQV-L7mH9ldRHrGp_2pFZzWYUh5QvSF9uEW-13dkAvaCzBBL9wH8vkPGTnEat_G-ipZJwpAt8gLoZ5_5YJysmjYFXSY6c_BZnKVFjN7BimN1jdJyOojWeDDFb6UFwO/&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.jussipalo.com/feeds/8213004146327154788/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.jussipalo.com/2021/03/office-add-in-empty-group-label.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7258322562721325894/posts/default/8213004146327154788'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7258322562721325894/posts/default/8213004146327154788'/><link rel='alternate' type='text/html' href='http://blog.jussipalo.com/2021/03/office-add-in-empty-group-label.html' title='Office Add-In: Empty group label'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi3N28b57Cnma7hlUU5WMoNlF5Qdcm0LRtuBPb3lwwlip-mtIqTlULi1p7M_E8FpaBNv8rnu8486KhYmI8zEZPyzXWUSTCqz1FLvwKMEDyoekHTHZTczwr8A4xTrlEi8LEi4UWidqm2xgFl/s72-c/image.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7258322562721325894.post-7320704295697211774</id><published>2021-02-26T09:58:00.026+02:00</published><updated>2021-03-18T14:53:22.627+02:00</updated><title type='text'>WebView2: How to hide scrollbars</title><content type='html'>&lt;h3 style=&quot;text-align: left;&quot;&gt;Problem&lt;/h3&gt;&lt;p&gt;When using the new&amp;nbsp;&lt;a href=&quot;https://docs.microsoft.com/en-us/microsoft-edge/webview2/&quot; target=&quot;_blank&quot;&gt;Microsoft Edge WebView2&lt;/a&gt;&amp;nbsp;control, it often displays scroll bars and the control doesn&#39;t have any explicit property to hide the scroll bars.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhg_yiOIyTbGEX0NioCtGqJXIUvb2aUDxVuu8e0ysbkahHHNRLp7Lz63xF50Q8s_HcgHFXeYuJhJFF38p2shWTID6WpNFmfy4FuyXNkAB6vna0nfDwydIWDB5So2Dzzr3Z7VCqptGLKRxPI/&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img data-original-height=&quot;399&quot; data-original-width=&quot;649&quot; height=&quot;246&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhg_yiOIyTbGEX0NioCtGqJXIUvb2aUDxVuu8e0ysbkahHHNRLp7Lz63xF50Q8s_HcgHFXeYuJhJFF38p2shWTID6WpNFmfy4FuyXNkAB6vna0nfDwydIWDB5So2Dzzr3Z7VCqptGLKRxPI/w400-h246/image.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;h3 style=&quot;text-align: left;&quot;&gt;Solution&lt;/h3&gt;&lt;p&gt;You need to use custom Javascript at the &lt;b&gt;NavigationCompleted &lt;/b&gt;event to hide the scrollbars.&amp;nbsp;&lt;/p&gt;&lt;p&gt;Simply add a new &lt;b&gt;NavigationCompleted &lt;/b&gt;event handler for the WebView2 control and use the &lt;b&gt;ExecuteScriptAsync &lt;/b&gt;method to run a Javascript that hides the scroll bars.&lt;/p&gt;&lt;!--HTML generated using hilite.me--&gt;&lt;div style=&quot;background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;&quot;&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;pre style=&quot;line-height: 125%; margin: 0px;&quot;&gt;1
2
3
4
5
6
7&lt;/pre&gt;&lt;/td&gt;&lt;td&gt;&lt;pre style=&quot;line-height: 125%; margin: 0px;&quot;&gt;&lt;span style=&quot;color: #008800; font-weight: bold;&quot;&gt;private&lt;/span&gt; &lt;span style=&quot;color: #008800; font-weight: bold;&quot;&gt;void&lt;/span&gt; &lt;span style=&quot;color: #0066bb; font-weight: bold;&quot;&gt;WebView2_NavigationCompleted&lt;/span&gt;(&lt;span style=&quot;color: #333399; font-weight: bold;&quot;&gt;object&lt;/span&gt; sender, CoreWebView2NavigationCompletedEventArgs e)
{
    &lt;span style=&quot;color: #008800; font-weight: bold;&quot;&gt;if&lt;/span&gt; (e.IsSuccess)
    {
        ((WebView2)sender).ExecuteScriptAsync(&lt;span style=&quot;background-color: #fff0f0;&quot;&gt;&quot;document.querySelector(&#39;body&#39;).style.overflow=&#39;hidden&#39;&quot;&lt;/span&gt;);
    }
}
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Note!&lt;/b&gt;&amp;nbsp;Code above hides scrollbars AND disables scrolling. If you would like to hide scrollbars but retain scrolling (with touch for example), please use this code instead.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;!--HTML generated using hilite.me--&gt;&lt;div style=&quot;background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;&quot;&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;pre style=&quot;line-height: 125%; margin: 0px;&quot;&gt;1
2
3
4
5
6
7&lt;/pre&gt;&lt;/td&gt;&lt;td&gt;&lt;pre style=&quot;line-height: 125%; margin: 0px;&quot;&gt;&lt;span style=&quot;color: #008800; font-weight: bold;&quot;&gt;private&lt;/span&gt; &lt;span style=&quot;color: #008800; font-weight: bold;&quot;&gt;void&lt;/span&gt; &lt;span style=&quot;color: #0066bb; font-weight: bold;&quot;&gt;WebView2_NavigationCompleted&lt;/span&gt;(&lt;span style=&quot;color: #333399; font-weight: bold;&quot;&gt;object&lt;/span&gt; sender, CoreWebView2NavigationCompletedEventArgs e)
{
    &lt;span style=&quot;color: #008800; font-weight: bold;&quot;&gt;if&lt;/span&gt; (e.IsSuccess)
    {
        ((WebView2)sender).ExecuteScriptAsync(&lt;span style=&quot;background-color: #fff0f0;&quot;&gt;&quot;document.querySelector(&#39;body&#39;).style.overflow=&#39;scroll&#39;;var style=document.createElement(&#39;style&#39;);style.type=&#39;text/css&#39;;style.innerHTML=&#39;::-webkit-scrollbar{display:none}&#39;;document.getElementsByTagName(&#39;body&#39;)[0].appendChild(style)&quot;&lt;/span&gt;);
    }
}
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.jussipalo.com/feeds/7320704295697211774/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.jussipalo.com/2021/02/webview2-how-to-hide-scrollbars.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7258322562721325894/posts/default/7320704295697211774'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7258322562721325894/posts/default/7320704295697211774'/><link rel='alternate' type='text/html' href='http://blog.jussipalo.com/2021/02/webview2-how-to-hide-scrollbars.html' title='WebView2: How to hide scrollbars'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhg_yiOIyTbGEX0NioCtGqJXIUvb2aUDxVuu8e0ysbkahHHNRLp7Lz63xF50Q8s_HcgHFXeYuJhJFF38p2shWTID6WpNFmfy4FuyXNkAB6vna0nfDwydIWDB5So2Dzzr3Z7VCqptGLKRxPI/s72-w400-h246-c/image.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7258322562721325894.post-8013211949500193282</id><published>2021-01-27T15:01:00.004+02:00</published><updated>2021-01-27T15:07:06.296+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Azure"/><category scheme="http://www.blogger.com/atom/ns#" term="MSI"/><title type='text'>Azure Managed Identity: Obtaining token gives error ‘invalid_client’</title><content type='html'>&lt;h2 style=&quot;text-align: left;&quot;&gt;Problem&lt;/h2&gt;&lt;p&gt;One of our Azure App Services suddenly started behaving badly and throwing HTTP 400 errors. From Application Insights we could see the error was coming from a call to LOCALHOST:PORT/MSI/token which is the location where access token is requested in case your code wants to access other Azure resources using Managed Identity (formerly MSI).&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgna0UTePemnIdLyEONU7Y0bQNB19ttakFEK1uJj1F67tjkSsPZaR2YQtjSpRajXqydxAWihYnkhsviaxdqreJgDWzkQDkDE1uXkLS1MOUbfJll1WHQz5rFs5YiMTrOuebCeh-kx6mtljhN/&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;477&quot; data-original-width=&quot;514&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgna0UTePemnIdLyEONU7Y0bQNB19ttakFEK1uJj1F67tjkSsPZaR2YQtjSpRajXqydxAWihYnkhsviaxdqreJgDWzkQDkDE1uXkLS1MOUbfJll1WHQz5rFs5YiMTrOuebCeh-kx6mtljhN/s16000/image.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;h2 style=&quot;text-align: left;&quot;&gt;Troubleshooting&lt;/h2&gt;&lt;p&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;I went to Kudu PowerShell console of the given App Service and tried to manually get the &lt;em&gt;access_token&lt;/em&gt;, but couldn’t. &lt;/span&gt;&lt;/p&gt;&lt;p&gt;Command for that is: &lt;br /&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;Invoke-WebRequest -Uri &#39;http://127.0.0.1:41332/MSI/token/?resource=https://management.azure.com/&amp;amp;api-version=2017-09-01&#39; -Method GET -Headers @{Metadata=&quot;true&quot;;Secret=&quot;$env:MSI_SECRET&quot;} -UseBasicParsing&lt;/span&gt;   &lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Note! &lt;/strong&gt;Port in the URL is different in your App Service, you can get it via&amp;nbsp;&lt;span style=&quot;font-family: courier;&quot;&gt;@env:MSI_ENDPOINT.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;All I got was &lt;em&gt;HTTP 401&lt;/em&gt; error with &lt;em&gt;‘invalid_client’&lt;/em&gt; error code. Strange. In respective DEV App Service there was no errors and &lt;em&gt;access_code&lt;/em&gt; was returned nicely.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiMeSUaL7T2Bi0MNIP2Gadx9dJA93hQKAzJRdJl-dOy7ki42xXK9xuSMLVtpaKtmCP9uB5KGSGvtfysAFmJISKdHeO4gxYlnMpPPdk1jpFsyiyVHHd9Oyy2l29z3BiRaLuEQp0iFuTXvL5A/&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;240&quot; data-original-width=&quot;588&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiMeSUaL7T2Bi0MNIP2Gadx9dJA93hQKAzJRdJl-dOy7ki42xXK9xuSMLVtpaKtmCP9uB5KGSGvtfysAFmJISKdHeO4gxYlnMpPPdk1jpFsyiyVHHd9Oyy2l29z3BiRaLuEQp0iFuTXvL5A/s16000/image.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;p&gt;By the way, details of the Uri and other parameters can be found &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/app-service/overview-managed-identity?tabs=powershell#obtain-tokens-for-azure-resources&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt;. Header is different if you’re using more recent &lt;em&gt;api-version&lt;/em&gt;. &lt;/p&gt;&lt;p&gt;By the way, if you just run the Invoke-WebRequest, you will get error:&lt;/p&gt;&lt;p&gt;&lt;em&gt;Win32 internal error &quot;The handle is invalid&quot; 0x6 occurred while reading the console output buffer. Contact Microsoft Customer Support Services.&lt;/em&gt;&lt;/p&gt;&lt;p&gt;No point in contacting MS Support, just run the following command and retry:&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;$ProgressPreference=&quot;SilentlyContinue&quot;&lt;/span&gt;&lt;/p&gt;&lt;h2 style=&quot;text-align: left;&quot;&gt;Solution&lt;/h2&gt;&lt;p&gt;Now, for the solution…good old &lt;strong&gt;&lt;span style=&quot;font-size: x-large;&quot;&gt;IISRESET&lt;/span&gt;&lt;/strong&gt;. Of course in Azure you restart the App Service in question. After restarting the App Service, you can re-run the &lt;em&gt;Invoke-WebRequest&lt;/em&gt;, and access_token is returned correctly, and App Service works.&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.jussipalo.com/feeds/8013211949500193282/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.jussipalo.com/2021/01/azure-managed-identity-obtaining-token.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7258322562721325894/posts/default/8013211949500193282'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7258322562721325894/posts/default/8013211949500193282'/><link rel='alternate' type='text/html' href='http://blog.jussipalo.com/2021/01/azure-managed-identity-obtaining-token.html' title='Azure Managed Identity: Obtaining token gives error ‘invalid_client’'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgna0UTePemnIdLyEONU7Y0bQNB19ttakFEK1uJj1F67tjkSsPZaR2YQtjSpRajXqydxAWihYnkhsviaxdqreJgDWzkQDkDE1uXkLS1MOUbfJll1WHQz5rFs5YiMTrOuebCeh-kx6mtljhN/s72-c/image.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7258322562721325894.post-2064186375863420764</id><published>2020-06-26T13:15:00.001+03:00</published><updated>2020-06-26T13:33:11.211+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Flow"/><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint"/><title type='text'>MS Flow: Simplest retry logic for SharePoint Online HTTP 400 errors</title><content type='html'>&lt;h3&gt;Problem&lt;/h3&gt;  &lt;p&gt;When setting SharePoint Online document properties from Flow, you will run into issues if the document is locked, i.e., someone has it open. In this case, SharePoint throws HTTP 400 that cannot be caught by the built-in retry-logic of the &lt;em&gt;Update Item&lt;/em&gt; Flow action.&lt;/p&gt;  &lt;h3&gt;Solution&lt;/h3&gt;  &lt;p&gt;Simplest Do Until loop I came up with can be seen below. I didn’t find using &lt;em&gt;Scope&lt;/em&gt; action necessary. In case you need to re-use this elsewhere in your Flow, it is quite straight forward to copy the &lt;em&gt;Do Until &lt;/em&gt;action and paste it elsewhere. Just remember to add &lt;em&gt;Set Variable&lt;/em&gt; action before each Do Until and set the &lt;strong&gt;fileLocked&lt;/strong&gt; variable to &lt;strong&gt;true&lt;/strong&gt;.&lt;/p&gt;  &lt;p&gt;At first, the two &lt;em&gt;Set variable &lt;/em&gt;actions were a bit confusing, the first one is only set to run after the SharePoint Update Item action has succeeded (and in that you set the fileLocked to false). The second one, however, is set to be run if the previous &lt;em&gt;Set variable&lt;/em&gt; action is skipped (and in that you set the fileLocked to true), and as the first one is skipped if the Update Item fails, we then know it did NOT succeed.&lt;/p&gt;  &lt;p&gt;It feels a bit weird to have the second&lt;em&gt; Set variable&lt;/em&gt; (Set variable 2) as fileLocked variable value is not changing, but this is the high level logic people seem to do this so there may be some room for further improvement.&lt;/p&gt; &lt;a href=&quot;https://drive.google.com/uc?id=1TOY0S49yXE8-eE9Ey38QjoBFqVS5lodw&quot;&gt;&lt;img title=&quot;flowretry&quot; style=&quot;margin-right: auto; margin-left: auto; float: none; display: block; background-image: none;&quot; border=&quot;0&quot; alt=&quot;flowretry&quot; src=&quot;https://drive.google.com/uc?id=15_ryUjNWz25zPlMcedBony7DILYcsZ1T&quot; width=&quot;536&quot; height=&quot;893&quot; /&gt;&lt;/a&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.jussipalo.com/feeds/2064186375863420764/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.jussipalo.com/2020/06/ms-flow-simplest-retry-logic-for.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7258322562721325894/posts/default/2064186375863420764'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7258322562721325894/posts/default/2064186375863420764'/><link rel='alternate' type='text/html' href='http://blog.jussipalo.com/2020/06/ms-flow-simplest-retry-logic-for.html' title='MS Flow: Simplest retry logic for SharePoint Online HTTP 400 errors'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7258322562721325894.post-8277274963798374220</id><published>2020-05-14T12:07:00.003+03:00</published><updated>2020-05-14T12:10:47.852+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Azure"/><category scheme="http://www.blogger.com/atom/ns#" term="Flow"/><category scheme="http://www.blogger.com/atom/ns#" term="Runbook"/><category scheme="http://www.blogger.com/atom/ns#" term="webhook"/><title type='text'>Microsoft Flow: Using HTTP Webhook action with Azure Automation Runbook</title><content type='html'>&lt;h3&gt;Task&lt;/h3&gt;&lt;p&gt;I needed to create new SharePoint Online Document Library and amongst other things set a Retention Label on that newly created Document Library using Microsoft Flow. Creating new doclib is straightforward using Flow, but I just couldn’t set the the Retention Label via REST from Flow. There is an API for that, but due to reasons I couldn’t get it to work from Flow. &lt;/p&gt;&lt;p&gt;We had an Azure Automation Runbook that was called at the end of the Flow anyway, so I decided to use that to set the Label on the SPO Library using SharePoint Online PnP’s &lt;em&gt;Set-PnPLabel.&lt;/em&gt; No problem. However, it takes a while for the Label to be applied to the Library and as email was sent to users at the end of the Flow, they found themselves in the library too early, i.e., the Label was not yet set.&lt;/p&gt;&lt;h3&gt;Solution&lt;/h3&gt;&lt;h5&gt;FLOW&lt;/h5&gt;&lt;p&gt;I could’ve used&amp;nbsp; a “Do Until” loop in Flow and poll the list but that’s not something we like to do, right? We like events and triggers, so why not use the &lt;em&gt;HTTP Webhook&lt;/em&gt; action, sounds exciting!&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgsESj3qJnpn9UsW0cJAu4p3DFjJCxZGRuFk3nuTAJMyocRnBWpphbqaoH7PMaJev9ZE56CF5mR8WC5CaKEk7M5xdoPWwSFcN6Wb_ukGxfD7kbd6Ad2ssohr9yeryf5ez62Vna6KPPoJaTA/&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;400&quot; data-original-width=&quot;607&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgsESj3qJnpn9UsW0cJAu4p3DFjJCxZGRuFk3nuTAJMyocRnBWpphbqaoH7PMaJev9ZE56CF5mR8WC5CaKEk7M5xdoPWwSFcN6Wb_ukGxfD7kbd6Ad2ssohr9yeryf5ez62Vna6KPPoJaTA/d/wh1.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;In the screenshot above, I’m calling the Azure Automation Runbook, but you can really call anything that is capable of listening to your request and at the and making a HTTP request back to the callback URL you define. You define your endpoint address in the &lt;em&gt;Subscribe - URI &lt;/em&gt;field.&lt;/p&gt;&lt;p&gt;In the &lt;em&gt;Subscribe - Body&lt;/em&gt; you must at least pass in the &lt;em&gt;listCallbackUrl()&lt;/em&gt; so that you know the endpoint of this specific Flow instance you need to call in your backend code. Note that &lt;em&gt;listCallbackUrl()&lt;/em&gt; is generated automatically, is specific to this running instance of the Flow, and &lt;strong&gt;can only be called once&lt;/strong&gt;. Flow processing will halt at this action and it will continue when your backend code calls the &lt;em&gt;listCallbackUrl().&lt;/em&gt; You can define timeout of how long the action waits for the callback in the action settings.&lt;/p&gt;&lt;p&gt;Here I’m also passing in the title of the SharePoint Library as I’m also doing some tricks on the library but you would pass in anything you need in your scenario.&lt;/p&gt;&lt;h5&gt;BACKEND&lt;/h5&gt;&lt;p&gt;In the backend code you will do whatever you need, but when you’re done, make HTTP POST call to the URL you received as a parameter in your backend code, in my case that would look like this in PowerShell.&lt;/p&gt;&lt;!--HTML generated using hilite.me--&gt;&lt;div style=&quot;background: rgb(255, 255, 255); border-color: gray; border-image: none 100% / 1 / 0 stretch; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; overflow: auto; padding: 0.2em 0.6em; width: auto;&quot;&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;pre style=&quot;line-height: 125%; margin: 0px;&quot;&gt; 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17&lt;/pre&gt;&lt;/td&gt;&lt;td&gt;&lt;pre style=&quot;line-height: 125%; margin: 0px;&quot;&gt;&lt;span style=&quot;color: #008800; font-weight: bold;&quot;&gt;param&lt;/span&gt;(
    [&lt;span style=&quot;color: #008800; font-weight: bold;&quot;&gt;Parameter&lt;/span&gt; (&lt;span style=&quot;color: #008800; font-weight: bold;&quot;&gt;Mandatory&lt;/span&gt; = &lt;span style=&quot;color: #996633;&quot;&gt;$true&lt;/span&gt;)]
    &lt;span style=&quot;color: #003366; font-weight: bold;&quot;&gt;[object]&lt;/span&gt;&lt;span style=&quot;color: #996633;&quot;&gt;$webhookData&lt;/span&gt;
)

&lt;span style=&quot;color: #888888;&quot;&gt;# If runbook was called from Webhook, WebhookData will not be null.&lt;/span&gt;
&lt;span style=&quot;color: #008800; font-weight: bold;&quot;&gt;if&lt;/span&gt; (&lt;span style=&quot;color: #996633;&quot;&gt;$WebhookData&lt;/span&gt;) {
    &lt;span style=&quot;color: #888888;&quot;&gt;# Retrieve VMs from Webhook request body&lt;/span&gt;
    &lt;span style=&quot;color: #996633;&quot;&gt;$body&lt;/span&gt; = (&lt;span style=&quot;color: #007020;&quot;&gt;ConvertFrom-Json&lt;/span&gt; -InputObject &lt;span style=&quot;color: #996633;&quot;&gt;$WebhookData&lt;/span&gt;.RequestBody)

    &lt;span style=&quot;color: #888888;&quot;&gt;####&lt;/span&gt;
    &lt;span style=&quot;color: #888888;&quot;&gt;# Do something in your code...&lt;/span&gt;
    &lt;span style=&quot;color: #888888;&quot;&gt;###&lt;/span&gt;
    
    &lt;span style=&quot;color: #888888;&quot;&gt;# ...and when you&#39;re done, call the callback URL&lt;/span&gt;
    &lt;span style=&quot;color: #007020;&quot;&gt;Invoke-WebRequest&lt;/span&gt; &lt;span style=&quot;color: #996633;&quot;&gt;$body&lt;/span&gt;.CallbackUrl -Method POST -UseBasicParsing
}
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;p&gt;If you look at the Flow when it is running, you see it pause at the &lt;em&gt;HTTP Webhook&lt;/em&gt; action, and continue as soon as the backend calls the callback URL. You can also manually call the callback URL using e.g., Postman, just paste in the callback URL and make sure method is POST. You will get HTTP 200 when the callback call succeeds.&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEju9_qmEkG3PxG93nycOj6nONJ3gmMMKM9qkN5yt7tc-CJmvCLQ9oKheyt8j2HNGQ1Tl4Yiq5uradSllpjQG1CRbvv9ZcRJnlPEQOqB3UbWIIlmyCeb1MPtdxXzkNB29Ioy7F4C1yrholqE/&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;443&quot; data-original-width=&quot;990&quot; height=&quot;286&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEju9_qmEkG3PxG93nycOj6nONJ3gmMMKM9qkN5yt7tc-CJmvCLQ9oKheyt8j2HNGQ1Tl4Yiq5uradSllpjQG1CRbvv9ZcRJnlPEQOqB3UbWIIlmyCeb1MPtdxXzkNB29Ioy7F4C1yrholqE/w640-h286/wh2.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.jussipalo.com/feeds/8277274963798374220/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.jussipalo.com/2020/05/task-i-needed-to-create-new-sharepoint.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7258322562721325894/posts/default/8277274963798374220'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7258322562721325894/posts/default/8277274963798374220'/><link rel='alternate' type='text/html' href='http://blog.jussipalo.com/2020/05/task-i-needed-to-create-new-sharepoint.html' title='Microsoft Flow: Using HTTP Webhook action with Azure Automation Runbook'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgsESj3qJnpn9UsW0cJAu4p3DFjJCxZGRuFk3nuTAJMyocRnBWpphbqaoH7PMaJev9ZE56CF5mR8WC5CaKEk7M5xdoPWwSFcN6Wb_ukGxfD7kbd6Ad2ssohr9yeryf5ez62Vna6KPPoJaTA/s72-c-d/wh1.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7258322562721325894.post-2346370220819949802</id><published>2020-04-14T12:12:00.001+03:00</published><updated>2020-04-14T12:23:55.164+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="OneNote"/><category scheme="http://www.blogger.com/atom/ns#" term="Teams"/><title type='text'>Cloning OneNote Tab without /clone REST endpoint</title><content type='html'>&lt;h3&gt;Series&lt;/h3&gt;&lt;p&gt;This is series of blog articles showing how to clone Teams Channels and Tabs without using the Clone REST endpoint or direct REST queries. Except we use the &lt;a href=&quot;https://www.nuget.org/packages/Microsoft.Graph/3.1.0&quot; target=&quot;_blank&quot;&gt;Microsoft.Graph (3.1.0).&lt;/a&gt; First post discusses things in general, details about different tab types are separated to individual articles.&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://blog.jussipalo.com/2020/04/cloning-teams-channels-and-tabs-without.html&quot; target=&quot;_blank&quot;&gt;Cloning Teams Channels and Tabs without /clone REST endpoint&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://blog.jussipalo.com/2020/04/cloning-planner-tab-without-clone-rest.html&quot; target=&quot;_blank&quot;&gt;Cloning Planner Tab without /clone REST endpoint&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Cloning &lt;em&gt;OneNote&lt;/em&gt; Tab without /clone REST endpoint &amp;lt;&amp;lt;YOU ARE HERE&amp;gt;&amp;gt;&lt;/strong&gt;&lt;/li&gt;&lt;li&gt;Cloning &lt;em&gt;Web Tab&lt;/em&gt; without /clone REST endpoint (TBD)&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://blog.jussipalo.com/2020/04/copying-teams-files-tab-content-using.html&quot; target=&quot;_blank&quot;&gt;Copying Teams Files tab content using MoveCopyUtil&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;h3&gt;Solution&lt;/h3&gt;&lt;p&gt;In this piece of code, we first determine current source tab is of type OneNote. We must first create new Notebook for the tab, and for this we add simple retry logic as you cannot have Notebooks with duplicate name. This retry logic adds running integer to Notebook name until the creation succeeds.&lt;/p&gt;&lt;p&gt;Now, after we have successfully created the Notebook, it is time to create the Tab. Do note the special format of the EntityId parameter for the tab, as well as rather identical URLs.&lt;/p&gt;&lt;p&gt;Finally, note that you may end up getting ServiceException although tab creation succeeds, thus the scary Exception swallowing.&lt;/p&gt;&lt;p&gt;Using term &lt;em&gt;cloning&lt;/em&gt; when it comes to this tab type can be a bit misleading, as we’re not cloning the tab content, but only the tab and creating new content. Perhaps think of this as &lt;em&gt;cloning&lt;/em&gt; from the Team perspective, while the individual tabs &lt;/p&gt;&lt;!-- HTML generated using hilite.me --&gt;&lt;div style=&quot;background: rgb(255, 255, 255); border-width: 0.1em 0.1em 0.1em 0.8em; border-style: solid; border-color: gray; padding: 0.2em 0.6em; border-image: none; width: auto; overflow: auto;&quot;&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;pre style=&quot;margin: 0px; line-height: 125%;&quot;&gt; 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71&lt;/pre&gt;&lt;/td&gt;&lt;td&gt;&lt;pre style=&quot;margin: 0px; line-height: 125%;&quot;&gt;&lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;if&lt;/span&gt; (sourceTab.TeamsApp.Id.Equals(TeamsAppId.OneNote))
{
logger?.LogInformation(&lt;span style=&quot;color: rgb(255, 0, 0); background-color: rgb(255, 170, 170);&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;background-color: rgb(255, 240, 240);&quot;&gt;&quot;Creating OneNote. Channel: {sourceChannel.DisplayName}. {newTeamId}&quot;&lt;/span&gt;);

&lt;span style=&quot;color: rgb(51, 51, 153); font-weight: bold;&quot;&gt;var&lt;/span&gt; newNotebook = &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;await&lt;/span&gt; retry.ExecuteAsync(&lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;async&lt;/span&gt; () =&amp;gt;
{
    var i = &lt;span style=&quot;color: rgb(102, 0, 238); font-weight: bold;&quot;&gt;0&lt;/span&gt;;
    Notebook nb = &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;null&lt;/span&gt;;
    &lt;span style=&quot;color: rgb(51, 51, 153); font-weight: bold;&quot;&gt;string&lt;/span&gt; nbName;

    &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;while&lt;/span&gt; (i &amp;lt; &lt;span style=&quot;color: rgb(102, 0, 238); font-weight: bold;&quot;&gt;100&lt;/span&gt; &amp;amp;&amp;amp; &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;null&lt;/span&gt; == nb)
    {
        nbName = &lt;span style=&quot;color: rgb(255, 0, 0); background-color: rgb(255, 170, 170);&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;background-color: rgb(255, 240, 240);&quot;&gt;&quot;{TextTools.RemoveSpecialCharactersForNotebook(requestData.title)}{(i &amp;gt; 0 ? $&quot;&lt;/span&gt; {i}&lt;span style=&quot;background-color: rgb(255, 240, 240);&quot;&gt;&quot; : &quot;&quot;)} Notebook&quot;&lt;/span&gt;;

        &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;try&lt;/span&gt;
        {
            nb = &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;await&lt;/span&gt; graphClient.Groups[newGroup.Id].Onenote.Notebooks.Request().AddAsync(&lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;new&lt;/span&gt; Notebook()
            {
                DisplayName = nbName
            });

            &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;break&lt;/span&gt;;
        }
        &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;catch&lt;/span&gt; (ServiceException ex)
        {
            &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;if&lt;/span&gt; ((&lt;span style=&quot;color: rgb(51, 51, 153); font-weight: bold;&quot;&gt;int&lt;/span&gt;)ex.StatusCode == &lt;span style=&quot;color: rgb(102, 0, 238); font-weight: bold;&quot;&gt;409&lt;/span&gt;)
            {
                &lt;span style=&quot;color: rgb(136, 136, 136);&quot;&gt;// this is fine, Notebook with such name already exists, let&#39;s find first available by appending integers to name&lt;/span&gt;
                logger?.LogWarning(&lt;span style=&quot;color: rgb(255, 0, 0); background-color: rgb(255, 170, 170);&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;background-color: rgb(255, 240, 240);&quot;&gt;&quot;Notebook with name &#39;{nbName}&#39; already exists, trying next integer. Channel: {sourceChannel.DisplayName}. {newTeamId}&quot;&lt;/span&gt;);
            }
        }
        &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;finally&lt;/span&gt;
        {
            i++;
        }
    }

    &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;return&lt;/span&gt; nb;
});

&lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;try&lt;/span&gt;
{
    logger?.LogInformation(&lt;span style=&quot;color: rgb(255, 0, 0); background-color: rgb(255, 170, 170);&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;background-color: rgb(255, 240, 240);&quot;&gt;&quot;Adding OneNote tab. Channel: {sourceChannel.DisplayName}. {newTeamId}&quot;&lt;/span&gt;);

    &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;await&lt;/span&gt; retry.ExecuteAsync(&lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;async&lt;/span&gt; () =&amp;gt;
    {
        &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;await&lt;/span&gt; graphClient.Teams[newTeamId].Channels[channelId].Tabs.Request().AddAsync(&lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;new&lt;/span&gt; TeamsTab()
        {
            ODataType = &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;null&lt;/span&gt;,
            DisplayName = newNotebook.DisplayName,
            Configuration = &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;new&lt;/span&gt; TeamsTabConfiguration()
            {
                EntityId = &lt;span style=&quot;color: rgb(255, 0, 0); background-color: rgb(255, 170, 170);&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;background-color: rgb(255, 240, 240);&quot;&gt;&quot;{Guid.NewGuid()}_{newNotebook.Id}&quot;&lt;/span&gt;,
                ContentUrl = &lt;span style=&quot;color: rgb(255, 0, 0); background-color: rgb(255, 170, 170);&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;background-color: rgb(255, 240, 240);&quot;&gt;&quot;https://www.onenote.com/teams/TabContent?entityid=%7BentityId%7D&amp;amp;subentityid=%7BsubEntityId%7D&amp;amp;auth_upn=%7Bupn%7D&amp;amp;notebookSource=New&amp;amp;notebookSelfUrl=https%3A%2F%2Fwww.onenote.com%2Fapi%2Fv1.0%2FmyOrganization%2Fgroups%2F{{groupId}}%2Fnotes%2Fnotebooks%2F{newNotebook.Id}&amp;amp;oneNoteWebUrl={newNotebook.Links.OneNoteWebUrl.Href}&amp;amp;notebookName={newNotebook.DisplayName}&amp;amp;ui={{locale}}&amp;amp;tenantId={{tid}}&quot;&lt;/span&gt;,
                RemoveUrl = &lt;span style=&quot;color: rgb(255, 0, 0); background-color: rgb(255, 170, 170);&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;background-color: rgb(255, 240, 240);&quot;&gt;&quot;https://www.onenote.com/teams/TabRemove?entityid=%7BentityId%7D&amp;amp;subentityid=%7BsubEntityId%7D&amp;amp;auth_upn=%7Bupn%7D&amp;amp;notebookSource=New&amp;amp;notebookSelfUrl=https%3A%2F%2Fwww.onenote.com%2Fapi%2Fv1.0%2FmyOrganization%2Fgroups%2F{{groupId}}%2Fnotes%2Fnotebooks%2F{newNotebook.Id}&amp;amp;oneNoteWebUrl={newNotebook.Links.OneNoteWebUrl.Href}&amp;amp;notebookName={newNotebook.DisplayName}&amp;amp;ui={{locale}}&amp;amp;tenantId={{tid}}&quot;&lt;/span&gt;,
                WebsiteUrl = &lt;span style=&quot;color: rgb(255, 0, 0); background-color: rgb(255, 170, 170);&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;background-color: rgb(255, 240, 240);&quot;&gt;&quot;https://www.onenote.com/teams/TabRedirect?redirectUrl={newNotebook.Links.OneNoteWebUrl.Href}&quot;&lt;/span&gt;
            },
            AdditionalData = &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;new&lt;/span&gt; Dictionary&amp;lt;&lt;span style=&quot;color: rgb(51, 51, 153); font-weight: bold;&quot;&gt;string&lt;/span&gt;, &lt;span style=&quot;color: rgb(51, 51, 153); font-weight: bold;&quot;&gt;object&lt;/span&gt;&amp;gt;()
            {
                {
                    &lt;span style=&quot;background-color: rgb(255, 240, 240);&quot;&gt;&quot;teamsApp@odata.bind&quot;&lt;/span&gt;, &lt;span style=&quot;color: rgb(255, 0, 0); background-color: rgb(255, 170, 170);&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;background-color: rgb(255, 240, 240);&quot;&gt;&quot;https://graph.microsoft.com/v1.0/appCatalogs/teamsApps/{sourceTab.TeamsApp.Id}&quot;&lt;/span&gt;
                }
            }
        });
    });
}
&lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;catch&lt;/span&gt; (ServiceException ex)
{
    HandleTabCreationException(ex, logger, sourceTab, newTeamId);
}
}
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.jussipalo.com/feeds/2346370220819949802/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.jussipalo.com/2020/04/cloning-onenote-tab-without-clone-rest.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7258322562721325894/posts/default/2346370220819949802'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7258322562721325894/posts/default/2346370220819949802'/><link rel='alternate' type='text/html' href='http://blog.jussipalo.com/2020/04/cloning-onenote-tab-without-clone-rest.html' title='Cloning OneNote Tab without /clone REST endpoint'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7258322562721325894.post-9169767662505029468</id><published>2020-04-09T13:38:00.001+03:00</published><updated>2020-04-14T12:24:14.396+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Planner"/><category scheme="http://www.blogger.com/atom/ns#" term="Teams"/><title type='text'>Cloning Planner Tab without /clone REST endpoint</title><content type='html'>&lt;h3&gt;Series&lt;/h3&gt;&lt;p&gt;This is series of blog articles showing how to clone Teams Channels and Tabs without using the Clone REST endpoint or direct REST queries. Except we use the &lt;a href=&quot;https://www.nuget.org/packages/Microsoft.Graph/3.1.0&quot; target=&quot;_blank&quot;&gt;Microsoft.Graph (3.1.0).&lt;/a&gt; First post discusses things in general, details about different tab types are separated to individual articles.&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://blog.jussipalo.com/2020/04/cloning-teams-channels-and-tabs-without.html&quot; target=&quot;_blank&quot;&gt;Cloning Teams Channels and Tabs without /clone REST endpoint&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Cloning &lt;em&gt;Planner&lt;/em&gt; Tab without /clone REST endpoint &amp;lt;&amp;lt;YOU ARE HERE&amp;gt;&amp;gt;&lt;/strong&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://blog.jussipalo.com/2020/04/cloning-onenote-tab-without-clone-rest.html&quot; target=&quot;_blank&quot;&gt;Cloning OneNote Tab without /clone REST endpoint&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Cloning &lt;em&gt;Web Tab&lt;/em&gt; without /clone REST endpoint (TBD)&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://blog.jussipalo.com/2020/04/copying-teams-files-tab-content-using.html&quot; target=&quot;_blank&quot;&gt;Copying Teams Files tab content using MoveCopyUtil&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;h3&gt;Solution&lt;/h3&gt;&lt;p&gt;In this piece of code, we first determine current source tab is of type Planner. Then comes the tricky part: you cannot use Application permissions to create the Planner Plan itself, but you must use Delegated permissions, so basically what you need is a dedicated user account, and use a &lt;em&gt;GraphServiceClient&lt;/em&gt; that uses &lt;em&gt;UsernamePasswordProvider &lt;/em&gt;as&lt;em&gt; IAuthenticationProvider &lt;/em&gt;for the Graph API calls. Yes, you really gotta put username and password of that user in Key Vault and fetch those here.&lt;/p&gt;&lt;p&gt;Now, after we have successfully created the Planner Plan, we will do a small trick and do not create the &lt;em&gt;contentUrl&lt;/em&gt; property for the new tab manually, but take the &lt;em&gt;ContentUrl&lt;/em&gt; from the source Tab and just replace the old Planner Id with the Id of the newly created Planner. Lovely. Just note that the &lt;em&gt;WebsiteUrl&lt;/em&gt; needs to be done separately, otherwise the “Go to website” link on top right of the Planner tab is broken and will be stuck loading and give error &lt;em&gt;“Error loading user settings. Please try again. If this continues please contact customer support.”&lt;/em&gt; after few minutes.&lt;/p&gt;&lt;p&gt;For creating the new Tab, there’s not much to say. These are the parameters you need to define based on a bit of trial and error. As Graph API evolves and improves, this is the part that will most probably need updating, but at least with Microsoft.Graph v. 3.1.0 it works – which is already old version as 3.2.0 was released few hours ago.&lt;/p&gt;&lt;p&gt;Finally, note that you may end up getting ServiceException although tab creation succeeds, thus the scary Exception swallowing.&lt;/p&gt;&lt;!-- HTML generated using hilite.me --&gt;&lt;div style=&quot;background: rgb(255, 255, 255); border-width: 0.1em 0.1em 0.1em 0.8em; border-style: solid; border-color: gray; padding: 0.2em 0.6em; border-image: none; width: auto; overflow: auto;&quot;&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;pre style=&quot;margin: 0px; line-height: 125%;&quot;&gt; 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51&lt;/pre&gt;&lt;/td&gt;&lt;td&gt;&lt;pre style=&quot;margin: 0px; line-height: 125%;&quot;&gt;&lt;span style=&quot;color: rgb(136, 136, 136);&quot;&gt;// Planner&lt;/span&gt;
&lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;if&lt;/span&gt; (sourceTab.TeamsApp.Id.Equals(TeamsAppId.Planner))
{
    logger?.LogInformation(&lt;span style=&quot;color: rgb(255, 0, 0); background-color: rgb(255, 170, 170);&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;background-color: rgb(255, 240, 240);&quot;&gt;&quot;Creating Planner. Channel: {sourceChannel.DisplayName}. {newGroup.Id}&quot;&lt;/span&gt;);

    &lt;span style=&quot;color: rgb(51, 51, 153); font-weight: bold;&quot;&gt;var&lt;/span&gt; newPlannerPlan = &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;await&lt;/span&gt; retry.ExecuteAsync(&lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;async&lt;/span&gt; () =&amp;gt;
    {
        &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;return&lt;/span&gt; &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;await&lt;/span&gt; Authentication.GetGraphApiClientClientUsernamePasswordProvider(keyvault).Planner.Plans.Request()
            .WithUsernamePassword(keyvault.GetSecret(&lt;span style=&quot;background-color: rgb(255, 240, 240);&quot;&gt;&quot;teamsClone--SPOUser&quot;&lt;/span&gt;), &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;new&lt;/span&gt; System.Net.NetworkCredential(&lt;span style=&quot;background-color: rgb(255, 240, 240);&quot;&gt;&quot;&quot;&lt;/span&gt;, keyvault.GetSecret(&lt;span style=&quot;background-color: rgb(255, 240, 240);&quot;&gt;&quot;teamsClone--SPOPassword&quot;&lt;/span&gt;)).SecurePassword)
            .AddAsync(&lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;new&lt;/span&gt; PlannerPlan()
            {
                Owner = newGroup.Id,
                Title = &lt;span style=&quot;color: rgb(255, 0, 0); background-color: rgb(255, 170, 170);&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;background-color: rgb(255, 240, 240);&quot;&gt;&quot;{TextTools.RemoveSpecialCharactersForNotebook(requestData.title)} Planner&quot;&lt;/span&gt;
            });
    });

    &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;try&lt;/span&gt;
    {
        &lt;span style=&quot;color: rgb(51, 51, 153); font-weight: bold;&quot;&gt;string&lt;/span&gt; contentUrl = sourceTab.Configuration.ContentUrl.Replace(sourceTab.Configuration.EntityId, newPlannerPlan.Id);
        &lt;span style=&quot;color: rgb(51, 51, 153); font-weight: bold;&quot;&gt;string&lt;/span&gt; websiteUrl = &lt;span style=&quot;color: rgb(255, 0, 0); background-color: rgb(255, 170, 170);&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;background-color: rgb(255, 240, 240);&quot;&gt;&quot;https://tasks.office.com/YOURTENANT.onmicrosoft.com/Home/Planner#/plantaskboard?groupId={newTeamId}&amp;amp;planId={newPlannerPlan.Id}&quot;&lt;/span&gt;;

        logger?.LogInformation(&lt;span style=&quot;color: rgb(255, 0, 0); background-color: rgb(255, 170, 170);&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;background-color: rgb(255, 240, 240);&quot;&gt;&quot;Adding Planner tab. Channel: {sourceChannel.DisplayName}, ContentUrl: {contentUrl}. {newGroup.Id}&quot;&lt;/span&gt;);

        &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;await&lt;/span&gt; retry.ExecuteAsync(&lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;async&lt;/span&gt; () =&amp;gt;
        {
            &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;await&lt;/span&gt; graphClient.Teams[newTeamId].Channels[channelId].Tabs.Request().AddAsync(&lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;new&lt;/span&gt; TeamsTab()
            {
                ODataType = &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;null&lt;/span&gt;,
                DisplayName = sourceTab.DisplayName,
                TeamsApp = sourceTab.TeamsApp,
                Configuration = &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;new&lt;/span&gt; TeamsTabConfiguration()
                {
                    EntityId = newPlannerPlan.Id,
                    ContentUrl = contentUrl,
                    RemoveUrl = contentUrl,
                    WebsiteUrl = webSiteUrl
                },
                AdditionalData = &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;new&lt;/span&gt; Dictionary&amp;lt;&lt;span style=&quot;color: rgb(51, 51, 153); font-weight: bold;&quot;&gt;string&lt;/span&gt;, &lt;span style=&quot;color: rgb(51, 51, 153); font-weight: bold;&quot;&gt;object&lt;/span&gt;&amp;gt;()
    {
        {
            &lt;span style=&quot;background-color: rgb(255, 240, 240);&quot;&gt;&quot;teamsApp@odata.bind&quot;&lt;/span&gt;, &lt;span style=&quot;color: rgb(255, 0, 0); background-color: rgb(255, 170, 170);&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;background-color: rgb(255, 240, 240);&quot;&gt;&quot;https://graph.microsoft.com/v1.0/appCatalogs/teamsApps/{sourceTab.TeamsApp.Id}&quot;&lt;/span&gt;
        }
    }
            });
        });
    }
    &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;catch&lt;/span&gt; (ServiceException ex)
    {
        HandleTabCreationException(ex, logger, sourceTab);
    }
}
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.jussipalo.com/feeds/9169767662505029468/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.jussipalo.com/2020/04/cloning-planner-tab-without-clone-rest.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7258322562721325894/posts/default/9169767662505029468'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7258322562721325894/posts/default/9169767662505029468'/><link rel='alternate' type='text/html' href='http://blog.jussipalo.com/2020/04/cloning-planner-tab-without-clone-rest.html' title='Cloning Planner Tab without /clone REST endpoint'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7258322562721325894.post-7233235680286910909</id><published>2020-04-09T12:54:00.001+03:00</published><updated>2020-04-14T12:28:01.193+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Teams"/><title type='text'>Cloning Teams Channels and Tabs without /clone REST endpoint</title><content type='html'>&lt;h3&gt;Series&lt;/h3&gt;&lt;p&gt;This is series of blog articles showing how to clone Teams Channels and Tabs without using the Clone REST endpoint or direct REST queries. Except we use the &lt;a href=&quot;https://www.nuget.org/packages/Microsoft.Graph/3.1.0&quot; target=&quot;_blank&quot;&gt;Microsoft.Graph (3.1.0).&lt;/a&gt; First post discusses things in general, details about different tab types are separated to individual articles.&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;strong&gt;Cloning Teams Channels and Tabs without /clone REST endpoint &amp;lt;&amp;lt;YOU ARE HERE&amp;gt;&amp;gt;&lt;/strong&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://blog.jussipalo.com/2020/04/cloning-planner-tab-without-clone-rest.html&quot; target=&quot;_blank&quot;&gt;Cloning Planner Tab without /clone REST endpoint&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://blog.jussipalo.com/2020/04/cloning-onenote-tab-without-clone-rest.html&quot; target=&quot;_blank&quot;&gt;Cloning OneNote Tab without /clone REST endpoint&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Cloning &lt;em&gt;Web Tab&lt;/em&gt; without /clone REST endpoint (TBD)&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://blog.jussipalo.com/2020/04/copying-teams-files-tab-content-using.html&quot; target=&quot;_blank&quot;&gt;Copying Teams Files tab content using MoveCopyUtil&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;h3&gt;Task&lt;/h3&gt;&lt;p&gt;As cloning a Microsoft Teams Team using the &lt;font face=&quot;Courier New&quot;&gt;https://graph.microsoft.com/v1.0/teams/{sourceeamId}/clone&lt;/font&gt; has few things that might surprise you (such as described &lt;a href=&quot;https://laurakokkarinen.com/cloning-teams-and-configuring-tabs-via-microsoft-graph-cloning-a-team/&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt;), you will anyway need go through all cloned tabs to verify they’re working. Why not instead create a fresh Channel based on the source Team Channel, then enumerate source Team tabs and recreate new tabs in the destination Channel based on the properties of the source Tab?&lt;/p&gt;&lt;h3&gt;Solution&lt;/h3&gt;&lt;p&gt;Enough chit-chat, lets dive in! &lt;/p&gt;&lt;p&gt;What happens in the code is that we first get source Team, Channels, and their Tabs. Having already created new Group and related Team (out of scope of this specific article), we start creating Channels in the new Team based on source Team Channels. &lt;/p&gt;&lt;p&gt;Reason why I didn’t include details of creating new Group and related Team here is because you could apply this same logic on existing Teams as well. Maybe if you’d like to push new Channel or Tab to existing Teams? Welcome, this code will work just nice.&lt;/p&gt;&lt;p&gt;After creating each Channel, we loop through the source Channel Tabs. Based on the source Tab type, and also how it is eventually been configured, we recreate identical Tab.&lt;/p&gt;&lt;p&gt;Good thing in this way of doing this is that you have full control of the Tab cloning operation.Then again it also means that you will have to implement that full control logic and program code.&lt;/p&gt;&lt;p&gt;Depending on the tab type, term &lt;em&gt;cloning&lt;/em&gt; might be a bit misleading, as in all cases we’re not cloning tab content but creating new background resource (such as Planner Plan or OneNote Notebook) and just binding to it from the tab. Maybe think of cloning here as cloning the Team &lt;em&gt;structure &lt;/em&gt;including channels and tabs.&lt;/p&gt;&lt;!-- HTML generated using hilite.me --&gt;&lt;div style=&quot;background: rgb(255, 255, 255); border-width: 0.1em 0.1em 0.1em 0.8em; border-style: solid; border-color: gray; padding: 0.2em 0.6em; border-image: none; width: auto; overflow: auto;&quot;&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;pre style=&quot;margin: 0px; line-height: 125%;&quot;&gt; 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41&lt;/pre&gt;&lt;/td&gt;&lt;td&gt;&lt;pre style=&quot;margin: 0px; line-height: 125%;&quot;&gt;logger?.LogInformation(&lt;span style=&quot;background-color: rgb(255, 240, 240);&quot;&gt;&quot;Getting source team channels and tabs&quot;&lt;/span&gt;);

&lt;span style=&quot;color: rgb(51, 51, 153); font-weight: bold;&quot;&gt;var&lt;/span&gt; sourceTeamChannels = &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;await&lt;/span&gt; retry.ExecuteAsync(&lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;async&lt;/span&gt; () =&amp;gt;
{
    &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;return&lt;/span&gt; &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;await&lt;/span&gt; graphClient.Teams[sourceTeamId].Channels.Request().GetAsync();
});

&lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;foreach&lt;/span&gt; (&lt;span style=&quot;color: rgb(51, 51, 153); font-weight: bold;&quot;&gt;var&lt;/span&gt; chan &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;in&lt;/span&gt; sourceTeamChannels)
{
    chan.Tabs = &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;await&lt;/span&gt; retry.ExecuteAsync(&lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;async&lt;/span&gt; () =&amp;gt;
    {
        &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;return&lt;/span&gt; &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;await&lt;/span&gt; graphClient.Teams[sourceTeamId].Channels[chan.Id].Tabs.Request().Expand(&lt;span style=&quot;background-color: rgb(255, 240, 240);&quot;&gt;&quot;TeamsApp&quot;&lt;/span&gt;).GetAsync();
    });
}

&lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;foreach&lt;/span&gt; (&lt;span style=&quot;color: rgb(51, 51, 153); font-weight: bold;&quot;&gt;var&lt;/span&gt; sourceChannel &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;in&lt;/span&gt; sourceTeamChannels)
{
    &lt;span style=&quot;color: rgb(51, 51, 153); font-weight: bold;&quot;&gt;var&lt;/span&gt; newChannel = &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;await&lt;/span&gt; retry.ExecuteAsync(&lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;async&lt;/span&gt; () =&amp;gt;
    {
        logger?.LogInformation(&lt;span style=&quot;color: rgb(255, 0, 0); background-color: rgb(255, 170, 170);&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;background-color: rgb(255, 240, 240);&quot;&gt;&quot;Adding channel {sourceChannel.DisplayName}. {newGroup.Id}&quot;&lt;/span&gt;);
        &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;return&lt;/span&gt; &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;await&lt;/span&gt; graphClient.Teams[newTeamId].Channels.Request().AddAsync(&lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;new&lt;/span&gt; Microsoft.Graph.Channel()
        {
            ODataType = &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;null&lt;/span&gt;,
            DisplayName = sourceChannel.DisplayName,
            Description = sourceChannel.Description
        });
    });

    channelId = newChannel.Id;

    &lt;span style=&quot;color: rgb(136, 136, 136);&quot;&gt;// here you should remove the Wiki tab (see separate article)&lt;/span&gt;

    &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;foreach&lt;/span&gt; (&lt;span style=&quot;color: rgb(51, 51, 153); font-weight: bold;&quot;&gt;var&lt;/span&gt; sourceTab &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;in&lt;/span&gt; sourceChannel.Tabs)
    {
        &lt;span style=&quot;color: rgb(136, 136, 136);&quot;&gt;// here you will have switch or if/else construct to determine source tab type&lt;/span&gt;
        &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;if&lt;/span&gt; (sourceTab.TeamsApp.Id.Equals(TeamsAppId.&lt;span style=&quot;color: rgb(136, 136, 136);&quot;&gt;/*TAB TYPE*/&lt;/span&gt;))
        {
            &lt;span style=&quot;color: rgb(136, 136, 136);&quot;&gt;// and actual tab type specific creation and configuration logic&lt;/span&gt;
        }
    }
}
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;p&gt;By the way, you’ll be needing this Exception handler later, as tab creation will throw specific &lt;em&gt;ServiceExceptions&lt;/em&gt; even though creation succeeds.&lt;/p&gt;&lt;!-- HTML generated using hilite.me --&gt;&lt;div style=&quot;background: rgb(255, 255, 255); border-width: 0.1em 0.1em 0.1em 0.8em; border-style: solid; border-color: gray; padding: 0.2em 0.6em; border-image: none; width: auto; overflow: auto;&quot;&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;pre style=&quot;margin: 0px; line-height: 125%;&quot;&gt; 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12&lt;/pre&gt;&lt;/td&gt;&lt;td&gt;&lt;pre style=&quot;margin: 0px; line-height: 125%;&quot;&gt;&lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;private&lt;/span&gt; &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;static&lt;/span&gt; &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;void&lt;/span&gt; &lt;span style=&quot;color: rgb(0, 102, 187); font-weight: bold;&quot;&gt;HandleTabCreationException&lt;/span&gt;(ServiceException ex, ILogger logger, TeamsTab sourceTab)
{
    &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;if&lt;/span&gt; (ex.StatusCode.ToString() == &lt;span style=&quot;background-color: rgb(255, 240, 240);&quot;&gt;&quot;BadRequest&quot;&lt;/span&gt; &amp;amp;&amp;amp; ex.Error.Message == &lt;span style=&quot;background-color: rgb(255, 240, 240);&quot;&gt;&quot;Value cannot be null.\r\nParameter name: entity&quot;&lt;/span&gt;)
    {
        &lt;span style=&quot;color: rgb(136, 136, 136);&quot;&gt;// this is fine: https://stackoverflow.com/questions/59784200/programmatically-creating-teamtab-used-to-work-but-now-gives-error-after-updati&lt;/span&gt;
        logger?.LogInformation(&lt;span style=&quot;color: rgb(255, 0, 0); background-color: rgb(255, 170, 170);&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;background-color: rgb(255, 240, 240);&quot;&gt;&quot;Tab {sourceTab.TeamsApp.Id} created: {sourceTab.DisplayName}&quot;&lt;/span&gt;);
    }
    &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;else&lt;/span&gt;
    {
        logger?.LogInformation(&lt;span style=&quot;color: rgb(255, 0, 0); background-color: rgb(255, 170, 170);&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;background-color: rgb(255, 240, 240);&quot;&gt;&quot;Error creating tab: {sourceTab.TeamsApp.Id}: {sourceTab.DisplayName}&quot;&lt;/span&gt;);
    }
}
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;p&gt;Also, extending Laura’s &lt;a href=&quot;https://laurakokkarinen.com/cloning-teams-and-configuring-tabs-via-microsoft-graph-configuring-the-sharepoint-and-files-tabs/&quot; target=&quot;_blank&quot;&gt;TeamsAppId class&lt;/a&gt; a bit will come handy, thank you Laura!&lt;/p&gt;&lt;!-- HTML generated using hilite.me --&gt;&lt;div style=&quot;background: rgb(255, 255, 255); border-width: 0.1em 0.1em 0.1em 0.8em; border-style: solid; border-color: gray; padding: 0.2em 0.6em; border-image: none; width: auto; overflow: auto;&quot;&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;pre style=&quot;margin: 0px; line-height: 125%;&quot;&gt;1
2
3
4
5
6
7
8&lt;/pre&gt;&lt;/td&gt;&lt;td&gt;&lt;pre style=&quot;margin: 0px; line-height: 125%;&quot;&gt;&lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;public&lt;/span&gt; &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;static&lt;/span&gt; &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;class&lt;/span&gt; &lt;span style=&quot;color: rgb(187, 0, 102); font-weight: bold;&quot;&gt;TeamsAppId&lt;/span&gt;
{
    &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;public&lt;/span&gt; &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;static&lt;/span&gt; &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;readonly&lt;/span&gt; &lt;span style=&quot;color: rgb(51, 51, 153); font-weight: bold;&quot;&gt;string&lt;/span&gt; OneNote = &lt;span style=&quot;background-color: rgb(255, 240, 240);&quot;&gt;&quot;0d820ecd-def2-4297-adad-78056cde7c78&quot;&lt;/span&gt;;
    &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;public&lt;/span&gt; &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;static&lt;/span&gt; &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;readonly&lt;/span&gt; &lt;span style=&quot;color: rgb(51, 51, 153); font-weight: bold;&quot;&gt;string&lt;/span&gt; Planner = &lt;span style=&quot;background-color: rgb(255, 240, 240);&quot;&gt;&quot;com.microsoft.teamspace.tab.planner&quot;&lt;/span&gt;;
    &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;public&lt;/span&gt; &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;static&lt;/span&gt; &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;readonly&lt;/span&gt; &lt;span style=&quot;color: rgb(51, 51, 153); font-weight: bold;&quot;&gt;string&lt;/span&gt; SharePoint = &lt;span style=&quot;background-color: rgb(255, 240, 240);&quot;&gt;&quot;2a527703-1f6f-4559-a332-d8a7d288cd88&quot;&lt;/span&gt;;
    &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;public&lt;/span&gt; &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;static&lt;/span&gt; &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;readonly&lt;/span&gt; &lt;span style=&quot;color: rgb(51, 51, 153); font-weight: bold;&quot;&gt;string&lt;/span&gt; Web = &lt;span style=&quot;background-color: rgb(255, 240, 240);&quot;&gt;&quot;com.microsoft.teamspace.tab.web&quot;&lt;/span&gt;;
    &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;public&lt;/span&gt; &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;static&lt;/span&gt; &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;readonly&lt;/span&gt; &lt;span style=&quot;color: rgb(51, 51, 153); font-weight: bold;&quot;&gt;string&lt;/span&gt; Wiki = &lt;span style=&quot;background-color: rgb(255, 240, 240);&quot;&gt;&quot;com.microsoft.teamspace.tab.wiki&quot;&lt;/span&gt;;
}
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.jussipalo.com/feeds/7233235680286910909/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.jussipalo.com/2020/04/cloning-teams-channels-and-tabs-without.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7258322562721325894/posts/default/7233235680286910909'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7258322562721325894/posts/default/7233235680286910909'/><link rel='alternate' type='text/html' href='http://blog.jussipalo.com/2020/04/cloning-teams-channels-and-tabs-without.html' title='Cloning Teams Channels and Tabs without /clone REST endpoint'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7258322562721325894.post-6181615008794186341</id><published>2020-04-08T12:55:00.001+03:00</published><updated>2020-04-14T12:15:06.847+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Teams"/><title type='text'>Copying Teams Files tab content using MoveCopyUtil</title><content type='html'>&lt;h3&gt;Series&lt;/h3&gt;&lt;p&gt;This is series of blog articles showing how to clone Teams Channels and Tabs without using the Clone REST endpoint or direct REST queries. Except we use the &lt;a href=&quot;https://www.nuget.org/packages/Microsoft.Graph/3.1.0&quot; target=&quot;_blank&quot;&gt;Microsoft.Graph (3.1.0).&lt;/a&gt; First post discusses things in general, details about different tab types are separated to individual articles.&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://blog.jussipalo.com/2020/04/cloning-teams-channels-and-tabs-without.html&quot; target=&quot;_blank&quot;&gt;Cloning Teams Channels and Tabs without /clone REST endpoint&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://blog.jussipalo.com/2020/04/cloning-planner-tab-without-clone-rest.html&quot; target=&quot;_blank&quot;&gt;Cloning Planner Tab without /clone REST endpoint&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://blog.jussipalo.com/2020/04/cloning-onenote-tab-without-clone-rest.html&quot; target=&quot;_blank&quot;&gt;Cloning OneNote Tab without /clone REST endpoint&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Cloning &lt;em&gt;Web Tab&lt;/em&gt; without /clone REST endpoint (TBD)&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Copying Teams Files tab content using MoveCopyUtil &amp;lt;&amp;lt;YOU ARE HERE&amp;gt;&amp;gt;&lt;/strong&gt;&lt;/li&gt;&lt;/ol&gt;&lt;h3&gt;Task&lt;/h3&gt;&lt;p&gt;As part of Teams provisioning, content of Files tab needed to be copied from source Team to the destination Team. As you might know, in practice it just means copying folders and files across SharePoint site collections.&lt;/p&gt;&lt;h3&gt;Solution&lt;/h3&gt;&lt;p&gt;&lt;em&gt;Microsoft.SharePoint.Client.MoveCopyUtil&lt;/em&gt; will do the trick UNLESS a folder name contains special characters, see &lt;a href=&quot;https://github.com/SharePoint/sp-dev-docs/issues/5261&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt; for example. This has been an issue for long in CSOM, and if at all possible, I recommend not having special characters in folder names, and not in file names either for that matter. &lt;/p&gt;&lt;p&gt;If you must support special character scenarios, it is doable, but will require carefully splitting and constructing the query parameters and effectively means you need to loop and create/copy folders and files one by one. I’ve spent &lt;em&gt;some&lt;/em&gt; time creating SPFx solution that manages to do this, and I recommend thinking not twice, but ten times before agreeing to support special characters in this case. Good thing is that in this Teams provisioning scenario you will have control over the source Team and should be able to work around any needs for special characters.&lt;/p&gt;&lt;h3&gt;Explanation of the code&lt;/h3&gt;&lt;p&gt;What happens in this code can probably be read quite well by looking at the &lt;em&gt;LogInformation&lt;/em&gt; entries, but the idea is that we get hold of the Drive item of the source and destination Group. &lt;em&gt;Drive.WebUrl&lt;/em&gt; is then absolute URL to the document library where Teams File tab contents are in their own sub-folders.&lt;/p&gt;&lt;p&gt;As a reminder, each File tab in a Team Channel maps to one root level folder (Channel name = folder name) in that document library you find at &lt;em&gt;Drive.WebUrl&lt;/em&gt;.&lt;/p&gt;&lt;p&gt;Another nice thing about &lt;em&gt;Group.Drive&lt;/em&gt; is that whenever we get hold of that, and it is not returning HTTP 404, we know Group provisioning (the process that runs in the background and creates all back-end dependencies, such as the SharePoint site) has been completed.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;retry &lt;/strong&gt;object is &lt;a href=&quot;https://github.com/App-vNext/Polly&quot; target=&quot;_blank&quot;&gt;Polly&lt;/a&gt;’s &lt;em&gt;AsyncRetryPolicy&lt;/em&gt; and ensures retry logic in case provisioning would not be yet ready at this point. It will retry the call as configured, in my case every 5 seconds, until the .GetAsync() completes successfully.&lt;/p&gt;&lt;p&gt;Next up there is some ugly parsing of the source document library path, namely we’re removing the document library part from the URL, leaving us with URL of the &lt;em&gt;SPWeb&lt;/em&gt;. There are many ways of doing this, and I admit this one is quite verbose way of doing it but doesn’t at least require additional HTTP query.&lt;/p&gt;&lt;p&gt;Then we get to the actual point, initializing SharePoint context using the source &lt;em&gt;SPWeb&lt;/em&gt;, and credentials stored in Azure Key Vault.&lt;/p&gt;&lt;p&gt;After getting all the root level folders (each corresponding a Channel, yes, good), we loop through each folder item and use &lt;em&gt;MoveCopyUtil.CopyFolder&lt;/em&gt; to copy it to destination document library. Just remember to set the &lt;em&gt;MoveCopyOptions&lt;/em&gt; to &lt;em&gt;KeepBoth&lt;/em&gt;, indicating this is a &lt;strong&gt;Copy&lt;/strong&gt; operation and not &lt;strong&gt;Move&lt;/strong&gt; operation.&lt;/p&gt;&lt;p&gt;I felt more comfortable doing &lt;em&gt;.ExecuteQuery&lt;/em&gt; for each folder, although it means few more HTTP calls, but allows improved error handling in case of those special characters, or some other problems that might occur during the copy operation.&lt;/p&gt;&lt;!-- HTML generated using hilite.me --&gt;&lt;div style=&quot;background: rgb(255, 255, 255); border-width: 0.1em 0.1em 0.1em 0.8em; border-style: solid; border-color: gray; padding: 0.2em 0.6em; border-image: none; width: auto; overflow: auto;&quot;&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;pre style=&quot;margin: 0px; line-height: 125%;&quot;&gt; 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75&lt;/pre&gt;&lt;/td&gt;&lt;td&gt;&lt;pre style=&quot;margin: 0px; line-height: 125%;&quot;&gt;&lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;public&lt;/span&gt; &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;static&lt;/span&gt; &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;async&lt;/span&gt; Task &lt;span style=&quot;color: rgb(0, 102, 187); font-weight: bold;&quot;&gt;CopyDocuments&lt;/span&gt;(&lt;span style=&quot;color: rgb(51, 51, 153); font-weight: bold;&quot;&gt;string&lt;/span&gt; srcGroupId, &lt;span style=&quot;color: rgb(51, 51, 153); font-weight: bold;&quot;&gt;string&lt;/span&gt; dstGroupId, AsyncRetryPolicy retry, GraphServiceClient graphClient, KeyVault keyvault, ILogger logger)
{
    &lt;span style=&quot;color: rgb(51, 51, 153); font-weight: bold;&quot;&gt;var&lt;/span&gt; sourceDrive = &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;await&lt;/span&gt; retry.ExecuteAsync(&lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;async&lt;/span&gt; () =&amp;gt;
    {
        &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;return&lt;/span&gt; &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;await&lt;/span&gt; graphClient.Groups[srcGroupId].Drive.Request().GetAsync();
    });

    &lt;span style=&quot;color: rgb(51, 51, 153); font-weight: bold;&quot;&gt;var&lt;/span&gt; destDrive = &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;await&lt;/span&gt; retry.ExecuteAsync(&lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;async&lt;/span&gt; () =&amp;gt;
    {
        &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;return&lt;/span&gt; &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;await&lt;/span&gt; graphClient.Groups[dstGroupId].Drive.Request().GetAsync();
    });

    &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;try&lt;/span&gt;
    {
        logger?.LogInformation(&lt;span style=&quot;color: rgb(255, 0, 0); background-color: rgb(255, 170, 170);&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;background-color: rgb(255, 240, 240);&quot;&gt;&quot;Copying SPO files, source drive: {sourceDrive.WebUrl}&quot;&lt;/span&gt;);
        logger?.LogInformation(&lt;span style=&quot;color: rgb(255, 0, 0); background-color: rgb(255, 170, 170);&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;background-color: rgb(255, 240, 240);&quot;&gt;&quot;Copying SPO files, destination drive: {destDrive.WebUrl}&quot;&lt;/span&gt;);

        &lt;span style=&quot;color: rgb(51, 51, 153); font-weight: bold;&quot;&gt;var&lt;/span&gt; sourceUri = &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;new&lt;/span&gt; Uri(sourceDrive.WebUrl);
        &lt;span style=&quot;color: rgb(51, 51, 153); font-weight: bold;&quot;&gt;string&lt;/span&gt; sourceSiteUrlWithoutLastSegment = sourceUri.AbsoluteUri.Remove(sourceUri.AbsoluteUri.Length - sourceUri.Segments.Last().Length);

        &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;using&lt;/span&gt; (&lt;span style=&quot;color: rgb(51, 51, 153); font-weight: bold;&quot;&gt;var&lt;/span&gt; srcContext = &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;new&lt;/span&gt; OfficeDevPnP.Core.AuthenticationManager()
            .GetSharePointOnlineAuthenticatedContextTenant(sourceSiteUrlWithoutLastSegment, keyvault.GetSecret(&lt;span style=&quot;background-color: rgb(255, 240, 240);&quot;&gt;&quot;teamsClone--SPOUser&quot;&lt;/span&gt;), keyvault.GetSecret(&lt;span style=&quot;background-color: rgb(255, 240, 240);&quot;&gt;&quot;teamsClone--SPOPassword&quot;&lt;/span&gt;)))
        {
            logger?.LogInformation(&lt;span style=&quot;color: rgb(255, 0, 0); background-color: rgb(255, 170, 170);&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;background-color: rgb(255, 240, 240);&quot;&gt;&quot;Copying SPO files, getting root folders&quot;&lt;/span&gt;);

            &lt;span style=&quot;color: rgb(136, 136, 136);&quot;&gt;// get folders at root                   &lt;/span&gt;
            &lt;span style=&quot;color: rgb(51, 51, 153); font-weight: bold;&quot;&gt;var&lt;/span&gt; targetList = srcContext.Web.Lists.GetByTitle(sourceDrive.Name);

            &lt;span style=&quot;color: rgb(136, 136, 136);&quot;&gt;// This method only gets the folders which are on top level of the list/library&lt;/span&gt;
            FolderCollection oFolderCollection = targetList.RootFolder.Folders;

            &lt;span style=&quot;color: rgb(136, 136, 136);&quot;&gt;// Load folder collection&lt;/span&gt;
            srcContext.Load(oFolderCollection);
            srcContext.ExecuteQuery();

            MoveCopyOptions option = &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;new&lt;/span&gt; MoveCopyOptions
            {
                KeepBoth = &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;true&lt;/span&gt;
            };

            logger?.LogInformation(&lt;span style=&quot;color: rgb(255, 0, 0); background-color: rgb(255, 170, 170);&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;background-color: rgb(255, 240, 240);&quot;&gt;&quot;Copying SPO files, looping folders&quot;&lt;/span&gt;);

            &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;foreach&lt;/span&gt; (&lt;span style=&quot;color: rgb(51, 51, 153); font-weight: bold;&quot;&gt;var&lt;/span&gt; folder &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;in&lt;/span&gt; oFolderCollection)
            {
                &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;if&lt;/span&gt; (folder.Name.Equals(&lt;span style=&quot;background-color: rgb(255, 240, 240);&quot;&gt;&quot;Forms&quot;&lt;/span&gt;))
                {
                    &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;continue&lt;/span&gt;;
                }

                &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;try&lt;/span&gt;
                {
                    logger?.LogInformation(&lt;span style=&quot;color: rgb(255, 0, 0); background-color: rgb(255, 170, 170);&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;background-color: rgb(255, 240, 240);&quot;&gt;&quot;Copying SPO files, copying folder &#39;{sourceUri.GetLeftPart(UriPartial.Authority) + folder.ServerRelativeUrl}&#39; -&amp;gt; &#39;{destDrive.WebUrl}/{folder.Name}&#39;&quot;&lt;/span&gt;);

                    MoveCopyUtil.CopyFolder(
                        srcContext,
                        sourceUri.GetLeftPart(UriPartial.Authority) + folder.ServerRelativeUrl,
                        &lt;span style=&quot;color: rgb(255, 0, 0); background-color: rgb(255, 170, 170);&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;background-color: rgb(255, 240, 240);&quot;&gt;&quot;{destDrive.WebUrl}/{folder.Name}&quot;&lt;/span&gt;,
                        option);

                    srcContext.ExecuteQuery();

                    logger?.LogInformation(&lt;span style=&quot;background-color: rgb(255, 240, 240);&quot;&gt;&quot;Copying done&quot;&lt;/span&gt;);
                }
                &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;catch&lt;/span&gt; (Exception ex)
                {
                    logger?.LogError(&lt;span style=&quot;color: rgb(255, 0, 0); background-color: rgb(255, 170, 170);&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;background-color: rgb(255, 240, 240);&quot;&gt;&quot;Error copying SPO folder {folder.Name}. {ex.Message}&quot;&lt;/span&gt;);
                }
            }
        }
    }
    &lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;catch&lt;/span&gt; (Exception ex)
    {
        logger?.LogError(&lt;span style=&quot;color: rgb(255, 0, 0); background-color: rgb(255, 170, 170);&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;background-color: rgb(255, 240, 240);&quot;&gt;&quot;Error copying SPO content. {ex.Message}&quot;&lt;/span&gt;);
    }
}
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.jussipalo.com/feeds/6181615008794186341/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.jussipalo.com/2020/04/copying-teams-files-tab-content-using.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7258322562721325894/posts/default/6181615008794186341'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7258322562721325894/posts/default/6181615008794186341'/><link rel='alternate' type='text/html' href='http://blog.jussipalo.com/2020/04/copying-teams-files-tab-content-using.html' title='Copying Teams Files tab content using MoveCopyUtil'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7258322562721325894.post-3062468396832227081</id><published>2020-04-03T12:01:00.004+03:00</published><updated>2021-03-30T11:38:13.367+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Graph"/><category scheme="http://www.blogger.com/atom/ns#" term="Teams"/><title type='text'>Remove Wiki tab during provisioning of Teams channels</title><content type='html'>&lt;h3&gt;Task&lt;/h3&gt;&lt;p&gt;Remove Wiki tab during provisioning of Teams channels.&lt;/p&gt;&lt;h3&gt;Solution&lt;/h3&gt;&lt;p&gt;As I’m not cloning my Team, but instead enumerating channels and tabs of the source Team used as a template, it was quite straightforward to include the Wiki tab remove logic to the stage where I’m anyway fetching Tabs for each source Team Channel.&lt;/p&gt;&lt;p&gt;This one includes Polly retry-logic for the DELETE operation (my first time using Polly so there’s probably lot of room for improvement). &lt;/p&gt;&lt;p&gt;It would also be nice to bake the Polly retry-logic into the GraphServiceClient itself instead of surrounding all calls. If you know it has already been done, please comment below. I’m always looking forward to improve my code.&lt;/p&gt;&lt;p&gt;I’m currently using version &lt;a href=&quot;https://www.nuget.org/packages/Microsoft.Graph/3.21.0&quot; target=&quot;_blank&quot;&gt;3.21.0&lt;/a&gt; of Microsoft.Graph library.&lt;/p&gt;&lt;p&gt;&lt;b&gt;Code updated to latest version March 30, 2021.&lt;/b&gt;&lt;/p&gt;&lt;!-- HTML generated using hilite.me --&gt;&lt;div style=&quot;background: #ffffff; overflow:auto;width:auto;border:solid gray;border-width:.1em .1em .1em .8em;padding:.2em .6em;&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td&gt;&lt;pre style=&quot;margin: 0; line-height: 125%&quot;&gt; 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89&lt;/pre&gt;&lt;/td&gt;&lt;td&gt;&lt;pre style=&quot;margin: 0; line-height: 125%&quot;&gt;&lt;span style=&quot;color: #333399; font-weight: bold&quot;&gt;var&lt;/span&gt; team = &lt;span style=&quot;color: #008800; font-weight: bold&quot;&gt;new&lt;/span&gt; Team()
{
    ODataType = &lt;span style=&quot;color: #008800; font-weight: bold&quot;&gt;null&lt;/span&gt;,
    MessagingSettings = sourceTeam.MessagingSettings,
    FunSettings = sourceTeam.FunSettings,
    GuestSettings = sourceTeam.GuestSettings,
    MemberSettings = sourceTeam.MemberSettings
};

team.MessagingSettings.ODataType = &lt;span style=&quot;color: #008800; font-weight: bold&quot;&gt;null&lt;/span&gt;;
team.FunSettings.ODataType = &lt;span style=&quot;color: #008800; font-weight: bold&quot;&gt;null&lt;/span&gt;;
team.GuestSettings.ODataType = &lt;span style=&quot;color: #008800; font-weight: bold&quot;&gt;null&lt;/span&gt;;
team.MemberSettings.ODataType = &lt;span style=&quot;color: #008800; font-weight: bold&quot;&gt;null&lt;/span&gt;;

Team newTeam;

&lt;span style=&quot;color: #008800; font-weight: bold&quot;&gt;try&lt;/span&gt;
{
    newTeam = &lt;span style=&quot;color: #008800; font-weight: bold&quot;&gt;await&lt;/span&gt; retry.ExecuteAsync(&lt;span style=&quot;color: #008800; font-weight: bold&quot;&gt;async&lt;/span&gt; () =&amp;gt;
    {
        &lt;span style=&quot;color: #008800; font-weight: bold&quot;&gt;return&lt;/span&gt; &lt;span style=&quot;color: #008800; font-weight: bold&quot;&gt;await&lt;/span&gt; graphClient.Groups[newGroup.Id].Team
        .Request()
        .PutAsync(team);
    });
}
&lt;span style=&quot;color: #008800; font-weight: bold&quot;&gt;catch&lt;/span&gt; (Exception ex)
{
    logger?.LogError(&lt;span style=&quot;color: #FF0000; background-color: #FFAAAA&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;background-color: #fff0f0&quot;&gt;&amp;quot;Error adding team to group: {ex.Message} {newGroup.Id}&amp;quot;&lt;/span&gt;);
    &lt;span style=&quot;color: #008800; font-weight: bold&quot;&gt;return&lt;/span&gt;;
}

&lt;span style=&quot;color: #888888&quot;&gt;// get new team channels&lt;/span&gt;
&lt;span style=&quot;color: #333399; font-weight: bold&quot;&gt;var&lt;/span&gt; newTeamId = newTeam.Id;

logger?.LogInformation(&lt;span style=&quot;color: #FF0000; background-color: #FFAAAA&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;background-color: #fff0f0&quot;&gt;&amp;quot;Getting new team channels {newTeamId}&amp;quot;&lt;/span&gt;);

&lt;span style=&quot;color: #333399; font-weight: bold&quot;&gt;var&lt;/span&gt; newTeamChannels = &lt;span style=&quot;color: #008800; font-weight: bold&quot;&gt;await&lt;/span&gt; retry.ExecuteAsync(&lt;span style=&quot;color: #008800; font-weight: bold&quot;&gt;async&lt;/span&gt; () =&amp;gt;
{
    &lt;span style=&quot;color: #008800; font-weight: bold&quot;&gt;return&lt;/span&gt; &lt;span style=&quot;color: #008800; font-weight: bold&quot;&gt;await&lt;/span&gt; graphClient.Teams[newTeamId].Channels.Request().GetAsync();
});

logger?.LogInformation(&lt;span style=&quot;color: #FF0000; background-color: #FFAAAA&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;background-color: #fff0f0&quot;&gt;&amp;quot;Getting new team tabs {newTeamId}&amp;quot;&lt;/span&gt;);

&lt;span style=&quot;color: #888888&quot;&gt;// and tabs&lt;/span&gt;
&lt;span style=&quot;color: #008800; font-weight: bold&quot;&gt;foreach&lt;/span&gt; (&lt;span style=&quot;color: #333399; font-weight: bold&quot;&gt;var&lt;/span&gt; chan &lt;span style=&quot;color: #008800; font-weight: bold&quot;&gt;in&lt;/span&gt; newTeamChannels)
{
    chan.Tabs = &lt;span style=&quot;color: #008800; font-weight: bold&quot;&gt;await&lt;/span&gt; retry.ExecuteAsync(&lt;span style=&quot;color: #008800; font-weight: bold&quot;&gt;async&lt;/span&gt; () =&amp;gt;
    {
        &lt;span style=&quot;color: #008800; font-weight: bold&quot;&gt;return&lt;/span&gt; &lt;span style=&quot;color: #008800; font-weight: bold&quot;&gt;await&lt;/span&gt; graphClient.Teams[newTeamId].Channels[chan.Id].Tabs.Request().Expand(&lt;span style=&quot;background-color: #fff0f0&quot;&gt;&amp;quot;TeamsApp&amp;quot;&lt;/span&gt;).GetAsync();
    });

    &lt;span style=&quot;color: #008800; font-weight: bold&quot;&gt;await&lt;/span&gt; Content.RemoveWikiTab(newTeamId, chan, retry, graphClient, logger);
}

&lt;span style=&quot;color: #888888&quot;&gt;// Define RemoveWikiTab somewhere else&lt;/span&gt;

&lt;span style=&quot;color: #888888&quot;&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
&lt;span style=&quot;color: #888888&quot;&gt;/// Removes wiki tab from given channel&lt;/span&gt;
&lt;span style=&quot;color: #888888&quot;&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
&lt;span style=&quot;color: #888888&quot;&gt;/// &amp;lt;param name=&amp;quot;newTeamId&amp;quot;&amp;gt;&amp;lt;/param&amp;gt;&lt;/span&gt;
&lt;span style=&quot;color: #888888&quot;&gt;/// &amp;lt;param name=&amp;quot;channel&amp;quot;&amp;gt;&amp;lt;/param&amp;gt;&lt;/span&gt;
&lt;span style=&quot;color: #888888&quot;&gt;/// &amp;lt;param name=&amp;quot;retry&amp;quot;&amp;gt;&amp;lt;/param&amp;gt;&lt;/span&gt;
&lt;span style=&quot;color: #888888&quot;&gt;/// &amp;lt;param name=&amp;quot;graphClient&amp;quot;&amp;gt;&amp;lt;/param&amp;gt;&lt;/span&gt;
&lt;span style=&quot;color: #888888&quot;&gt;/// &amp;lt;param name=&amp;quot;logger&amp;quot;&amp;gt;&amp;lt;/param&amp;gt;&lt;/span&gt;
&lt;span style=&quot;color: #888888&quot;&gt;/// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;&lt;/span&gt;
&lt;span style=&quot;color: #008800; font-weight: bold&quot;&gt;public&lt;/span&gt; &lt;span style=&quot;color: #008800; font-weight: bold&quot;&gt;static&lt;/span&gt; &lt;span style=&quot;color: #008800; font-weight: bold&quot;&gt;async&lt;/span&gt; Task &lt;span style=&quot;color: #0066BB; font-weight: bold&quot;&gt;RemoveWikiTab&lt;/span&gt;(&lt;span style=&quot;color: #333399; font-weight: bold&quot;&gt;string&lt;/span&gt; newTeamId, Microsoft.Graph.Channel channel, AsyncRetryPolicy retry, GraphServiceClient graphClient, ILogger logger)
{
    &lt;span style=&quot;color: #008800; font-weight: bold&quot;&gt;for&lt;/span&gt; (&lt;span style=&quot;color: #333399; font-weight: bold&quot;&gt;int&lt;/span&gt; i = channel.Tabs.Count - &lt;span style=&quot;color: #6600EE; font-weight: bold&quot;&gt;1&lt;/span&gt;; i &amp;gt;= &lt;span style=&quot;color: #6600EE; font-weight: bold&quot;&gt;0&lt;/span&gt;; i--)
    {
        &lt;span style=&quot;color: #008800; font-weight: bold&quot;&gt;if&lt;/span&gt; (channel.Tabs[i].TeamsApp.Id == TeamsAppId.Wiki)
        {
            &lt;span style=&quot;color: #008800; font-weight: bold&quot;&gt;try&lt;/span&gt;
            {
                &lt;span style=&quot;color: #008800; font-weight: bold&quot;&gt;await&lt;/span&gt; retry.ExecuteAsync(&lt;span style=&quot;color: #008800; font-weight: bold&quot;&gt;async&lt;/span&gt; () =&amp;gt;
                {
                    logger?.LogInformation(&lt;span style=&quot;color: #FF0000; background-color: #FFAAAA&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;background-color: #fff0f0&quot;&gt;&amp;quot;Removing wiki on channel {channel.DisplayName}. {newTeamId}&amp;quot;&lt;/span&gt;);

                    &lt;span style=&quot;color: #008800; font-weight: bold&quot;&gt;await&lt;/span&gt; graphClient.Teams[newTeamId].Channels[channel.Id].Tabs[channel.Tabs[i].Id].Request().DeleteAsync();
                });

                channel.Tabs.RemoveAt(i);
            }
            &lt;span style=&quot;color: #008800; font-weight: bold&quot;&gt;catch&lt;/span&gt; (Exception ex)
            {
                logger?.LogError(&lt;span style=&quot;color: #FF0000; background-color: #FFAAAA&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;background-color: #fff0f0&quot;&gt;&amp;quot;Error removing wiki tab on channel: {channel.DisplayName}. {ex.Message}&amp;quot;&lt;/span&gt;);
            }
        }
    }
}
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

</content><link rel='replies' type='application/atom+xml' href='http://blog.jussipalo.com/feeds/3062468396832227081/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.jussipalo.com/2020/04/remove-wiki-tab-during-provisioning-of.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7258322562721325894/posts/default/3062468396832227081'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7258322562721325894/posts/default/3062468396832227081'/><link rel='alternate' type='text/html' href='http://blog.jussipalo.com/2020/04/remove-wiki-tab-during-provisioning-of.html' title='Remove Wiki tab during provisioning of Teams channels'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7258322562721325894.post-3608332519968338485</id><published>2020-03-31T12:43:00.001+03:00</published><updated>2020-03-31T12:48:23.057+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint"/><category scheme="http://www.blogger.com/atom/ns#" term="ULS"/><title type='text'>SharePoint: Story of an orphan assemblyBinding and a misleading SPSite error message</title><content type='html'>&lt;h3&gt;Error&lt;/h3&gt;&lt;p&gt;I have .NET console application doing all kinds of magic, but as a first step it creates instance of SPSite using the same piece of code I’ve used hundreds, if not thousands, of times over the last two decades:&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;font face=&quot;Courier New&quot;&gt;using(var site = new SPSite(“http://xyz”)) &lt;/font&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;But no, after few seconds it threw exception:&lt;/p&gt;&lt;p&gt;&lt;em&gt;The Web application at http://xyz could not be found. Verify that you have typed the URL correctly. If the URL should be serving existing content, the system administrator may need to add a new request URL mapping to the intended application.&lt;br&gt;&lt;br&gt;&lt;/em&gt;&lt;/p&gt;&lt;h3&gt;Thoughts&lt;/h3&gt;&lt;p&gt;Having done all the suggested steps in &lt;a href=&quot;https://blog.stefan-gossner.com/2011/09/18/common-issue-new-spsite-api-call-returns-the-web-application-at-httpserverport-could-not-be-found/&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt; (including comments), and in all blog and forum posts related to this issue on the internet,&lt;em&gt; &lt;/em&gt;I finally looked at ULS logs. Should’ve done it sooner. It had logged this error message when creating instance of SPSite:&lt;/p&gt;&lt;p&gt;&lt;em&gt;Unexpected error while verifying backwards compatibility for [SPConfigurationDatabase] [e6f4eb31-959b-48da-a3a9-44d23f908f2e]: Microsoft.SharePoint.Upgrade.SPUpgradeException: Failed to call GetTypes on assembly Microsoft.Office.Server.Search, Version=16.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c. Could not load file or assembly &#39;Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed&#39; or one of its dependencies. The system cannot find the file specified. Could not load file or assembly &#39;Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed&#39; or one of its dependencies. The system cannot find the file specified. Could not load file or assembly &#39;Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed&#39; or one of its dependencies. The system cannot find the file specified.&lt;/em&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/p&gt;&lt;p&gt;What on earth, I don’t use Newtonsoft.Json in my project…?!&lt;/p&gt;&lt;p&gt;But I did! Only for a short while, though.&lt;/p&gt;&lt;p&gt;During some stage of the development I had added &lt;em&gt;Newtonsoft.Json&lt;/em&gt; from NuGet, then removed it. It left orphan &lt;em&gt;assemblyBinding&lt;/em&gt; reference pointing to &lt;em&gt;Newtonsoft.Json&lt;/em&gt; in the app.config of the console application.&lt;/p&gt;&lt;p&gt;So basically my &lt;strong&gt;app.config&lt;/strong&gt; in Visual Studio eventually the &lt;strong&gt;consoleapp.exe.config&lt;/strong&gt; looked like this:&lt;/p&gt;&lt;p&gt;&lt;font face=&quot;Courier New&quot;&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&amp;gt;&lt;br&gt;
&amp;lt;configuration&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;startup&amp;gt; &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;supportedRuntime version=&quot;v4.0&quot; sku=&quot;.NETFramework,Version=v4.6&quot;/&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/startup&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp; &amp;lt;runtime&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;assemblyBinding xmlns=&quot;urn:schemas-microsoft-com:asm.v1&quot;&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;dependentAssembly&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;assemblyIdentity name=&quot;Newtonsoft.Json&quot; publicKeyToken=&quot;30ad4fe6b2a6aeed&quot; culture=&quot;neutral&quot;/&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;bindingRedirect oldVersion=&quot;0.0.0.0-12.0.0.0&quot; newVersion=&quot;12.0.0.0&quot;/&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/dependentAssembly&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/assemblyBinding&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp; &amp;lt;/runtime&amp;gt;&lt;br&gt;
&amp;lt;/configuration&amp;gt;&lt;/font&gt;&lt;/p&gt;&lt;p&gt;This caused the slightly misleading Exception being thrown when doing the SPSite thing.&lt;br&gt;&lt;br&gt;&lt;/p&gt;&lt;h3&gt;Solution&lt;/h3&gt;&lt;p&gt;I removed the orphan &amp;lt;assemblyBinding&amp;gt;&amp;lt;/assemblyBinding&amp;gt; under &amp;lt;runtime&amp;gt; in my app.config, rebuilt the app, and sun started shining, and all was good:&lt;/p&gt;&lt;p&gt;&lt;font face=&quot;Courier New&quot;&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&amp;gt;&lt;br&gt;
&amp;lt;configuration&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;startup&amp;gt; &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;supportedRuntime version=&quot;v4.0&quot; sku=&quot;.NETFramework,Version=v4.6&quot;/&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/startup&amp;gt;&lt;br&gt;
&amp;lt;/configuration&amp;gt;&lt;/font&gt;&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.jussipalo.com/feeds/3608332519968338485/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.jussipalo.com/2020/03/sharepoint-orphan-assemblybinding-and.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7258322562721325894/posts/default/3608332519968338485'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7258322562721325894/posts/default/3608332519968338485'/><link rel='alternate' type='text/html' href='http://blog.jussipalo.com/2020/03/sharepoint-orphan-assemblybinding-and.html' title='SharePoint: Story of an orphan assemblyBinding and a misleading SPSite error message'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7258322562721325894.post-4607837823532832893</id><published>2020-02-04T11:15:00.001+02:00</published><updated>2020-02-04T11:15:38.993+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint"/><title type='text'>SharePoint: Web part SPUserCodeNoAvailableServersFoundException error</title><content type='html'>&lt;h3&gt;Problem&lt;/h3&gt;&lt;p&gt;Web part is not loading, you see exception SPUserCodeNoAvailableServersFoundException.&lt;/p&gt;&lt;h3&gt;Solution&lt;/h3&gt;&lt;p&gt;Start “Microsoft SharePoint Foundation Sandboxed Code Service”.&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Go to Central Admin&lt;/li&gt;&lt;li&gt;Go to System Settings –&amp;gt; Manage services in this farm&lt;/li&gt;&lt;li&gt;At “Microsoft SharePoint Foundation Sandboxed Code Service” click “Enable Auto Provisioning”&lt;/li&gt;&lt;/ol&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.jussipalo.com/feeds/4607837823532832893/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.jussipalo.com/2020/02/sharepoint-web-part-spusercodenoavailab.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7258322562721325894/posts/default/4607837823532832893'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7258322562721325894/posts/default/4607837823532832893'/><link rel='alternate' type='text/html' href='http://blog.jussipalo.com/2020/02/sharepoint-web-part-spusercodenoavailab.html' title='SharePoint: Web part SPUserCodeNoAvailableServersFoundException error'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7258322562721325894.post-4084829357792316109</id><published>2020-01-30T16:10:00.001+02:00</published><updated>2020-01-30T16:12:42.467+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint"/><title type='text'>SharePoint: Setting list view specific persisted spcolumnsize programmatically</title><content type='html'>&lt;h3&gt;Problem&lt;/h3&gt;&lt;p&gt;I needed to set default list view column widths programmatically on SharePoint Online modern list. I was using PnPjs to create and configure the list.&lt;/p&gt;&lt;h3&gt;Thoughts&lt;/h3&gt;&lt;p&gt;In modern SPO list view you can change column width, it is then temporarily stored in browser Local Storage as &lt;code&gt;spcolumnsize-unsaved-VIEWGUID&lt;/code&gt;. However, you also have the option of saving it into View somehow, as asterisk (*) appears next to view name on SharePoint and you can &quot;Save View As&quot; to persist the column width &lt;em&gt;somewhere&lt;/em&gt;. After saving the view even if you remove the &lt;code&gt;spcolumnsize-unsaved-VIEWGUID &lt;/code&gt;Local Storage key, and refresh the page, it comes back as &lt;code&gt;spcolumnsize-VIEWGUID&lt;/code&gt;, so clearly it is stored somewhere in SharePoint.&lt;/p&gt;&lt;h3&gt;Solution&lt;/h3&gt;&lt;p&gt;Column widths are persisted in &lt;em&gt;ListViewXml&lt;/em&gt; view property inside &lt;em&gt;ColumnWidth&lt;/em&gt; element as &lt;em&gt;FieldRef &lt;/em&gt;elements. Do note that the &lt;em&gt;FieldRef&lt;/em&gt; Names must be column display names, NOT internal field names. I didn’t implement fancy XML parsing, just injected the &lt;em&gt;ColumnWidth&lt;/em&gt; element at the end just before ending &lt;em&gt;View&lt;/em&gt; tag.&lt;p&gt;&lt;font face=&quot;Courier New&quot;&gt;// set field widths&lt;br&gt;let lv: any = await list.defaultView.select(&#39;ListViewXml&#39;).get();&lt;/font&gt;&lt;p&gt;&lt;font face=&quot;Courier New&quot;&gt;let lvXml: string = lv.ListViewXml.replace(&lt;br&gt;&#39;&amp;lt;/View&amp;gt;&#39;, &#39;&amp;lt;ColumnWidth&amp;gt;&amp;lt;FieldRef Name=&quot;Column title 1&quot; width=&quot;370&quot; /&amp;gt;&amp;lt;FieldRef Name=&quot;Some other column&quot; width=&quot;90&quot; /&amp;gt;&amp;lt;/ColumnWidth&amp;gt;&amp;lt;/View&amp;gt;&#39;);&lt;br&gt;&lt;br&gt;await list.defaultView.setViewXml(lvXml);&lt;/font&gt;&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.jussipalo.com/feeds/4084829357792316109/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.jussipalo.com/2020/01/sharepoint-setting-list-view-specific.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7258322562721325894/posts/default/4084829357792316109'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7258322562721325894/posts/default/4084829357792316109'/><link rel='alternate' type='text/html' href='http://blog.jussipalo.com/2020/01/sharepoint-setting-list-view-specific.html' title='SharePoint: Setting list view specific persisted spcolumnsize programmatically'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7258322562721325894.post-7165114361659815422</id><published>2019-12-12T12:15:00.001+02:00</published><updated>2019-12-12T12:41:22.706+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint"/><category scheme="http://www.blogger.com/atom/ns#" term="SPFx"/><title type='text'>SPFx: Changing Folder Content Type using PnPjs</title><content type='html'>&lt;h3&gt;Task&lt;/h3&gt;&lt;p&gt;Needed to create Folders with custom Content Type in SharePoint document library from my SPFx web part, as there was a need to add some custom fields, such as Description, to the Folder item.&lt;/p&gt;&lt;h3&gt;Solution&lt;/h3&gt;&lt;p&gt;This one took a few hours to figure out, you need to do it in few steps as you cannot change the content type of a folder using &lt;font face=&quot;Courier New&quot;&gt;sp.web.folders…update&lt;/font&gt; as REST API doesn’t allow &lt;em&gt;ContentTypeId&lt;/em&gt; parameter when updating Folder content types, and you will get error:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;font color=&quot;#ff0000&quot;&gt;“The property &#39;ContentTypeId&#39; does not exist on type &#39;SP.Folder’. Make sure to only use property names that are defined by the type”&lt;/font&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Also if you would use &lt;font face=&quot;Courier New&quot;&gt;…folder.getItem()&lt;/font&gt;&lt;font face=&quot;Arial&quot;&gt;, it will fail if folder has special characters.&lt;/font&gt;&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Create folder as normal Folder&lt;/li&gt;&lt;li&gt;Get list item ID of the folder&lt;/li&gt;&lt;li&gt;Update folder as a list item&lt;/li&gt;&lt;/ol&gt;&lt;!-- HTML generated using hilite.me --&gt;&lt;div style=&quot;background: rgb(255, 255, 255); border-width: 0.1em 0.1em 0.1em 0.8em; border-style: solid; border-color: gray; padding: 0.2em 0.6em; border-image: none; width: auto; overflow: auto;&quot;&gt;&lt;pre style=&quot;margin: 0px; line-height: 125%;&quot;&gt;&lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;let&lt;/span&gt; etfn &lt;span style=&quot;color: rgb(51, 51, 51);&quot;&gt;=&lt;/span&gt; await sp.web.getList(listUrl).getListItemEntityTypeFullName();

&lt;span style=&quot;color: rgb(136, 136, 136);&quot;&gt;// first create folder&lt;/span&gt;
&lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;let&lt;/span&gt; far: &lt;span style=&quot;color: rgb(51, 51, 153); font-weight: bold;&quot;&gt;FolderAddResult&lt;/span&gt; &lt;span style=&quot;color: rgb(51, 51, 51);&quot;&gt;=&lt;/span&gt; await sp.web.folders.add(listUrl &lt;span style=&quot;color: rgb(51, 51, 51);&quot;&gt;+&lt;/span&gt; &lt;span style=&quot;background-color: rgb(255, 240, 240);&quot;&gt;&#39;/&#39;&lt;/span&gt; &lt;span style=&quot;color: rgb(51, 51, 51);&quot;&gt;+&lt;/span&gt; targetParentFolderName &lt;span style=&quot;color: rgb(51, 51, 51);&quot;&gt;+&lt;/span&gt; targetFolderName);

&lt;span style=&quot;color: rgb(136, 136, 136);&quot;&gt;// then get list item ID of the folder&lt;/span&gt;
&lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;let&lt;/span&gt; fData: &lt;span style=&quot;color: rgb(51, 51, 153); font-weight: bold;&quot;&gt;any&lt;/span&gt; &lt;span style=&quot;color: rgb(51, 51, 51);&quot;&gt;=&lt;/span&gt; await sp.web.getFolderById(far.data.UniqueId).select(&lt;span style=&quot;background-color: rgb(255, 240, 240);&quot;&gt;&#39;ID&#39;&lt;/span&gt;).listItemAllFields.get();            

&lt;span style=&quot;color: rgb(136, 136, 136);&quot;&gt;// then get folder as list item&lt;/span&gt;
&lt;span style=&quot;color: rgb(0, 136, 0); font-weight: bold;&quot;&gt;let&lt;/span&gt; item: &lt;span style=&quot;color: rgb(51, 51, 153); font-weight: bold;&quot;&gt;Item&lt;/span&gt; &lt;span style=&quot;color: rgb(51, 51, 51);&quot;&gt;=&lt;/span&gt; sp.web.getList(listUrl).items.getById(fData[&lt;span style=&quot;background-color: rgb(255, 240, 240);&quot;&gt;&#39;ID&#39;&lt;/span&gt;]);

await item.update({
    ContentTypeId&lt;span style=&quot;color: rgb(51, 51, 51);&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;background-color: rgb(255, 240, 240);&quot;&gt;&#39;CUSTOM_FOLDER_CONTENTTYPE&#39;&lt;/span&gt;,
    PF_FolderDescription&lt;span style=&quot;color: rgb(51, 51, 51);&quot;&gt;:&lt;/span&gt; &lt;span style=&quot;background-color: rgb(255, 240, 240);&quot;&gt;&#39;Some description...&#39;&lt;/span&gt;
}, &lt;span style=&quot;background-color: rgb(255, 240, 240);&quot;&gt;&#39;*&#39;&lt;/span&gt;, etfn);
&lt;/pre&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.jussipalo.com/feeds/7165114361659815422/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.jussipalo.com/2019/12/spfx-changing-folder-content-type.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7258322562721325894/posts/default/7165114361659815422'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7258322562721325894/posts/default/7165114361659815422'/><link rel='alternate' type='text/html' href='http://blog.jussipalo.com/2019/12/spfx-changing-folder-content-type.html' title='SPFx: Changing Folder Content Type using PnPjs'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7258322562721325894.post-127429144529555709</id><published>2019-09-17T11:53:00.001+03:00</published><updated>2019-09-17T11:58:44.945+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="OOS"/><category scheme="http://www.blogger.com/atom/ns#" term="SharePoint"/><category scheme="http://www.blogger.com/atom/ns#" term="WAC"/><title type='text'>Office Online Server: X-WOPI-ServerError &quot;Verifying signature failed&quot;</title><content type='html'>&lt;h3&gt;
Problem&lt;/h3&gt;
After migrating from old OOS (WAC) server to new one, integration between SharePoint and Office Online Server stopped working, and no documents could be opened in browser.
&lt;br /&gt;
&lt;br /&gt;
Looking at the network traffic using WireShark, you see X-WOPI-ServerError &quot;Verifying signature failed&quot;.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhkM4nMDFkChsff7GWav9TQgyQLVvN6lkRBca1CYBi4j1vNraEl0Ful8cig3gEqGSvD9Kj9_SSMdXP-D5HtWrz8xxqhvvS7fGx8E-JKKWIPVmTlyKhQUGIWd3wWAOBylB7dXOC9ILSmwQsn/s1600/oos.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;368&quot; data-original-width=&quot;800&quot; height=&quot;147&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhkM4nMDFkChsff7GWav9TQgyQLVvN6lkRBca1CYBi4j1vNraEl0Ful8cig3gEqGSvD9Kj9_SSMdXP-D5HtWrz8xxqhvvS7fGx8E-JKKWIPVmTlyKhQUGIWd3wWAOBylB7dXOC9ILSmwQsn/s320/oos.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;h3&gt;
Solution&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Ensure HTTPS (TCP 443) flows from SP servers to OOS&lt;/li&gt;
&lt;li&gt;Run &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot;;&quot;&gt;Update-SPWOPIProofKey -ServerName YOUR_OOS_URL&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
This will update the required keys in SharePoint and documents can again be opened in browser.</content><link rel='replies' type='application/atom+xml' href='http://blog.jussipalo.com/feeds/127429144529555709/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.jussipalo.com/2019/09/office-online-server-x-wopi-servererror.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7258322562721325894/posts/default/127429144529555709'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7258322562721325894/posts/default/127429144529555709'/><link rel='alternate' type='text/html' href='http://blog.jussipalo.com/2019/09/office-online-server-x-wopi-servererror.html' title='Office Online Server: X-WOPI-ServerError &quot;Verifying signature failed&quot;'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhkM4nMDFkChsff7GWav9TQgyQLVvN6lkRBca1CYBi4j1vNraEl0Ful8cig3gEqGSvD9Kj9_SSMdXP-D5HtWrz8xxqhvvS7fGx8E-JKKWIPVmTlyKhQUGIWd3wWAOBylB7dXOC9ILSmwQsn/s72-c/oos.png" height="72" width="72"/><thr:total>0</thr:total></entry></feed>