tag:blogger.com,1999:blog-28577797003320844752024-03-14T05:17:08.776+02:00SharePoint TrenchesReal World stories from the SharePoint trenchesIvan Yankulovhttp://www.blogger.com/profile/01518276480144054762noreply@blogger.comBlogger64125tag:blogger.com,1999:blog-2857779700332084475.post-40770806276577662362018-11-12T10:04:00.001+02:002018-11-12T10:04:52.813+02:00Attach additional event listener to out of the box SharePoint ribbon control <div style="text-align: justify;">
Have you ever had a use case where you must do something additional when an out of the box ribbon control is clicked, like "Open With Explorer" or "Export to Excel"? Maybe not, until now?</div>
<div style="text-align: justify;">
What could make this use case valid is the fact that the ribbon is slowly being phased out and it is no longer available in the modern experience, in addition not all features available in the ribbon are supported by all browsers and clients.</div>
<div style="text-align: justify;">
Having something additional being executed when a button from the ribbon is clicked can help you collect usage data for this features and better plan the move to modern experience or (like it or not) making Edge default browser, which does not support "Open with Explorer".</div>
<div style="text-align: justify;">
I am not aware of any other way to collect this information in SharePoint on-prem or Online.</div>
<div style="text-align: justify;">
Here is an example script that can be added as Scriptlink user custom action and it will attach additional click event listener on the "Open With Explorer" button. Everything that the function will do is to log the action, user name and the document library title in the console, but you can do whatever you find for useful, like logging it in the ULS or calling an API that will record the event.<br />
I have tested it in SharePoint 2016 but it should work in SharePoint 2013 and SharePoint Online classic experience lists, it requires JQuery.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://3.bp.blogspot.com/-iN7DAFC_JNs/W-cfN9P25cI/AAAAAAAAIlk/TPk7nQXg6IUOdPAInKrzENN902sMJfmIACLcBGAs/s1600/Open_In_Explorer_Action.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="715" data-original-width="1233" height="369" src="https://3.bp.blogspot.com/-iN7DAFC_JNs/W-cfN9P25cI/AAAAAAAAIlk/TPk7nQXg6IUOdPAInKrzENN902sMJfmIACLcBGAs/s640/Open_In_Explorer_Action.jpg" width="640" /></a></div>
<br /></div>
<div style="text-align: justify;">
<br />
The Script:<br />
<br />
<script src="https://gist.github.com/ivanyankulov/fa97efcb1dc2a8b7c09ca459e48638bc.js"></script>
</div>
Ivan Yankulovhttp://www.blogger.com/profile/01518276480144054762noreply@blogger.com0tag:blogger.com,1999:blog-2857779700332084475.post-16129420342832020072018-04-23T09:58:00.002+03:002018-04-23T09:58:22.032+03:00Closing, Opening and Unlocking SharePoint site collections<div style="text-align: justify;">
The way to implement some sort of site collection life cycle in SharePoint Server and the classic SharePoint Online sites is the Site Policy.</div>
<div style="text-align: justify;">
With the site policy you can set when to close the site and what time to wait after closure and delete it.</div>
<div style="text-align: justify;">
Closing and Opening of site can be done very easily using server or client side code if the site already has policy assigned.</div>
<div style="text-align: justify;">
Below is an example server side powershell code for closing and opening site collections. Note that the code should be executed within elevated privilege context.</div>
<div style="text-align: justify;">
<br />
<hr />
<pre style="background: #1e1e1e; color: gainsboro; font-family: "consolas"; font-size: 11;"><span style="color: lightcyan;">Add-PSSnapin</span> <span style="color: violet;">*sh*</span>
<span style="color: palegreen;">## Close Site Collection</span>
<span style="color: lightgrey;">[</span><span style="color: darkseagreen;">Microsoft.SharePoint.SPSecurity</span><span style="color: lightgrey;">]::</span><span style="color: whitesmoke;">RunWithElevatedPrivileges</span><span style="color: whitesmoke;">(</span>
<span style="color: whitesmoke;">{</span>
<span style="color: orangered;">$spSite</span> <span style="color: lightgrey;">=</span> <span style="color: lightcyan;">Get-SPSite</span> <span style="color: violet;">http://portal.azdev.l/sites/TestSite/</span>
<span style="color: lightgrey;">[</span><span style="color: darkseagreen;">Microsoft.Office.RecordsManagement.InformationPolicy.ProjectPolicy</span><span style="color: lightgrey;">]::</span><span style="color: whitesmoke;">`
</span> <span style="color: whitesmoke;">CloseProject</span><span style="color: whitesmoke;">(</span><span style="color: orangered;">$spSite</span><span style="color: lightgrey;">.</span><span style="color: whitesmoke;">OpenWeb</span><span style="color: whitesmoke;">(</span><span style="color: whitesmoke;">))</span>
<span style="color: whitesmoke;">}</span>
<span style="color: whitesmoke;">)</span>
<span style="color: palegreen;">## Open Site Collection</span>
<span style="color: lightgrey;">[</span><span style="color: darkseagreen;">Microsoft.SharePoint.SPSecurity</span><span style="color: lightgrey;">]::</span><span style="color: whitesmoke;">RunWithElevatedPrivileges</span><span style="color: whitesmoke;">(</span>
<span style="color: whitesmoke;">{</span>
<span style="color: orangered;">$spSite</span> <span style="color: lightgrey;">=</span> <span style="color: lightcyan;">Get-SPSite</span> <span style="color: violet;">http://portal.azdev.l/sites/TestSite/</span>
<span style="color: lightgrey;">[</span><span style="color: darkseagreen;">Microsoft.Office.RecordsManagement.InformationPolicy.ProjectPolicy</span><span style="color: lightgrey;">]::</span><span style="color: whitesmoke;">`
</span> <span style="color: whitesmoke;">OpenProject</span><span style="color: whitesmoke;">(</span><span style="color: orangered;">$spSite</span><span style="color: lightgrey;">.</span><span style="color: whitesmoke;">OpenWeb</span><span style="color: whitesmoke;">(</span><span style="color: whitesmoke;">))</span>
<span style="color: whitesmoke;">}</span>
<span style="color: whitesmoke;">)</span>
</pre>
<hr />
<br />
Reopening the site will also update the "Project Expiration date". This is the date when the site will be deleted according to the applied site policy.<br />
You might need to reopen a site if for example you need to do some administrative task over the site collection like disabling feature, removing event receiver or something similar.<br />
However, changing the deletion date might not be acceptable.<br />
When a site is closed a special read-only lock is applied. If you check in the Central Administration you will see below.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://3.bp.blogspot.com/-AxZtOAETgoU/WtzhdqZsFMI/AAAAAAAAGbg/qnGsVldkZ-Y1QSJwZEhH1UfbzEmDPwz4gCLcBGAs/s1600/Archived_Site.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="Archived Site" border="0" data-original-height="161" data-original-width="444" height="145" src="https://3.bp.blogspot.com/-AxZtOAETgoU/WtzhdqZsFMI/AAAAAAAAGbg/qnGsVldkZ-Y1QSJwZEhH1UfbzEmDPwz4gCLcBGAs/s400/Archived_Site.JPG" title="Archived Site" width="400" /></a></div>
If you have to do change in couple of closed sites, you can remove the lock from the Central Administration UI. Doing this for hundreds or thousand of closed sites will not be very practical.<br />
The issue is that doing below command will not unlock the site if it was closed by site policy or using the <a href="https://msdn.microsoft.com/en-us/library/microsoft.office.recordsmanagement.informationpolicy.projectpolicy_members.aspx" target="_blank">ProjectPolicy</a> class.<br />
<br />
<hr />
<pre style="background: #1e1e1e; color: gainsboro; font-family: "consolas"; font-size: 13;"><span style="color: lightcyan;">Set-SPSite</span> <span style="color: moccasin;">-Identity</span> <span style="color: violet;">http://portal.contoso.net<span style="color: violet;">/sites/TestSite</span></span> <span style="color: moccasin;">-LockState</span> <span style="color: violet;">Unlock</span></pre>
<hr />
<br />
The key thing to notice on the picture above is the term "Archived". The SPSite object has <a href="https://msdn.microsoft.com/en-us/library/microsoft.sharepoint.spsite.archived.aspx" target="_blank">Archived</a> Boolean property, if it is true the site is "archived" and read-only, if false and there is no other lock type applied, the site will be read-write. You can just change the value of that property with PowerShell, setting the value to false will not alter the project expiration date.<br />
<br />
<hr />
<pre style="background: #1e1e1e; color: gainsboro; font-family: "consolas"; font-size: 13;"><span style="color: orangered;">$spSite</span> <span style="color: lightgrey;">=</span> <span style="color: lightcyan;">Get-SPSite</span> <span style="color: violet;">http://portal.contoso.net/sites/TestSite</span>
<span style="color: palegreen;">## Unlock the site</span>
<span style="color: orangered;">$spSite</span><span style="color: lightgrey;">.</span><span style="color: whitesmoke;">Archived</span> <span style="color: lightgrey;">=</span> <span style="color: orangered;">$false</span>
<span style="color: palegreen;">## DO YOUR THING</span>
<span style="color: palegreen;">## Lock back the site</span>
<span style="color: orangered;">$spSite</span><span style="color: lightgrey;">.</span><span style="color: whitesmoke;">Archived</span> <span style="color: lightgrey;">=</span> <span style="color: orangered;">$true</span></pre>
<hr />
<br />
There is no client side analog that I am aware of. I hope it was helpful!</div>
Ivan Yankulovhttp://www.blogger.com/profile/01518276480144054762noreply@blogger.com1tag:blogger.com,1999:blog-2857779700332084475.post-76820660988070077362018-03-26T11:09:00.001+03:002018-03-26T11:09:51.654+03:00Build trust for federated search between two SharePoint Server farmsFederated search is when you aim to receive search result from separate SharePoint (on-premises) by performing a search query in a separate on-premise SharePoint farm.<br />
If you have done such configuration probably you have seen the <a href="https://technet.microsoft.com/en-us/library/dn133749(v=office.16).aspx" target="_blank">official documentation</a> for setting it up. This procedure will work in most of the cases.<br />
However, this will not work if you do not have outbound connectivity from the remote farm that will receive the search query (ReceivingFarm) to the farm that is sending the query (SendingFarm).<br />
In that case the federated search will be possible as long as the SendingFarm can access the ReceivingFarm, vice versa is not required, but you should take a bit different approach when building the trust since the SendingFarm web app metadata end point will not be available.<br />
The first thing that needs to be done is to export the root and the token signing certificates from the SendingFarm and also get the Issuer Name (NameIdentifier) of the SendingFarm STS .<br />
<hr />
<pre style="background: #1e1e1e; color: gainsboro; font-family: "consolas"; font-size: 13;"><span style="color: palegreen;">## Export Root Certificate</span>
<span style="color: orangered;">$rootCert</span> <span style="color: lightgrey;">=</span> <span style="color: whitesmoke;">(</span><span style="color: lightcyan;">Get-SPCertificateAuthority</span><span style="color: whitesmoke;">)</span><span style="color: lightgrey;">.</span><span style="color: whitesmoke;">RootCertificate</span>
<span style="color: orangered;">$rootCert</span><span style="color: lightgrey;">.</span><span style="color: whitesmoke;">Export</span><span style="color: whitesmoke;">(</span><span style="color: palevioletred;">"Cert"</span><span style="color: whitesmoke;">)</span> <span style="color: lightgrey;">|</span> <span style="color: lightcyan;">Set-Content</span> <span style="color: palevioletred;">"C:\SendingFarmRoot.cer"</span> <span style="color: moccasin;">-Encoding</span> <span style="color: violet;">byte</span>
<span style="color: palegreen;">## Export Signing Certificate</span>
<span style="color: orangered;">$stsCert</span> <span style="color: lightgrey;">=</span> <span style="color: whitesmoke;">(</span><span style="color: lightcyan;">Get-SPSecurityTokenServiceConfig</span><span style="color: whitesmoke;">)</span><span style="color: lightgrey;">.</span><span style="color: whitesmoke;">LocalLoginProvider</span><span style="color: lightgrey;">.</span><span style="color: whitesmoke;">SigningCertificate</span>
<span style="color: orangered;">$stsCert</span><span style="color: lightgrey;">.</span><span style="color: whitesmoke;">Export</span><span style="color: whitesmoke;">(</span><span style="color: palevioletred;">"Cert"</span><span style="color: whitesmoke;">)</span> <span style="color: lightgrey;">|</span> <span style="color: lightcyan;">Set-Content</span> <span style="color: palevioletred;">"C:\SendingFarmSTS.cer"</span> <span style="color: moccasin;">-Encoding</span> <span style="color: violet;">byte</span>
<span style="color: palegreen;">## Get the STS Issuer Name</span>
<span style="color: orangered;">$issuerName</span> <span style="color: lightgrey;">=</span> <span style="color: whitesmoke;">(</span><span style="color: lightcyan;">Get-SPSecurityTokenServiceConfig</span><span style="color: whitesmoke;">)</span><span style="color: lightgrey;">.</span><span style="color: whitesmoke;">NameIdentifier</span></pre>
<hr />
The difference from the official procedure will be how we are going to create the trusted token issuer and the trusted root authority in the ReceivingFarm, this is step 3 in the <a href="https://technet.microsoft.com/en-us/library/dn133749(v=office.16).aspx" target="_blank">official procedure</a>.<br />
First copy the SendingFarm certificated to the ReceivingFarm.<br />
Having above done you can create the trusted security token issuer and the trusted root authority in the ReceivingFarm.<br />
<hr />
<pre style="background: #1e1e1e; color: gainsboro; font-family: "consolas"; font-size: 13;"><span style="color: palegreen;">## Read SendingFarm Signing certificate</span>
<span style="color: orangered;">$stsCert</span> <span style="color: lightgrey;">=</span> <span style="color: lightcyan;">Get-PfxCertificate</span> <span style="color: palevioletred;">"C:\Install\Certs\SendingFarmSTS.cer"</span>
<span style="color: palegreen;">## Read SendingFarm root certificate</span>
<span style="color: orangered;">$rootCert</span> <span style="color: lightgrey;">=</span> <span style="color: lightcyan;">Get-PfxCertificate</span> <span style="color: palevioletred;">"C:\Install\Certs\SendingFarmRoot.cer"</span>
<span style="color: palegreen;"># Create a trusted security token issuer</span>
<span style="color: orangered;">$i</span> <span style="color: lightgrey;">=</span> <span style="color: lightcyan;">New-SPTrustedSecurityTokenIssuer</span> <span style="color: moccasin;">-Name</span> <span style="color: palevioletred;">"SendingFarm"</span> <span style="color: whitesmoke;">`
</span> <span style="color: moccasin;">-Certificate</span> <span style="color: orangered;">$stsCert</span> <span style="color: whitesmoke;">`
</span> <span style="color: moccasin;">-IsTrustBroker:</span><span style="color: orangered;">$false</span> <span style="color: whitesmoke;">`
</span> <span style="color: moccasin;">-RegisteredIssuerName</span> <span style="color: palevioletred;">"<SendingFarm IssuerName>"</span>
<span style="color: palegreen;"># Configure trust of the token-signing certificate'</span>
<span style="color: palegreen;"># by adding the trust used to sign oAuth tokens'</span>
<span style="color: palegreen;"># to the list of trusted root authorities'</span>
<span style="color: palegreen;"># in ReceivingFarm</span>
<span style="color: lightcyan;">New-SPTrustedRootAuthority</span> <span style="color: moccasin;">-Name</span> <span style="color: palevioletred;">"SendingFarm"</span> <span style="color: whitesmoke;">`
</span> <span style="color: moccasin;">-Certificate</span> <span style="color: orangered;">$rootCert</span></pre>
<hr />
<br />
Now, you can continue with the trust configuration as it is described in the <a href="https://technet.microsoft.com/en-us/library/dn133749(v=office.16).aspx" target="_blank">documentation</a>.<br />
<br />
I hope you found this helpful!Ivan Yankulovhttp://www.blogger.com/profile/01518276480144054762noreply@blogger.com0tag:blogger.com,1999:blog-2857779700332084475.post-20499669044433487112018-01-19T10:42:00.003+02:002018-01-21T10:35:57.680+02:00Search result security trimming for File Share content source with ADFS users<div style="text-align: justify;">
<div style="text-align: justify;">
Indexing of file shares is a common requirement if you have legacy file share that hasn't been migrated to SharePoint or you are using file share for archiving purposes. SharePoint Search can provide this functionality.</div>
</div>
<div style="text-align: justify;">
<div style="text-align: justify;">
SharePoint also support search result trimming for file share content. That means that if the user does not have permission to a certain content on the file share, the user will not see the content appearing in the search results.</div>
</div>
<div style="text-align: justify;">
<div style="text-align: justify;">
If you are using Windows integrated authentication the security trimming does not require anything special, it will just work. This is not the case if your users are using ADFS to authenticate against SharePoint. If you are using ADFS it is mandatory to have two more claims in order to make the security trimming working.</div>
</div>
<div style="text-align: justify;">
<div style="text-align: justify;">
Those claims are <b>Primary SID </b>and <b>Primary Group SID. </b>In some articles you can find that the Primary SID is required in S2S authentication scenario, but nothing about the Primary Group SID. The Primary SID is the User object SID and the Primary Group SID is the SID of the Domain's primary group</div>
</div>
<div style="text-align: justify;">
<div style="text-align: justify;">
In this post I will demonstrate how to setup it up in ADFS and SharePoint. I have tested it with ADFS 4.0 and SharePoint Server 2016.</div>
</div>
<div style="text-align: justify;">
<div style="text-align: justify;">
<br /></div>
</div>
<div style="text-align: justify;">
<div style="text-align: justify;">
On the ADFS side you will need to create two Issuance Transformation rules using template "Pass Through or Filter an Incoming Claim".</div>
</div>
<div style="text-align: justify;">
<div style="text-align: justify;">
You can use below rules to append your rule file and import it to your SharePoint Relying Party Trust(s).</div>
<div style="text-align: justify;">
But first, you will have to export your current rules by using below command.</div>
<br />
<hr />
<pre style="background: #1e1e1e; color: gainsboro; font-family: "consolas"; font-size: 13;"><span style="color: orangered;">$sprp</span> <span style="color: lightgrey;">=</span> <span style="color: lightcyan;">Get-AdfsRelyingPartyTrust</span> <span style="color: moccasin;">-Name</span> <span style="color: palevioletred;">"<SharePointRP_Name>"</span>
<span style="color: orangered;">$sprp</span><span style="color: lightgrey;">.</span><span style="color: whitesmoke;">IssuanceTransformRules</span> <span style="color: lightgrey;">|</span> <span style="color: lightcyan;">Out-File</span> <span style="color: palevioletred;">"C:\IssuanceTransformRules.txt"</span></pre>
<hr />
<br />
Append the file with below rules for Primary SID and Primary Group SID or any additional rules you might want.<br />
<br /></div>
<div style="text-align: justify;">
</div>
<hr />
<pre style="background: #1e1e1e; color: gainsboro; font-family: "consolas"; font-size: 13;"><span style="color: orangered;">@RuleTemplate</span> <span style="color: lightgrey;">=</span> <span style="color: palevioletred;">"PassThroughClaims"</span>
<span style="color: orangered;">@RuleName</span> <span style="color: lightgrey;">=</span> <span style="color: palevioletred;">"Pass Primary Group SID"</span>
<span style="color: lightcyan;">c:[Type</span> <span style="color: violet;">==</span> <span style="color: palevioletred;">"http://schemas.microsoft.com/ws/2008/06/identity/claims/primarygroupsid"</span><span style="color: violet;">]</span>
<span style="color: lightcyan;">=></span> <span style="color: violet;">issue</span><span style="color: whitesmoke;">(</span><span style="color: lightcyan;">claim</span> <span style="color: violet;">=</span> <span style="color: violet;">c</span><span style="color: whitesmoke;">)</span><span style="color: whitesmoke;">;</span>
<span style="color: orangered;">@RuleTemplate</span> <span style="color: lightgrey;">=</span> <span style="color: palevioletred;">"PassThroughClaims"</span>
<span style="color: orangered;">@RuleName</span> <span style="color: lightgrey;">=</span> <span style="color: palevioletred;">"Pass Primary SID"</span>
<span style="color: lightcyan;">c:[Type</span> <span style="color: violet;">==</span> <span style="color: palevioletred;">"http://schemas.microsoft.com/ws/2008/06/identity/claims/primarysid"</span><span style="color: violet;">]</span>
<span style="color: lightcyan;">=></span> <span style="color: violet;">issue</span><span style="color: whitesmoke;">(</span><span style="color: lightcyan;">claim</span> <span style="color: violet;">=</span> <span style="color: violet;">c</span><span style="color: whitesmoke;">)</span><span style="color: whitesmoke;">;</span></pre>
<hr />
<br />
<div style="text-align: justify;">
Now, import the file containing your old and newly added rules.</div>
<br />
<hr />
<pre style="background: #1e1e1e; color: gainsboro; font-family: "consolas"; font-size: 13;"><span style="color: lightcyan;">Set-AdfsRelyingPartyTrust</span> <span style="color: moccasin;">-TargetName</span> <span style="color: palevioletred;">"<SharePointRP_Name>"</span><span style="color: whitesmoke;">`
</span> <span style="color: moccasin;">-IssuanceTransformRulesFile</span> <span style="color: palevioletred;">"C:\IssuanceTransformRules.txt"</span></pre>
<hr />
<br />
<div style="text-align: justify;">
On the SharePoint side you will have to create the claim type mappings for the two new claims. You can use the example script below.</div>
<br />
<hr />
<pre style="background: #1e1e1e; color: gainsboro; font-family: "consolas"; font-size: 13;"><span style="color: lightcyan;">Add-PSSnapin</span> <span style="color: violet;">*SH*</span>
<span style="color: orangered;">$sts</span> <span style="color: lightgrey;">=</span> <span style="color: lightcyan;">Get-SPTrustedIdentityTokenIssuer</span>
<span style="color: orangered;">$sts</span><span style="color: lightgrey;">.</span><span style="color: whitesmoke;">ClaimTypes</span><span style="color: lightgrey;">.</span><span style="color: whitesmoke;">Add</span><span style="color: whitesmoke;">(</span><span style="color: palevioletred;">"http://schemas.microsoft.com/ws/2008/06/identity/claims/primarygroupsid"</span><span style="color: whitesmoke;">)</span>
<span style="color: orangered;">$sts</span><span style="color: lightgrey;">.</span><span style="color: whitesmoke;">ClaimTypes</span><span style="color: lightgrey;">.</span><span style="color: whitesmoke;">Add</span><span style="color: whitesmoke;">(</span><span style="color: palevioletred;">"http://schemas.microsoft.com/ws/2008/06/identity/claims/primarysid"</span><span style="color: whitesmoke;">)</span>
<span style="color: orangered;">$sts</span><span style="color: lightgrey;">.</span><span style="color: whitesmoke;">Update</span><span style="color: whitesmoke;">(</span><span style="color: whitesmoke;">)</span>
<span style="color: orangered;">$map</span> <span style="color: lightgrey;">=</span> <span style="color: lightcyan;">New-SPClaimTypeMapping</span> <span style="color: whitesmoke;">`
</span><span style="color: moccasin;">-IncomingClaimType</span> <span style="color: palevioletred;">"http://schemas.microsoft.com/ws/2008/06/identity/claims/primarygroupsid"</span> <span style="color: whitesmoke;">`
</span><span style="color: moccasin;">-IncomingClaimTypeDisplayName</span> <span style="color: palevioletred;">"Primary group SID"</span> <span style="color: moccasin;">-SameAsIncoming</span>
<span style="color: orangered;">$map2</span> <span style="color: lightgrey;">=</span> <span style="color: lightcyan;">New-SPClaimTypeMapping</span> <span style="color: whitesmoke;">`
</span><span style="color: moccasin;">-IncomingClaimType</span> <span style="color: palevioletred;">"http://schemas.microsoft.com/ws/2008/06/identity/claims/primarysid"</span> <span style="color: whitesmoke;">`
</span><span style="color: moccasin;">-IncomingClaimTypeDisplayName</span> <span style="color: palevioletred;">"Primary SID"</span> <span style="color: moccasin;">-SameAsIncoming</span>
<span style="color: lightcyan;">Add-SPClaimTypeMapping</span> <span style="color: moccasin;">-Identity</span> <span style="color: orangered;">$map</span> <span style="color: moccasin;">-TrustedIdentityTokenIssuer</span> <span style="color: orangered;">$sts</span>
<span style="color: lightcyan;">Add-SPClaimTypeMapping</span> <span style="color: moccasin;">-Identity</span> <span style="color: orangered;">$map2</span> <span style="color: moccasin;">-TrustedIdentityTokenIssuer</span> <span style="color: orangered;">$sts</span></pre>
<hr />
<br />
<div style="text-align: justify;">
And that's is all you need to do. If everything is fine you will see values for the two new claims and the security trimming should work for the ADFS users.</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://2.bp.blogspot.com/-iy1Ulc7nTpw/WmC3tykLokI/AAAAAAAAGKM/sfi0hAgqZeEl79SphmALB3mcBLkAG2i_gCLcBGAs/s1600/ADFS_Claims.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="378" data-original-width="810" height="297" src="https://2.bp.blogspot.com/-iy1Ulc7nTpw/WmC3tykLokI/AAAAAAAAGKM/sfi0hAgqZeEl79SphmALB3mcBLkAG2i_gCLcBGAs/s640/ADFS_Claims.jpg" width="640" /></a></div>
<br />
<div style="text-align: justify;">
If you are wondering how to see the claims, I am using one of the many SharePoint Claims Viewer web parts found on the internet. I am also using <a href="http://ldapcp.com/" target="_blank">LDAPCP</a> for claims provider. Above requirement and scripts will be the same if you are using the OOTB claims provider.</div>
<div style="text-align: justify;">
<b>I hope you found it helpful!</b></div>
Ivan Yankulovhttp://www.blogger.com/profile/01518276480144054762noreply@blogger.com0tag:blogger.com,1999:blog-2857779700332084475.post-91287578642411307972018-01-02T15:44:00.001+02:002018-01-02T15:44:10.841+02:00Change Site Policy Deletion notification email template in SharePoint<div style="text-align: justify;">
The Site Policies in SharePoint are information management tool that helps you implement some site life cycle management. Whether this is dictated by internal house keeping rules or some external regulations that apply to your organisation, the Site Policy is the out of the box way to go if you want to "close" a site, delete it or both, automaticaly after certain period of time.</div>
<div style="text-align: justify;">
With site policies you have the option to notify the site owners in advance before the site is deleted. The mail looks like the one below.<br />
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://3.bp.blogspot.com/-qPCgV1Ml6KY/Wktvse8NEhI/AAAAAAAAGII/_lxvYbwpitooumg3zuuywMMTzHNoRehvwCLcBGAs/s1600/DeletionNotice.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="Site Deletion Notice" border="0" data-original-height="562" data-original-width="1320" height="272" src="https://3.bp.blogspot.com/-qPCgV1Ml6KY/Wktvse8NEhI/AAAAAAAAGII/_lxvYbwpitooumg3zuuywMMTzHNoRehvwCLcBGAs/s640/DeletionNotice.png" title="Site Deletion Notice" width="640" /></a></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
The information in this email might not be suitable for your organization.</div>
<div style="text-align: justify;">
Fortunately there is a way to change the default Site Policy notification email body template and the email subject. This is not done in some XML template file like the Alerts template, maybe there is one, but I have not found it. There is SSOM and CSOM API that you can use to set custom email body template per policy.</div>
<div style="text-align: justify;">
The documentation of this is very poor and the best resource on this is the article <a href="https://blogs.technet.microsoft.com/tothesharepoint/2013/03/28/site-policy-in-sharepoint/" target="_blank">Site Policy in SharePoint</a>.</div>
<div style="text-align: justify;">
Unfortunately I have not managed to make this work server side or using PowerShell. I have tried with SharePoint 2013, SharePoint 2016 and SharePoint Online ssom and csom as well.</div>
<div style="text-align: justify;">
The only way I found it working is from console application using the CSOM approach.</div>
<div style="text-align: justify;">
The site policy post above is good and the code should work as it is, but it has some gaps.</div>
<div style="text-align: justify;">
There are three placeholders that we can use, placeholders for Site Url, Deletion Date and Mailbox Id.<br />
However the placeholders with curly braces that are demonstrated in the post will not work.</div>
<div style="text-align: justify;">
I would like to save you some time testing especially if you are targeting SharePoint Online, as there you cannot manually run the "<a href="https://technet.microsoft.com/en-us/library/cc678870%28v=office.16%29.aspx" target="_blank">Expiration Policy</a>" timer job.<br />
<br />
The correct placeholders are below, without curly braces or any spaces.</div>
<div style="text-align: justify;">
<hr />
<b>SiteUrl:</b> <!--SiteUrl--><br />
<b>Deletion Date:</b> <!--SiteDeleteDate--><br />
<b>Mailbox ID:</b> <!--TeamMailboxID-->
<br />
<hr />
</div>
<br />
I hope you found this helpful!Ivan Yankulovhttp://www.blogger.com/profile/01518276480144054762noreply@blogger.com0tag:blogger.com,1999:blog-2857779700332084475.post-17716050478903419862017-12-19T11:32:00.001+02:002017-12-19T11:32:34.906+02:00Site collection app catalog available in SharePoint Online<div style="text-align: justify;">
<div style="text-align: justify;">
The site collection app catalog is now generally available for all tenants in SharePoint Online.</div>
</div>
<div>
<div style="text-align: justify;">
<div style="text-align: justify;">
It allows you to make SharePoint Add-Ins and SPFx solutions available only in certain site collections. This is a great improvements because it allows more flexible deployment options, you can test a solutions only on site collection level before pushing it to the entire tenant and it can decentralize the management of add-ins and SPFx packages.</div>
</div>
</div>
<div>
<div style="text-align: justify;">
<div style="text-align: justify;">
You can create Site Collection App catalog by using <a href="https://technet.microsoft.com/en-us/library/fp161388.aspx" target="_blank">SharePoint Online Management Shell</a>.</div>
</div>
</div>
<div>
<div style="text-align: justify;">
<div style="text-align: justify;">
Note that you will still need to configure tenant app catalog. If you try to provision site collection app catalog without tenant app catalog you will get below exception.</div>
</div>
</div>
<div>
<hr />
<span style="color: red;">Add-SPOSiteCollectionAppCatalog : Cannot invoke method or retrieve property from null object. Object returned by the</span><br />
<span style="color: red;">following call stack is null. "TenantAppCatalog</span><br />
<span style="color: red;">RootWeb</span><br />
<span style="color: red;">GetSiteByUrl</span><br />
<span style="color: red;">new Microsoft.Online.SharePoint.TenantAdministration.Tenant()</span><br />
<hr />
<br />
For more information on site collection app catalog check out below PnP Webcast:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allow="encrypted-media" allowfullscreen="" frameborder="0" gesture="media" height="315" src="https://www.youtube.com/embed/ZfUKkdMnSYQ" width="560"></iframe></div>
<br /></div>
Ivan Yankulovhttp://www.blogger.com/profile/01518276480144054762noreply@blogger.com0tag:blogger.com,1999:blog-2857779700332084475.post-29552999156127500642017-12-17T11:27:00.002+02:002017-12-17T11:27:17.886+02:00Fantastic 40 is back in SPFx form<div style="text-align: justify;">
Well, actually not, but I hope that the title of this post will make you want to check it out.</div>
<div style="text-align: justify;">
I would like to share a great project called "<a href="https://github.com/OlivierCC/spfx-40-fantastics#spfx-fantastic-40-web-parts" target="_blank">SPFx Fantastic 40 Web Parts</a>". Except the name, this project has almost nothing to do with the old "<a href="https://blogs.technet.microsoft.com/praveenh/2010/12/17/fantastic-40-application-templates-for-sharepoint-wss-moss/" target="_blank">Fantastic 40 Application Templates for SharePoint (WSS & MOSS)</a>" because it is a collection of 40 SPFx Client Side Web Parts. It is open source project so you can use it as you find for useful. It was created by Olivier Carpentier, but the code is provided "as is" without support from Microsoft.</div>
<div style="text-align: justify;">
I am so excited because the web parts look great and they might be a solution to common needs that the out of the box modern webparts don't fulfill.</div>
<div style="text-align: justify;">
It is also a great learning resource and demonstration of what can be done with SPFx.</div>
<div style="text-align: justify;">
If it is not an issue for you to consume the web parts assets from CDNs you do not control you can download and deploy the *.sppkg as it is and it will work. I also tried most of the web parts on SharePoint Server 2016 with classic pages and they work and look great.</div>
<div style="text-align: justify;">
The web parts are grouped in seven categories and below you can find some samples.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<b>Menu & Carousels & News Management: News Slider</b></div>
<div style="text-align: justify;">
<b><br /></b></div>
<div style="text-align: justify;">
</div>
<div style="text-align: justify;">
The News Slider Web Part renders a simple news slider carousel to your page. You can manage your active news, manage the layout and easily render a cool slider to enhance your pages.</div>
<div style="text-align: justify;">
<b><br /></b></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://github.com/OlivierCC/spfx-40-fantastics/raw/master/assets/newsslideroverview.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="500" data-original-width="800" height="250" src="https://github.com/OlivierCC/spfx-40-fantastics/raw/master/assets/newsslideroverview.gif" width="400" /></a></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<b>Social Tools: Tweets Feed</b></div>
<div style="text-align: justify;">
<b><br /></b></div>
<div style="text-align: justify;">
The Tweets Feed Web Part is a SharePoint client side web part built with the SharePoint Framework (SPFx). This web part generates a Twitter Feed on the page, based on the specified account. This Web Part uses the <a href="https://dev.twitter.com/web/embedded-timelines/parameters" target="_blank">Twitter API</a> to integrate the timeline.</div>
<div style="text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://github.com/OlivierCC/spfx-40-fantastics/raw/master/assets/tweetsfeedoverview.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="556" data-original-width="800" height="277" src="https://github.com/OlivierCC/spfx-40-fantastics/raw/master/assets/tweetsfeedoverview.gif" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div style="text-align: justify;">
<b>Maps, Charts & Graphs: Bar Chart</b></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
The Bar Chart Web Part is a SharePoint client side web part built with the SharePoint Framework (SPFx). This web part insert a Bar Chart in your pages, and you can manage the bar chart settings as items, color, title, legends, etc. This web part uses <a href="http://www.chartjs.org/" target="_blank">chart.js</a> lib.</div>
<div style="text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://github.com/OlivierCC/spfx-40-fantastics/raw/master/assets/barchartoverview.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="585" data-original-width="800" height="292" src="https://github.com/OlivierCC/spfx-40-fantastics/raw/master/assets/barchartoverview.gif" width="400" /></a></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<b>Images Galleries & Tools: Grid Gallery</b></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
The grid gallery Web Part renders a pictures slideshow with grid of thumbnails. This web part implements <a href="https://github.com/vvvmax/unitegallery/" target="_blank">unitegallery.js</a> (a popular jquery script) as a client side web part for SharePoint.</div>
<div style="text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://github.com/OlivierCC/spfx-40-fantastics/raw/master/assets/gridgalleryoverview.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="502" data-original-width="800" height="250" src="https://github.com/OlivierCC/spfx-40-fantastics/raw/master/assets/gridgalleryoverview.gif" width="400" /></a></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<b>Video & Audio: Media Player</b></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
The Media Player Web Part is a SharePoint client side web part built with the SharePoint Framework (SPFx). With it, you can insert a video in your pages that is a HTML 5 compatible video or audio files, a YouTube video or a Vimeo video. This web part uses <a href="https://plyr.io/" target="_blank">Plyr.js</a> lib.</div>
<div style="text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://github.com/OlivierCC/spfx-40-fantastics/raw/master/assets/mediaplayeroverview.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="590" data-original-width="800" height="295" src="https://github.com/OlivierCC/spfx-40-fantastics/raw/master/assets/mediaplayeroverview.gif" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both;">
<b>Text Tools: Tabs</b></div>
<div class="separator" style="clear: both;">
<br /></div>
<div class="separator" style="clear: both;">
The Tabs Web Part is a SharePoint client side web part built with the SharePoint Framework (SPFx). This web part helps to create a tab (you manage, add, delete, edit or move a tab dynamically) and the web part editor can easily modify the tabs content thanks a HTML editor (WYSIWYG). This tab control is responsive, so the layout will adapt the render with the screen size.</div>
<div style="text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://github.com/OlivierCC/spfx-40-fantastics/raw/master/assets/tabsoverview.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="507" data-original-width="800" height="252" src="https://github.com/OlivierCC/spfx-40-fantastics/raw/master/assets/tabsoverview.gif" width="400" /></a></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<b>Tools: Stock Info</b></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
The Stock Info Web Part is a SharePoint client side web part built with the SharePoint Framework (SPFx). This web part generates a stock graph picture for a specified stock. This web part uses the Yahoo Financial service.</div>
<div style="text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://github.com/OlivierCC/spfx-40-fantastics/raw/master/assets/stockinfooverview.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="531" data-original-width="800" height="265" src="https://github.com/OlivierCC/spfx-40-fantastics/raw/master/assets/stockinfooverview.gif" width="400" /></a></div>
<div style="text-align: justify;">
<br /></div>
Ivan Yankulovhttp://www.blogger.com/profile/01518276480144054762noreply@blogger.com0tag:blogger.com,1999:blog-2857779700332084475.post-30416529785425726192017-08-19T15:02:00.001+03:002017-08-19T15:02:39.643+03:00Build TreeView with XML data in PowerShell [Tip]<div style="text-align: justify;">
In one of my recent scripts I worked on, I had to visualize XML data in a tree view manor.</div>
<div style="text-align: justify;">
I achieved this by using the <a href="https://msdn.microsoft.com/en-us/library/system.windows.forms.treeview(v=vs.110).aspx" target="_blank">TreeView</a> Windows Forms control and I think that the result is good and can be used as an example if you have to do something similar.</div>
<div style="text-align: justify;">
I tweaked the function and made it a standalone "XML Browser" script that is visualizing the XML document and if you double click on the element you will copy the Outer XML text to the clipboard.</div>
<div style="text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://3.bp.blogspot.com/-0Z93S3m6O5c/WZgieJ2keUI/AAAAAAAAFcE/VMWCoT1WDYYx8iVmMphmZu98ispRIF90QCLcBGAs/s1600/XML%2BBrowser.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="PowerShell XML Browser" border="0" data-original-height="507" data-original-width="846" height="380" src="https://3.bp.blogspot.com/-0Z93S3m6O5c/WZgieJ2keUI/AAAAAAAAFcE/VMWCoT1WDYYx8iVmMphmZu98ispRIF90QCLcBGAs/s640/XML%2BBrowser.JPG" title="PowerShell XML Browser" width="640" /></a></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
In order to visualize xml you need to supply the path to it and the starting element. On the screenshot above I have a web.config file loaded and the starting element I want to visualize is "configuration". You can find the code and the example below. I hope you find it helpful!</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<br />
<script src="https://gist.github.com/ivanyankulov/40bcb0968499035b370d34429003694e.js"></script></div>
Ivan Yankulovhttp://www.blogger.com/profile/01518276480144054762noreply@blogger.com0tag:blogger.com,1999:blog-2857779700332084475.post-19318933436530920202017-04-06T16:14:00.001+03:002017-04-06T16:16:44.760+03:00Nintex Workflow UDA Usage report script<div style="text-align: justify;">
Yesterday I worked with a client that have many Nintex workflow published with heavy usage of UDAs(User Defined Actions). I wanted to get a detailed report on the UDA usage. Unfortunately I am not aware of any out of the box Nintex tool that can do that. The Analyze button can give you some information, but you need to click on the workflow to find out where it is located, you need to be in the scope where the UDA is published, you can get information for one UDA at a time and the information is not really "exportable".</div>
<div style="text-align: justify;">
This is why I created a powershell script that will give you information for the UDA usage across the farm on all levels. It will give you useful information like UDA Name, Workflow Name, Defined At, List, Web, Site, WebApplication, WorkflowType, Author, UDA Version Used, Workflow Id.</div>
<div style="text-align: justify;">
There are two "modes" of the script, the default will give you just the GUIDs of the list,web,site and the web apps. If you want to get the name of the list and the URLs you need to use the second mode that will require more time to complete but will give you nice looking URLs instead GUIDs. If you want to get the URLs just use switch parameter GetUrls. The result can be saved in CSV format or it can be outputted in powershell. If you give value for CSVPath the Grid View will open at the end to visualize the data. The main source of information is the Nintex Configuration database and you can use the script with SQL authentication if you have an account with enough permissions and your SQL supports it.</div>
<div style="text-align: justify;">
I have tested the script with SharePoint 2016,2013 and 2010 and the oldest Nintex Workflow version I tested was 2.3.7.0.</div>
<div style="text-align: justify;">
You can see the code and the output examples below. <b>I hope you find it useful!</b></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<script src="https://gist.github.com/ivanyankulov/5c284a2ede78e8a0c8706ea8ed30e597.js"></script></div>
Output with URLs retrieved:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-tAHDSYJiJjA/WOX_VfGT9zI/AAAAAAAAEqw/_0YomZR_27g--ybgPeS-OU3qQFou63YAgCLcB/s1600/UDA_Usage_Report.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="Nintex Workflow UDA Usage report with URLs" border="0" height="112" src="https://1.bp.blogspot.com/-tAHDSYJiJjA/WOX_VfGT9zI/AAAAAAAAEqw/_0YomZR_27g--ybgPeS-OU3qQFou63YAgCLcB/s640/UDA_Usage_Report.JPG" title="Nintex Workflow UDA Usage report with URLs" width="640" /></a></div>
<br />
Quick output with GUIDs:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://3.bp.blogspot.com/-LycrUk2Tsco/WOYAM5v29bI/AAAAAAAAEq0/wLxPc4rn33cUVeL1xkj1u7yIuGXoBGl0ACLcB/s1600/UDA_Usage_Report_GUIDS.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="Nintex Workflow UDA Usage report with GUIDs" border="0" height="72" src="https://3.bp.blogspot.com/-LycrUk2Tsco/WOYAM5v29bI/AAAAAAAAEq0/wLxPc4rn33cUVeL1xkj1u7yIuGXoBGl0ACLcB/s640/UDA_Usage_Report_GUIDS.JPG" title="Nintex Workflow UDA Usage report with GUIDs" width="640" /></a></div>
<br />Ivan Yankulovhttp://www.blogger.com/profile/01518276480144054762noreply@blogger.com0tag:blogger.com,1999:blog-2857779700332084475.post-35326323764199129972017-03-24T10:13:00.001+02:002017-03-25T08:55:53.688+02:00Troubleshoot PowerShell Add-Type Load Error [Tip]<div style="text-align: justify;">
In the last couple of days I am working with a client that has a DMS solution based on SharePoint Server 2010. We inherited the solution so it has it's specifics. One of those little things (that make life exciting) is that they have fields with custom data types. </div>
<div style="text-align: justify;">
I had to do a powershell script that will edit some document metadata. I had to update standard SharePoint native data type fields, but after updating the item in powershell I lost the values of the custom data type fields. I realized that I need the custom data type loaded in the powershell session. So I started to import some DLLs, in the order that I thought it makes sense as we do not have the source code of the solutions.This was fine until I received the error below:</div>
<hr />
<div style="text-align: justify;">
<div style="text-align: justify;">
<span style="color: red;">Add-Type : Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information.</span></div>
<hr style="text-align: justify;" />
</div>
<div style="text-align: justify;">
This error is completely generic and the only useful thing is that it tells us where we can find more useful information.</div>
<div style="text-align: justify;">
This simple error handling script turned out to be life saver for me as it showed exactly what the load error is and which dependent assembly I need to load first :)</div>
<div style="text-align: justify;">
<br /></div>
<script src="https://gist.github.com/ivanyankulov/b1e1b23d87ce4e4a139dbcbc7e06cb3f.js"></script>
<br />
<div style="text-align: justify;">
The nice blue text is our LoaderExceptions property of the exception. <b>I hope that you find it useful!</b></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://3.bp.blogspot.com/-IX-oqCYF6E8/WNTRWJG-FsI/AAAAAAAAEnw/nUjRdr1bEhwXu35DT10ARDEtLAThMbG4wCLcB/s1600/LoaderExceptions.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="LoaderExceptions Powershell" border="0" height="202" src="https://3.bp.blogspot.com/-IX-oqCYF6E8/WNTRWJG-FsI/AAAAAAAAEnw/nUjRdr1bEhwXu35DT10ARDEtLAThMbG4wCLcB/s640/LoaderExceptions.JPG" title="LoaderExceptions in Powershell" width="640" /></a></div>
<br />Ivan Yankulovhttp://www.blogger.com/profile/01518276480144054762noreply@blogger.com1tag:blogger.com,1999:blog-2857779700332084475.post-63601505573735504942017-01-22T21:44:00.001+02:002017-01-29T17:09:40.228+02:00Conditionally Show/Hide and Require SharePoint fields with JavaScript <div style="text-align: justify;">
<div style="text-align: justify;">
<span style="font-family: "arial" , "helvetica" , sans-serif;">In my last project I worked on DMS system based on SharePoint Server 2016 and had a very common requirement for the document forms. The requirement was to have Document Status field, Approval Reason and Rejected Reason fields. It is logical to want to hide Approval Reason when the document status is Rejected or Rejected Reason when the document is Approved.The client also wanted to make the fields required when the corresponding document status is selected. </span></div>
</div>
<div style="text-align: justify;">
<div style="text-align: justify;">
<span style="font-family: "arial" , "helvetica" , sans-serif;">All customizations were going to be deployed using the classic way, with farm solution. I also had Nintex Forms, but I was unable to use it in this case due to other technical constraints.</span></div>
</div>
<div style="text-align: justify;">
<div style="text-align: justify;">
<span style="font-family: "arial" , "helvetica" , sans-serif;">That's why I decided to solve this requirement using JQuery and JavaScript script that are deployed with the WSP solution and included in the mater page.</span></div>
</div>
<div style="text-align: justify;">
<div style="text-align: justify;">
<span style="font-family: "arial" , "helvetica" , sans-serif;">The end result was pretty good and this is why I decided to share the script and a way to safely deploy it in SharePoint Online without the need to edit the master page or the list forms. The script is really simple and can be used/deployed as it is or with minor changes by person with moderate JavaScript experience.</span></div>
</div>
<div style="text-align: justify;">
<div style="text-align: justify;">
<span style="font-family: "arial" , "helvetica" , sans-serif;">Few notes on the SPO environment that was used. There are 3 custom site columns with following Title, InternalNames and Type: </span></div>
</div>
<div style="text-align: justify;">
<div style="text-align: justify;">
<span style="font-family: "arial" , "helvetica" , sans-serif;">- Title: Document Status, InternalName: DocumentStatus, Choice, radio buttons</span></div>
</div>
<div style="text-align: justify;">
<div style="text-align: justify;">
<span style="font-family: "arial" , "helvetica" , sans-serif;">- Title: Approval Reason, InternalName: ApprovalReason, Multi-line text, <b>Not required by definition</b></span></div>
</div>
<div style="text-align: justify;">
<div style="text-align: justify;">
<span style="font-family: "arial" , "helvetica" , sans-serif;">- Title: Rejected Reason, InternalName: RejectedReason, Multi-line text, <b>Not required by definition</b></span></div>
</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<span style="font-family: "arial" , "helvetica" , sans-serif;">You can see the script below:</span></div>
<div style="text-align: justify;">
<br />
<script src="https://gist.github.com/ivanyankulov/f14dbda7157328b81200a5206475739c.js"></script></div>
<div style="text-align: justify;">
<span style="font-family: "arial" , "helvetica" , sans-serif;">There are two main functions, showOrHideFields that will be started when the page is loaded and will show or hide Approval Reason or Rejected Reason field depending on the value of the Document Status field in New,View and Edit forms. The second function is with the specific name PreSaveAction, it will be launched when Check In or Save button is clicked and will not allow the form to be saved if Approval Reason or Rejected Reason fields are empty and will pop-out an "error" message below the field, again depending on the Document Status field value.</span></div>
<div style="text-align: justify;">
<span style="font-family: "arial" , "helvetica" , sans-serif;">Below you can see how the form looks like in New,Edit and View mode.</span></div>
<div style="text-align: justify;">
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-mbFl1oViJa0/WITqo1LvM9I/AAAAAAAAEaM/GOXpvknHK0EqigktyREHcr_ibT6NNGG4ACLcB/s1600/Forms.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="New, Edit and View forms" border="0" height="201" src="https://1.bp.blogspot.com/-mbFl1oViJa0/WITqo1LvM9I/AAAAAAAAEaM/GOXpvknHK0EqigktyREHcr_ibT6NNGG4ACLcB/s640/Forms.jpg" title="New, Edit and View forms" width="640" /></a></div>
<div style="text-align: justify;">
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span></div>
<div style="text-align: justify;">
<span style="font-family: "arial" , "helvetica" , sans-serif;">In order to deploy the script without modifying the forms or the master page we are going to use the SharePoint <a href="https://github.com/SharePoint/PnP-PowerShell" target="_blank">PnP PowerShell module for SharePoint Online</a>. In order to "inject" the javascript links we are going to use <a href="https://github.com/SharePoint/PnP-PowerShell/blob/master/Documentation/AddPnPJavaScriptLink.md" target="_blank">Add-PnPJavaScriptLink</a> command. In the example below I am uploading the JS file, adding ScriptLink to it and adding ScriptLink to Google hosted JQuery library.</span></div>
<div style="text-align: justify;">
<span style="font-family: "arial" , "helvetica" , sans-serif;">
</span>
<br />
<hr />
<span style="font-family: "arial" , "helvetica" , sans-serif;">
</span>
<br />
<pre style="background: #1e1e1e; color: gainsboro; font-family: "consolas"; font-size: 13;"><span style="font-family: "arial" , "helvetica" , sans-serif;"><span style="color: lightcyan;">Add-PnPFile</span> <span style="color: moccasin;">-Path</span> <span style="color: palevioletred;">"C:\Users\Ivan\Documents\ShowHide.js"</span> <span style="color: moccasin;">-Folder</span> <span style="color: palevioletred;">"Style Library/scripts/"</span> <span style="color: whitesmoke;">`
</span> <span style="color: moccasin;">-Checkout</span> <span style="color: moccasin;">-Publish</span> <span style="color: moccasin;">-CheckInComment</span> <span style="color: palevioletred;">""</span>
<span style="color: lightcyan;">Add-PnPJavaScriptLink</span> <span style="color: moccasin;">-Name</span> <span style="color: violet;">JQuery</span> <span style="color: whitesmoke;">`
</span> <span style="color: moccasin;">-Url</span> <span style="color: palevioletred;">"https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"</span>
<span style="color: lightcyan;">Add-PnPJavaScriptLink</span> <span style="color: moccasin;">-Name</span> <span style="color: violet;">ShowHide</span> <span style="color: whitesmoke;">`
</span> <span style="color: moccasin;">-Url</span> <span style="color: palevioletred;">"https://mod44444.sharepoint.com/Style%20Library/scripts/ShowHide.js"</span></span></pre>
<span style="font-family: "arial" , "helvetica" , sans-serif;">
</span>
<br />
<hr />
<span style="font-family: "arial" , "helvetica" , sans-serif;">
</span></div>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Once the commands are executed the scripts will be loaded in all classic pages in the web(default scope for this command).</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;">Unfortunately this really useful way of injecting JavaScript will not work with the modern pages and the new Library and List experience. More info on this huge gap can be found in this <a href="http://sharepoint.stackexchange.com/questions/191498/sharepoint-framework-modern-pages-with-scriptlink-custom-action" target="_blank">post</a>.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<b><span style="font-family: "arial" , "helvetica" , sans-serif;">I hope that this was helpful!</span></b>Ivan Yankulovhttp://www.blogger.com/profile/01518276480144054762noreply@blogger.com1tag:blogger.com,1999:blog-2857779700332084475.post-18962409047391588452016-11-14T09:07:00.001+02:002016-11-14T18:30:45.777+02:00Trust failed error when browsing the Central Administration<div style="text-align: justify;">
In this quick post I am going to share an issue that I recently hit with one SharePoint Server deployment. While browsing the Central Administration I got below error when clicking on the Manage service applications page.</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://2.bp.blogspot.com/-MfX1-MTL_bw/WCWIAn334DI/AAAAAAAADu0/LtskzwVDIdA79yfjBRQcgI4c0GmUo-FGgCLcB/s1600/TrustError.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="307" src="https://2.bp.blogspot.com/-MfX1-MTL_bw/WCWIAn334DI/AAAAAAAADu0/LtskzwVDIdA79yfjBRQcgI4c0GmUo-FGgCLcB/s640/TrustError.JPG" width="640" /></a></div>
<div>
<br />
<div style="text-align: justify;">
The key thing with this error is to know the background story, something I was missing.</div>
<div style="text-align: justify;">
The story is that this farm was migrated from one domain to another.<br />
Everything was working fine the new farm was in production when we started to get this error.</div>
<div style="text-align: justify;">
There was one small detail that we were not aware of and it is that there was domain trust between the new and the old domain during the migration. This is why everithing was working fine until the network link between the old and the new domain was cut.</div>
<div style="text-align: justify;">
With this small detail the error below started to make sense. You will see this error in different .NET apps if the app is trying to do something with identity from a trusted domain but no domain controller from the trusted domain can be reached.</div>
<div style="text-align: justify;">
<hr />
<div style="text-align: center;">
<span style="color: red;">The trust relationship between the primary domain and the trusted domain failed.
</span></div>
<hr />
</div>
<div style="text-align: justify;">
By looking at the "Delegated Administrators" I concluded that there are accounts from the old domain that have permissions over some of the service applications. I was even unable to get the service applications using Get-SPServiceApplication in powershell. It seems that there is some identity checking when we access the service application management page and it is failing because the trusted domain cannot be reached. The same exception can be reproduced if you try to translate username from the trusted domain to SID. The lines below are a good test to check if there is an issue with the trusted domain with PowerShell.</div>
<div style="text-align: justify;">
<hr />
<pre style="background: #1e1e1e; color: gainsboro; font-family: "consolas"; font-size: 13;"><span style="color: orangered;">$userName</span> <span style="color: lightgrey;">=</span> <span style="color: palevioletred;">"DOMAIN\User"</span>
<span style="color: orangered;">$objUser</span> <span style="color: lightgrey;">=</span> <span style="color: lightcyan;">New-Object</span> <span style="color: violet;">System.Security.Principal.NTAccount</span><span style="color: whitesmoke;">(</span><span style="color: orangered;">$userName</span><span style="color: whitesmoke;">)</span>
<span style="color: orangered;">$strSID</span> <span style="color: lightgrey;">=</span> <span style="color: orangered;">$objUser</span><span style="color: lightgrey;">.</span><span style="color: whitesmoke;">Translate</span><span style="color: whitesmoke;">(</span><span style="color: lightgrey;">[</span><span style="color: darkseagreen;">System.Security.Principal.SecurityIdentifier</span><span style="color: lightgrey;">]</span><span style="color: whitesmoke;">)</span>
<span style="color: orangered;">$strSID</span><span style="color: lightgrey;">.</span><span style="color: whitesmoke;">Value</span></pre>
<hr />
</div>
</div>
<div style="text-align: justify;">
Here are some of the things that might not work if you are in this situation:</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
- You will not be able to access the service management page</div>
<div style="text-align: justify;">
- You will not be able to enumerate the service applications in powershell</div>
<div style="text-align: justify;">
- In my case the Search and UPA was the SAs with administrators from the trusted domain and you will not be able to restart the service instances</div>
<div style="text-align: justify;">
- The UPA might stop working working completely</div>
<div style="text-align: justify;">
- If you clear the configuration cache the Timer Service will fall in a loop of rebuild attempts and crashes and no timer jobs will be executed.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
As you can see this situation might not be a good place to be :).</div>
<div style="text-align: justify;">
The solution to this will be to restore the connection to the trusted domain and I am talking about a physical availability to a DC from the trusted domain or just remove the trust from the current domain. Sometimes the second solution might be the only possible solution, or just maybe this relationship was just not removed by the domain admins when the connection was cut.</div>
<div style="text-align: justify;">
If you remove the domain trust the error will be fixed and the translate method in powershell will fail with <i>"Some or all identity references could not be translated."</i> which it seems is handled better. Than you will be able to do some proper cleanup, if you wish.</div>
<div style="text-align: justify;">
I hope that this post was helpful! </div>
Ivan Yankulovhttp://www.blogger.com/profile/01518276480144054762noreply@blogger.com0tag:blogger.com,1999:blog-2857779700332084475.post-9469833906254717122016-11-08T15:10:00.001+02:002016-11-08T15:10:18.985+02:00Run PowerShell script on Windows 10 PC through the MDM Channel in Intune<div style="text-align: justify;">
In the last couple of weeks I've been working on an internal project that includes software distribution of Windows apps on MDM enrolled Windows 10 PCs using cloud only Intune deployment. Yes that's right, no SharePoint in this post, but a real world EMS story.</div>
<div style="text-align: justify;">
The easiest way to publish classic windows apps on Windows 10 PC that is MDM enrolled will be by publishing <a href="https://docs.microsoft.com/en-us/intune/deploy-use/add-apps" target="_blank">Windows Installer through MDM (*.msi)</a> installer.</div>
<div style="text-align: justify;">
The important thing with this installer type is that the installation should go without any user interaction required especially when you use "Required Install".</div>
<div style="text-align: justify;">
The issue I hit is related to Dell software that is essential for the remote work and almost everyone in the company is using it. However for some reason the software publisher (Dell Software) is considered not trusted in Windows 10. There is this great thing in Windows (since Win 7) called SmartScreen that will pop-up a question asking if we trust the software publisher, before running executable with not trusted publisher. If we manually install the software we are clicking Yes and everithing is fine, the signing certificate is added to the Trusted Publishers certificate store.</div>
<div style="text-align: justify;">
However, when we are deploying the package over Intune this issue will cause the installation to fail with exit <a href="https://support.microsoft.com/en-us/kb/834484" target="_blank">code 1603</a>.</div>
<div style="text-align: justify;">
The way to fix this is to extract the signing certificate and install it in the Trusted Publisher on the target computer or to turn off SmartScreen with a policy, but the second is not a good security practice. The issue is that we cannot deploy cert to the Trusted Publishers store using Intune configuration policy.<br />
My solution is to use PowerShell script that will be deployed and executed over the MDM channel.<br />
The issue is that Intune does not support direct script deployment. There are some articles on the net that are demonstrating how to package batch script in self-extracting executable using <a href="https://haukeberg.wordpress.com/2016/03/02/create-a-gpo-script-for-microsoft-intune/" target="_blank">IExpress</a>.<br />
However we need to wrap PowerShell script in MSI package suitable for MDM deployment.<br />
I think that this is a very useful technique and I will try to put all the peaces together in this post, so you can deploy and run every PowerShell script on Windows 10 MDM PCs.<br />
The easiest(and free) way to do this will be to create a self-extracting exe with IExpress, wrap the exe in MSI and publish it to Intune.<br />
In order to reliably wrap the PS script in exe I used a script that I found in the TechNet Gallery called <a href="https://gallery.technet.microsoft.com/Create-EXEFromps1-Create-efc8436c/">Create-EXEFrom.ps1</a>. It will do a really good job wrapping the PS script and you can also add additional files in the package, like in my case I will need Dell Software certificate that should be installed on the target machine. Below is an example line for wrapping MyApp.ps1 script (this will be name used in all sample code) including the certificate we need.<br />
<hr />
<pre style="background: #1e1e1e; color: #dadada; font-family: "consolas"; font-size: 13;"><span style="color: lightcyan;">.\Create-EXEFrom.ps1</span> <span style="color: moccasin;">-PSScriptPath</span> <span style="color: palevioletred;">"C:\MyApp.ps1"</span> <span style="color: moccasin;">-SupplementalFilePaths</span> <span style="color: palevioletred;">"C:\Certificate.cer"</span>
</pre>
<hr />
<br />
The exe will be created in the same folder and will be called "MyApp.exe".<br />
The tricky part is that our exe and msi package should also be executed without any interaction required, including bypassing of the SmartScreen. This can be done by properly signing both packages with valid code signing certificate. In my case I have used the certificate that we normally use in bluesource for signing mobile apps. In order to sign the packages you can use the <a href="https://msdn.microsoft.com/en-us/library/8s9b9yaz%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396" target="_blank">signtool</a>.<br />
If the signing is successful you should see below in your file properties and you should be able to run the exe without SmartScreen alerts.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://2.bp.blogspot.com/-Qccg1sC-mw8/WCGNFbotHAI/AAAAAAAADuI/6-gPsDvRuAYppPQtBsPdX--S4Y_uDyLgQCLcB/s1600/BlueSource_Cert.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="Publisher Certificate" border="0" height="259" src="https://2.bp.blogspot.com/-Qccg1sC-mw8/WCGNFbotHAI/AAAAAAAADuI/6-gPsDvRuAYppPQtBsPdX--S4Y_uDyLgQCLcB/s640/BlueSource_Cert.JPG" title="Publisher Certificate" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
Now when we have signed exe we should wrap it in MSI package.</div>
<div class="separator" style="clear: both; text-align: justify;">
The easiest free way for me was to use <a href="http://wixtoolset.org/" target="_blank">WiX Toolset</a> to do that. I put together really simple WiX project with only one custom action that will execute the exe. Below you can see the sample xml with the cmd commands I used to compile the WiX project.</div>
<script src="https://gist.github.com/ivanyankulov/605fc5492bb09d2a197efdfe988afcb9.js"></script></div>
If you are new to WiX you should have your WiX bin folder in the PATH variable to make the cmd script work as it is. In my case it is "C:\Program Files (x86)\WiX Toolset v3.10\bin"(I know it is not the newest version).<br />
Note that the package will be installed under the SYSTEM account and you should consider that in your scripts. You can find how to test MSI package in following <a href="https://blogs.technet.microsoft.com/intunesupport/2016/06/13/support-tip-best-practices-for-intune-software-distribution-to-pcs/" target="_blank">article</a>.<br />
Next step is to publish the MSI as "Windows Installer through MDM (*.msi)" installer type as it is shown below.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://2.bp.blogspot.com/-giF3iB2Qrz0/WCGXWbN3ODI/AAAAAAAADuY/wLpt7OojEJwHJYgbTFOqMi9xGRUpArCtQCLcB/s1600/Publish_MSI.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="Intune Publish MSI" border="0" height="443" src="https://2.bp.blogspot.com/-giF3iB2Qrz0/WCGXWbN3ODI/AAAAAAAADuY/wLpt7OojEJwHJYgbTFOqMi9xGRUpArCtQCLcB/s640/Publish_MSI.jpg" title="Intune Publish MSI" width="640" /></a></div>
<br />
The last thing that's left is to deploy the newly published app and maybe running some tests won't be a bad idea :).<br />
<br />
I hope that this non-SharePoint post, written by a SharePoint guy will be helpful!Ivan Yankulovhttp://www.blogger.com/profile/01518276480144054762noreply@blogger.com0tag:blogger.com,1999:blog-2857779700332084475.post-80374458631206270532016-10-14T12:43:00.002+03:002016-10-14T13:53:46.038+03:00Build slider bar graph date time search refiner with custom intervals<div style="text-align: justify;">
A couple of weeks ago I worked with a client that had this requirement for their search center in SharePoint Online. They had a repository with different research documents and these documents had a Publishing Date date/time field with values up to 30 years ago.</div>
<div style="text-align: justify;">
The client wanted to build a result page for this documents and have a slider bar refiner with custom intervals up to 10 years ago. </div>
<div style="text-align: justify;">
If we have a numeric based managed property we can specify a custom refiner interval like the one below.</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-QcrTW9cNam0/V_-CzQlErjI/AAAAAAAADqw/t6jRo23tgv0wu3dgMoqmn_qzjtIN-pfSQCLcB/s1600/Num_refiner.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://1.bp.blogspot.com/-QcrTW9cNam0/V_-CzQlErjI/AAAAAAAADqw/t6jRo23tgv0wu3dgMoqmn_qzjtIN-pfSQCLcB/s1600/Num_refiner.png" /></a></div>
<div style="text-align: justify;">
Unfortunately the Custom option is missing for date and time datatype. We have predefined intervals that are up to one year ago and "Defined in search schema" which I am not sure what is suppose to mean, but this will be the error you will get if you select this option.</div>
<hr />
<span style="color: red;">For this Display Template you must specify custom intervals for the values that will be shown. Please change the refinement settings to use custom intervals.
</span><br />
<hr style="text-align: justify;" />
<div style="text-align: justify;">
It really does not tell us much if you don't have an option to specify custom interval in the UI.</div>
<div style="text-align: justify;">
Luckily if you export the Refinement webpart you can see more refiner settings. All selected refiners are represented as JSON and below are the settings of our Publication Date refiner(formatted).</div>
<div style="text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-uRrnLvJZ98I/V_-M1GEWhaI/AAAAAAAADrA/X8ybLA00ytoPXDBZKq0dYOSteiTg6xjoACLcB/s1600/Publication_Date_Refiner.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="216" src="https://1.bp.blogspot.com/-uRrnLvJZ98I/V_-M1GEWhaI/AAAAAAAADrA/X8ybLA00ytoPXDBZKq0dYOSteiTg6xjoACLcB/s640/Publication_Date_Refiner.JPG" width="640" /></a></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
There are two settings that grab the attention and they are highlighted in the picture above. They are "useDefaultDateIntervals", which obviously means if the default intervals that cover only one year should be used and "intervals" that should represent the custom intervals. After some research on the web I found that the intervals value should be array of integers that are representing the intervals in days. I came up with these intervals for my client: Ten Years Ago, Five Years Ago, Three Years Ago, One Year Ago, Six Months Ago, Three Months Ago, One Month Ago, 7 days Ago and Today. This will be set with flowing intervals value:</div>
<hr />
<div style="text-align: center;">
[-3650,-1825,-1095,-365,-180,-90,-30,-7,0]
</div>
<hr />
The first step will be to update the values for "useDefaultDateIntervals" and "intervals". Set the "useDefaultDateIntervals" to false and for "intervals" use your interval array like the picture below.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://2.bp.blogspot.com/-5Vh9bNEMn9Y/V_-YCcc7aTI/AAAAAAAADrQ/JuiTar2DT-40xGYemnodXD_sN3AKqNKuQCLcB/s1600/Publication_Date_Refiner_custom.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="364" src="https://2.bp.blogspot.com/-5Vh9bNEMn9Y/V_-YCcc7aTI/AAAAAAAADrQ/JuiTar2DT-40xGYemnodXD_sN3AKqNKuQCLcB/s640/Publication_Date_Refiner_custom.JPG" width="640" /></a></div>
<br />
Then you will need to import the webpart and use it in your page. The result is below.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://4.bp.blogspot.com/-w-cjJcsmj0c/V_-ZZcNtxhI/AAAAAAAADrc/PkiZKlNhpZIIEHWkTZHlSr_-1NXz6ZALgCLcB/s1600/Publication_Date_Slider_Bar.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://4.bp.blogspot.com/-w-cjJcsmj0c/V_-ZZcNtxhI/AAAAAAAADrc/PkiZKlNhpZIIEHWkTZHlSr_-1NXz6ZALgCLcB/s1600/Publication_Date_Slider_Bar.JPG" /></a></div>
<br />
<div style="text-align: justify;">
We have our custom intervals and they are working as we expect(at least with me). However we can see one big issue and it is that the intervals are not labeled appropriately. This should be fixed in the refiner display template.</div>
<div style="text-align: justify;">
As it is not a good practice or practical in this case to edit the out of the box display template I created a new display template based on the out of the box "Slider with bar graph".</div>
<div style="text-align: justify;">
In the new template I have specified values for the Label and the NextIntervalLabel of all "filter boundaries". In this example we are going to have 10 boundaries. NextIntervalLabel is used when you move the mouse over the bar and the Label is used for boundary label in the slider. You can see the entire template below.</div>
<script src="https://gist.github.com/ivanyankulov/8612488a61a11b9f34960af3a995a6e6.js"></script><br />
On line 104 we can see how to get all boundaries and their values for Label and NextIntervalLabel.<br />
After deploying and setting the new display template we can see that the labels are much more accurate.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-iWvLjH_z6q4/WACDMCPHO7I/AAAAAAAADrs/HQYfqCmnSgMc4I_SQX6tPKBi6knM7hTQwCLcB/s1600/Publication_Date_Slider_Bar_Custom.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://1.bp.blogspot.com/-iWvLjH_z6q4/WACDMCPHO7I/AAAAAAAADrs/HQYfqCmnSgMc4I_SQX6tPKBi6knM7hTQwCLcB/s1600/Publication_Date_Slider_Bar_Custom.JPG" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div style="text-align: justify;">
There is small detail that should be updated and it is the start and end labels of the bar graph.</div>
Unfortunately my solution to that is to change the text by selecting the elements by class name and this is not the most elegant solution if you have more than one slider bar refiners, in that case you will need to change the index number to get the correct elements. You can see the code below.<br />
<br />
<script src="https://gist.github.com/ivanyankulov/60209ce688ad2cbf2a31e123e1e799cf.js"></script>
With this final touch this is how our custom slider bar graph refiner looks like.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://3.bp.blogspot.com/-s5D_oUesiag/WACIxD-gbfI/AAAAAAAADr8/0Cv-qFZXXxgVh4riKHub4igHaDUICYTLQCLcB/s1600/Publication_Date_Slider_Bar_Final.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://3.bp.blogspot.com/-s5D_oUesiag/WACIxD-gbfI/AAAAAAAADr8/0Cv-qFZXXxgVh4riKHub4igHaDUICYTLQCLcB/s1600/Publication_Date_Slider_Bar_Final.JPG" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
It looks really cool and useful. If you check the refiner settings in the UI now you will see that "Defined in search schema" is selected. I found this misleading since I have done nothing special in the search schema.<br />
<b>I hope that this was helpful!</b>Ivan Yankulovhttp://www.blogger.com/profile/01518276480144054762noreply@blogger.com5tag:blogger.com,1999:blog-2857779700332084475.post-82274044914664300842016-09-06T09:23:00.001+03:002016-09-06T09:23:24.343+03:00Set Managed Metadata field value with PowerShell and CSOM<div style="text-align: justify;">
In the <a href="http://www.sptrenches.com/2016/08/migrate-term-store-to-sharepoint-online.html" target="_blank">previous post</a> I demonstrated an easy way to migrate managed metadata term store objects to SharePoint Online with PowerShell.</div>
<div style="text-align: justify;">
Now when you have migrated the terms you might need to migrate some documents and set the metadata fields in SharePoint Online. In the same project I had to migrate around 600 documents to SPO including the metadata which had 6 managed metadata fields, 4 of them were multi-valued.</div>
<div style="text-align: justify;">
In this post I will share a powershell snipped to make <a href="https://msdn.microsoft.com/en-us/library/microsoft.sharepoint.client.taxonomy.taxonomyfieldvaluecollection.aspx?f=255&MSPPError=-2147217396" target="_blank">TaxonomyFieldValueCollection</a> and use it as value for field of type Managed Metadata.</div>
<div style="text-align: justify;">
I am showing this method because I got some mixed results when I used simple string as value. It is hard for me to explain why simply updating with taxonomy string did not worked in all cases.<br />
For example, if the document was created in Office Web Apps I was unable to set the fields using a simple string. You can try using the string method and then cross-check if everithing is set, because if you feed only metadata string(multi-valued) or just guid(for single-valued) you might not get any error, but the field will be left blank.</div>
<div style="text-align: justify;">
<div style="text-align: justify;">
The challenge for me in the "TaxonomyFieldValueCollection" approach was to create <a href="https://msdn.microsoft.com/en-us/library/microsoft.sharepoint.client.taxonomy.taxonomyfield.aspx" target="_blank">TaxonomyField</a> object instance, because I had to use the generic client context method <a href="https://msdn.microsoft.com/en-us/library/office/ee541159.aspx" target="_blank">CastTo</a> and PowerShell don't work well with generic methods. This is why I decided it is worth sharing this example. You can see the code below.</div>
</div>
<div style="text-align: justify;">
<br /></div>
<script src="https://gist.github.com/ivanyankulov/16b3f7675c413301cfd940a7ff6bb57a.js"></script>
Now a couple of words about the string that is used. In the example above I am setting multi-valued MM field with collection of two terms. The string is in format "<int>;#<label>|<guid> " with ;# delimiter between the terms. The integer is the item id of the term in the <a href="https://blogs.msdn.microsoft.com/spses/2011/11/28/managed-metadata-taxonomy-more/" target="_blank">Taxonomy Hidden List</a>, if you are using the term for first time or you do not know this id you can use the default value "-1".<br />
The label part speaks for itself, this is the label of the term and the most important part is the guid of the term. If something is wrong with the format of the string you will see below error message.<br />
<hr />
<span style="color: red;">"The given value for a taxonomy field was not formatted in the required <int>;#<label>|<guid> format."
</span><br />
<hr />
<br />
This method is working every time for all items. I hope that this was helpful!Ivan Yankulovhttp://www.blogger.com/profile/01518276480144054762noreply@blogger.com0tag:blogger.com,1999:blog-2857779700332084475.post-38035812434351645182016-08-21T17:05:00.001+03:002016-08-21T17:09:24.878+03:00Migrate SharePoint 2010 Term Store to SharePoint Online with PowerShell<div style="text-align: justify;">
Last week I worked with a customer on migrating one SharePoint 2010 site to a new SharePoint Online.</div>
<div style="text-align: justify;">
I can qualify the site as Knowledge Base designed for optimal discoverability of the documents that are uploaded. To achieve a good discoverability you will need some good metadata describing the resources. Many times the metadata that is used is actually managed metadata that needs to be migrated/recreated in SharePoint Online.</div>
<div style="text-align: justify;">
If you have 10 or 20 terms it will not be an issue to recreate them, but if you have 400 for example it will not be very practical to manually recreate all terms.</div>
<div style="text-align: justify;">
There are many powershell scripts out there to export/import terms, but the success rate and the complexity might vary. This is why I would like to share how I did it and it worked out pretty well for me.</div>
<div style="text-align: justify;">
For the purpose we are going use the custom cmdlets provided for free by <a href="http://blog.falchionconsulting.com/index.php/downloads/" target="_blank">Gary Lapointe</a>.</div>
<div style="text-align: justify;">
For demonstration purposes I will export one term set group with one term set that has limited number of terms. You can check it out below, it also has some parent/child terms.</div>
<div style="text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://2.bp.blogspot.com/-hZkZh2BLm1I/V7gfIiX11LI/AAAAAAAADfo/yqWOq-QI-5IdPjJVyQxafbJzz2UMsGnYACLcB/s1600/2010_Terms.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="SharePoint 2010 Term Store" border="0" height="181" src="https://2.bp.blogspot.com/-hZkZh2BLm1I/V7gfIiX11LI/AAAAAAAADfo/yqWOq-QI-5IdPjJVyQxafbJzz2UMsGnYACLcB/s400/2010_Terms.JPG" title="SharePoint 2010 Term Store" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
In order to export the term set group you will need to deploy the WSP that will add the custom <a href="http://blog.falchionconsulting.com/index.php/downloads/" target="_blank">SharePoint Server 2010</a> commands. By doing so you will add the <a href="http://www.falchionconsulting.com/PowerShellViewer/Default.aspx" target="_blank">additional 2010 commands</a> directly to the Microsoft.SharePoint.PowerShell snap-in.</div>
<div class="separator" style="clear: both; text-align: justify;">
To export taxonomy object as xml we are going to use <a href="http://www.falchionconsulting.com/PowerShellViewer/Default.aspx?Version=SP2010&Cmdlet=Export-SPTerms" target="_blank">Export-SPTerms</a>. You will need to supply some taxonomy object as input parameter, this will be a taxonomy session if you want to export everything, for more examples see the cmdlet help. You can see how the Legal term set group looks as xml below.</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://3.bp.blogspot.com/-hE8Lms0yF8Q/V7lx-AtNk5I/AAAAAAAADgs/o__8cyhAXPEBw9Y8hMEVZrYrHGwKnEdjgCLcB/s1600/2010_Terms_XML.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="Input XML" border="0" height="182" src="https://3.bp.blogspot.com/-hE8Lms0yF8Q/V7lx-AtNk5I/AAAAAAAADgs/o__8cyhAXPEBw9Y8hMEVZrYrHGwKnEdjgCLcB/s400/2010_Terms_XML.JPG" title="Input XML" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
As you can see all essential information that is needed is exported, even some that will be an issue if you are importing the terms to a different environment or SharePoint Online. This is the Owner or every attribute that represents on-prem identity that you might have. The import command will also try to set this properties with the same values and it will fail because the identity as it was exported cannot be found. The way to workaround this is just to set different value for Owner that will be a valid Online identity. Now it is up to you to decide if you want to do this tradeoff and migrate the objects with different Owner than the source. Below are two lines (3 to make it fit better) that will take the content of the exported XML and will set new Owner for each XML node where the Owner attribute is not empty and later the same XML object can be used for input of the import command.</div>
<hr />
<pre style="background: #1e1e1e; color: gainsboro; font-family: "consolas"; font-size: 13;"><span style="color: lightgrey;">[</span><span style="color: darkseagreen;">xml</span><span style="color: lightgrey;">]</span><span style="color: orangered;">$termXML</span> <span style="color: lightgrey;">=</span> <span style="color: lightcyan;">Get-Content</span> <span style="color: palevioletred;">"C:\Legal.xml"</span>
<span style="color: whitesmoke;">(</span><span style="color: orangered;">$termXML</span><span style="color: lightgrey;">.</span><span style="color: whitesmoke;">SelectNodes</span><span style="color: whitesmoke;">(</span><span style="color: palevioletred;">"//*"</span><span style="color: whitesmoke;">))</span> <span style="color: lightgrey;">|</span> <span style="color: lightcyan;">Where</span> <span style="color: whitesmoke;">{</span><span style="color: orangered;">$_</span><span style="color: lightgrey;">.</span><span style="color: whitesmoke;">Owner</span> <span style="color: lightgrey;">-ne</span> <span style="color: orangered;">$null</span><span style="color: whitesmoke;">}</span> <span style="color: lightgrey;">|</span> <span style="color: whitesmoke;">`
</span><span style="color: lightcyan;">ForEach-Object</span> <span style="color: whitesmoke;">{</span><span style="color: orangered;">$_</span><span style="color: lightgrey;">.</span><span style="color: whitesmoke;">SetAttribute</span><span style="color: whitesmoke;">(</span><span style="color: palevioletred;">"Owner"</span><span style="color: lightgrey;">,</span> <span style="color: palevioletred;">"i:0#.f|membership|admin@MOD******.onmicrosoft.com"</span><span style="color: whitesmoke;">)}</span></pre>
<hr />
<div style="text-align: left;">
To import the taxonomy objects in SPO you will need to download and install the <a href="http://blog.falchionconsulting.com/index.php/downloads/" target="_blank">SharePoint Online Custom Cmdlets</a>. </div>
<div style="text-align: left;">
This will actually install a new module called Lapointe.SharePointOnline.PowerShell.</div>
<div style="text-align: justify;">
The command that we are going to use for the import is <a href="http://www.falchionconsulting.com/PowerShellViewer/Default.aspx?Version=SPO&Cmdlet=Import-SPOTaxonomy" target="_blank">Import-SPOTaxonomy</a>. For InputFile parameter we are going to use the variable from the above lines after we have set all identity attributes. If you are importing an object that is not a top level term store you should specify ParentTermStore(can get it with Get-SPOTermStore), if not you should switch on the parameter "Tenant". Before all that, you should connect to a site in your target tenant using <a href="http://www.falchionconsulting.com/PowerShellViewer/Default.aspx?Version=SPO&Cmdlet=Connect-SPOSite" target="_blank">Connect-SPOSite</a>. Below are the lines to import the Legal term set group.</div>
<hr />
<pre style="background: #1e1e1e; color: gainsboro; font-family: "consolas"; font-size: 13;"><span style="color: lightcyan;">Connect-SPOSite</span> <span style="color: moccasin;">-Url</span> <span style="color: palevioletred;">"https://mod******.sharepoint.com"</span>
<span style="color: lightcyan;">Import-SPOTaxonomy</span> <span style="color: moccasin;">-InputFile</span> <span style="color: orangered;">$termXML</span> <span style="color: moccasin;">-ParentTermStore</span> <span style="color: whitesmoke;">(</span><span style="color: lightcyan;">Get-SPOTermStore</span><span style="color: whitesmoke;">)</span></pre>
<hr />
<div style="text-align: justify;">
And this is it. Our Legal term set group is recreated and available in the entire tenant. One nice thing is that the GUIDs will be copied as well.</div>
<div style="text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://3.bp.blogspot.com/-JM15gjjFhh8/V7m15TRX-bI/AAAAAAAADhM/a8oCrggqTHEw-izJetIDcIoS2iJf9hgmwCLcB/s1600/SPO_Terms.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="SharePoint Online Term Store" border="0" height="265" src="https://3.bp.blogspot.com/-JM15gjjFhh8/V7m15TRX-bI/AAAAAAAADhM/a8oCrggqTHEw-izJetIDcIoS2iJf9hgmwCLcB/s400/SPO_Terms.JPG" title="SharePoint Online Term Store" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
I hope that this was helpful and big thanks to Gary Lapointe for writing this great tools! The same approach should work for SharePoint 2013, but I have not tested this.</div>
<div style="text-align: justify;">
<br /></div>
Ivan Yankulovhttp://www.blogger.com/profile/01518276480144054762noreply@blogger.com2tag:blogger.com,1999:blog-2857779700332084475.post-71900805393563876262016-08-01T19:51:00.003+03:002016-08-01T19:51:43.334+03:00Display related item repeating section in Nintex Workflow task form <div style="text-align: justify;">
Last week I worked with a customer that had repeating sections in Nintex Forms 2013 item form and Nintex Workflow 2013 workflow associated with the list. The customer had the requirement to be able to properly display the repeating section data in the workflow task forms. This requirement does not seems to be a straightforward to accomplish, but in this post I am going to demonstration that this is actually very simple and since I haven't found this in other sources I am sharing my solution and other useful links in this post.</div>
<div style="text-align: justify;">
The issue with the repeating section is that it is living as "section"only in the form. You can connect the entire repeating section to a field with type "Multiple lines of text" and you will see that our repeating section value is actually saved as XML.</div>
<div style="text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://2.bp.blogspot.com/-ceaxtnM8_q8/V5743hX3HzI/AAAAAAAADdA/XfsWnt25DDUF5xiElhtijuSBItCFx-GegCLcB/s1600/Repeating_Section.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="Nintex Repeating Section" border="0" height="126" src="https://2.bp.blogspot.com/-ceaxtnM8_q8/V5743hX3HzI/AAAAAAAADdA/XfsWnt25DDUF5xiElhtijuSBItCFx-GegCLcB/s640/Repeating_Section.JPG" title="Nintex Repeating Section" width="640" /></a></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
The item actually looks like this:</div>
<div style="text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://2.bp.blogspot.com/-crLUECEvPv8/V575oz4G9YI/AAAAAAAADdI/g7RJv1NeG9onzbJa4GlFl63oobQglpdzgCLcB/s1600/Nintex_Repeating_Section%2B_Form.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="Nintex Repeating Section Form" border="0" height="290" src="https://2.bp.blogspot.com/-crLUECEvPv8/V575oz4G9YI/AAAAAAAADdI/g7RJv1NeG9onzbJa4GlFl63oobQglpdzgCLcB/s400/Nintex_Repeating_Section%2B_Form.JPG" title="Nintex Repeating Section Form" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div style="text-align: justify;">
The first nice thing that is not directly related to the title of this post is to make the XML data looks better in List View. To accomplish this I am going to use the CSR (Client-side rendering) approach demonstrated in this post <a href="https://community.nintex.com/community/tech-blog/blog/2015/12/18/displaying-repeating-section-as-table-in-list-view-with-csr" target="_blank">"Displaying Repeating Section as table in List View - the CSR approach"</a>. Adapting and applying the script to my list view gives me below result that is way better than the XML.</div>
<div style="text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://4.bp.blogspot.com/-shcrG2UZbvY/V57_8YcA_hI/AAAAAAAADdY/ynDDlZqEvLsYgjL2yAaShK_Mv9UQNbAqQCLcB/s1600/Repeating_Section_CSR.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="Repeating Section CSR" border="0" height="235" src="https://4.bp.blogspot.com/-shcrG2UZbvY/V57_8YcA_hI/AAAAAAAADdY/ynDDlZqEvLsYgjL2yAaShK_Mv9UQNbAqQCLcB/s400/Repeating_Section_CSR.JPG" title="Repeating Section CSR" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
The way to make sense out of the repeating section in workflow is by querying the XML from the field. I will not go in dept since there are many resource on the subject. One thing that can help you in this task is this article <a href="http://www.vadimtabakman.com/nintex-formsworkflow-parsing-repeating-section-data.aspx" target="_blank">"Nintex Forms/Workflow - Parsing Repeating Section Data"</a> by Vadim Tabakman.</div>
<div style="text-align: justify;">
<b>Now to the reason to write this post. </b>If you have tasks in your workflow it will not be unusual you or your customer/users to want to see the related item properties right in the task form instead clicking on links. If you leave the form as it is, the best you can get is to view the repeating section as XML. You can edit the task forms with Nintex Forms for most of the task templates you will get a good starting point and all item properties controls will be created. However check out how this controls look like in three common tasks. From left to right Flexi Task, Request review and Request data.</div>
<div style="text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-dN4B5s72tBs/V59cWm6vKhI/AAAAAAAADdo/ikU-KFgCU2Aid5Xdb1Y-4ammRsMt5bX4wCLcB/s1600/Task_Forms.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="Nintex Task Forms" border="0" height="207" src="https://1.bp.blogspot.com/-dN4B5s72tBs/V59cWm6vKhI/AAAAAAAADdo/ikU-KFgCU2Aid5Xdb1Y-4ammRsMt5bX4wCLcB/s400/Task_Forms.JPG" title="Nintex Task Forms" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
As you can see the data from the repeating section is displayed as XML. Even in the "Request data" template where I have used "List item" control to display the related item. </div>
<div class="separator" style="clear: both; text-align: justify;">
This was also the case with the customer, they had many "Request data" tasks and all of them were using "List item" control to display the related item.</div>
<div class="separator" style="clear: both; text-align: justify;">
The solution to this is very simple, just create a new repeating section in the task form, <b>recreate all child controls by replicating the data type and the Name of the controls. </b>Then connect the repeating section control to the related item field that contains the XML from the related item. Checkout how a Flexi task looks like if you recreate the repeating section as described.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://4.bp.blogspot.com/-67ZfjLJNuDY/V59qHaPFgOI/AAAAAAAADd4/nqtyrB8ZwqgyQjqP5oc025ctrskpueLdACLcB/s1600/Flexi_Task_Form.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="Flexi Task Form" border="0" height="400" src="https://4.bp.blogspot.com/-67ZfjLJNuDY/V59qHaPFgOI/AAAAAAAADd4/nqtyrB8ZwqgyQjqP5oc025ctrskpueLdACLcB/s400/Flexi_Task_Form.JPG" title="Flexi Task Form" width="382" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div style="text-align: justify;">
The data from the repeating section in the related item is represented as repeating section in the task form as well. Just make sure that the names of the controls are as in the original item, make the repeating section read only in the task form and you will be completely fine.</div>
<div style="text-align: justify;">
I tested the same approach in SharePoint 2016 and Office 365. However something interesting is happening with the XML as you can see in the screenshot below (the field is called Rep)</div>
<div style="text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://4.bp.blogspot.com/-Kq9F7GYfDow/V598Eu-Vt8I/AAAAAAAADeI/BmSGCGkOg9EPhKZQFWB1is772Rlq_FcNwCLcB/s1600/Task_Form_SPO.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="Task Form Office 365" border="0" height="320" src="https://4.bp.blogspot.com/-Kq9F7GYfDow/V598Eu-Vt8I/AAAAAAAADeI/BmSGCGkOg9EPhKZQFWB1is772Rlq_FcNwCLcB/s320/Task_Form_SPO.JPG" title="Task Form Office 365" width="279" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div style="text-align: justify;">
The important thing is that the repeating section is visualized as expected. If I found what is happening with the XML might blog about it.</div>
<div style="text-align: justify;">
<b>I hope that this was helpful! </b></div>
Ivan Yankulovhttp://www.blogger.com/profile/01518276480144054762noreply@blogger.com1tag:blogger.com,1999:blog-2857779700332084475.post-71701000825378204532016-06-27T10:36:00.000+03:002016-06-27T10:36:57.967+03:00Useful file handling commands in the SharePoint PnP PowerShell module<div style="text-align: justify;">
Last week I got a request from one of our customers to help them to move some of the files from one SharePoint library to another in different web. Sounds an easy and quick task, but the catch was that the library had ~ 12000 documents and 1500 folders and the customer also wanted to keep the Created, Created by, Modified and Modified by column values. The number of items that had to be moved was ~ 3500. Pointless to say that with such number of items the Explorer view is not working, the new OneDrive client does not support sync from SharePoint libraries yet and I still had to figure out how to effectively copy the metadata. The way to accomplish this is with PowerShell or with 3rd party migration tool. Since the customer had only this requirements and not migration of the version history for example, my weapon of choice was powershell.</div>
<div style="text-align: justify;">
In this post I wont to share a couple of <a href="https://github.com/OfficeDev/PnP-PowerShell" target="_blank">SharePoint PnP PowerShell</a> cmdlets that greatly helped me in writing my migration script. <a href="http://www.bluesource.co.uk/" target="_blank">Bluesource</a> is also a contributor to the PnP project, thanks to my colleague <a href="https://veenstra.me.uk/" target="_blank">Pieter Veenstra</a>.</div>
<div style="text-align: justify;">
The first thing I want to share is a new feature that came with the June 2016 release. It is the option to map SharePoint site as PSDrive. This is done at the begging using Connect-SPOnline with CreateDrive parameter. You will then get a PSDrive called SPO and a PSProvider also called SPO. See how it looks below.</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://3.bp.blogspot.com/-nXVw3Fup7m0/V3AKuWDl9xI/AAAAAAAADYI/uSK0mBx7p7wJEN8i5AQ5ypykVwJJ-TUvgCLcB/s1600/SPO_PSDrive.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="400" src="https://3.bp.blogspot.com/-nXVw3Fup7m0/V3AKuWDl9xI/AAAAAAAADYI/uSK0mBx7p7wJEN8i5AQ5ypykVwJJ-TUvgCLcB/s400/SPO_PSDrive.JPG" width="395" /></a></div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
As mentioned above you will connect to the <b>site </b>and you will be looking at the root web. The sub webs will be shown as folders. You can do many standard things in this PSDrive like listing items, copy, move and more. One thing I was unable to do is listing the items in lists with 5000+ items, it seems that the view threshold limitation is kicking in. The other thing is copy items from SPO drive to the local file system, this is because you cannot copy items from one drive to another if the PSProviders are different. Also it would have been nice if this SPO drive is persistent and you can access it in Windows Explorer, this is not available and I am not sure if it is possible. </div>
<div class="separator" style="clear: both; text-align: justify;">
I did not used this in my script, but I think that it is nice to have and you can learn more about this and other improvements in the <a href="https://channel9.msdn.com/blogs/OfficeDevPnP/Office-365-Developer--SharePoint-Patterns-and-Practices-June-2016-Community-Call" target="_blank">June 2016 Community Call</a>.</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
<b>Get-SPOFile</b> - This is one very useful command that will help you to download a file by supplying the server relative url to it. This was easy task after I retrieved all items and their FileLeafRef and FileDirRef fields using the technique from my <a href="http://spyankulov.blogspot.bg/2016/06/get-all-items-in-5000-large-list-with.html" target="_blank">previous post</a>. </div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
<b>Ensure-SPOFolder</b> - With this command you can get a folder by giving a <b>web relative url </b>to the folder. If the folder does not exist it will create it even if the folder is nested in other non-existing folders, they will be created as well.</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
<b>Add-SPOFile</b> - With this command you can upload a file by supplying <b>web relative url </b>of the folder, the file will be uploaded with the same name. If the folder does not exist this command will create it before uploading the file. Really nice command!</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
I hope that this was helpful!</div>
Ivan Yankulovhttp://www.blogger.com/profile/01518276480144054762noreply@blogger.com0tag:blogger.com,1999:blog-2857779700332084475.post-55651364648662674692016-06-20T08:58:00.000+03:002016-06-20T08:58:18.460+03:00Get All Items in 5000+ large list with CSOM in PowerShell<div style="text-align: justify;">
Last week I had to write a script that needed to take all items in large SharePoint Online list.</div>
<div style="text-align: justify;">
By large I mean above 5000 items. This means that the list is above the list view threshold in SharePoint Online, which is 5000 and we cannot change that. The way to get all items in SharePoint Online is to use CAML query. However if it is just an empty query without any filtering it will fail, if you use unindexed column for filtering or ordering the query will fail, if you filter/order by indexed column and the query returns more than 5000 items it will fail again. The error in this and other scenarios is similar to the one below.<br />
<hr />
<span style="color: red;">Exception calling "ExecuteQuery" with "0" argument(s): "The attempted operation is prohibited because it exceeds the list view threshold enforced by
the administrator."
</span><br />
<hr />
The way to workaround this is pagination of the view. This means that we will have a row limit of the result that the query can return that should be less or equal to 5000. Once we get the first 5000 items we can do another query for the next 5000 starting from the position where the first result(page) ends. This is the same with what we do in the UI scrolling foreword in the list view. Below is an example PowerShell snippet that will take all items from a list using 5000 items page size ordering the items by ID.<br />
<br />
<pre style="background: #1e1e1e; color: gainsboro; font-family: "consolas"; font-size: 13;"><span style="color: orangered;">$list</span> <span style="color: lightgrey;">=</span> <span style="color: orangered;">$ctx</span><span style="color: lightgrey;">.</span><span style="color: whitesmoke;">Web</span><span style="color: lightgrey;">.</span><span style="color: whitesmoke;">Lists</span><span style="color: lightgrey;">.</span><span style="color: whitesmoke;">GetByTitle</span><span style="color: whitesmoke;">(</span><span style="color: orangered;">$DocLibName</span><span style="color: whitesmoke;">)</span>
<span style="color: orangered;">$ctx</span><span style="color: lightgrey;">.</span><span style="color: whitesmoke;">Load</span><span style="color: whitesmoke;">(</span><span style="color: orangered;">$list</span><span style="color: whitesmoke;">)</span>
<span style="color: orangered;">$ctx</span><span style="color: lightgrey;">.</span><span style="color: whitesmoke;">ExecuteQuery</span><span style="color: whitesmoke;">(</span><span style="color: whitesmoke;">)</span>
<span style="color: palegreen;">## View XML</span>
<span style="color: orangered;">$qCommand</span> <span style="color: lightgrey;">=</span> <span style="color: palevioletred;">@"
<View Scope="RecursiveAll">
<Query>
<OrderBy><FieldRef Name='ID' Ascending='TRUE'/></OrderBy>
</Query>
<RowLimit Paged="TRUE">5000</RowLimit>
</View>
"@</span>
<span style="color: palegreen;">## Page Position</span>
<span style="color: orangered;">$position</span> <span style="color: lightgrey;">=</span> <span style="color: orangered;">$null</span>
<span style="color: palegreen;">## All Items</span>
<span style="color: orangered;">$allItems</span> <span style="color: lightgrey;">=</span> <span style="color: whitesmoke;">@(</span><span style="color: whitesmoke;">)</span>
<span style="color: lightcyan;">Do</span><span style="color: whitesmoke;">{</span>
<span style="color: orangered;">$camlQuery</span> <span style="color: lightgrey;">=</span> <span style="color: lightcyan;">New-Object</span> <span style="color: violet;">Microsoft.SharePoint.Client.CamlQuery</span>
<span style="color: orangered;">$camlQuery</span><span style="color: lightgrey;">.</span><span style="color: whitesmoke;">ListItemCollectionPosition</span> <span style="color: lightgrey;">=</span> <span style="color: orangered;">$position</span>
<span style="color: orangered;">$camlQuery</span><span style="color: lightgrey;">.</span><span style="color: whitesmoke;">ViewXml</span> <span style="color: lightgrey;">=</span> <span style="color: orangered;">$qCommand</span>
<span style="color: palegreen;">## Executing the query</span>
<span style="color: orangered;">$currentCollection</span> <span style="color: lightgrey;">=</span> <span style="color: orangered;">$list</span><span style="color: lightgrey;">.</span><span style="color: whitesmoke;">GetItems</span><span style="color: whitesmoke;">(</span><span style="color: orangered;">$camlQuery</span><span style="color: whitesmoke;">)</span>
<span style="color: orangered;">$ctx</span><span style="color: lightgrey;">.</span><span style="color: whitesmoke;">Load</span><span style="color: whitesmoke;">(</span><span style="color: orangered;">$currentCollection</span><span style="color: whitesmoke;">)</span>
<span style="color: orangered;">$ctx</span><span style="color: lightgrey;">.</span><span style="color: whitesmoke;">ExecuteQuery</span><span style="color: whitesmoke;">(</span><span style="color: whitesmoke;">)</span>
<span style="color: palegreen;">## Getting the position of the previous page</span>
<span style="color: orangered;">$position</span> <span style="color: lightgrey;">=</span> <span style="color: orangered;">$currentCollection</span><span style="color: lightgrey;">.</span><span style="color: whitesmoke;">ListItemCollectionPosition</span>
<span style="color: palegreen;"># Adding current collection to the allItems collection</span>
<span style="color: orangered;">$allItems</span> <span style="color: lightgrey;">+=</span> <span style="color: orangered;">$currentCollection</span>
<span style="color: whitesmoke;">}</span>
<span style="color: palegreen;"># the position of the last page will be Null</span>
<span style="color: lightcyan;">Until</span><span style="color: whitesmoke;">(</span><span style="color: orangered;">$position</span> <span style="color: lightgrey;">-eq</span> <span style="color: orangered;">$null</span><span style="color: whitesmoke;">)</span> </pre>
</div>
<br />
<div style="text-align: justify;">
Few word about the query, I am using RecursiveAll because I used it against library and I wanted to get all items in all folders, the size of the page is 5000, just on the edge of the threshold and I am ordering the result by ID because this column is always indexed.</div>
<div style="text-align: justify;">
I am using Do-Until loop to get all pages and setting the position to be the position of the last item collection that was retrieved.</div>
This is really a powerful and quick way to workaround the annoying 5000 list view threshold. I hope you find it useful!Ivan Yankulovhttp://www.blogger.com/profile/01518276480144054762noreply@blogger.com12tag:blogger.com,1999:blog-2857779700332084475.post-53617048352459779042016-06-12T18:41:00.002+03:002016-06-12T18:41:52.716+03:00Disable SharePoint Event Firing in PowerShell process<div style="text-align: justify;">
Last week I worked with a customer that is using SharePoint 2010 as part of their enterprise DMS solution. Only a small part of the users are accessing the SharePoint sites directly, but they are accessing and adding documents using 3rd party Outlook integration product and in-house legacy LOB system integrations with SharePoint. If you have dealt with such DMS solutions(which is not uncommon in some industries) you will know that during the exploitation you might end up with a complex folder structures created based on the document metadata. You might also end up with large numbers of empty folders.</div>
<div style="text-align: justify;">
The empty folders are an issue for my customer and they reached me with a request to write a PowerShell cleanup script that will run on schedule and will delete the empty folders.</div>
<div style="text-align: justify;">
The catch is that there is an ItemDeleting event receiver that is preventing the deletion of any item including folders. You can see in my dev. machine a similar event receiver in action. It is also stopping the operation when I call Recycle() on item in PowerShell.</div>
<div style="text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-byzBAjDJ8Co/V11YJ1SdgeI/AAAAAAAADXU/OJAdVH4ses0C1TasF9EtNl0mQo0YtffzACLcB/s1600/Unable_To_Delete_Document.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" height="324" src="https://1.bp.blogspot.com/-byzBAjDJ8Co/V11YJ1SdgeI/AAAAAAAADXU/OJAdVH4ses0C1TasF9EtNl0mQo0YtffzACLcB/s640/Unable_To_Delete_Document.JPG" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
If you are a developer, most probably you know how to disable the event firing inside an event receiver in order to prevent the firing of other event receivers. This is done by setting the value of property <a href="https://msdn.microsoft.com/en-us/library/microsoft.sharepoint.speventreceiverbase.eventfiringenabled.aspx" target="_blank">SPItemEventReceiver.EventFiringEnabled</a>. We can do the same thing in powershell with below code and prevent any events from being fired.</div>
<div class="separator" style="clear: both; text-align: justify;">
<br /></div>
<pre style="background: #1e1e1e; color: gainsboro; font-family: "consolas"; font-size: 13;"><span style="color: orangered;">$assembly</span> <span style="color: lightgrey;">=</span> <span style="color: lightgrey;">[</span><span style="color: darkseagreen;">Reflection.Assembly</span><span style="color: lightgrey;">]::</span><span style="color: whitesmoke;">LoadWithPartialName</span><span style="color: whitesmoke;">(</span><span style="color: palevioletred;">"Microsoft.SharePoint"</span><span style="color: whitesmoke;">)</span><span style="color: whitesmoke;">;</span>
<span style="color: orangered;">$type</span> <span style="color: lightgrey;">=</span> <span style="color: orangered;">$assembly</span><span style="color: lightgrey;">.</span><span style="color: whitesmoke;">GetType</span><span style="color: whitesmoke;">(</span><span style="color: palevioletred;">"Microsoft.SharePoint.SPEventManager"</span><span style="color: whitesmoke;">)</span><span style="color: whitesmoke;">;</span>
<span style="color: orangered;">$prop</span> <span style="color: lightgrey;">=</span> <span style="color: orangered;">$type</span><span style="color: lightgrey;">.</span><span style="color: whitesmoke;">GetProperty</span><span style="color: whitesmoke;">(</span><span style="color: lightgrey;">[</span><span style="color: darkseagreen;">string</span><span style="color: lightgrey;">]</span><span style="color: palevioletred;">"EventFiringDisabled"</span><span style="color: lightgrey;">,</span><span style="color: whitesmoke;">`
</span><span style="color: lightgrey;">[</span><span style="color: darkseagreen;">System.Reflection.BindingFlags</span><span style="color: lightgrey;">]</span> <span style="color: whitesmoke;">`
</span><span style="color: whitesmoke;">(</span><span style="color: lightgrey;">[</span><span style="color: darkseagreen;">System.Reflection.BindingFlags</span><span style="color: lightgrey;">]::</span><span style="color: whitesmoke;">NonPublic</span> <span style="color: lightgrey;">-bor</span> <span style="color: lightgrey;">[</span><span style="color: darkseagreen;">System.Reflection.BindingFlags</span><span style="color: lightgrey;">]::</span><span style="color: whitesmoke;">Static</span><span style="color: whitesmoke;">))</span><span style="color: whitesmoke;">;</span>
<span style="color: palegreen;">#SET EVENT FIRING DISABLED.</span>
<span style="color: orangered;">$prop</span><span style="color: lightgrey;">.</span><span style="color: whitesmoke;">SetValue</span><span style="color: whitesmoke;">(</span><span style="color: orangered;">$null</span><span style="color: lightgrey;">,</span> <span style="color: orangered;">$true</span><span style="color: lightgrey;">,</span> <span style="color: orangered;">$null</span><span style="color: whitesmoke;">)</span><span style="color: whitesmoke;">;</span>
<span style="color: palegreen;"><#
DO WHAT YOU NEED TO DO
#></span>
<span style="color: palegreen;">#SET EVENT FIRING ENABLED.</span>
<span style="color: orangered;">$prop</span><span style="color: lightgrey;">.</span><span style="color: whitesmoke;">SetValue</span><span style="color: whitesmoke;">(</span><span style="color: orangered;">$null</span><span style="color: lightgrey;">,</span> <span style="color: orangered;">$false</span><span style="color: lightgrey;">,</span> <span style="color: orangered;">$null</span><span style="color: whitesmoke;">)</span><span style="color: whitesmoke;">;</span> </pre>
<br />
<div style="text-align: justify;">
This code will disable the event firing in the current PowerShell thread and I am able to delete/recycle any item without executing the event handler. I have tested this with SharePoint 2010 and 2013, haven't tested it on SharePoint 2016, but I assume that it will work there too.</div>
<b>This is very powerful technique use it carefully on your own responsibility. </b>I hope that this was helpfull!Ivan Yankulovhttp://www.blogger.com/profile/01518276480144054762noreply@blogger.com0tag:blogger.com,1999:blog-2857779700332084475.post-84442370988074976822016-05-15T20:20:00.001+03:002016-05-15T20:24:58.483+03:00Pause a Nintex workflow for less than 5 minutes in SharePoint Server and Office 365 Last week I spent almost 2 days fixing a complex Nintex/SharePoint 2013 issue with one of our customers. The customer was not very big in terms of headcount, but they were using Nintex workflow to automate all sorts of processes(one of the biggest I have worked with).<br />
There were Workflow timer jobs stucking/failing, workflows exiting with errors for no obvious reason and more. The issue was resolved with a couple of fixes and at least the workflows were executed when they should and were ending as they were designed to.<br />
Some of the issues and improvement points I flagged were: not properly scaled Nintex deployment, incorrect service topology, outdated product versions and poor workflow design.<br />
Now, the fourth (poor workflow design) was partially dictated by the inadequate scale of the deployment. They were using a lot Pause and Commit pending changes actions. Many of the workflows were designed to have two minute pause after the first couple of actions.<br />
As maybe you know the pause action actually pauses the workflow instance for the defined period of time, but the workflow will not resume immediately, it will be resumed when the "Workflow" Timer Job is executed. The default schedule of this job is every 5 minutes. This means that you cannot pause a workflow for less than 5 minutes or pause it for exactly the time you have set. You can change the schedule of the Workflow timer job to workaround the first limitation, but this can put additional load on your system.<br />
This is why I demonstrated an alternative of the Pause action that do not pause the workflow instance, but just waits a certain amount of time before continuing the execution. I have not seen this approach in other sources and this is why I decided to share and explain it in this post.<br />
There is another alternative to pause a workflow for less than 5 minutes. It is described in this <a href="https://community.nintex.com/community/build-your-own/blog/2015/03/04/how-to-pause-a-workflow-for-less-than-5-minutes" target="_blank">article</a>.<br />
As you can see this alternative requires <a href="https://community.nintex.com/community/build-your-own/blog/2015/10/06/ntx-powershell-action-stable-release" target="_blank">"NTX PowerShell Action"</a>. This is great, but this action is open source, it is deployed with Farm solution and although developed and published by Nintex Employee this addon is not backed and supported by Nintex. The PowerShell action is fantastic, but in my opinion it is not worth to deploy it just to use it as Pause alternative. Also you cannot use it in Office 365(SharePoint Online).<br />
The PowerShell example works by executing the powershell code that will just wait a certain amount of time, then it will continue the execution. Obviously to pause a workflow we need to do some sort of waiting. There is no out of the box action that just waits, as we know Pause action is not doing anything, but actually idling the instance execution at certain point and waits for the timer job to resume it after the time is elapsed. With the powershell example we use the powershell (.Net) framework to achieve wating without doing anything for certain time. The same thing can be achieved with <a href="https://msdn.microsoft.com/en-us/library/ms187331.aspx" target="_blank">T-SQL statement</a> execution and in Nintex Workflow both On-Prem. and Office 365 we have "<b>Execute SQL</b>" action.<br />
If we want to put a wait in our SQL query for two minutes we can use the code below:<br />
<hr />
<div style="text-align: center;">
<span style="color: red;">WAITFOR DELAY '00:02'
</span></div>
<hr />
I am not a SQL guy and was surprised to find out that this statement works outside of the SQL Management tools.<br />
Below is the designer look of my demo workflow in SharePoint 2013. This should also work for SharePoint/Nintex 2010.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://4.bp.blogspot.com/-k6lbsjxX7is/VzhVyiBIPsI/AAAAAAAADU8/Bx0bh3yfgpc4j7XiHnd5_-nzPraaKcfTACLcB/s1600/SQL_Pause_2013.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="WorkflowDesigner" border="0" height="331" src="https://4.bp.blogspot.com/-k6lbsjxX7is/VzhVyiBIPsI/AAAAAAAADU8/Bx0bh3yfgpc4j7XiHnd5_-nzPraaKcfTACLcB/s640/SQL_Pause_2013.JPG" title="Pause Workflow for less than 5 minutes" width="640" /></a></div>
<br />
As you can see it is pretty simple just for PoC. Below is the configuration of the "Execute SQL" action.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://4.bp.blogspot.com/-Iy32T7wO8vc/Vzhh-o0bKbI/AAAAAAAADVM/eqMh6aOKAJM3_V0cuOvthBmgEKuK77bggCLcB/s1600/Execute_SQL_Configuration_2013.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="Execute SQL Action Configuration" border="0" height="400" src="https://4.bp.blogspot.com/-Iy32T7wO8vc/Vzhh-o0bKbI/AAAAAAAADVM/eqMh6aOKAJM3_V0cuOvthBmgEKuK77bggCLcB/s400/Execute_SQL_Configuration_2013.JPG" title="Execute SQL Action Configuration" width="396" /></a></div>
<br />
I am using a connection string that is using "SQL" as server, this is alias to the SQL instance that hosts my SharePoint, I am using SSPI security with Windows credential that are actually my farm account saved as global constant.<br />
Below are the details from the execution. You can see that Execute SQL actions took exactly 2 minutes to complete.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-OHTh_zAL-lQ/VzhjviW7DLI/AAAAAAAADVY/pTamGVdlvtIim-VQGUwOSmylOWOuZwcAQCLcB/s1600/Pause_Execute_SQL_Details_2013.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="Workflow Execution Detail" border="0" height="174" src="https://1.bp.blogspot.com/-OHTh_zAL-lQ/VzhjviW7DLI/AAAAAAAADVY/pTamGVdlvtIim-VQGUwOSmylOWOuZwcAQCLcB/s640/Pause_Execute_SQL_Details_2013.JPG" title="Workflow Execution Detail" width="640" /></a></div>
Unfortunately you cannot use this approach on-premise for pauses longer than 5 minutes without doing a loop and in this loop execute multiple times delays that are less than 5 minutes. If you do set delay more than 5 minutes the workflow will fail with error <i>"Error performing database operation. Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding." </i>even if you set connection timeout in the connection string to be more than the 5 minute delay. I will do some more tests/research and might report this as bug.<br />
<br />
As described in the MSDN documentation of the <a href="https://msdn.microsoft.com/en-us/library/ms187331.aspx" target="_blank">WAITFOR</a> statement, it should work against Azure SQL Database. In Nintex workflow for Office 365 we also have <a href="https://community.nintex.com/community/tech-blog/blog/2015/01/22/fill-your-sql-boots-new-execute-sql-action-for-o365" target="_blank">Execute SQL</a> action. I actually tested this and noticed two things, the connection timeout you specified in the connection string will be set to 365 if the number is bigger than that, also if you set a delay longer than 4 minutes you will get some unexpected http errors during the execution, the workflow manager will do a couple of retries and then it will fail. I think that both are issues with the Workflow Manager in SharePoint Online.<br />
This is not so important because the Pause action in the SharePoint 2013 workflows (Workflow Manager) are not depending on SharePoint timer jobs and you will not get the same pause issues as in on-premise 2010 framework, but it is still an option. See example configuration of the action below.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://2.bp.blogspot.com/-tiJiwM8Tu40/VziX8m_kzGI/AAAAAAAADVs/hgZqRWW-WT8ozDPuuikBXBMnaPGoqXUqgCLcB/s1600/Execute_SQL_O365.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="Execute SQL Office 365" border="0" height="296" src="https://2.bp.blogspot.com/-tiJiwM8Tu40/VziX8m_kzGI/AAAAAAAADVs/hgZqRWW-WT8ozDPuuikBXBMnaPGoqXUqgCLcB/s640/Execute_SQL_O365.JPG" title="Execute SQL Office 365" width="640" /></a></div>
<br />
<br />
My final words are that this might be extremely useful if you need to put some short pauses(not more than 5 min.) in your on-premise workflows. I hope you find this useful!Ivan Yankulovhttp://www.blogger.com/profile/01518276480144054762noreply@blogger.com0tag:blogger.com,1999:blog-2857779700332084475.post-57704655267326551212016-02-17T10:51:00.000+02:002016-02-17T10:51:25.721+02:00Get a quick report of the SharePoint Databases with PowerShell [Tip]Here comes another useful PowerShell one-liner I often use.<br />
It will give you a quick overview of the SharePoint databases with properties like: Name, Server(Alias), TypeName, Web application name, Web application URL, Site collection count and the Size.<br />
The size is actually the amount of disk space required for uncompressed backup. It might look something like a script, but actually it is a long and simple one-liner. You can see it below, I have used grave-accent(`) <a href="http://ss64.com/ps/syntax-esc.html" target="_blank">escape characters</a> to fit it better in the blog. You can see it in one line <a href="https://drive.google.com/file/d/0B8rWEgqtmjukTnBUdE9aZlhaN1E/view?usp=sharing" target="_blank">here</a>. Instead of piping to Format-Table you can generate CSV by piping to Export-CSV and later work with it in Excel.<br />
<hr />
<pre><span style="font-size: 11px;"><span style="color: cadetblue;">Get-SPDatabase</span><span style="color: black;"> </span><span style="color: blue;">|</span><span style="color: black;"> </span><span style="color: cadetblue;">Select-Object</span><span style="color: black;"> </span><span style="color: blue;">Name</span><span style="color: black;">,@</span><span style="color: black;">{</span><span style="color: blue;">Expression</span><span style="color: red;">=</span><span style="color: black;">{</span><span style="color: navy;">$_</span><span style="color: black;">.</span><span style="color: blue;">Server</span><span style="color: black;">}</span><span style="color: blue;">;Label</span><span style="color: red;">=</span><span style="color: maroon;">"Server"</span><span style="color: black;">}</span><span style="color: black;">,</span><span style="color: blue;">TypeName</span><span style="color: black;">,@</span><span style="color: black;">{</span><span style="color: blue;">Expression</span><span style="color: red;">=</span><span style="color: cadetblue;">`</span><span style="color: black;">
{</span><span style="color: navy;">$_</span><span style="color: black;">.</span><span style="color: saddlebrown;">WebApplication</span><span style="color: black;">.</span><span style="color: blue;">Name</span><span style="color: black;">}</span><span style="color: blue;">;Label</span><span style="color: red;">=</span><span style="color: maroon;">"WebAppLication"</span><span style="color: black;">}</span><span style="color: black;">,@</span><span style="color: black;">{</span><span style="color: blue;">Expression</span><span style="color: red;">=</span><span style="color: black;">{</span><span style="color: navy;">$_</span><span style="color: black;">.</span><span style="color: saddlebrown;">WebApplication</span><span style="color: black;">.</span><span style="color: blue;">Url</span><span style="color: black;">}</span><span style="color: blue;">;Label</span><span style="color: red;">=</span><span style="color: maroon;">"WebAppLicationUrl"</span><span style="color: black;">}</span><span style="color: cadetblue;">`</span><span style="color: black;">
</span><span style="color: black;">,@</span><span style="color: black;">{</span><span style="color: blue;">Expression</span><span style="color: red;">=</span><span style="color: black;">{(</span><span style="color: navy;">$_</span><span style="color: black;">.</span><span style="color: saddlebrown;">WebApplication</span><span style="color: black;">.</span><span style="color: saddlebrown;">Sites</span><span style="color: black;"> </span><span style="color: blue;">|</span><span style="color: black;"> </span><span style="color: blue;">Measure</span><span style="color: black;">)</span><span style="color: black;">.</span><span style="color: blue;">Count</span><span style="color: black;">}</span><span style="color: blue;">;Label</span><span style="color: red;">=</span><span style="color: maroon;">"SC Count"</span><span style="color: black;">}</span><span style="color: black;">,@</span><span style="color: black;">{</span><span style="color: blue;">Label</span><span style="color: black;"> </span><span style="color: red;">=</span><span style="color: maroon;">"Size in MB"</span><span style="color: blue;">;</span><span style="color: cadetblue;">`</span><span style="color: black;">
</span><span style="color: blue;">Expression</span><span style="color: black;"> </span><span style="color: red;">=</span><span style="color: black;">{</span><span style="color: navy;">$_</span><span style="color: black;">.</span><span style="color: blue;">disksizerequired</span><span style="color: red;">/</span><span style="color: black;">1024</span><span style="color: red;">/</span><span style="color: black;">1024</span><span style="color: black;">}} </span><span style="color: blue;">|</span><span style="color: black;"> </span><span style="color: cadetblue;">Format-Table</span><span style="color: black;"> </span><span style="color: cadetblue;">-AutoSize</span></span>
</pre>
<hr />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://2.bp.blogspot.com/-DpzFKTETyE4/VsQs5KOx0lI/AAAAAAAADOs/8a_7bnxzGjg/s1600/Get_All_DBs.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="Get SharePoint database report" border="0" height="264" src="https://2.bp.blogspot.com/-DpzFKTETyE4/VsQs5KOx0lI/AAAAAAAADOs/8a_7bnxzGjg/s640/Get_All_DBs.gif" title="Get SharePoint database report" width="640" /></a></div>
<br />Ivan Yankulovhttp://www.blogger.com/profile/01518276480144054762noreply@blogger.com0tag:blogger.com,1999:blog-2857779700332084475.post-71124690778192625572016-02-16T10:20:00.000+02:002016-02-16T23:39:01.108+02:00Get Application Pool Identity credentials[Tip]In this short tip I am going to post a PowerShell one-liner from my list of extremely useful one-liners. It can get the the credentials of the IIS application pools identity.<br />
I use it mainly in two scenarios:<br />
<b> 1.</b> Imagine that you will do a remote work on customer where you have only temporary access and credentials. Many times the account that is provided is Farm Admin, has local admin permissions on the SharePoint boxes, however it does not have permission to use PowerShell against SharePoint(no Shell Admin). You can use this short PowerShell script and get the Farm account(STS is running under it), many times it is left in the local admin group and you can log in with it and do what you need to do. Not a best practice, but it is a massive time saver.<br />
<b>2. </b>Imagine that you are working on issue where you need to restart the User Profile Synchronization Service instance and you need the Farm account password. You can get it with this script.<br />
<br />
In order to use it you will need to have local admin permission. I can confirm that it is working on IIS 7.5,8.0 and 8.5.<br />
<hr />
<pre style="text-align: justify;"><span style="font-size: 10px;"><span style="color: cadetblue;">Get-WmiObject</span><span style="color: black;"> </span><span style="color: cadetblue;">-Namespace</span><span style="color: black;"> </span><span style="color: maroon;">"root\MicrosoftIISV2"</span><span style="color: black;"> </span><span style="color: cadetblue;">-Class</span><span style="color: black;"> </span><span style="color: maroon;">"IIsApplicationPoolSetting"</span><span style="color: black;"> </span><span style="color: blue;">|</span><span style="color: black;"> </span><span style="color: blue;">Select</span><span style="color: black;"> </span><span style="color: blue;">WAMUserName</span><span style="color: black;">,</span><span style="color: black;"> </span><span style="color: blue;">WAMUserPass</span></span>
</pre>
<hr />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://3.bp.blogspot.com/-z0rfbd3yC6s/VsLbOvO1ZQI/AAAAAAAADOM/e6lTF-FOPBw/s1600/Get_IIS_Cred.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="Get IIS Application pool credentials" border="0" height="248" src="https://3.bp.blogspot.com/-z0rfbd3yC6s/VsLbOvO1ZQI/AAAAAAAADOM/e6lTF-FOPBw/s640/Get_IIS_Cred.gif" title="Get IIS Application pool credentials" width="640" /></a></div>
<br />Ivan Yankulovhttp://www.blogger.com/profile/01518276480144054762noreply@blogger.com0tag:blogger.com,1999:blog-2857779700332084475.post-62076643665821326562016-02-15T10:21:00.000+02:002016-02-15T16:35:27.254+02:00Copy List Views in SharePoint and SharePoint Online with PowerShell<div style="text-align: justify;">
In the last couple of weeks I am working with a customer that mainly uses SharePoint Server as DMS(Document Management System). I had to move a large number of documents from one library to another due to corruption in some of the files caused by excessive use of unique permissions (~ 32 000).</div>
<div style="text-align: justify;">
In this post I will not talk about why you should limit the usage of unique permissions especial in big libraries, it's a long story.</div>
<div style="text-align: justify;">
As part of the work I had to copy many list views to the new library. I am not a fan of "Save as Template" approach, my solution was to use a PowerShell script and copy the views programmatically.</div>
<div style="text-align: justify;">
The script did its job and I thought that it will be nice to have something like this for SharePoint Online.</div>
<div style="text-align: justify;">
I was unable to find any ready script that can do this, so I wrote one.</div>
<div style="text-align: justify;">
Both scripts are doing basically the same thing, getting the source and destination webs, getting the source and destination lists, getting the source and destination View collections and create new view in the destination using properties from the source.</div>
<div style="text-align: justify;">
It was a bit tricky to load what I need and not making the script extremely slow with CSOM, since we cannot use simple lambda expressions syntax in PowerShell. My solution to this was to use a function written by the SharePoint automation superstar Gary Lapointe. You can check it out in his <a href="https://www.itunity.com/article/loading-specific-values-lambda-expressions-sharepoint-csom-api-windows-powershell-1249" target="_blank">article for ItUnity</a>, where he explains how to workaround the limitation in PowerShell concerning the lambda expressions. I highly recommend to read the entire series dedicated on using PowerShell against SharePoint Online.</div>
<div style="text-align: justify;">
You can download both scripts (on premises and online) below. <b>Please, Test, Rate and use Q&A section in the Gallery!</b></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: center;">
<span style="color: #666666; font-family: "trebuchet ms" , "trebuchet" , "verdana" , sans-serif; font-size: medium; line-height: 18.48px;"> </span><span style="color: #666666; font-family: "trebuchet ms" , "trebuchet" , "verdana" , sans-serif; font-size: 13.2px; line-height: 18.48px;"><i><b>Download <u>On Premises</u> script from: </b><a href="https://gallery.technet.microsoft.com/Script-to-copy-SharePoint-9efff249" style="color: #00abec; font-weight: bold; text-decoration: none;" target="_blank">TechNet Gallery</a></i></span></div>
<div style="text-align: center;">
<span style="color: #666666; font-family: "trebuchet ms" , "trebuchet" , "verdana" , sans-serif; font-size: 13.2px; line-height: 18.48px;"><br /></span></div>
<div style="text-align: center;">
<i style="color: #666666; font-family: 'Trebuchet MS', Trebuchet, Verdana, sans-serif; font-size: 13.2px; line-height: 18.48px;"><b>Download <u>SharePoint Online</u> script from: </b><a href="https://gallery.technet.microsoft.com/Script-to-copy-SharePoint-0a8d049b" style="color: #00abec; font-weight: bold; text-decoration: none;" target="_blank">TechNet Gallery</a></i></div>
Ivan Yankulovhttp://www.blogger.com/profile/01518276480144054762noreply@blogger.com1tag:blogger.com,1999:blog-2857779700332084475.post-70920338689376302512015-11-16T11:11:00.001+02:002015-11-16T11:11:49.087+02:00Display and Fill related item fields in workflow task with Nintex for Office 365 A couple of weeks ago I posted an article called "<a href="http://spyankulov.blogspot.bg/2015/10/move-away-form-workflow-tasks-with.html" target="_blank">Move away from the Workflow Tasks with Nintex for Office 365</a>". The goal of this post was to show some key techniques that you can use if you want to automate a process without using tasks and do all the work in the form so users can see what they are approving.<br />
However, if you want or need to stick with the tasks there is way to display and <b>fill</b> fields from the related item in the task form.<br />
To do this you will need to edit the task template from the workflow designer. This feature was introduced with <a href="https://community.nintex.com/community/getting-started/product-release-announcements/blog/2015/07/30/new-release-nintex-forms-for-office-365" target="_blank">July 2015 release of Nintex Forms for Office 365</a>.<br />
To illustrate how this is working I am going to use the familiar simple Vacation Request form. See how it looks in the form designer below.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-vpd-670wpAU/VkjzfN5UnoI/AAAAAAAADHk/efBRvgvu4J8/s1600/Vacation_Request.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="Vacation Request" border="0" height="201" src="http://4.bp.blogspot.com/-vpd-670wpAU/VkjzfN5UnoI/AAAAAAAADHk/efBRvgvu4J8/s400/Vacation_Request.JPG" title="Vacation Request" width="400" /></a></div>
<br />
You can see a field with label "Manager Comment" this field is visible only when the form is not in "New Mode", it should contain some information from the manager that will approve the request.<br />
In Nintex Workflow for Office 365 there is no Request Data action, but we can include the field that requires information on task completion in the task form.<br />
If you open a Assign a Task(or Start a Task Process) action configuration page you will see "Edit Task Form" in the action ribbon. By clicking it you will get to the familiar Nintex Forms Designer interface.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-lT6RlvHhQEg/Vkj7LGTf7II/AAAAAAAADIA/V775fM2RvT0/s1600/Edit_Task_Form.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="201" src="http://3.bp.blogspot.com/-lT6RlvHhQEg/Vkj7LGTf7II/AAAAAAAADIA/V775fM2RvT0/s400/Edit_Task_Form.jpg" width="400" /></a></div>
<br />
In the picture above I am editing the default Nintex task content type and once you open the form designer the initial form includes task columns and item column. Initially all related item columns are disabled, but you can change that for any column you want and make it editable in the task, you can also connect control from the task form to related item column. With some rearrangement you ca see how the Vacation Request approval task looks below.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-SptAJLrIuhM/VkkFYw8SoBI/AAAAAAAADIQ/S8TmJC4iHoY/s1600/Task_Form.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="198" src="http://1.bp.blogspot.com/-SptAJLrIuhM/VkkFYw8SoBI/AAAAAAAADIQ/S8TmJC4iHoY/s400/Task_Form.JPG" width="400" /></a></div>
<br />
There is something you should consider if you have many tasks with modified forms. This is something I hit with a customer and later reproduced. This is not yet confirmed by Nintex.<br />
When you edit a task form, the task will be created with Nintex content type(ending with GUID), even if you have specified your own custom content type. This is not an issue because the Nintex content type will have the same columns as the original. However you will have to edit all Task Action forms in the workflow regardless of what content type they are using. If for example two tasks have the same initial custom content type, they will be created under the same Nintex content type after you edit both forms.<br />
This is still not a big deal. However, every time you edit a task form two hidden variables are created and you can easily end up hitting the variable count limitation in the Workflow Manager which is 50 in SharePoint Online. See below error when you try to publish a workflow that has more than 50 variables.<br />
<hr />
<span style="color: red;">Error publishing workflow. Workflow XAML failed validation due to the following errors: Activity 'DynamicActivity' has 52 arguments, which exceeds the maximum number of arguments per activity (50). HTTP headers received from the server - ActivityId: 9e1fc3bc-5a7c-4821-9605-d595acea851d. NodeId: . Scope: . Client ActivityId : 29ca419d-d068-2000-213e-aae9dfcc2677. The remote server returned an error: (400) Bad Request.
</span><br />
<hr />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-LCpkISejzuQ/VkkPolhJXtI/AAAAAAAADIg/tylD-DemEpc/s1600/Var_Count_Error.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="193" src="http://4.bp.blogspot.com/-LCpkISejzuQ/VkkPolhJXtI/AAAAAAAADIg/tylD-DemEpc/s400/Var_Count_Error.jpg" width="400" /></a></div>
<br />
This is not an issue with Nintex, this is just the way the things are working in the background.<br />
<b>In my humble opinion Microsoft should rethink this limitation in SharePoint Online!</b><br />
<b><br /></b>
I hope that this was helpful!Ivan Yankulovhttp://www.blogger.com/profile/01518276480144054762noreply@blogger.com1