Home
Create subsite with PowerShell and Task Scheduler in SharePoint Server 2016
This is a common scenario, which I’ve come across several times. You have a list of subsites to be created. It contains all the properties needed to create the subsite, but you don’t know how to do it. Either your stuck with creating a Workflow using Visual Studio or SharePoint Designer. If you use SharePoint Designer, you can use REST API. But it’s limited to 50 properties, which you will reach soon if your creating unique permissions, custom groups, adding users, and custom template. I’ve tried this approach for a couple of weeks, and it’s a daunting task. Further, the workflow manager farm or the workflow itself is pain to work with. It works on Monday, but not on Tuesday. So, I’ve decided to take this “creating subsite” task out of the workflow and are using PowerShell instead. To me, it’s better, since I’m more skilled with PowerShell – and once you get it to work – it never fails. Never! So, here’s what we’ll do in our script. Create a subsite that has a
In plain English, this script creates a subsite, owner, member and visitor group. Set permission on each group and add one site owner and several members – all based on my Custom List of Subsites. The Task Scheduler Create a new Task, where you make sure you trigger the 32-bit version of PowerShell which lives in System32 subfolders. The action can be tricky to get right. First see too that you run with bypass executionpolicy and point to your PowerShell script. C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -executionpolicy bypass -file C:\tasks\New-SPWeb-CustomTemplate.ps1 The script mentioned above is quite long, so don’t just copy-paste. Make sure you use your values in variables and fields. The Script if ($ver.Version.Major -gt 1) {$host.Runspace.ThreadOptions = "ReuseThread"} if ((Get-PSSnapin "Microsoft.SharePoint.PowerShell" -ErrorAction SilentlyContinue) -eq $null) { Add-PSSnapin "Microsoft.SharePoint.PowerShell" } # Instance variables $web = Get-SPWeb "http://SiteCollection" $list = $web.Lists["Project"] $fields = $list.fields $items = $list.items $subsite = $null $createWeb = $false $webs = Get-SPSite "http://SiteCollection" | Get-SPWeb foreach($item in $items) { if($item["subsiteCreated"] -eq $false) { Write-Host $item["SubsiteURL"] $item["subsiteCreated"] $item["Projektledare"] $subsite = $item $createWeb = $true # If we find an item, we use that one and skip the rest until next run break } } # To see wether or not there alredy is an subsite on the same URL $newWeb = "http://SiteCollection" + $item["SubsiteURL"] #Create a subsite from a new item if it's not already present if($createWeb -and $newWeb -notin $webs.Url) { ### Create subsite ### # If we use the -template property when we use New-SPWeb, the script fails. That's why we need to apply template # after the subsite is created Write-Host "Creating Web" $item["SubsiteURL"] -ForegroundColor Green $mainurl = "http://SiteCollection" + $subsite["SubsiteURL"] $template = $web.GetAvailableWebTemplates(1053) | Where-Object {$_.Title -eq "subsiteWeb"} $web = New-SPWeb $mainurl -Language 1053 -Name $subsite["SubsiteURL"] -UniquePermissions -UseParentTopNav $web.ApplyWebTemplate($template.Name) ### Create Owner Group ### Write-Host " Creating Owners group" -ForegroundColor Yellow $groupName = "Owner of " + $subsite["SubsiteURL"] $ownerName = $item["Projektledare"].split("#") $memberName = $item["Projektledare"].split("#") $description = "Owner of subsite " + $item["SubsiteURL"] if ($web.SiteGroups[$groupName] -ne $null) { throw "Group $groupName already exists!" } $op = New-SPClaimsPrincipal $item["ProjectManager"] -IdentityType WindowsSamAccountName $mp = New-SPClaimsPrincipal $item["ProjectManager"] -IdentityType WindowsSamAccountName $users = $web | Get-SPUser foreach($user in $users) { if($user.DisplayName -eq $ownerName[1]) { $op = $user } if($user.DisplayName -eq $memberName[1]) { $mp = $user } } $owner = $web | Get-SPUser $op $member = $web | Get-SPUser $mp # Add user to group Write-Host " Adding user to group" -ForegroundColor Yellow $web.SiteGroups.Add($groupName, $owner, $member, $description) $SPGroup = $web.SiteGroups[$groupName] $web.RoleAssignments.Add($SPGroup) $web.Update() # Set permission on group Write-Host " Setting permissions on group" -ForegroundColor Yellow $role = $web.RoleDefinitions["Full Control"] $RoleAssignment = New-Object Microsoft.SharePoint.SPRoleAssignment($SPGroup) $RoleAssignment.RoleDefinitionBindings.Add($role) $web.RoleAssignments.Add($RoleAssignment) $web.Update() ### Create Member Group ### Write-Host " Creating Member group" -ForegroundColor Yellow $groupName = "Medlemmar i " + $subsite["SubsiteURL"] $ownerName = $item["ProjectManager"].split("#") $memberNames = $item["Projektdeltagare"].User.UserLogin $description = "Medlemmar i projektet " + $item["SubsiteURL"] if ($web.SiteGroups[$groupName] -ne $null) { throw "Group $groupName already exists!" } $owner = $web | Get-SPUser $op $member = $web | Get-SPUser $memberNames[0] # Add user to group Write-Host " Adding user to group" -ForegroundColor Yellow $web.SiteGroups.Add($groupName, $owner, $null, $description) # Setting members to null, since we'll add them later $SPGroup = $web.SiteGroups[$groupName] $web.RoleAssignments.Add($SPGroup) $web.Update() # Add more users to group foreach($memberName in $memberNames) { $member = $web | Get-SPUser $memberName $SPGroup.AddUser($member) } $web.Update() # Set permission on group Write-Host " Setting permissions on group" -ForegroundColor Yellow $role = $web.RoleDefinitions["Contribute"] $RoleAssignment = New-Object Microsoft.SharePoint.SPRoleAssignment($SPGroup) $RoleAssignment.RoleDefinitionBindings.Add($role) $web.RoleAssignments.Add($RoleAssignment) $web.Update() ### Create Visitor Group, with no users ### Write-Host " Creating Visitor group" -ForegroundColor Yellow $groupName = "Visitor in " + $subsite["SubsiteURL"] $ownerName = $item["ProjectManager"].split("#") $description = "Visitor in subsite " + $item["SubsiteURL"] if ($web.SiteGroups[$groupName] -ne $null) { throw "Group $groupName already exists!" } # Add user to group Write-Host " Adding group" -ForegroundColor Yellow $web.SiteGroups.Add($groupName, $owner, $null, $description) $SPGroup = $web.SiteGroups[$groupName] $web.RoleAssignments.Add($SPGroup) $web.Update() # Set permission on group Write-Host " Setting permissions on group" -ForegroundColor Yellow $role = $web.RoleDefinitions["Read"] $RoleAssignment = New-Object Microsoft.SharePoint.SPRoleAssignment($SPGroup) $RoleAssignment.RoleDefinitionBindings.Add($role) $web.RoleAssignments.Add($RoleAssignment) $web.Update() $item["subsiteCreated"] = $true $item.Update(); $web.Dispose(); } |
Initialize-SPResourceSecurity and IISRESET fix inaccessible new Term Store
We've all seen this in a new farm, and it's annoying.
The Managed Metadata Service or Connection is currently not available. The Application Pool or Managed Metadata Web Service may not have been started. Please Contact your Administrator.
And so far I've been unable to solve this, permanently. You check the application pool, services.msc, services on server, database login user mappings, and everything is OK. But today I saw this comment on the post SharePoint Error : The Managed Metadata Service or Connection is currently not available. The Application Pool or Managed Metadata Web Service may not have been started.
It says:
Robin Willems August 19, 2015 at 1:08 am I was getting "Failed to get term store for proxy ‘Managed Metadata Service Application Proxy’. Exception: System.Security.SecurityException: Requested registry access is not allowed" It was fixed by Running Sharepoint Management Shell (Powershell) and Type Initialize-SPResourceSecurity <enter> After that i did an IISRESET /noforce and it was fixed. Without having much hope I run: PS C:\> Initialize-SPResourceSecurity PS C:\> IISRESET Attempting stop... Internet services successfully stopped Attempting start... Internet services successfully restarted PS C:\> Reload the Term Store - and it just worked. One wonder why this isn't initiated by default after creating a new service application? Anyway - this does the trick when installing using AutoSPInstaller in a SharePoint Server 2016 Farm. Reference: Initialize-SPResourceSecurity |
Add custom tile to Office 365 App Launcher
So you're a global admin in your Office 365 tenant, and your exited to add custom tiles to the app launcher. So you follow the four top rated guides from your google search which all says basically the same [1] [2] [3] [4]. Just follow the link to "View all my apps" which is supposed to be located at the bottom of the app launcher. As it turns out, this isn't the case anymore. Today we can see the Get More Apps link instead, leading to a totally different page. Frustrating as this may be, the real URL is https://portal.office.com/myapps. There is another solotion, which isn't described too well. But you have another option. In the new App Launcher experience, you can see all your apps in the App Launcher using the link ALL. At the bottom of this screen (you may need to scroll) you see the Other apps section where your custom apps live. From there you can pin the app to your Home screen of the App Launcher, which is what you see when you click on the start of the App Launcher. Pin it to home, and all is solved. Both of these methods work the same. |
Auditing in SharePoint 2013/2016
SPFx - the first steps
Starting with SharePoint Framework can be a daunting task. Especially since one may be new to TypeScript, Node, Gulp and Yeoman which are preferred parts of the framework. In essence SPFx can be a great step for other developers to start working with SharePoint, since you don't need a local SharePoint environment. The only thing you need is a developer tenant of Office 365, which comes for free for up to a year. You could develop locally as well, but I find it easier to work with the developer tenant directly since you have a real Office 365 instance already in place and don't need to use (and produce) Mockup data. But lets leave the tools for a minute. Just accept the fact that they work, and that you have used scaffolding with Yeoman ‘yo @microsoft/sharepoint’ and started your HelloWorld project with ‘gulp serve’. That’s all we need for now. If not, head over to the source HelloWorld WebPart, and come back here when your done. So now you have your HelloWorld webpart running both locally and on your development tenant. But if we want to add another property in the property pane? That's quite simple, since everything (so far) is in the same .ts file. First, at the top add the PropertyPaneCheckbox in the import clause of @microsoft/sp-client-preview. When done, we can add the checkbox in our webpart property. I added three just for fun so my group now looks like this: groupFields: [ PropertyPaneTextField('description', { label: strings.DescriptionFieldLabel }), PropertyPaneCheckbox('valid', { text: 'Valid' }), PropertyPaneCheckbox('governed', { text: 'Managed by IT' }), PropertyPaneCheckbox('hr', { text: 'Only visible for HR' }) ] And here comes the cool part. When I save my .ts file - gulp (which is still running) makes funny noises (OK, no sound provided in PowerShell which I use) with verbose messages. It recompliles your webpart according to your request. Reloading the webpart at my development tenant, I see the webpart change instantly. I don't even have to delete it and add it again (like old times). Everything just works Now. Suddenly, programming is fun again when you don't have to wait for hooking up to your environment. I just works, and my previous changes is still there. |
An exception of type Microsoft.SharePoint.Administration.SPUpdatedConcurrencyException was thrown
When you run the command PSConfig.exe -cmd upgrade -inplace b2b -wait and get an error, you often solve it by running Get-SPProduct -local to ensure that the the server is in sync. The error message you get is 11/23/2015 08:34:40 1 ERR Failed to upgrade SharePoint Products. An exception of type Microsoft.SharePoint.Administration.SPUpdatedConcurrencyException was thrown. Additional exception information: An update conflict has occurred, and you must re-try this action. The object SPUpgradeSession Name=Upgrade-20151123-083423-444 was updated by DOMAIN\SP_Farm, in the PSCONFIG (5092) process, on machine SERVER. View the tracing log for more information about the conflict. Microsoft.SharePoint.Administration.SPUpdatedConcurrencyException: An update conflict has occurred, and you must re-try this action. The object SPUpgradeSession Name=Upgrade-20151123-083423-444 was updated by DOMAIN\SP_Farm, in the PSCONFIG (5092) process, on machine SERVER. View the tracing log for more information about the conflict. at Microsoft.SharePoint.Administration.SPConfigurationDatabase.StoreObject(SPPersistedObject obj, Boolean storeClassIfNecessary, Boolean ensure) at Microsoft.SharePoint.Administration.SPPersistedObject.BaseUpdate() at Microsoft.SharePoint.Upgrade.SPUpgradeSession.Update() at Microsoft.SharePoint.Upgrade.SPUpgradeSession.ContinueOnLocalThread(Guid id, Boolean consoleOutput) at Microsoft.SharePoint.PostSetupConfiguration.UpgradeTask.Run() at Microsoft.SharePoint.PostSetupConfiguration.TaskThread.ExecuteTask() You may get stuck in a position where you still can't upgrade. Then you have to expand your PSConfig command into this: PSConfig.exe -cmd upgrade -inplace b2b -wait -force -cmd applicationcontent -install -cmd installfeatures -cmd secureresources This command solved the error in my 6-tier farm with 2 WFE, 2 APP and 2 SQL Servers mirrored and belonging to AlwaysOn Availability Group. As a side note - I have to remove the UsageAndHealth-DB from the availability group before upgrading SharePoint. Source: Vladilens comment of the article SharePoint 2010 /2013: “An exception of type Microsoft.SharePoint.Administration.SPUpdatedConcurrencyException was thrown” while installing an update |
Find the FIM Client path
If you have the two FIM services running (Forefront Identity Manager Service & Forefront Identity Manager Synchronization Service) you can start the Forefront Identity Manager 2010, which you use to manage synchronization i detail. The path to the FIM Client is: C:\Program Files\Microsoft Office Servers\15.0\Synchronization Service\UIShell\miisclient.exe |
There is a compatibility range mismatch between the Web server and database "WSS_Content"
This an annoying error message which can happen in various scenarios. I got this one trying to assign a SPWeb object. I knew the SPWeb existed since it was the root site collection. The complete error message was: There is a compatibility range mismatch between the Web server and database "WSS_Content", and connections to the data have been blocked to due to this incompatibility. This can happen when a content database has not been upgraded to be within the compatibility range of the Web server, or if the database has been upgraded to a higher level than the web server. The Web server and the database must be upgraded to the same version and build level to return to compatibility range. Searching the web get many answers, but none that linked to the source. There isn’t any reference (yet) on SharePoint 2013, but it works just as well for 2013 as well. The command-line you run is PSConfig.exe -cmd upgrade -inplace b2b -wait Running the GUI-version of “SharePoint 2013 Products Configuration Wizard” doesn’t help, so you really need to run the script using SharePoint 2013 Management Shell as administrator. But you need to do so with your SP_Install or SP_Farm account which shouldn’t be local administrator on the machine. To overcome this problem temporarily add SP_Install or SP_Farm as local administrator and proceed with the script. You may need to run the script several times, as the script does a lot of magic on your content database. I needed four times to make it work all the way without warnings. All four upgrade sequences need to be successful before you’re done. The -cmd is a mandatory parameter where you specify which action you want to perform. Here we’re using the upgrade command to fix our error of compatibility mismatch. With the –inplace parameter we specify whether to use version to version upgrade or build to build. This can be quite confusing since when we look at our Configuration database version in the Servers in Farm page in Central administration (<CentralAdminURL:Port>/_admin/FarmServers.aspx) and it specifies a build number on SharePoint Foundation 2013 only. Every time you install a Cumulative Update (CU) or Public Update (PU) you need to run PSConfig. Most of the blogs use b2b parameter value, because you are patching the server, not changing version (i.e. SharePoint 2010 to SharePoint 2013). So we’re using the b2b parameter value in this scenario. See SharePoint Build Number vs Version? for more information. Using –wait parameter is important to use since it specifies that SP Management Shell doesn’t return until the upgrade process is completed. And we want to wait and see that our failing content database is really upgraded. There may be things to do after the upgrade i successful. Please check out the log: Reference: PSConfig command-linereference (SharePoint Server 2010) |
WARNING: The user hasn't logged on to mailbox Discovery Search Mailbox
Service Connection – Configure Service Application Associations by adding a member to a custom group of connections in SharePoint Server 2010.
If you have an existing named proxy group of Service Connections, where you want to add members (new connections to new services in a service farm), you need to fire up PowerShell to add new members (connections). At first we need to know the name of the service application proxy group. This is done by a fairly simple PS-command. Get-SPServiceApplicationProxyGroup | select Name Next you copy the name of the Service Application Group that you want to add a new member to, and replace the <SA Group Name> with the real name. $sapg = Get-SPServiceApplicationProxyGroup | Where-Object {$_.Name -eq "<SA Group Name>"} Now you have a reference to the custom group, and need to get the proxy you want to add as a new member. Get-SPServiceApplicationProxy | select DisplayName, Id Copy the Id of the ServiceApplicationProxy you want to add and use it as the -Identity parameter $sap = Get-SPServiceApplicationProxy -Identity 53f7b267-de00-4b7d-a12c-0fb505e94669 Finally add your Proxy to the Proxy Group Add-SPServiceApplicationProxyGroupMember -Identity $sapg -Member $sap Check the Web Application Service Connection, and verify that you have successfully added the new member |