Idag när jag köttade lite Powershell bestämde jag mig för att lösa ett jäkligt drygt problem jag haft i SharePoint när jag exporterat/importerat (backup/restore) en SiteCollection innehållandes massa rapporter och alla rapporter tappat sin DataSource-link. Vilket innebar massa manuellt klickande och klipp & klistrande.
Med mina nya powershell kunskaper kom jag fram till följande script:
1. Uppdaterar connectionString i min shared datasource och sätter lite andra variabler
2. Anropar SharePoints ReportServer-webbservice och ändrar datasource till ovan nämnda shared datasource på samtliga rapporter.
Nåväl, here goes (tänk på att du får ändra variablerna så de funkar i din miljö):
#Powershell
Clear-Host
# Add SharePoint snapin if needed
if ((Get-PSSnapin -Name Microsoft.SharePoint.Powershell -ErrorAction SilentlyContinue) -eq $null)
{
Add-PSSnapin Microsoft.SharePoint.Powershell
}
# Variables
$webApplicationUrl = "http://my.hostheader.com/"
$hostHeader = $webApplicationUrl -replace "http://", ""
$connectionString = "Data Source=MyDbServer;Initial Catalog=MyDataBase;Integrated Security=SSPI;"
$webApplicationUNCPath = "\\$hostHeader\DavWWWRoot\"
$dataSourcesLibraryName = "Data Sources"
$dataSourceDefinitionName = "MySharedDataSource.rsds"
$dataSourceLink = "$webApplicationUrl/$dataSourcesLibraryName/$dataSourceDefinitionName"
$dataSourceUNCFilePath = $webApplicationUNCPath + $dataSourcesLibraryName + "\" + $dataSourceDefinitionName
$reportsLibraryName = "MyReports"
$reportServerUri = "$webApplicationUrl/_vti_bin/ReportServer/ReportService2010.asmx?WSDL"
# Script
$site = Get-SPSite($webApplicationUrl)
$web = $site.OpenWeb()
$dataSources = $web.Lists | Where-Object { $_.Title -eq $dataSourcesLibraryName }
$dataSource = $dataSources.Items | Where-Object { $_.Name -eq $dataSourceDefinitionName }
$reports = $web.Lists | Where-Object { $_.Title -eq $reportsLibraryName }
## Change properties on the shared data source object (through xml manipulation)
$xml = [xml](Get-Content $dataSourceUNCFilePath)
$xml.DataSourceDefinition.ConnectString = $connectionString
$xml.DataSourceDefinition.CredentialRetrieval = "Integrated"
$xml.DataSourceDefinition.Enabled = "True"
$windowsCredentialsNode = $xml.DataSourceDefinition.ChildNodes | Where-Object { $_.Name -eq "WindowsCredentials" }
if ($windowsCredentialsNode -ne $NULL)
{
$xml.DataSourceDefinition.RemoveChild($windowsCredentialsNode)
}
$ImpersonateUserNode = $xml.DataSourceDefinition.ChildNodes | Where-Object { $_.Name -eq "ImpersonateUser" }
if ($ImpersonateUserNode -ne $NULL)
{
$xml.DataSourceDefinition.RemoveChild($ImpersonateUserNode)}
$xml.Save($dataSourceUNCFilePath)
# Iterate through reports and set correct shared datasource
$Proxy = New-WebServiceProxy -Uri $reportServerUri -UseDefaultCredential ;
# Gather the webservice types for later use
$WebServiceTypes = @{}
foreach ($Type in $Proxy.GetType().Assembly.GetExportedTypes())
{
$WebServiceTypes.Add($Type.Name, $Type.FullName);
}
# Get list of all reports
$ReportItems = $Proxy.ListChildren("/", $true) | Where-Object { $_.Name -Like "*.rdl" } | Where-Object { $_.Path -Like "$webApplicationUrl/$reportsLibraryName" }
$dataSources = $web.Lists | Where-Object { $_.Title -eq $dataSourcesLibraryName }
$dataSource = $dataSources.Items | Where-Object { $_.Name -eq $dataSourceDefinitionName }
# Declare DataSourceReference object
$ref = New-Object $WebServiceTypes.DataSourceReference
$ref.Reference = $dataSourceLink;
# Declare DataSourceReference object
$ds = New-Object $WebServiceTypes.DataSource
$ds.Name = $dataSource.DisplayName
$ds.Item = $ref
# Apply DataSource to all Reports
foreach ($ReportItem in $ReportItems)
{
$dss = $Proxy.GetItemDataSources($ReportItem.Path)
$dss[0] = $ds
Try
{
$Proxy.SetItemDataSources($ReportItem.Path, $dss)
}
Catch [System.Exception]
{
"Error: Could not fix datasource for report: {0}" -f $ReportItem.Name
}
}
$Proxy.Dispose()
$site.Dispose()
Edit #1: Kan vara intressant att veta att min sitecollection ligger på webbapplikationens rot-nivå också.
Edit #2: Bytte implementationen med att hämta objekt ur xml eftersom den gamla inte returnerade System.Xml.XmlElement objekt som fungerar ihop med RemoveChild-metoden. Rättade även så att enbart rapporter i ett utvalt dokumentbibliotek ($reportsLibraryName) "fixas" utav scriptet ifall man kör på en farm innehållandes massa olika rapporter.
Sådärja, jämt dretgött detta! :)
Inga kommentarer:
Skicka en kommentar