This Powershell script will let you remove a specific User Profile property without having to use Central Administration. This can be handy in a few different scenarios.
Script is:
Add-PsSnapin Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue
$site = Get-SPSite "http://somesharepointsite.com"
$context = Get-SPServiceContext($site)
$upcm = New-Object Microsoft.Office.Server.UserProfiles.UserProfileConfigManager($context)
$cm = $upcm.ConnectionManager
$pdtc = $upcm.GetPropertyDataTypes()
$ppm = $upcm.ProfilePropertyManager
$cpm = $ppm.GetCoreProperties()
$ptpm = $ppm.GetProfileTypeProperties([Microsoft.Office.Server.UserProfiles.ProfileType]::User)
$psm = [Microsoft.Office.Server.UserProfiles.ProfileSubTypeManager]::Get($context)
$ps = $psm.GetProfileSubtype([Microsoft.Office.Server.UserProfiles.ProfileSubtypeManager]::GetDefaultProfileName([Microsoft.Office.Server.UserProfiles.ProfileType]::User))
$pspm = $ps.Properties
# Remove User Profile Property by Name
$cpm.RemovePropertyByName("NAMEOFPROPERTYTODELETE")
Day to day Powershell, SharePoint, and Project Server experiences. Any scripts here are provided as-is, and you're encouraged to test them before you run them on production. Most are scripts I've altered to suit my needs, and come from places like Stack Overflow or TechNet.
Wednesday, November 16, 2016
Tuesday, October 4, 2016
Get all groups & members for a Site Collection
Add-PsSnapin Microsoft.SharePoint.PowerShell
$siteUrl = "http://somesite/sites/collection"
$web = Get-SPWeb $siteUrl
@(foreach ($group in $web.SiteGroups) {
foreach($user in $group.Users) {
$usergroup = New-Object System.Object
$usergroup | Add-Member -type NoteProperty -name GroupName -value $group.Name
$usergroup | Add-Member -type NoteProperty -name UserName -value $user.Name
Write-Output $usergroup
}
}) | Export-Csv c:\userlist.csv -NoTypeInformation
$siteUrl = "http://somesite/sites/collection"
$web = Get-SPWeb $siteUrl
@(foreach ($group in $web.SiteGroups) {
foreach($user in $group.Users) {
$usergroup = New-Object System.Object
$usergroup | Add-Member -type NoteProperty -name GroupName -value $group.Name
$usergroup | Add-Member -type NoteProperty -name UserName -value $user.Name
Write-Output $usergroup
}
}) | Export-Csv c:\userlist.csv -NoTypeInformation
Thursday, August 11, 2016
Powershell to edit a SharePoint Web Application's web.config file
You really want to do this instead of directly editing the web.config file. If you change the web.config directly, SharePoint won't know it's actually changed. During the next patch or Config Wizard, SharePoint will overwrite the web.config with what it thinks should be there, which is bad.
For our purposes, we store the config changes in a csv file that Powershell will run. That config file holds things like cache timeout settings for some of our custom apps, a custom branding url, and a switch for debug mode to be enabled for specific apps.
That config file can contain anything you might want, but it will need three columns. They are: Name, Owner, and Value
Ours looks like this:
The Powershell is:
# Change this variable to the target Web App
$webAppUrl = "http://somewebapp.com"
$CSVLocation = "F:\Temp\ConfigMods.csv"
# Add Snapin if it is not already loaded
if ((Get-PSSnapin | ? {$_.Name -eq "Microsoft.SharePoint.PowerShell"}) -eq $null)
{
Add-PSSnapin "Microsoft.SharePoint.PowerShell"
}
# Import configuration
$mods = Import-CSV $CSVLocation
$webApp = Get-SPWebApplication $webAppUrl
# Get the mods that need to be checked
$ownerstodelete = $mods | Group-Object owner | Select-Object Name
# For each mod
foreach($owner in $ownerstodelete)
{
# Create an array
$modstodelete = @()
# For each current web mod
foreach($mod in $webApp.WebConfigModifications)
{
# If mod is marked
if($mod.Owner -eq $owner.Name)
{
# Add to the array
$modstodelete += $mod
}
}
Write-Host "Removing $($modstodelete.Count) web.config modifications from $($webAppUrl)" -ForegroundColor Yellow
# Foreach mode to be deleted
foreach($delmod in $modstodelete)
{
# Delete the mod
$webApp.WebConfigModifications.Remove($delmod) > $null
Write-Host " + Deleted mod $($delmod.Value)" -ForegroundColor Red
}
}
# Reset sequence
$i = 0;
Write-Host ""
Write-Host "Adding $($mods.Count) web.config modifications to $($webAppUrl)" -ForegroundColor Yellow
# For each mod to add
foreach($modEntry in $mods)
{
# Create the mod value
$modValue = [system.string]::format(“<add key=""{0}"" value=""{1}"" />", $modEntry.Name, $modEntry.Value)
# Create the mod object
$mod = New-Object Microsoft.SharePoint.Administration.SPWebConfigModification
$mod.Path = "configuration/appSettings"
$mod.Name = [string]::Format("add[@key='{0}']", $modEntry.Name)
$mod.Sequence = $i++
$mod.Owner = $modEntry.Owner
$mod.Type = 0
$mod.Value = $modValue
# Add the mod to the web app
$webApp.WebConfigModifications.Add($mod)
Write-Host " + Added mod $($modValue)" -ForegroundColor Cyan
}
# Update the web app
$webApp.Update()
# Apply web config changes
$webApp.WebService.ApplyWebConfigModifications()
# Run all Admin timer jobs
net stop SPAdminV4 > $null
Start-SPAdminJob
net start SPAdminV4 > $null
Write-Host ""
Write-Host "Web.config changes have been applied successfully" -ForegroundColor Green
For our purposes, we store the config changes in a csv file that Powershell will run. That config file holds things like cache timeout settings for some of our custom apps, a custom branding url, and a switch for debug mode to be enabled for specific apps.
That config file can contain anything you might want, but it will need three columns. They are: Name, Owner, and Value
Ours looks like this:
Name | Owner | Value |
app.DebugMode | itsp | FALSE |
app.BrandingUrl | itsp | http://somesite.com/sites/common |
app.Cache.CacheTimeout | itsp | 1 |
app.Cache.IsCacheEnabled | itsp | FALSE |
app.Lists.EventsList | itsp | Events Calendar |
app.Lists.ContactsList | itsp | Contacts |
app.Lists.LinksList | itsp | Local Links |
app.Lists.AssetsList | itsp | Site Assets |
The Powershell is:
# Change this variable to the target Web App
$webAppUrl = "http://somewebapp.com"
$CSVLocation = "F:\Temp\ConfigMods.csv"
# Add Snapin if it is not already loaded
if ((Get-PSSnapin | ? {$_.Name -eq "Microsoft.SharePoint.PowerShell"}) -eq $null)
{
Add-PSSnapin "Microsoft.SharePoint.PowerShell"
}
# Import configuration
$mods = Import-CSV $CSVLocation
$webApp = Get-SPWebApplication $webAppUrl
# Get the mods that need to be checked
$ownerstodelete = $mods | Group-Object owner | Select-Object Name
# For each mod
foreach($owner in $ownerstodelete)
{
# Create an array
$modstodelete = @()
# For each current web mod
foreach($mod in $webApp.WebConfigModifications)
{
# If mod is marked
if($mod.Owner -eq $owner.Name)
{
# Add to the array
$modstodelete += $mod
}
}
Write-Host "Removing $($modstodelete.Count) web.config modifications from $($webAppUrl)" -ForegroundColor Yellow
# Foreach mode to be deleted
foreach($delmod in $modstodelete)
{
# Delete the mod
$webApp.WebConfigModifications.Remove($delmod) > $null
Write-Host " + Deleted mod $($delmod.Value)" -ForegroundColor Red
}
}
# Reset sequence
$i = 0;
Write-Host ""
Write-Host "Adding $($mods.Count) web.config modifications to $($webAppUrl)" -ForegroundColor Yellow
# For each mod to add
foreach($modEntry in $mods)
{
# Create the mod value
$modValue = [system.string]::format(“<add key=""{0}"" value=""{1}"" />", $modEntry.Name, $modEntry.Value)
# Create the mod object
$mod = New-Object Microsoft.SharePoint.Administration.SPWebConfigModification
$mod.Path = "configuration/appSettings"
$mod.Name = [string]::Format("add[@key='{0}']", $modEntry.Name)
$mod.Sequence = $i++
$mod.Owner = $modEntry.Owner
$mod.Type = 0
$mod.Value = $modValue
# Add the mod to the web app
$webApp.WebConfigModifications.Add($mod)
Write-Host " + Added mod $($modValue)" -ForegroundColor Cyan
}
# Update the web app
$webApp.Update()
# Apply web config changes
$webApp.WebService.ApplyWebConfigModifications()
# Run all Admin timer jobs
net stop SPAdminV4 > $null
Start-SPAdminJob
net start SPAdminV4 > $null
Write-Host ""
Write-Host "Web.config changes have been applied successfully" -ForegroundColor Green
Powershell to rename a Site Collection or change the Site Collection's managed path
This one will actually back up the named Site Collection, then restore it using the new managed path. One thing most people don't mention is this won't necessarily put the Site Collection back in the same database it came from - so keep an eye on your databases in the Manage Content Databases area of Central Admin. You want to be sure the Site Collection you're moving is in a content database that has enough Site Collections available before it hits a warning. You also want to make sure you don't have another content db out there that has a much higher number of available slots.
SharePoint is lazy - and it'll go where the most room is. Keep an eye on that.
Anyway, here's the script.
***
Add-PSSnapin Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue
#Get the Source Site Collection URL
$sourceURL = Read-Host “Enter the Source URL”
#Get the Target Site Collection URL
$targetURL = Read-Host “Enter the Destination URL”
#Location for the backup file
$backupPath = Read-Host “Where do you want the backup stored”
Try
{
#Set the Error Action
$ErrorActionPreference = "Stop"
Write-Host "Backing up the Source Site Collection..."-ForegroundColor DarkGreen
Backup-SPSite $sourceURL -Path $backupPath -force
Write-Host "Backup Completed!`n"
#Delete source Site Collection
Write-Host "Deleting the Source Site Collection..."
Remove-SPSite -Identity $sourceURL -Confirm:$false
Write-Host "Source Site Deleted!`n"
#Restore Site Collection to new URL
Write-Host "Restoring to Target Site Collection..."
Restore-SPSite $targetURL -Path $backupPath -Confirm:$false
Write-Host "Site Restored to Target!`n"
#Remove backup files
Remove-Item $backupPath
}
catch
{
Write-Host "Operation Failed. Find the Error Message below:" -ForegroundColor Red
Write-Host $_.Exception.Message -ForegroundColor Red
}
finally
{
#Reset the Error Action to Default
$ErrorActionPreference = "Continue"
}
write-host "Process Completed!"
SharePoint is lazy - and it'll go where the most room is. Keep an eye on that.
Anyway, here's the script.
***
Add-PSSnapin Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue
#Get the Source Site Collection URL
$sourceURL = Read-Host “Enter the Source URL”
#Get the Target Site Collection URL
$targetURL = Read-Host “Enter the Destination URL”
#Location for the backup file
$backupPath = Read-Host “Where do you want the backup stored”
Try
{
#Set the Error Action
$ErrorActionPreference = "Stop"
Write-Host "Backing up the Source Site Collection..."-ForegroundColor DarkGreen
Backup-SPSite $sourceURL -Path $backupPath -force
Write-Host "Backup Completed!`n"
#Delete source Site Collection
Write-Host "Deleting the Source Site Collection..."
Remove-SPSite -Identity $sourceURL -Confirm:$false
Write-Host "Source Site Deleted!`n"
#Restore Site Collection to new URL
Write-Host "Restoring to Target Site Collection..."
Restore-SPSite $targetURL -Path $backupPath -Confirm:$false
Write-Host "Site Restored to Target!`n"
#Remove backup files
Remove-Item $backupPath
}
catch
{
Write-Host "Operation Failed. Find the Error Message below:" -ForegroundColor Red
Write-Host $_.Exception.Message -ForegroundColor Red
}
finally
{
#Reset the Error Action to Default
$ErrorActionPreference = "Continue"
}
write-host "Process Completed!"
Tuesday, August 2, 2016
Forcing PDFs to open in the client in SharePoint 2013
So you want to have total control over how a PDF opens in SharePoint? You're probably like me in that your implementation has Office Web Apps (OWA), and your organization is using Firefox, IE, maybe Safari and Chrome.
All these browsers have different ways of handling PDFs, with OWA having another method on top of all that. But if you want to take advantage of signing / active forms in PDFs, you'll need to force SharePoint to use the Adobe client to open the files.
Luckily, there's an easy way to do this. Javascript to the rescue.
First, take the Javascript below, save it as pdffix.js, and put it in the C:\Program Files\Common Files\microsoft shared\Web Server Extensions\15\TEMPLATE\LAYOUTS directory of each Web Front End server on your farm:
(function () {
if (typeof SPClientTemplates === 'undefined')
return;
var PdfCtx = {};
PdfCtx.Templates = {};
PdfCtx.Templates.Fields = { 'LinkFilename': { 'View': PdfClientLinkFilenameNoMenu } };
SPClientTemplates.TemplateManager.RegisterTemplateOverrides(PdfCtx);
})();
function GetExtension(szHref) {
var sz = new String(szHref);
var re = /^.*\.([^\.]*)$/;
return (sz.replace(re, "$1")).toLowerCase();
}
var stsOpen = null;
function IsPdfClientInstalled() {
if (stsOpen == null) {
if (Boolean(window.ActiveXObject)) {
try {
stsOpen = new ActiveXObject("PdfFile.OpenDocuments");
}
catch (e) {
stsOpen = null;
}
}
}
return (stsOpen != null);
}
function OpenPdfInClient(pdfFileUrl) {
var fRet = true;
try {
fRet = typeof stsOpen.ViewDocument2 != "undefined" && stsOpen.ViewDocument2(window,
pdfFileUrl, '');
}
catch (e) {
fRet = false;
};
if (event != null) {
event.cancelBubble = true;
event.returnValue = false;
}
return fRet;
}
function PdfNewGif(listItem, listSchema, ret) {
if (listItem["Created_x0020_Date.ifnew"] == "1") {
var spCommonSrc = GetThemedImageUrl("spcommon.png");
ret.push("<span class=\"ms-newdocument-iconouter\"><img class=\"ms-newdocument-icon\"
src=\"");
ret.push(spCommonSrc);
ret.push("\" alt=\"");
ret.push(Strings.STS.L_SPClientNew);
ret.push("\" title=\"");
ret.push(Strings.STS.L_SPClientNew);
ret.push("\" /></span>");
}
}
function PdfClientLinkFilenameNoMenu(param1, param2, listItem, listSchema) {
var ret = [];
var fileUrl = listItem.FileRef;
if (fileUrl != null && typeof fileUrl != 'undefined' && TrimSpaces(fileUrl) != "") {
if (listItem.FSObjType == '1') {
if (listSchema.IsDocLib == '1') {
RenderDocFolderLink(ret, listItem.FileLeafRef, listItem, listSchema);
}
else {
RenderListFolderLink(ret, listItem.FileLeafRef, listItem, listSchema);
}
}
else {
ret.push("<a class='ms-listlink' href=\"");
ret.push(listItem.FileRef);
ret.push("\" onmousedown=\"return VerifyHref(this,event,'");
ret.push(listSchema.DefaultItemOpen);
ret.push("','");
ret.push(listItem["HTML_x0020_File_x0020_Type.File_x0020_Type.mapcon"]);
ret.push("','");
ret.push(listItem["serverurl.progid"]);
ret.push("')\" onclick=\"");
var appInstalled = IsPdfClientInstalled();
var szExt = GetExtension(listItem.FileRef);
if (appInstalled && szExt == 'pdf' && browseris.ie) {
ret.push("return OpenPdfInClient('");
ret.push("http://");
ret.push(window.location.hostname);
ret.push(listItem.FileRef);
}
else {
ret.push("return DispEx(this,event,'TRUE','FALSE','");
ret.push(listItem["File_x0020_Type.url"]);
ret.push("','");
ret.push(listItem["File_x0020_Type.progid"]);
ret.push("','");
ret.push(listSchema.DefaultItemOpen);
ret.push("','");
ret.push(listItem["HTML_x0020_File_x0020_Type.File_x0020_Type.mapcon"]);
ret.push("','");
ret.push(listItem["HTML_x0020_File_x0020_Type"]);
ret.push("','");
ret.push(listItem["serverurl.progid"]);
ret.push("','");
ret.push(Boolean(listItem["CheckoutUser"]) ? listItem["CheckoutUser"][0].id :
'');
ret.push("','");
ret.push(listSchema.Userid);
ret.push("','");
ret.push(listSchema.ForceCheckout);
ret.push("','");
ret.push(listItem.IsCheckedoutToLocal);
ret.push("','");
ret.push(listItem.PermMask);
}
ret.push("')\">");
var fileRef = listItem["FileLeafRef"];
if (fileRef != null) {
var index = fileRef.lastIndexOf('.');
fileRef = index >= 0 ? fileRef.substring(0, index) : fileRef;
}
ret.push(fileRef);
ret.push("</a>");
PdfNewGif(listItem, listSchema, ret);
}
}
else {
ret.push("<nobr>");
ret.push(listItem["FileLeafRef"]);
ret.push("</nobr>");
}
return ret.join('');
}
****
Now, we Powershell.
Run the following Powershell commands, on a per-Library basis, to force PDFs to use this Javascript to open the files in the client.
add-pssnapin microsoft.sharepoint.powershell
$web = Get-SPWeb http://somesharepointsite.com/sites/teamsite
$list = $web.Lists["My PDF Documents"]
$field = $list.Fields.GetFieldByInternalName("LinkFilename")
$field.JSLink = "/_layouts/15/PdfFix.js"
$field.Update($true)
***
Once that script runs, it'll be active. No need to IIS reset or recycle application pools.
ONE IMPORTANT NOTE: You're dumping customizations directly to the /15 hive. This means Cumulative Updates / Service Packs will ALMOST CERTAINLY break this function.
We had the unfortunate experience of enabling this, then immediately patching to the May Cumulative Update the following weekend. We had to re-run the Powershell script to re-enable the function (the .js file was not deleted).
All these browsers have different ways of handling PDFs, with OWA having another method on top of all that. But if you want to take advantage of signing / active forms in PDFs, you'll need to force SharePoint to use the Adobe client to open the files.
Luckily, there's an easy way to do this. Javascript to the rescue.
First, take the Javascript below, save it as pdffix.js, and put it in the C:\Program Files\Common Files\microsoft shared\Web Server Extensions\15\TEMPLATE\LAYOUTS directory of each Web Front End server on your farm:
(function () {
if (typeof SPClientTemplates === 'undefined')
return;
var PdfCtx = {};
PdfCtx.Templates = {};
PdfCtx.Templates.Fields = { 'LinkFilename': { 'View': PdfClientLinkFilenameNoMenu } };
SPClientTemplates.TemplateManager.RegisterTemplateOverrides(PdfCtx);
})();
function GetExtension(szHref) {
var sz = new String(szHref);
var re = /^.*\.([^\.]*)$/;
return (sz.replace(re, "$1")).toLowerCase();
}
var stsOpen = null;
function IsPdfClientInstalled() {
if (stsOpen == null) {
if (Boolean(window.ActiveXObject)) {
try {
stsOpen = new ActiveXObject("PdfFile.OpenDocuments");
}
catch (e) {
stsOpen = null;
}
}
}
return (stsOpen != null);
}
function OpenPdfInClient(pdfFileUrl) {
var fRet = true;
try {
fRet = typeof stsOpen.ViewDocument2 != "undefined" && stsOpen.ViewDocument2(window,
pdfFileUrl, '');
}
catch (e) {
fRet = false;
};
if (event != null) {
event.cancelBubble = true;
event.returnValue = false;
}
return fRet;
}
function PdfNewGif(listItem, listSchema, ret) {
if (listItem["Created_x0020_Date.ifnew"] == "1") {
var spCommonSrc = GetThemedImageUrl("spcommon.png");
ret.push("<span class=\"ms-newdocument-iconouter\"><img class=\"ms-newdocument-icon\"
src=\"");
ret.push(spCommonSrc);
ret.push("\" alt=\"");
ret.push(Strings.STS.L_SPClientNew);
ret.push("\" title=\"");
ret.push(Strings.STS.L_SPClientNew);
ret.push("\" /></span>");
}
}
function PdfClientLinkFilenameNoMenu(param1, param2, listItem, listSchema) {
var ret = [];
var fileUrl = listItem.FileRef;
if (fileUrl != null && typeof fileUrl != 'undefined' && TrimSpaces(fileUrl) != "") {
if (listItem.FSObjType == '1') {
if (listSchema.IsDocLib == '1') {
RenderDocFolderLink(ret, listItem.FileLeafRef, listItem, listSchema);
}
else {
RenderListFolderLink(ret, listItem.FileLeafRef, listItem, listSchema);
}
}
else {
ret.push("<a class='ms-listlink' href=\"");
ret.push(listItem.FileRef);
ret.push("\" onmousedown=\"return VerifyHref(this,event,'");
ret.push(listSchema.DefaultItemOpen);
ret.push("','");
ret.push(listItem["HTML_x0020_File_x0020_Type.File_x0020_Type.mapcon"]);
ret.push("','");
ret.push(listItem["serverurl.progid"]);
ret.push("')\" onclick=\"");
var appInstalled = IsPdfClientInstalled();
var szExt = GetExtension(listItem.FileRef);
if (appInstalled && szExt == 'pdf' && browseris.ie) {
ret.push("return OpenPdfInClient('");
ret.push("http://");
ret.push(window.location.hostname);
ret.push(listItem.FileRef);
}
else {
ret.push("return DispEx(this,event,'TRUE','FALSE','");
ret.push(listItem["File_x0020_Type.url"]);
ret.push("','");
ret.push(listItem["File_x0020_Type.progid"]);
ret.push("','");
ret.push(listSchema.DefaultItemOpen);
ret.push("','");
ret.push(listItem["HTML_x0020_File_x0020_Type.File_x0020_Type.mapcon"]);
ret.push("','");
ret.push(listItem["HTML_x0020_File_x0020_Type"]);
ret.push("','");
ret.push(listItem["serverurl.progid"]);
ret.push("','");
ret.push(Boolean(listItem["CheckoutUser"]) ? listItem["CheckoutUser"][0].id :
'');
ret.push("','");
ret.push(listSchema.Userid);
ret.push("','");
ret.push(listSchema.ForceCheckout);
ret.push("','");
ret.push(listItem.IsCheckedoutToLocal);
ret.push("','");
ret.push(listItem.PermMask);
}
ret.push("')\">");
var fileRef = listItem["FileLeafRef"];
if (fileRef != null) {
var index = fileRef.lastIndexOf('.');
fileRef = index >= 0 ? fileRef.substring(0, index) : fileRef;
}
ret.push(fileRef);
ret.push("</a>");
PdfNewGif(listItem, listSchema, ret);
}
}
else {
ret.push("<nobr>");
ret.push(listItem["FileLeafRef"]);
ret.push("</nobr>");
}
return ret.join('');
}
****
Now, we Powershell.
Run the following Powershell commands, on a per-Library basis, to force PDFs to use this Javascript to open the files in the client.
add-pssnapin microsoft.sharepoint.powershell
$web = Get-SPWeb http://somesharepointsite.com/sites/teamsite
$list = $web.Lists["My PDF Documents"]
$field = $list.Fields.GetFieldByInternalName("LinkFilename")
$field.JSLink = "/_layouts/15/PdfFix.js"
$field.Update($true)
***
Once that script runs, it'll be active. No need to IIS reset or recycle application pools.
ONE IMPORTANT NOTE: You're dumping customizations directly to the /15 hive. This means Cumulative Updates / Service Packs will ALMOST CERTAINLY break this function.
We had the unfortunate experience of enabling this, then immediately patching to the May Cumulative Update the following weekend. We had to re-run the Powershell script to re-enable the function (the .js file was not deleted).
Wednesday, May 25, 2016
When your MySite doesn't recognize you
So consider the following scenario:
Users log in to their MySites and are able to see their Profile and Newsfeed. However, whenever they click on their Tasks link, they get redirected back to their Newsfeed. It's almost as though SharePoint is treating them as a stranger to their own MySite.
We spun several hours on this problem, and I'm not sure our scenario fits for everyone.
The cause of our problem was we had migrated many thousands of MySites from one farm to a new farm. We did this as part of a large scale farm upgrade. When we did that, we did not backup and restore the User Profile databases.
Both farms were in the same domain, same usernames in Active Directory. However, the rub came in the mismatch between the User Profile databases and the MySite content databases.
When a User Profile is imported from Active Directory, SharePoint assigns a GUID to that Profile and stores it in the User Profile database. It then assigns that GUID to the MySite (in the MySites Property Bag) when the user first creates their MySite.
In our case, since the MySites were attached already, the creation action never fired. And since the Profile GUID in the MySite Property Bag was different than the GUID in the Profile Database, when the user tried to click on their Tasks list, SharePoint didn't recognize them.
But there's a fix. You can do this on a multiple site basis, or on an individual MySite basis. The Powershell is:
$Web = Get-SPWeb http://[MySiteURL]/personal/[UserID]
$Web.SetProperty("urn:schemas-microsoft-com:sharepoint:portal:profile:userprofile_guid", "[NewGUID]")
$Web.Update()
You can get the NewGUID by querying UserProfileManager in PowerShell or by going to User Profile Service Application -> Manage User Profiles -> Find the user profile that is having issues -> Edit User Profile
Then get the GUID out of the URL ProfAdminEdit.aspx?guid=[NewGUID]
The credit for this one goes to Matt Coleman and Matt Royer - two of the guys on our team that dug pretty deep on this problem. Hopefully it helps someone else out there.
Users log in to their MySites and are able to see their Profile and Newsfeed. However, whenever they click on their Tasks link, they get redirected back to their Newsfeed. It's almost as though SharePoint is treating them as a stranger to their own MySite.
We spun several hours on this problem, and I'm not sure our scenario fits for everyone.
The cause of our problem was we had migrated many thousands of MySites from one farm to a new farm. We did this as part of a large scale farm upgrade. When we did that, we did not backup and restore the User Profile databases.
Both farms were in the same domain, same usernames in Active Directory. However, the rub came in the mismatch between the User Profile databases and the MySite content databases.
When a User Profile is imported from Active Directory, SharePoint assigns a GUID to that Profile and stores it in the User Profile database. It then assigns that GUID to the MySite (in the MySites Property Bag) when the user first creates their MySite.
In our case, since the MySites were attached already, the creation action never fired. And since the Profile GUID in the MySite Property Bag was different than the GUID in the Profile Database, when the user tried to click on their Tasks list, SharePoint didn't recognize them.
But there's a fix. You can do this on a multiple site basis, or on an individual MySite basis. The Powershell is:
$Web = Get-SPWeb http://[MySiteURL]/personal/[UserID]
$Web.SetProperty("urn:schemas-microsoft-com:sharepoint:portal:profile:userprofile_guid", "[NewGUID]")
$Web.Update()
You can get the NewGUID by querying UserProfileManager in PowerShell or by going to User Profile Service Application -> Manage User Profiles -> Find the user profile that is having issues -> Edit User Profile
Then get the GUID out of the URL ProfAdminEdit.aspx?guid=[NewGUID]
The credit for this one goes to Matt Coleman and Matt Royer - two of the guys on our team that dug pretty deep on this problem. Hopefully it helps someone else out there.
Thursday, May 12, 2016
Take ownership of SharePoint files with no checked in version, check them in, and publish with Powershell
This script will take ownership of all files in a library, then set whatever required metadata needs to be set, then check the items in.
Handy if a user has uploaded a ton of data using Explorer View, but never updated the metadata, and never actually checked in the files.
if ((Get-PSSnapin | ? { $_.Name -eq "Microsoft.SharePoint.PowerShell" }) -eq $null) {
Add-PSSnapin "Microsoft.SharePoint.PowerShell"
}
function BrowseItems($list, $Locationterm, $Departmentterm) {
$files = $list.CheckedOutFiles
foreach($file in $files)
{
$file.TakeOverCheckOut() #Take ownership of checked out document
}
foreach ($item in $list.Items) {
$itemFile = $item.File
if ($itemFile -ne $null) {
if ($itemFile.CheckOutStatus -ne "None") {
$LocationtaxField = [Microsoft.SharePoint.Taxonomy.TaxonomyField]$item.Fields["GAC Location"]
$DepartmenttaxField = [Microsoft.SharePoint.Taxonomy.TaxonomyField]$item.Fields["GAC Department"]
$fileName = $itemFile.Name
$userName = $itemFile.CheckedOutByUser.Name;
$item["Title"] = $fileName
$LocationtaxField.SetFieldValue($item,$Locationterm)
$DepartmenttaxField.SetFieldValue($item,$Departmentterm)
$item.update()
#Write-Host "Doing automatic CheckIn on the item" -f green -NoNewline
$itemFile.CheckIn("Automatic CheckIn (Administrator)")
#Write-Host " Done!" -f Yellow
if( $list.EnableVersioning -and $list.EnableMinorVersions) {
#Write-Host "Doing automatic Publish on the item" -f green -NoNewline
$itemFile.Publish("Automatic Publish (Administrator)")
Write-Host "." -f Yellow
}
}
}
}
}
$url = "http://somesite.com/sites/teamsite/subweb"
$web = Get-SPWeb $url
$site = $web.Site
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Taxonomy")
$session = New-Object Microsoft.SharePoint.Taxonomy.TaxonomySession($site)
$termStore = $session.TermStores[0]
$Locationgroup = $termStore.Groups["Locations"]
$LocationtermSet = $Locationgroup.TermSets["Location"]
$Locationterms = $LocationtermSet.GetAllTerms()
$Locationterm = $Locationterms | ?{$_.Name -eq "SomeCity"}
$Departmentgroup = $termStore.Groups["Departments"]
$DepartmenttermSet = $Departmentgroup.TermSets["Department"]
$Departmentterms = $DepartmenttermSet.GetAllTerms()
$Departmentterm = $Departmentterms | ?{$_.Name -eq "SomeDepartment"}
$list = $web.lists["Some Document Library"]
BrowseItems $list $Locationterm $Departmentterm
Thursday, May 5, 2016
Rename a List or Library in SharePoint 2013 with Powershell
Don't save the List or Library as a template, then restore it. Use Powershell instead!
add-pssnapin microsoft.sharepoint.powershell
$libOriginalUrl = "/Lists/OldListURL/";
$libNewUrl = "/Lists/NewListURL";
$web = Get-SPWeb -Identity http://somesite.com/sites/teamsite
$lib = $web.GetList($web.Url + $libOriginalUrl)
$rootFolder = $lib.RootFolder;
$rootFolder.MoveTo($web.Url + $libNewUrl)
add-pssnapin microsoft.sharepoint.powershell
$libOriginalUrl = "/Lists/OldListURL/";
$libNewUrl = "/Lists/NewListURL";
$web = Get-SPWeb -Identity http://somesite.com/sites/teamsite
$lib = $web.GetList($web.Url + $libOriginalUrl)
$rootFolder = $lib.RootFolder;
$rootFolder.MoveTo($web.Url + $libNewUrl)
Thursday, April 14, 2016
Powershell to set all pages in a subsite to a specific Page Layout
Add-PSSnapin Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue
#Variables for Web and Page URLs
$WebURL="http://somesite.company.com/sites/collection/subsite"
$OldPageLayoutName="OldPageLayout.aspx"
$NewPageLayoutName="NewPageLayout.aspx"
#Get the web and page
$Web = Get-SPWeb $WebURL
#Get Publishing Site and Web
$PublishingSite = New-Object Microsoft.SharePoint.Publishing.PublishingSite($Web.Site)
$PublishingWeb = [Microsoft.SharePoint.Publishing.PublishingWeb]::GetPublishingWeb($web)
#Get New Page Layout
$SitePageLayouts = $PublishingSite.GetPageLayouts($false)
$NewPageLayout = $SitePageLayouts | ? {$_.Name -eq $NewPageLayoutName}
#Get Pages Library
$PublishingPages = $PublishingWeb.GetPublishingPages()
#Iterate throgh each page
foreach ($Page in $PublishingPages)
{
$Page.CheckOut()
$Page.Layout = $NewPageLayout
$Page.ListItem.Update();
$Page.CheckIn("Page layout Updated via PowerShell")
#$page.ListItem.File.Publish("")
if ($Page.ListItem.ParentList.EnableModeration)
{
$Page.ListItem.File.Approve("Publishing Page Layout Updated!");
}
write-host "Updated Page layout on: "$Page.url
}
$Web.Dispose()
#Variables for Web and Page URLs
$WebURL="http://somesite.company.com/sites/collection/subsite"
$OldPageLayoutName="OldPageLayout.aspx"
$NewPageLayoutName="NewPageLayout.aspx"
#Get the web and page
$Web = Get-SPWeb $WebURL
#Get Publishing Site and Web
$PublishingSite = New-Object Microsoft.SharePoint.Publishing.PublishingSite($Web.Site)
$PublishingWeb = [Microsoft.SharePoint.Publishing.PublishingWeb]::GetPublishingWeb($web)
#Get New Page Layout
$SitePageLayouts = $PublishingSite.GetPageLayouts($false)
$NewPageLayout = $SitePageLayouts | ? {$_.Name -eq $NewPageLayoutName}
#Get Pages Library
$PublishingPages = $PublishingWeb.GetPublishingPages()
#Iterate throgh each page
foreach ($Page in $PublishingPages)
{
$Page.CheckOut()
$Page.Layout = $NewPageLayout
$Page.ListItem.Update();
$Page.CheckIn("Page layout Updated via PowerShell")
#$page.ListItem.File.Publish("")
if ($Page.ListItem.ParentList.EnableModeration)
{
$Page.ListItem.File.Approve("Publishing Page Layout Updated!");
}
write-host "Updated Page layout on: "$Page.url
}
$Web.Dispose()
Monday, March 21, 2016
Powershell to remove all alerts for a user in a Web Application
This script will delete all alerts for a specific user on a Web App. It's useful when a user is deleted, but the MySite cleanup job did not remove their collection level alerts.
Credit on this one to: http://www.sharepointdiary.com/2011/11/managing-alerts-using-powershell.html - Salaudeen Rajack.
##### Remove all alerts for specific user from a Web Application #####
$SPwebApp = Get-SPWebApplication "http://somesharepointsite.com"
$SpecificUser = "AD\someuser"
foreach ($SPsite in $SPwebApp.Sites)
{ # get the collection of webs
foreach($SPweb in $SPsite.AllWebs)
{ $alerts = $SPweb.Alerts
# if 1 or more alerts for a particular user, Make a note of them by copying their ID to an Array
if ($alerts.Count -gt 0)
{ $myalerts = @()
foreach ($alert in $alerts)
{ if ($alert.User -like $SpecificUser)
{ $myalerts += $alert
}
} ### now we have alerts for this site, we can delete them
foreach ($alertdel in $myalerts)
{ $alerts.Delete($alertdel.ID)
write-host $alertdel.ID
}
}
}
}
Credit on this one to: http://www.sharepointdiary.com/2011/11/managing-alerts-using-powershell.html - Salaudeen Rajack.
##### Remove all alerts for specific user from a Web Application #####
$SPwebApp = Get-SPWebApplication "http://somesharepointsite.com"
$SpecificUser = "AD\someuser"
foreach ($SPsite in $SPwebApp.Sites)
{ # get the collection of webs
foreach($SPweb in $SPsite.AllWebs)
{ $alerts = $SPweb.Alerts
# if 1 or more alerts for a particular user, Make a note of them by copying their ID to an Array
if ($alerts.Count -gt 0)
{ $myalerts = @()
foreach ($alert in $alerts)
{ if ($alert.User -like $SpecificUser)
{ $myalerts += $alert
}
} ### now we have alerts for this site, we can delete them
foreach ($alertdel in $myalerts)
{ $alerts.Delete($alertdel.ID)
write-host $alertdel.ID
}
}
}
}
Friday, March 18, 2016
Powershell to approve all items in a SharePoint list
This script will set all items in the list to Approved. Handy if you've bulk updated a bunch of items than need to get them published.
add-pssnapin microsoft.sharepoint.powershell
#$site = new-object Microsoft.SharePoint.SPSite("http://somesite.com/news")
$web = get-spweb "http://somesite.com/news/2016/"
$list = $web.Lists["Pages to be Changed"]
$items = $list.Items
foreach ($item in $items)
{
$item["_ModerationStatus"] = 0
$item.Update()
}
Remove WWW prefix from SharePoint URLs
It's not every day you are tasked with doing something, with Microsoft in the room, and the Microsoft rep goes "Wow, we should totally put that on TechNet."
This is one of those things.
If you want to remove the www prefix from a url for all SharePoint sites, here's how:
1. Download and install the URL Rewrite Module on all web front ends. Get it here: http://www.iis.net/downloads/microsoft/url-rewrite
2. Configure Alternate Access Mappings in SharePoint to allow the www url. We added an Internal URL for our WWW entry, and mapped it to the public url. Our AAM settings looked like this when we were done:

3. Add a binding in IIS for the additional WWW url. Our bindings looked like this:

4. Configure the URL Rewrite Module for the new address. Do that by:
- Adding a Blank Rule
- Enter the pattern http://www.somesite.com/*
- Choose Rewrite for the Action Type
- Enter the pattern http://somesite.com/*
- Save it.
Why this works:
SharePoint needs an Alternate Access Mapping for the www url. Once that's in place, IIS needs a binding to recognize the request from SharePoint. Once THAT is entered, the rewrite module will see the www request come in, pick it up, and reroute it.
The users will see the site automatically replace the URL to http://somesite.com.
This is one of those things.
If you want to remove the www prefix from a url for all SharePoint sites, here's how:
1. Download and install the URL Rewrite Module on all web front ends. Get it here: http://www.iis.net/downloads/microsoft/url-rewrite
2. Configure Alternate Access Mappings in SharePoint to allow the www url. We added an Internal URL for our WWW entry, and mapped it to the public url. Our AAM settings looked like this when we were done:
3. Add a binding in IIS for the additional WWW url. Our bindings looked like this:
4. Configure the URL Rewrite Module for the new address. Do that by:
- Adding a Blank Rule
- Enter the pattern http://www.somesite.com/*
- Choose Rewrite for the Action Type
- Enter the pattern http://somesite.com/*
- Save it.
Why this works:
SharePoint needs an Alternate Access Mapping for the www url. Once that's in place, IIS needs a binding to recognize the request from SharePoint. Once THAT is entered, the rewrite module will see the www request come in, pick it up, and reroute it.
The users will see the site automatically replace the URL to http://somesite.com.
Subscribe to:
Posts (Atom)