PowerShell: Generare i file di solution per SharePoint in automatico
Quello che segue è uno script che usavo per generare in automatico il file .DDF e manifest.xml necessari per creare i file di solution (.WSP) di SharePoint 2007 (WSS3 - MOSS).
Completa anche le informazioni mancanti nei file Feature.xml che vanno valorizzati con ID, nome feature, scope, ecc...
Lo script per funzionare richiede che i file siano in una struttura di cartelle che rispecchia quella di SharePoint, come la seguente:
La prima cosa da fare è creare il file solution.xml con i corretti nomi degli assembly (andrebbe automatizzata anche questa parte)
successivamente si può lanciare lo script PowerShell 1.0
In pratica lo script scorre tutte le cartelle sotto la 12 e genera le corrette entry nei file manifest.xml, solution.ddf e nei vari feature.xml.
Per generare il pacchetto solution (.WSP)
Per l'installazione delle solution e approfondimenti, vedi anche:
Come creare un file di solution (.wsp)
Microsoft SharePoint Solution Installer
Completa anche le informazioni mancanti nei file Feature.xml che vanno valorizzati con ID, nome feature, scope, ecc...
Lo script per funzionare richiede che i file siano in una struttura di cartelle che rispecchia quella di SharePoint, come la seguente:
Text
+- 12
| +- CONFIG
| +- TEMPLATE
| +- CONTROLTEMPLATES
| +- FEATURES
| | +- MiaFeature1
| | | +- Feature.xml
| | | +- eventuali altri file
| | +- MiaFeature2
| +- IMAGES
| +- SiteTemplates
| +- CONTROLTEMPLATES
| +- THEMES
+- DLL
+- Solution
| +- solution.xml
+- script.ps1
La prima cosa da fare è creare il file solution.xml con i corretti nomi degli assembly (andrebbe automatizzata anche questa parte)
XML: solution.xml
<?xml version="1.0" encoding="utf-8" ?>
<Solution Id="45C275D7-8475-4b05-BD17-B0A02DDF4343"
FileName="BdcPages.wsp">
<Assemblies>
<Assembly Location="BdcHelper.dll"
DeploymentTarget="GlobalAssemblyCache"
Namespace="BdcHelper" />
<Assembly Location="BDCDataLayer.dll"
DeploymentTarget="GlobalAssemblyCache"
Namespace="BDCDataLayer" />
</Assemblies>
</Solution>
successivamente si può lanciare lo script PowerShell 1.0
PowerShell: makesolution.ps1
#genera i file di solution
# solution.ddf
# manifest.xml
# *\features.xml
#basandosi sul file solution\solution.xml che va impostato
#con il corretto SolutionId e nome file WSP
#v. 1.0 26-06-2008
################################################################
# Functions
function MyWrite ($msg){
Write-Host $msg -ForegroundColor green;
}
function MyWriteF ($msg){
Write-Host "Write file: $msg" -ForegroundColor Gray;
}
################################################################
$dt = date;
MyWrite "Begin: $dt";
########################################################################
# nome file wsp
MyWrite "Read configuration";
[xml]$solutionXML = Get-Content "solution.xml";
$solutionId = $solutionXML.Solution.Id;
$solutionWSP = $solutionXML.Solution.FileName;
MyWrite "Solution Id: $solutionId";
MyWrite "File wsp: $solutionWSP";
########################################################################
# costanti percorsi
$root = "..";
$hiveControls = "$root\12\TEMPLATE\CONTROLTEMPLATES"
$hiveFeatures = "$root\12\TEMPLATE\FEATURES"
$hiveImages = "$root\12\TEMPLATE\IMAGES"
$hiveLayouts = "$root\12\TEMPLATE\LAYOUTS"
$hiveSiteTemplates = "$root\12\TEMPLATE\SiteTemplates"
$hiveSiteThemes = "$root\12\TEMPLATE\THEMES"
$hiveConfig = "$root\12\CONFIG"
$hiveDLL = "$root\DLL";
$hiveSolution = "$root\Solution";
$fileSolution = "";
$fileManifest = "";
########################################################################
# Assemblies
MyWrite "Make: Assemblies";
$fileManifest += "`r`n<Assemblies>`r`n";
$fileSolution += ";---------------------------------------------`r`n;Assemblies`r`n";
$fileManifest += " <!-- Assemblies -->`r`n";
$path = $hiveDLL;
$solutionXML.Solution.Assemblies.Assembly | ForEach-Object -Process {
$fileName = $_.Location;
$deploy = $_.DeploymentTarget;
$namespace = $_.Namespace
$file = Get-Item "$path\$fileName"
$dll = [System.reflection.assembly]::ReflectionOnlyLoadFrom($file.FullName);
$fullName = $dll.FullName;
$fileManifest += "
<Assembly Location=`"$fileName`" DeploymentTarget=`"$deploy`" >
<SafeControls>
<SafeControl Assembly=`"$fullName`"
Namespace=`"$namespace`"
TypeName=`"*`"
Safe=`"True`" />
</SafeControls>
</Assembly>
";
$fileSolution += "`"$hiveDLL\$fileName`" $fileName`r`n";
$dll = $null;
}
$fileManifest += "</Assemblies>`r`n";
########################################################################
# FEATURE
MyWrite "Make: Features";
$fileManifest += "`r`n<FeatureManifests>`r`n";
$path = $hiveFeatures
$pathLen = 0;
$pathFrom = "";
$pathTo = "";
#processo tutte le artelle feature
$items = Get-ChildItem "$path\*" | where { $_.Mode.StartsWith("d") }
$items | ForEach-Object -Process {
$file = $_;
$pathLen = $file.FullName.Length+1;
$dirName = $file.name;
$pathFrom = "$path\$dirName";
$pathTo = $dirName;
MyWrite " $dirName";
$fileManifest += " <!-- $dirName -->`r`n";
$fileSolution += ";---------------------------------------------`r`n;$dirName`r`n";
#processo il contenuto della feature
#controllo se esiste il file feature.xml
$ft = Get-Item "$file\feature.xml";
if($ft){
#ok feature.xml esiste
[xml]$featureXml = Get-Content $ft.FullName;
$nodeEM = $featureXml.Feature.ElementManifests;
if ($nodeEM) {
$nodeEM.RemoveAll();
$fileManifest += " <FeatureManifest Location=`"$dirName\$($ft.Name)`" />`r`n";
$fileSolution += "$hiveFeatures\$dirName\$($ft.Name) $dirName\$($ft.Name)`r`n";
Get-ChildItem "$file\*" -Recurse -Exclude *.cs | where { $_.Mode.StartsWith("-") } | ForEach-Object -Process {
$file = $_;
$dirName = $file.directory.name;
$fileName = $file.name;
$element ="";
$location = $file.FullName.Substring($pathLen);
[xml]$node = $null;
$skip = $false;
if($file.Extension.ToLower().Equals(".xml")) {
[xml]$xml = Get-Content $_.FullName;
if($xml.Feature) {
#feature.xml --- non faccio niente
$element = "";
$skip = $true;
} elseif($xml.Elements) {
#file elements
$element = "ElementManifest";
$skip = $true;
}
}
if ($skip -eq $false) {
$element = "ElementFile";
}
if($element.Equals("") -eq $false){
$nd = $featureXML.CreateElement($element, "http://schemas.microsoft.com/sharepoint/");
$nd.SetAttribute("Location", $location);
[void]$nodeEM.AppendChild($nd);
$fileSolution += "`"$pathFrom\$location`" $pathTo\$location`r`n";
}
}
$fNew = $ft.FullName;
MyWriteF "$($ft.Directory.Name)\$($ft.Name)";
attrib -R $fNew;
$featureXml.save($fNew);
}
}
}
$fileManifest += "</FeatureManifests>`r`n";
########################################################################
# TemplateFiles
$fileManifest += "`r`n<TemplateFiles>`r`n";
MyWrite "Make: CONTROLTEMPLATES";
$fileSolution += ";---------------------------------------------`r`n;CONTROLTEMPLATES`r`n";
$fileManifest += " <!-- CONTROLTEMPLATES -->`r`n";
$path = $hiveControls
$pathLen = (Get-Item $path).FullName.Length+1;
$pathFrom = $path;
$pathTo = "";
Get-ChildItem "$path\*" -Recurse -Exclude *.cs | where { $_.Extension.ToLower().Equals(".ascx") } | ForEach-Object -Process {
$dirName = $_.directory.name;
$fileName = $_.name;
$pathTo = "CONTROLTEMPLATES";
$location = "$($_.FullName.Substring($pathLen))";
$fileManifest += " <TemplateFile Location=`"$location`" />`r`n";
$fileSolution += "$pathFrom\$location $pathTo\$location`r`n";
}
MyWrite "Make: IMAGES";
$fileSolution += ";---------------------------------------------`r`n;IMAGES`r`n";
$fileManifest += " <!-- IMAGES -->`r`n";
$path = $hiveImages
$pathLen = (Get-Item $path).FullName.Length+1;
$pathFrom = $path;
Get-ChildItem "$path\*" -Recurse -Exclude *.cs | ForEach-Object -Process {
$dirName = $_.directory.name;
$fileName = $_.name;
$pathTo = "IMAGES";
$location = "$($_.FullName.Substring($pathLen))";
$fileManifest += " <TemplateFile Location=`"$location`" />`r`n";
$fileSolution += "$pathFrom\$location $pathTo\$location`r`n";
}
MyWrite "Make: LAYOUTS";
$fileSolution += ";---------------------------------------------`r`n;LAYOUTS`r`n";
$fileManifest += " <!-- LAYOUTS -->`r`n";
$path = $hiveLayouts;
$pathLen = (Get-Item $path).FullName.Length+1;
$pathFrom = $path;
Get-ChildItem "$path\*" -Recurse -Exclude *.cs | ForEach-Object -Process {
$dirName = $_.directory.name;
$fileName = $_.name;
$pathTo = "LAYOUTS";
$location = "$($_.FullName.Substring($pathLen))";
$fileManifest += " <TemplateFile Location=`"$location`" />`r`n";
$fileSolution += "$pathFrom\$location $pathTo\$location`r`n";
}
$fileManifest += "</TemplateFiles>`r`n";
########################################################################
# TemplateFiles
$fileManifest += "`r`n<RootFiles>`r`n";
MyWrite "Make: CONFIG";
$fileSolution += ";---------------------------------------------`r`n;CONFIG`r`n";
$fileManifest += " <!-- CONFIG -->`r`n";
$path = $hiveConfig;
$pathLen = (Get-Item $path).FullName.Length+1;
$pathFrom = $path;
Get-ChildItem "$path\*" -Recurse -Exclude *.cs | ForEach-Object -Process {
$dirName = $_.directory.name;
$fileName = $_.name;
$pathTo = "CONFIG";
$location = "$($_.FullName.Substring($pathLen))";
$fileManifest += " <RootFile Location=`"$location`" />`r`n";
$fileSolution += "$pathFrom\$location $pathTo\$location`r`n";
}
$fileManifest += "</RootFiles>`r`n";
################################################################
# output manifest.xml
MyWriteF "manifest.xml";
attrib -R "$hiveSolution\manifest.xml";
"<!-- file: $solutionWSP - Date: $dt-->
<Solution SolutionId=`"$solutionId`" xmlns=`"http://schemas.microsoft.com/sharepoint/`" >
$fileManifest
</Solution>" > "$hiveSolution\manifest.xml";
################################################################
# output solution.ddf
MyWriteF "solution.ddf";
attrib -R "$hiveSolution\solution.ddf";
";file: $solutionWSP - Date: $dt
.OPTION EXPLICIT
.Set CabinetNameTemplate=$solutionWSP
.set DiskDirectoryTemplate=CDROM
.Set CompressionType=MSZIP
.Set UniqueFiles=`"On`"
.Set Cabinet=on
.Set DiskDirectory1=
solution\manifest.xml manifest.xml
$fileSolution
" > "$hiveSolution\solution.ddf";
$dt = date;
MyWrite "End: $dt";
In pratica lo script scorre tutte le cartelle sotto la 12 e genera le corrette entry nei file manifest.xml, solution.ddf e nei vari feature.xml.
Per generare il pacchetto solution (.WSP)
DOS / Batch file
c:\windows\system32\makecab.exe /F solution.ddf
Come creare un file di solution (.wsp)
Microsoft SharePoint Solution Installer
Lo script non gestisce tutte le casistiche è può sicuramente essere milgliorato, in ogni caso si possono trovare vari spunti sull'uso di PowerShell con XML