SharePoint 2010 + PowerShell: Export/Import Calendar Items
Today has been miserable. All I wanted to do was import a SharePoint 2007 calendar into SharePoint 2010 to use as sample data for a prototype site. I was caaarraaazzy enough to believe it would be a simple import/export, but no. There's no such thing. Maybe I could use Outlook calendaring or idq files as a medium? No. So I decided to do the good ol "Save this as a template and include content" workaround. Then I followed Tom's awesome instructions on how to hack the SharePoint 2007 template to get SharePoint 2010 to use it.
That worked! It imported over 3000 calendar items, but then the library itself was broken. When I'd make modifications (such as checking the box to make the calendar a resource), it would throw unknown errors IN MY FACE. So I decided I would just create a fresh SharePoint 2010 Calendar, then import the data using a PowerShell script which would just copy list item data from one calendar to another. This should work for almost any list in SharePoint. Here's how I did it, y'all:
First, create a new Calendar using the regular Calendar template. Then, run this script after changing $siteURL, $sourceListName and $destListName to suit your environment.
$siteURL = "http://sharepoint/"
$sourceListName = "Corporate Calendar"
$destListName= "Prototype Calendar"
$site = Get-SPSite $siteURL
$web = $site.RootWeb
$sourceList = $web.Lists[$sourceListName]
$destList = $web.Lists[$destListName]
$columns = $sourceList.Fields;
$sourceItems = $sourceList.GetItems();
foreach($sourceItem in $sourceItems) {
$newItem = $destList.AddItem();
foreach($column in $columns) {
if ($column.ReadOnlyField -eq $False -and $column.InternalName -ne "Attachments") {
$newItem[$($column.InternalName)] = $sourceItem[$($column.InternalName)];
}
}
$newItem.Update();
}
$web.dispose()
$site.dispose()
Note that I didn't include support for attachments at this time; 8 hours after starting on this Copy Calendar Events journey began, I'm just too beat! Perhaps I'll add it later.
Update: My awesome friend Trevor shared this link with me: Create random or demo SharePoint Content with PowerShell Cool.
SQL Server: Advanced SUSPECT Database Recovery
I hope I never have to use this article, but if I do, it will be a lifesaver. Check out Paul Randal's post on recovering a SUSPECT database that's been detached. He shows not only how to corrupt a database whilst keeping it functional, he also shows just why detaching a SUSPECT database is a horrible idea....and how you can ultimately recover from doing so.
SharePoint + Powershell: Remove Hold, Record Declaration on All Documents in a Library
In order to delete a Records Library or Records Center, all holds and records in a library must be removed and the Holds and Processing timer job must be run. If this criteria is not met, the "Delete this Document Library" will not be an option in the library settings.
Here is how you can do this programmatically. Note that I did not include the deletion of documents or the document library itself.
$siteURL = $args[0]
$libraryName= $args[1]
$site = Get-SPSite $siteURL
$web = $site.RootWeb
$library = $web.Lists[$libraryName]
$records = $library.Items[0]
# First, remove all holds from all items in the Library
$holdsList = $web.Lists["Holds"]
$holds = $holdsList.Items[0]
[Microsoft.Office.RecordsManagement.Holds.Hold]::RemoveHold($records,$holds,"Holds have been removed.")
# Next, undeclare all items as records. Ps. BulkUndeclareItemsAsRecords is useless.
foreach ($record in $records) {
[Microsoft.Office.RecordsManagement.RecordsRepository.Records]::UndeclareItemAsRecord($item)
}
Start-SPTimerJob HoldProcessing
$web.Dispose()
$site.Dispose()
Thanks to anavijai for the sample Hold removing code.
SharePoint 2010 + PowerShell: Delete Site Content Type
So first, you have to delete all of the content type's children or you'll receive the error "Error: content type in use." Once the dependencies are gone, you can delete the custom site content type itself.
$sitename = $args[0]
$contentType = $args[1]
$web = Get-SPWeb $sitename
$ct = $web.ContentTypes[$contentType]
if ($ct) {
$ctusage = [Microsoft.SharePoint.SPContentTypeUsage]::GetUsages($ct)
foreach ($ctuse in $ctusage) {
$list = $web.GetList($ctuse.Url)
$contentTypeCollection = $list.ContentTypes;
$contentTypeCollection.Delete($contentTypeCollection[$ContentType].Id);
Write-host "Deleted $contentType content type from $ctuse.Url"
}
$ct.Delete()
Write-host "Deleted $contentType from site."
} else { Write-host "Nothing to delete." }
$web.Dispose()
Viola.
SharePoint 2010 + PowerShell: View Dependencies of Content Types (aka Content Type Usage)
Earlier today, I created some test Content Types while playing around with the fancy new Content Organizer. I ran into a few errors, though, and subsequently wanted to delete the dummy content types to start over. I was unable to, however, because the content types were still in use. By what? I didn't know.
Too bad SharePoint doesn't have a feature similar to SQL Server Management Studio's "View Dependencies." Till it does.. here is a PowerShell script that does the trick.
$sitename= "http://sharepoint"
$contentType = "My Custom Content Type"
$web = Get-SPWeb $sitename
$ct = $web.AvailableContentTypes[$contentType]
$ctusage = [Microsoft.SharePoint.SPContentTypeUsage]::GetUsages($ct)
foreach ($ctuse in $ctusage) {
$ctuse.Url
}
$web.Dispose()
Looking for content type usage within subsites? A more thorough script can be found at StackExchange.
PowerShell Workaround: “Replicate Directory Changes” Permissions in AD Required for SharePoint 2010 Profile Syncs
According to the SharePoint 2010 Communities FAQ, Microsoft is burdening SharePoint 2010 Administrators with new requirements to obtain Active Directory accounts with "Replicate Directory Changes" permissions because...
In order to interrogate AD about “what has changed since time xyz”, we need the replicate-directory-changes permissions on partitions being synchronized, for example the domain partition being synchronized.These permissions are needed in particular to be able to read data within the deleted objects container of the partition. Standard users do not have permissions to read the content of this container, and we cannot simply grant rights over that container to the synchronization account.
While this may be the cleanest way to go about things, it's an unfortunate requirement for SharePoint admins within organizations which understandably frown upon making such concessions for service accounts, especially when the change wasn't required for SharePoint 2007 farms.
Microsoft's recommended architecture is to to use the published information from a centralized farm but some SharePoint administrators are on their own and do not have that luxury. I encountered this issue in a lab environment and was able to circumvent it by writing a quick and dirty script to add new users from AD and sync all SharePoint users with AD. This script only addresses one site collection and does not drill down to its subsites. Run it as often as you would run a regular sync.
# SharePoint <-> AD Group Sync
# netnerds.net
#
# What it does:
# Uses LDAP to get a list of users from a specific group in AD (in this case the "All Finance Users" group)
# Enables "Allow Unsafe Updates" for the given Site Collection then returns it to its previous state.
# Adds AD Users (but ignores nested AD groups) to the specified SharePoint Group
# Syncs all Site Users with Active Directory. This includes name changes, etc.
# 1,2,3 Go
$ldappath = "LDAP://CN=All Finance Users,OU=Finance,DC=icanhas,DC=net"
$spgroupname = "Icanhas Intranet Members"
$sitename= "http://sharepoint"
$domain = $env:USERDOMAIN
$adgroup = [ADSI]($ldappath)
$spsite = SPSite($sitename)
$rootweb = $spsite.rootweb
$spgroup = $rootweb.Groups[$spgroupname]
$allowUnsafeUpdates = $spsite.AllowUnsafeUpdates
$spsite.allowUnsafeUpdates = 1
foreach ($memberDN in $adgroup.member) {
$member = [ADSI]("LDAP://$memberDN") | where {$_.properties.objectcategory -match "CN=Person"}
if ($member){
$username = $domain + "\" + $member.sAMAccountName
$spsiteuser = $rootweb.EnsureUser($username)
$spUser = $rootweb.AllUsers[$spsiteuser]
$spgroup.AddUser($spsiteuser)
}
}
$spsite.allowUnsafeUpdates = $allowUnsafeUpdates
$rootweb.dispose()
$spsite.dispose()
Get-SPUser –Web $sitename| Set-SPUser –SyncFromAD
Note the AD Sync on the last line. Surprisingly enough, PowerShell's SyncFromAD works without explicitly allowing Replicate Directory Changes. To test this, first I tried a domain account with regular privileges then I went a step further and denied Replicate Directory Changes for that account and it still worked.
You may want to make additional changes such as: deleting users that no longer exist in AD, and replicating all changes to subsites.
Ahh, just good enough
Find LDAP DN of Users and Groups using the Command Line
I always forget this command, so here's a handy reference (for moi):
| Find LDAP Path of... | Command |
| OU | dsquery OU –name "OU name" |
| Group | dsquery group –name "Group name" |
| Username | dsquery user –name username |
| Computer | dsquery computer -name computername |
Fun!
SQL Server Maintenance Plan Recommendation: Use Ola Hallengren’s Pre-Built Scripts
This set of maintenance plans has been recommended by SQL Pros one too many times to ignore. If you have a rather standard environment, check out Ola Hallengren's scripts for SQL Server Backup, Integrity Check, Index and Statistics Maintenance. Actually, if you have a pretty high end environment, you can explore it as well. Ola states:
I have developed a solution for backup, integrity check, index and statistics maintenance in SQL Server 2005, SQL Server 2008 and SQL Server 2008 R2. The solution is based on stored procedures, functions, sqlcmd and SQL Server Agent jobs. The solution has been designed for the most critical enterprise environments and it is used in many organizations around the world. The solution is recommended by SQL Server community experts, it was awarded Gold in the SQL Server Magazine Awards 2010 and it is free.
SharePoint 2010: Configuration Wizard Shows Missing Patches
I'm unsure if this is related to my earlier issue, but today, after installing the SharePoint 2010 June Cumulative Update (KB2536599), I encountered an error while running the Configuration Wizard. It kept telling me that various portions of KB2536599 were missing from a particular server. I verified that they were, in fact, installed by checking them out in Add/Remove programs, then I tried rebooting. No Go.
I researched The Google and found this poor chap encountered the same error then wiped out his entire farm. Deity, I hope I don't have to do that. His situation is one of the reasons I'm _really_ apprehensive about using the -force switch in psconfig. Anyway, disconnecting the affected server using psconfig -cmd configdb disconnect and reconnecting it via Configuration Wizard seems to have worked for me so far.
That's twice in one day that I've had to use that "solution." I don't know about this... let's just say I'd be really sick to my stomach right now if this weren't just the lab.
Update: Yeahhhh, that didn't work very well. It appears as though I could have solved it with extensive research but I ended up keeping the SharePoint servers as is and creating a fresh farm in the db server.
SharePoint 2010: Malformed Configuration Database Name after Update Causes Exception
Recently, I updated my SharePoint 2010 RTM farm to SharePoint 2010 SP1. I followed the steps touched on here on my WFE. I had a good hour before the June Cumulative rollup would be finished downloading so I figured I'd run the Configuration Wizard on my WFE then go and upgrade my index server.
I was soon presented with the screen that lists the configuration server and database names. I had a feeling things wouldn't go well when I saw the following:
Configuration Database Server "172.20.1.10 "
Configuration Database Name SharePoint_Config
Yep, the server name includes 3 extra characters: two quotes and one space. That, of course, isn't a resolvable hostname and I soon encountered the error:
Failed to initiate the upgrade sequence.An exception of type System.Data.SqlClient.SqlException was thrown. Additional exception information: A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: Named Pipes Provider, error: 40 - Could not open a connection to SQL Server)
Total number of configuration settings run: 2
Ugh. I figured, perhaps, I could fix this using PowerShell, but quickly skimming the available commands, I didn't see anything that may be useful aside from New-SPConfigurationDatabase. That didn't work, of course, because the server was already associated with a Config Database. So then I poked around with psconfig and running psconfig -cmd configdb -connect -server 172.20.1.10 -database SharePoint_Config -passphrase mypp didn't work because I was already connected to a farm.
I finally gave in and disconnected my server from the farm using psconfig -cmd configdb disconnect then I ran the Configuration Wizard again and set myself back up. To finish up the upgrade, I executed psconfig.exe -cmd upgrade -inplace b2b -wait.
My farm worked well until I applied the June Cumulative Rollup, after which I had to just start from scratch. I'm unsure if the FAIL is related.


