A la hora de crear Columnas en SharePoint (versiones Server), nos encontrabamos con el formato de creación en Visual Studio, ya fuera por medio de código C#, o bien declarativamente, generando los XML de las columnas como módulos dentro de un SharePoint Project. En este post veremos cómo realizar estas tareas, haciendolas reutilizables por medio de PowerShell.
Las columnas de sitio, o SPField, internamente se guardan en las BBDD de Contenido de SharePoint como un XML con la siguiente estructura común:
- Id: Identificador único de tipo GUID
- Type: Introducir el nombre del tipo de columna. Consultar este enlace.
- Name: Nombre interno de la columna.
- Description: Descripción de la columna (no obligatorio).
- DisplayName: Nombre a mostrar de la columna.
- StaticName: Nombre de la columna en BBDD (por BestPractice lo ideal es cargar el mismo valor aquí y en el Name).
- Group: Grupo de columnas a la que pertenece.
- Required: Escribimos TRUE o FALSE.
Después hay ciertas excepciones a controlar:
- Format:
- Las columnas de tipo DateTime deberán incluir el formato DateTime / DateOnly.
- Las columnas de tipo Choice los valores Dropdown / RadioButtons.
- List: Debemos informar a qué lista apunta para los campos Lookup, y User.
- UserSelectionMode: Los campos User deben indicar si permiten personas y/o grupos
Hay dos casos más adicionales:
- Las columnas de tipo Choice deben tener un anidado de XML con sus valores de opción.
- Los Managed Metadata deben incluir una columna interna adicional y oculta de tipo Note que acompaña a la columna principal.
¿Y qué pasa si lo metemos todo junto en nuestra coctelera de código, y lo creamos como una función de PowerShell?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 |
function Add-FieldAsXml { param( [Parameter(Mandatory=$true,Position=1)][System.Guid]$Guid, [Parameter(Mandatory=$true,Position=2)][string]$Name, [Parameter(Mandatory=$true,Position=3)][string]$DisplayName, [Parameter(Mandatory=$true,Position=4)][string]$Group, [Parameter(Mandatory=$true,Position=5)][string]$FieldType, [Parameter(Mandatory=$false,Position=6)][string]$Description = "", [Parameter(Mandatory=$true,Position=7)][string]$Required, [Parameter(Mandatory=$false,Position=8)][string]$RowChoices = "", [Parameter(Mandatory=$false,Position=9)][string]$ManagedTerm = "" ) $FieldNotFound = $false try { $Field = $Web.Fields.GetByInternalNameOrTitle($Name) $Ctx.Load($Field) $Ctx.ExecuteQuery() } catch { Write-Host "`n`tColumna $($Name) no encontrada. Se va a crear." -ForeGroundColor DarkGreen Add-LogMessage -Text "INFO - Columna $($Name) no encontrada. A continuación se creará" $FieldNotFound = $true } if ($FieldNotFound) { $FieldXML = '<Field Id="{' + $Guid + '}" Type="' + $FieldType + '" Name="' + $Name + '" Description="' + $Description + '" DisplayName="' + $DisplayName + '" StaticName="' + $Name + '" Group="' + $Group + '" Required="' + $Required + '"' switch($FieldType) { "DateTime" { # Format: DateTime / DateOnly $FieldXML += ' Format="DateOnly"' } "Choice" { # Format: Dropdown / RadioButtons $FieldXML += ' Format="Dropdown"' } "TaxonomyFieldTypeMulti" { $FieldXML += ' Mult="TRUE"' } "User" { $FieldXML += ' List="UserInfo" UserSelectionMode="PeopleAndGroups"' } } $FieldXML += '>' if ($FieldType -eq "Choice") { $Choices = $RowChoices -split ('\n') Add-LogMessage -Text "INFO - $($Choices)" $FieldXML += '<CHOICES>' foreach ($Choice in $Choices) { Add-LogMessage -Text "INFO - $($Choice)" $FieldXML += '<CHOICE>' + $Choice + '</CHOICE>' } $FieldXML += '</CHOICES>' } $Web = $Ctx.Web $Ctx.Load($Web.Fields) $Ctx.ExecuteQuery() $AddOption = [Microsoft.SharePoint.Client.AddFieldOptions]::AddFieldInternalNameHint if ($FieldType -eq "TaxonomyFieldType" -or $FieldType -eq "TaxonomyFieldTypeMulti") { Add-LogMessage -Text "Buscar TermSet $($ManagedTerm)" $AnchorId = [Guid]::Empty if ($ManagedTerm -match ";") { $TermSetName = $ManagedTerm.split(";")[0] $TermSet = $TermGroup.TermSets.GetByName($TermSetName) $Term = Find-TermSet -TermString $ManagedTerm $Ctx.Load($TermSet) $Ctx.Load($Term) $Ctx.ExecuteQuery() $AnchorId = $Term.Id } else { $TermSet = $TermGroup.TermSets.GetByName($ManagedTerm) $Ctx.Load($TermSet) $Ctx.ExecuteQuery() } $TermStoreId = $TermStore.Id $TermSetId = $TermSet.Id Add-LogMessage -Text "TermStore $($TermStoreId)" Add-LogMessage -Text "TermSet $($TermSetId)" $NoteGuid = [guid]::NewGuid() $FieldXml_0 = '<Field Type="Note" DisplayName="' + $Name + '_0" StaticName="' + $Name + 'TaxHTField0" Name="' + $Name + 'TaxHTField0" ID="{' + $NoteGuid + '}" ShowInViewForms="FALSE" Required="FALSE" Hidden="TRUE" Group="' + $Group + '" CanToggleHidden="TRUE" />' $NewField_0 = $Web.Fields.AddFieldAsXml($FieldXml_0, $true, $AddOption) $Ctx.Load($NewField_0) try { $Ctx.ExecuteQuery() Write-Host "`n`tCreada columna oculta para $($Title) con éxito" -ForeGroundColor DarkGreen Add-LogMessage -Text "Creada columna oculta para $Title con éxito." } catch { Write-Warning "`nError en la creación de la columna $($Name)_0. Revise el log." Add-LogMessage -Text "WARNING - $_.Exception.Message" } # Chris O'brien http://www.sharepointnutsandbolts.com/2013/09/provisioning-managed-metadata-fields-in-Office-365.html $FieldXML += '<Default/> <Customization> <ArrayOfProperty> <Property> <Name>SspId</Name> <Value xmlns:q1="http://www.w3.org/2001/XMLSchema" p4:type="q1:string" xmlns:p4="http://www.w3.org/2001/XMLSchema-instance">' + $TermStoreId + '</Value> </Property> <Property> <Name>GroupId</Name> </Property> <Property> <Name>TermSetId</Name> <Value xmlns:q2="http://www.w3.org/2001/XMLSchema" p4:type="q2:string" xmlns:p4="http://www.w3.org/2001/XMLSchema-instance">' + $TermSetId + '</Value> </Property> <Property> <Name>AnchorId</Name> <Value xmlns:q3="http://www.w3.org/2001/XMLSchema" p4:type="q3:string" xmlns:p4="http://www.w3.org/2001/XMLSchema-instance">' + $AnchorId + '</Value> </Property> <Property> <Name>UserCreated</Name> <Value xmlns:q4="http://www.w3.org/2001/XMLSchema" p4:type="q4:boolean" xmlns:p4="http://www.w3.org/2001/XMLSchema-instance">false</Value> </Property> <Property> <Name>Open</Name> <Value xmlns:q5="http://www.w3.org/2001/XMLSchema" p4:type="q5:boolean" xmlns:p4="http://www.w3.org/2001/XMLSchema-instance">false</Value> </Property> <Property> <Name>TextField</Name> <Value xmlns:q6="http://www.w3.org/2001/XMLSchema" p4:type="q6:string" xmlns:p4="http://www.w3.org/2001/XMLSchema-instance">{' + $NoteGuid + '}</Value> </Property> <Property> <Name>IsPathRendered</Name> <Value xmlns:q7="http://www.w3.org/2001/XMLSchema" p4:type="q7:boolean" xmlns:p4="http://www.w3.org/2001/XMLSchema-instance">false</Value> </Property> <Property> <Name>IsKeyword</Name> <Value xmlns:q8="http://www.w3.org/2001/XMLSchema" p4:type="q8:boolean" xmlns:p4="http://www.w3.org/2001/XMLSchema-instance">false</Value> </Property> <Property> <Name>TargetTemplate</Name> </Property> <Property> <Name>CreateValuesInEditForm</Name> <Value xmlns:q9="http://www.w3.org/2001/XMLSchema" p4:type="q9:boolean" xmlns:p4="http://www.w3.org/2001/XMLSchema-instance">false</Value> </Property> <Property> <Name>FilterAssemblyStrongName</Name> <Value xmlns:q10="http://www.w3.org/2001/XMLSchema" p4:type="q10:string" xmlns:p4="http://www.w3.org/2001/XMLSchema-instance">Microsoft.SharePoint.Taxonomy, Version=16.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c</Value> </Property> <Property> <Name>FilterClassName</Name> <Value xmlns:q11="http://www.w3.org/2001/XMLSchema" p4:type="q11:string" xmlns:p4="http://www.w3.org/2001/XMLSchema-instance">Microsoft.SharePoint.Taxonomy.TaxonomyField</Value> </Property> <Property> <Name>FilterMethodName</Name> <Value xmlns:q12="http://www.w3.org/2001/XMLSchema" p4:type="q12:string" xmlns:p4="http://www.w3.org/2001/XMLSchema-instance">GetFilteringHtml</Value> </Property> <Property> <Name>FilterJavascriptProperty</Name> <Value xmlns:q13="http://www.w3.org/2001/XMLSchema" p4:type="q13:string" xmlns:p4="http://www.w3.org/2001/XMLSchema-instance">FilteringJavascript</Value> </Property> </ArrayOfProperty> </Customization>' } $FieldXML += '</Field>' Add-LogMessage -Text "INFO - $FieldXML" $NewField = $Web.Fields.AddFieldAsXml($FieldXML, $true, $AddOption) $Ctx.Load($NewField) try { $Ctx.ExecuteQuery() Write-Host "`n`tCreada columna $($Name) con éxito" -ForeGroundColor DarkGreen Add-LogMessage -Text "Creada columna $Name con éxito." } catch { Write-Warning "`nError en la creación de la columna $($Name). Revise el log." Add-LogMessage -Text "WARNING - $_.Exception.Message" } } else { Write-Host "`n`tColumna $($Name) existente" -ForeGroundColor DarkGray Add-LogMessage -Text "Columna $Name ya existe." } } |
Lo hemos vuelto a conseguir. Yeah!