A little Background:
On one of the projects I was involved with, Search Metadata properties were heavily being leveraged. When creating staging or production environments, the task of creating nearly 150 Metadata columns was becoming tedious. We first wrote a script that would manually enter in the names of the metadata properties, and then if new properties were added would mean that we would have to update the script. This left lots of room for error, as well as lots of lines of code.
We modified the script to dynamically get all the properties and create xml files to represent different portions of the metadata properties and then use the xml file to create the new properties in the destination environment.
To get a successful MetaData Property for search, you need:
- Ensure crawled property exists (run a crawl)
- Create a new managed property.
- Create a property mapping to map the crawled property to the managed property.
Let us take a look at an example of a metadata property in the source environment at (/_admin/search/listmanagedproperties.aspx) in central admin.
"IsProBono" is the name of the Managed Data Property.
Clicking on the property will give you this
Notice that the name of the Crawled Property is "ows_Pro_x00200_Bono_x0020_Event". Highlighted in yellow are the attributes of the Search Metadata property and we'll have to consider them when creating the property in the destination server.
Here are the steps we're going to take in order to move the mappings from one environment to another.
- Create a custom Export xml file that will have the following as a template.
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04">
<Obj>
<CrawledPropertyName></CrawledPropertyName>
<ManagedPropertyName></ManagedPropertyName>
<PropertyType></PropertyType>
<IncludeInMd5></IncludeInMd5>
<RespectPriority></RespectPriority>
<FullTextQueriable></FullTextQueriable>
<EnableScoping></EnableScoping>
<HasMultipleValues></HasMultipleValues>
</Obj>
</Objs>
- Create an export script on the source server to populate this xml file with nodes.
- Make sure you have done a full crawl of the destination content source. This will make sure that all the necessary crawled properties are created.
- Move the xml file to the destination server and run the import script to create the Managed Properties and Mapped Properties
ONTO the CODE
EXPORTS
$DATE = get-date
$LogPath = "c:\Logs"
$LogFileName = "SearchService.txt"
$FilePath = $LogPath + "\" + $LogFileName
$logFileCreated = $False
#Method to take care of writing log files to a file on the server.
function write-log([string]$label, [string]$logMsg)
{
if($logFileCreated -eq $False)
{
write-host "Creating log file..."
if((Test-Path -path $LogPath) -ne $True)
{
write-host "Provide proper values to LogPath folder" -ForegroundColor Red
}
else
{
Add-Content -Path $FilePath -Value $logHeader
$script:logFileCreated = $True
write-host "Log file created..."
}
}
else
{
[string]$info = [System.String]::Format("[$Date] {0}: {1}",$label, $logMsg)
Add-Content -Path $FilePath -Value $info
}
}
#Load the Sharepoint Powershell snapin
$snapin = Get-PSSnapin | Where-Object {$_.Name -eq 'Microsoft.SharePoint.Powershell'}
if ($snapin -eq $null)
{
Write-Host "Loading SharePoint Powershell Snapin"
Add-PSSnapin "Microsoft.SharePoint.Powershell"
}
$CrawledPropertyName = "ows*"
#Name of the Search Service Application
$SearchService = "Search Service Application"
#Path to the location of the config xml files
$PathXmlFiles = "C:\deploy\xml"
$path = "C:\deploy\xml\exportedfile.xml"
$xmlfile = New-Object XML
#Load the template xml config file
$xmlfile.Load($path)
#These three lines get the managed properties, crawl properties, and mapped properties of the service and also create
#xml file copies of those.
$prop = Get-SPEnterpriseSearchMetadataCrawledProperty -SearchApplication $SearchService | Where-Object {$_.name -like $CrawledPropertyName} | Export-Clixml $PathXmlFiles\getCrawledMetaDataProperty.xml
$mp = Get-SPEnterpriseSearchMetadataManagedProperty -SearchApplication $SearchService | Export-Clixml $PathXmlFiles\getMetaDataProperty.xml
$map = Get-SPEnterpriseSearchMetadataMapping -SearchApplication $SearchService -ManagedProperty $mp | Export-Clixml $PathXmlFiles\getCrawledMetaDataMapProperty.xml
$xmlmetadata3 = Import-Clixml $PathXmlFiles\getCrawledMetaDataMapProperty.xml
try
{
$oldObject = (@($xmlfile.Objs.obj)[0])
foreach ($mapdata in $xmlmetadata3)
{
$created2 = Get-SPEnterpriseSearchMetadataManagedProperty -SearchApplication $SearchService | Where-Object {$_.PID -eq $mapdata.ManagedPid }
#get a reference to the managed property
$managedpropertyRef = Get-SPEnterpriseSearchMetadataManagedProperty -SearchApplication $SearchService | Where-Object {$_.PID -eq $mapdata.ManagedPid }
#get a reference to the crawl property
$crawledpropertyRef = Get-SPEnterpriseSearchMetadataCrawledProperty -SearchApplication $SearchService | Where-Object {$_.Name -eq $mapdata.CrawledPropertyName }
$message = "Crawled Property Name: " +$mapdata.CrawledPropertyName +" Mapped to ManagedPropertyName: " +$managedpropertyRef.Name
Write-Host $message
write-log ("!!INFO!!" , $message)
#add new xml node
$newObject = $oldObject.Clone()
$newObject.CrawledPropertyName = $mapdata.CrawledPropertyName
$newObject.ManagedPropertyName = $managedpropertyRef.Name
$propertyType = [int]$managedpropertyRef.ManagedType
$includeInMd5 =[int]$managedpropertyRef.IncludeInMd5
$respectPriority =[int]$managedpropertyRef.RespectPriority
$fullTextQueriable =[int]$managedpropertyRef.FullTextQueriable
$enableScoping = [int]$managedpropertyRef.EnabledForScoping
$hasMultipleValues = [int]$managedpropertyRef.HasMultipleValues
#set the managed property settings
$newObject.PropertyType = [string]$propertyType.ToString()
$newObject.IncludeInMd5 = [string]$includeInMd5.ToString()
$newObject.RespectPriority = [string]$respectPriority.ToString()
$newObject.FullTextQueriable = [string]$fullTextQueriable.ToString()
$newObject.EnableScoping = [string]$enableScoping.ToString()
$newObject.HasMultipleValues = [string]$hasMultipleValues.ToString()
$xmlfile.objs.AppendChild($newObject) > $null
}
# remove objects with undefined ManagedPropertyName (remove template)
$xmlfile.objs.obj | Where-Object {$_.ManagedPropertyName -eq ""} | ForEach-Object {[void]$xmlfile.objs.RemoveChild($_)}
$xmlfile.Save("$path")
}catch
{
}
- Running this script will create three xml files in the c:\deploy\xml path, and update an existing one (exportedfile.xml)
IMPORTS
- The "exportedfile.xml" xml file into some directory on the destination server.
- Make references to it in your import script
$xml = [xml](Get-Content c:\deploy\xml\exportedfile.xml )
- Loop through each one and check to see if those objects exist in the database, if so do nothing otherwise create them
- #For Crawl Properties if the items don't exist, then simply put an entry in the log file for your records.
- #For Managed Properties – loop through each section and create scoping, and other attributes and set a number for the true/false value (the xml shows it as true false, but the
- Powershell method uses 1 or 0's.
try
{
$external_counter = 0
$total_counter = 0
foreach ($mapdata in $xml.Objs.Obj)
{
if($mapdata) {
$total_counter ++
$created = Get-SPEnterpriseSearchMetadataCrawledProperty -SearchApplication $SearchService | Where-Object {$_.Name -eq $mapdata.CrawledPropertyName }
if ($created)
{
Write-Host "Crawled Property " + $created.Name " already present" -ForegroundColor:Yellow
$message = "Crawled Property "+ $created.Name + " already present"
write-log ("!!INFO!!",$message)
#get a reference to the managed property
$managedpropertyRef = Get-SPEnterpriseSearchMetadataManagedProperty -SearchApplication $SearchService | Where-Object {$_.Name -eq $mapdata.ManagedPropertyName }
#get a reference to the crawl property
$crawledpropertyRef = Get-SPEnterpriseSearchMetadataCrawledProperty -SearchApplication $SearchService | Where-Object {$_.Name -eq $mapdata.CrawledPropertyName }
if($managedpropertyRef) {
#if Managed Property does not exist then create it
$createdMap = Get-SPEnterpriseSearchMetadataMapping -SearchApplication $SearchService -ManagedProperty $managedpropertyRef
if($createdMap)
{
write-log ("!!INFO!!" , "Mapped Property Exists for " + $managedpropertyRef.Name)
}else{
New-SPEnterpriseSearchMetadataMapping -SearchApplication $SearchService -ManagedProperty $managedpropertyRef -CrawledProperty $crawledpropertyRef
write-log ("!!INFO!!" , "New Mapped Property created for "+ $managedpropertyRef.Name)
$external_counter ++
}
}
else {
try
{
#create the managed property and then create the mapping
$propertyType = [int]$mapdata.PropertyType
$includeInMd5 =[int]$mapdata.IncludeInMd5
$respectPriority =[int]$mapdata.RespectPriority
$fullTextQueriable =[int]$mapdata.FullTextQueriable
$enableScoping = [int]$mapdata.EnabledForScoping
$hasMultipleValues = [boolean]$hasMultipleValues
#write-log ("!!INFO!!" , "About to create a new Managed Property -Name "+ $mapdata.ManagedPropertyName +" -Type "+$propertyType) #+" -EnabledForScoping "+ $enableScoping + " -FullTextQueriable "+$fullTextQueriable + " -IncludeInMd5 "+$includeInMd5 + " -RespectPriority "+$respectPriority)
$managedproperty = New-SPEnterpriseSearchMetadataManagedProperty -SearchApplication $SearchService -Name $mapdata.ManagedPropertyName -Type $propertyType -EnabledForScoping $enableScoping -FullTextQueriable $fullTextQueriable -IncludeInMd5 $includeInMd5 -RespectPriority $respectPriority
if($managedproperty -ne $null){
$managedproperty.HasMultipleValues = $hasMultipleValues
$managedproperty.update()
}
New-SPEnterpriseSearchMetadataMapping -SearchApplication $SearchService -ManagedProperty $managedproperty -CrawledProperty $crawledpropertyRef
write-log ("!!INFO!!" , "New Mapped Property created for "+ $managedpropertyRef.Name)
$external_counter ++
}catch [Exception]
{ Write-Host "There was an error trying to add Mapped Property " + $mapdata.CrawledPropertyName -ForegroundColor:Red
write-log ("!!ERROR!!","There was an error trying to add Mapped Property " + $mapdata.CrawledPropertyName)
return $_.Exception.Message
}
}
}
else {
Write-Host "Crawled Property " + $mapdata.CrawledPropertyName + " Does Not Exist" -ForegroundColor:Red
write-log ("!!INFO!!", "Crawled Property " + $mapdata.CrawledPropertyName + " Does Not Exist")
}
}
}
write-log ("!!TOTALS!!","Of "+ $total_counter + "there were "+ $external_counter +" mapped properties created")
}catch
{
}
Here are the links to download the scripts.
Download link for the Export Script
Download link for Import Script