iPhone Dev: Base SDK Missing Solved
Someone awesome sent me the code to an iPhone app that he created for RealCajunRecipes.com. I unzipped the file, and opened the project in XCode 4.2. I immediately noticed the upper left hand drop down (what's that called anyway?) said "Base SDK Missing." So I went to all the usual places to change the SDK, I saved it and restarted XCode. Nope, I still encountered the following error when trying to Build my project: error: There is no SDK with the name or path 'iphonesimulator3.1'.
Google searches gave me the same "solution" over and over but none of it worked. Ultimately, I had to go into my projects .xcodeproj directory to edit the file project.pbxproj.
I changed the lines that referenced SDKROOT from SDKROOT = iphonesimulator3.1 to SDKROOT = iphoneos, restarted XCode and successfully built the app.
SharePoint + PowerShell: Batch Import Models, Create ECT’s, Set Permissions
Here is a script that will batch import Models, create associated ECT's, and set permissions for users and admins. Please modify the variables as needed.
# script from netnerds.net
# Make sure the namespace is the same as the namespace in your exported bdcm files
# My $siteURL happens to be the same as my $namespace. That may not be the case for you.
# Do this only on dev machines
# I'm running this on the SharePoint 2010 server so I made my servicecontext localhost
#
# What this does:
# Scans current directory for BDC Export(.bdcm) files
# Creates the External System/Lob and the External Content Types
# Creates External Lists from those ECT's
# Sets the proper permissions
$adminGroup = "DOMAIN\SharePoint Admins"
$userGroup = "DOMAIN\SharePoint Users"
$serviceContext = "http://localhost/"
$nameSpace = "http://sharepoint/"
$SiteUrl = $nameSpace
$bdc = Get-SPBusinessDataCatalogMetadataObject -BdcObjectType Catalog -ServiceContext $serviceContext
$pathtobdcmfiles = Get-Location
$importFiles = Get-Childitem -path $pathtobdcmfiles | Where {$_.extension -eq ".bdcm" -and $_.basename -ne "catalog"}
foreach ($file in $importFiles) {
Import-SPBusinessDataCatalogModel -Path $file.FullName -Identity $bdc -force -ModelsIncluded -PropertiesIncluded -PermissionsIncluded -Verbose
# THIS WHOLE CHUNK COMES FROM: http://gallery.technet.microsoft.com/scriptcenter/82437789-f294-4bcd-8210-a1ba0e081f82/
# IT MAKES THE EXTERNAL LISTS FROM THE MODELS. AWESOME.
$Model = Get-SPBusinessDataCatalogMetadataObject -BdcObjectType Model -Name $file.baseName -ServiceContext $ServiceContext
$ListUrl = "Lists/{0}"
ForEach ($Entity in $Model.AllEntities)
{
$ns = $Entity.Namespace
Write-Host "Entity Namespace : $ns"
$name = $entity.Name
Write-Host "Entity Name : $name"
Write-Host "Looking for MethodInstance specific finder..."
$sf = $Entity.MethodInstances | Where-Object{ $_.MethodInstanceType -eq [Microsoft.BusinessData.MetadataModel.MethodInstanceType]::SpecificFinder }
If($sf -eq $null)
{
Write-Host "Skipping external list creation as Method Instance of Type SpecificFinder was not found in Entity : $name"
break
}
else
{
Write-Host "Creating and Configuring SPListDataSource"
$ds = New-Object -TypeName Microsoft.SharePoint.SPListDataSource
$instanceName = [String]::Empty
ForEach($instance in $entity.LobSystem.LobSystemInstances){$instanceName = $Instance.Name}
$ds.SetProperty("LobSystemInstance", $instanceName)
$ds.SetProperty("EntityNamespace", $ns)
$ds.SetProperty("Entity", $name)
$ds.SetProperty("SpecificFinder", $sf.Name)
$site = $null
Try
{
$site = Get-SPSite -Identity $SiteUrl
$web = $site.OpenWeb()
$web.Lists.Add($Entity.Name, "", [String]::Format($ListUrl, $Entity.Name), $ds);
}
Finally
{
$web.Dispose()
$site.Dispose()
}
}
}
#END CHUNK
}
$claimAdmin = New-SPClaimsPrincipal -Identity $adminGroup -IdentityType WindowsSamAccountName
$claimUsers = New-SPClaimsPrincipal -Identity $userGroup -IdentityType WindowsSamAccountName
Grant-SPBusinessDataCatalogMetadataObject -Identity $bdc -Principal $claimAdmin -Right "Execute,SetPermissions,Edit,SelectableInClients"
Grant-SPBusinessDataCatalogMetadataObject -Identity $bdc -Principal $claimUsers -Right "Execute,Edit,SelectableInClients"
Copy-SPBusinessDataCatalogAclToChildren -MetadataObject $bdc
#Ignore this, its what I wish my namespace was...
#$nameSpace = "http://$env:USERDNSDOMAIN/".toLower()
As they say in the SuSE Linux motd: Have a lot of fun!
SharePoint + PowerShell: Import All BDCM Files in a Directory and Set Permissions
In order to invest as little effort as possible creating and recreating and recreating my External Content Types on my development server, I exported the ECT's then deleted External Content Types, External Systems, and BDC Models. I saved them all in a directory on the SharePoint server, then I placed ImportALLbdcms.ps1 in the same directory and ran it.
$adminGroup = "DOMAIN\SharePoint Admins" #for bdc permissions
$userGroup = "Domain\SharePoint Users"
$serviceContext = "http://localhost/"
$nameSpace = "http://$env:USERDNSDOMAIN/".toLower()
$bdc = Get-SPBusinessDataCatalogMetadataObject -BdcObjectType Catalog -ServiceContext $serviceContext
$pathtobdcmfiles = Get-Location
$importFiles = Get-Childitem -path $pathtobdcmfiles | Where {$_.extension -eq ".bdcm" -and $_.basename -ne "catalog"}
foreach ($file in $importFiles) {
Import-SPBusinessDataCatalogModel -Path $file.FullName -Identity $bdc -force -ModelsIncluded -PropertiesIncluded -PermissionsIncluded -Verbose
write-host $file.fullname
}
$claimAdmin = New-SPClaimsPrincipal -Identity $adminGroup -IdentityType WindowsSamAccountName
$claimUsers = New-SPClaimsPrincipal -Identity $userGrup -IdentityType WindowsSamAccountName
Grant-SPBusinessDataCatalogMetadataObject -Identity $bdc -Principal $claimAdmin -Right "Execute,SetPermissions,Edit,SelectableInClients"
Grant-SPBusinessDataCatalogMetadataObject -Identity $bdc -Principal $claimUsers -Right "Execute,Edit,SelectableInClients"
Copy-SPBusinessDataCatalogAclToChildren -MetadataObject $bdc
Sorry for a junky intro and no conclusion, I've been working 19 hour straight and I'm about exhausted. Anyway, HTHY!
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!


