1638 lines
47 KiB
PowerShell
1638 lines
47 KiB
PowerShell
[CmdletBinding()]
|
|
param(
|
|
[string]$WebUrl,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$OutputPath,
|
|
|
|
[switch]$IncludeHiddenLibraries,
|
|
|
|
[switch]$IncludeHiddenLists,
|
|
|
|
[string]$TargetWebUrl,
|
|
|
|
[string]$MappingCsvPath,
|
|
|
|
[switch]$ImportFiles,
|
|
|
|
[switch]$ImportLists,
|
|
|
|
[switch]$OverwriteFiles,
|
|
|
|
[switch]$ExportOnly,
|
|
|
|
[switch]$ImportOnly
|
|
)
|
|
|
|
Set-StrictMode -Version Latest
|
|
$ErrorActionPreference = "Stop"
|
|
|
|
function Initialize-SharePointPowerShell {
|
|
Import-Module SharePointServer
|
|
}
|
|
|
|
function Ensure-Directory {
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$Path
|
|
)
|
|
|
|
if (-not [System.IO.Directory]::Exists($Path)) {
|
|
[System.IO.Directory]::CreateDirectory($Path) | Out-Null
|
|
}
|
|
}
|
|
|
|
function Invoke-MigrationImport {
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$InputPath,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$TargetWebUrl,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$MappingCsvPath,
|
|
|
|
[switch]$ImportFiles,
|
|
|
|
[switch]$ImportLists,
|
|
|
|
[switch]$OverwriteFiles
|
|
)
|
|
|
|
$resolvedInputPath = [System.IO.Path]::GetFullPath($InputPath)
|
|
$filesRootPath = [System.IO.Path]::Combine($resolvedInputPath, "Files")
|
|
$listsRootPath = [System.IO.Path]::Combine($resolvedInputPath, "Lists")
|
|
$manifestPath = [System.IO.Path]::Combine($resolvedInputPath, "manifest.csv")
|
|
$fieldMapping = Get-FieldMapping -Path $MappingCsvPath
|
|
$containerManifestMap = Get-ContainerManifestMap -ManifestRows (Read-ManifestRows -ManifestPath $manifestPath)
|
|
|
|
if ($fieldMapping.Count -eq 0) {
|
|
throw "Die Mapping-CSV enthaelt keine gueltigen Zuordnungen."
|
|
}
|
|
|
|
$shouldImportFiles = $ImportFiles.IsPresent
|
|
$shouldImportLists = $ImportLists.IsPresent
|
|
|
|
if (-not $shouldImportFiles -and -not $shouldImportLists) {
|
|
$shouldImportFiles = $true
|
|
$shouldImportLists = $true
|
|
}
|
|
|
|
$targetWeb = $null
|
|
|
|
try {
|
|
$targetWeb = Get-SPWeb -Identity $TargetWebUrl -ErrorAction Stop
|
|
|
|
if ($shouldImportFiles) {
|
|
Import-SPDocumentLibraries -Web $targetWeb -FilesRootPath $filesRootPath -FieldMapping $fieldMapping -ContainerManifestMap $containerManifestMap -OverwriteFiles:$OverwriteFiles
|
|
}
|
|
|
|
if ($shouldImportLists) {
|
|
Import-SPLists -Web $targetWeb -ListsRootPath $listsRootPath -FieldMapping $fieldMapping -ContainerManifestMap $containerManifestMap
|
|
}
|
|
|
|
Write-Host ("Import abgeschlossen. Quelle: {0}" -f $resolvedInputPath)
|
|
}
|
|
finally {
|
|
if ($null -ne $targetWeb) {
|
|
$targetWeb.Dispose()
|
|
}
|
|
}
|
|
}
|
|
|
|
function Get-SafePathSegment {
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$Name
|
|
)
|
|
|
|
$invalidChars = [System.IO.Path]::GetInvalidFileNameChars()
|
|
$safeName = $Name
|
|
|
|
foreach ($char in $invalidChars) {
|
|
$safeName = $safeName.Replace($char, "_")
|
|
}
|
|
|
|
$safeName = $safeName.Trim()
|
|
|
|
if ([string]::IsNullOrWhiteSpace($safeName)) {
|
|
return "_"
|
|
}
|
|
|
|
return $safeName
|
|
}
|
|
|
|
function Test-IsCatalogList {
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[Microsoft.SharePoint.SPList]$List
|
|
)
|
|
|
|
try {
|
|
return [bool]$List.IsCatalog
|
|
}
|
|
catch {
|
|
return $false
|
|
}
|
|
}
|
|
|
|
function Get-SafeCollectionCount {
|
|
param(
|
|
$Value
|
|
)
|
|
|
|
if ($null -eq $Value) {
|
|
return 0
|
|
}
|
|
|
|
try {
|
|
return [int]$Value.Count
|
|
}
|
|
catch {
|
|
}
|
|
|
|
try {
|
|
return [int]$Value.Length
|
|
}
|
|
catch {
|
|
}
|
|
|
|
return @($Value).Length
|
|
}
|
|
|
|
function Combine-PathSegments {
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$BasePath,
|
|
|
|
[string[]]$Segments = @()
|
|
)
|
|
|
|
$combinedPath = $BasePath
|
|
|
|
foreach ($segment in $Segments) {
|
|
if (-not [string]::IsNullOrWhiteSpace($segment)) {
|
|
$combinedPath = [System.IO.Path]::Combine($combinedPath, $segment)
|
|
}
|
|
}
|
|
|
|
return $combinedPath
|
|
}
|
|
|
|
function Convert-SPFieldValue {
|
|
param(
|
|
[Parameter(ValueFromPipeline = $true)]
|
|
$Value
|
|
)
|
|
|
|
if ($null -eq $Value) {
|
|
return $null
|
|
}
|
|
|
|
if ($Value -is [System.DateTime]) {
|
|
return $Value.ToString("o")
|
|
}
|
|
|
|
if ($Value -is [Microsoft.SharePoint.SPFieldUserValue]) {
|
|
return @{
|
|
LookupId = $Value.LookupId
|
|
LookupValue = $Value.LookupValue
|
|
Email = $Value.User.Email
|
|
LoginName = $Value.User.LoginName
|
|
}
|
|
}
|
|
|
|
if ($Value -is [Microsoft.SharePoint.SPFieldUserValueCollection]) {
|
|
return @($Value | ForEach-Object { Convert-SPFieldValue $_ })
|
|
}
|
|
|
|
if ($Value -is [Microsoft.SharePoint.SPFieldLookupValue]) {
|
|
return @{
|
|
LookupId = $Value.LookupId
|
|
LookupValue = $Value.LookupValue
|
|
}
|
|
}
|
|
|
|
if ($Value -is [Microsoft.SharePoint.SPFieldLookupValueCollection]) {
|
|
return @($Value | ForEach-Object { Convert-SPFieldValue $_ })
|
|
}
|
|
|
|
if ($Value -is [Microsoft.SharePoint.SPFieldUrlValue]) {
|
|
return @{
|
|
Url = $Value.Url
|
|
Description = $Value.Description
|
|
}
|
|
}
|
|
|
|
if ($Value -is [System.Guid]) {
|
|
return $Value.ToString()
|
|
}
|
|
|
|
if ($Value -is [System.Collections.IEnumerable] -and -not ($Value -is [string])) {
|
|
return @($Value | ForEach-Object { Convert-SPFieldValue $_ })
|
|
}
|
|
|
|
$typeName = $Value.GetType().FullName
|
|
if ($typeName -like "*TaxonomyFieldValue") {
|
|
return @{
|
|
Label = $Value.Label
|
|
TermGuid = $Value.TermGuid
|
|
WssId = $Value.WssId
|
|
}
|
|
}
|
|
|
|
if ($typeName -like "*TaxonomyFieldValueCollection") {
|
|
return @($Value | ForEach-Object {
|
|
@{
|
|
Label = $_.Label
|
|
TermGuid = $_.TermGuid
|
|
WssId = $_.WssId
|
|
}
|
|
})
|
|
}
|
|
|
|
return $Value
|
|
}
|
|
|
|
function Get-FieldTextValue {
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[Microsoft.SharePoint.SPField]$Field,
|
|
|
|
$RawValue
|
|
)
|
|
|
|
try {
|
|
return $Field.GetFieldValueAsText($RawValue)
|
|
}
|
|
catch {
|
|
return $null
|
|
}
|
|
}
|
|
|
|
function Get-ItemFieldTextValue {
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[Microsoft.SharePoint.SPListItem]$Item,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$InternalName
|
|
)
|
|
|
|
$field = $null
|
|
|
|
try {
|
|
$field = $Item.Fields.GetFieldByInternalName($InternalName)
|
|
}
|
|
catch {
|
|
$field = $null
|
|
}
|
|
|
|
if ($null -eq $field) {
|
|
try {
|
|
$field = $Item.Fields.GetFieldByStaticName($InternalName)
|
|
}
|
|
catch {
|
|
$field = $null
|
|
}
|
|
}
|
|
|
|
if ($null -eq $field) {
|
|
return $null
|
|
}
|
|
|
|
$rawValue = $null
|
|
|
|
try {
|
|
$rawValue = $Item[$field.InternalName]
|
|
}
|
|
catch {
|
|
try {
|
|
$rawValue = $Item[$field.Id]
|
|
}
|
|
catch {
|
|
$rawValue = $null
|
|
}
|
|
}
|
|
|
|
return Get-FieldTextValue -Field $field -RawValue $rawValue
|
|
}
|
|
|
|
function Get-ListItemFieldMetadata {
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[Microsoft.SharePoint.SPListItem]$Item
|
|
)
|
|
|
|
$fieldMetadata = @()
|
|
|
|
foreach ($field in $Item.Fields) {
|
|
$rawValue = $null
|
|
|
|
try {
|
|
$rawValue = $Item[$field.InternalName]
|
|
}
|
|
catch {
|
|
try {
|
|
$rawValue = $Item[$field.Id]
|
|
}
|
|
catch {
|
|
$rawValue = $null
|
|
}
|
|
}
|
|
|
|
$fieldMetadata += [PSCustomObject]@{
|
|
InternalName = $field.InternalName
|
|
TypeAsString = $field.TypeAsString
|
|
TextValue = Get-FieldTextValue -Field $field -RawValue $rawValue
|
|
Value = Convert-SPFieldValue $rawValue
|
|
}
|
|
}
|
|
|
|
return $fieldMetadata
|
|
}
|
|
|
|
function Get-ListItemFieldValueMap {
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[Microsoft.SharePoint.SPListItem]$Item,
|
|
|
|
[switch]$AsText
|
|
)
|
|
|
|
$fieldValues = [ordered]@{}
|
|
|
|
foreach ($field in $Item.Fields) {
|
|
$rawValue = $null
|
|
|
|
try {
|
|
$rawValue = $Item[$field.InternalName]
|
|
}
|
|
catch {
|
|
try {
|
|
$rawValue = $Item[$field.Id]
|
|
}
|
|
catch {
|
|
$rawValue = $null
|
|
}
|
|
}
|
|
|
|
if ($AsText) {
|
|
$fieldValues[$field.InternalName] = Get-FieldTextValue -Field $field -RawValue $rawValue
|
|
}
|
|
else {
|
|
$fieldValues[$field.InternalName] = Convert-SPFieldValue $rawValue
|
|
}
|
|
}
|
|
|
|
return [PSCustomObject]$fieldValues
|
|
}
|
|
|
|
function Get-ListItemAttachmentMetadata {
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[Microsoft.SharePoint.SPListItem]$Item
|
|
)
|
|
|
|
$attachments = @()
|
|
$attachmentCollection = $Item.Attachments
|
|
|
|
if ((Get-SafeCollectionCount $attachmentCollection) -eq 0) {
|
|
return $attachments
|
|
}
|
|
|
|
foreach ($attachmentName in @($attachmentCollection)) {
|
|
$attachments += [PSCustomObject]@{
|
|
FileName = $attachmentName
|
|
Url = $attachmentCollection.UrlPrefix + $attachmentName
|
|
}
|
|
}
|
|
|
|
return $attachments
|
|
}
|
|
|
|
function Get-ListItemMetadataObject {
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[Microsoft.SharePoint.SPListItem]$Item
|
|
)
|
|
|
|
$attachmentCollection = $Item.Attachments
|
|
|
|
return [PSCustomObject]@{
|
|
Id = $Item.ID
|
|
UniqueId = $Item.UniqueId.ToString()
|
|
Title = if ($Item.Fields.ContainsField("Title")) { $Item["Title"] } else { $null }
|
|
ContentTypeId = $Item.ContentTypeId.ToString()
|
|
FileSystemObjectType = $Item.FileSystemObjectType.ToString()
|
|
DisplayName = $Item.DisplayName
|
|
Name = if ($Item.Name) { $Item.Name } else { $null }
|
|
Url = if ($Item.Url) { $Item.Url } else { $null }
|
|
ServerRelativeUrl = if ($Item.Folder) { $Item.Folder.ServerRelativeUrl } else { $null }
|
|
Created = if ($null -ne $Item["Created"]) { ([datetime]$Item["Created"]).ToString("o") } else { $null }
|
|
Modified = if ($null -ne $Item["Modified"]) { ([datetime]$Item["Modified"]).ToString("o") } else { $null }
|
|
CreatedBy = Get-ItemFieldTextValue -Item $Item -InternalName "Author"
|
|
ModifiedBy = Get-ItemFieldTextValue -Item $Item -InternalName "Editor"
|
|
HasAttachments = (Get-SafeCollectionCount $attachmentCollection) -gt 0
|
|
Attachments = Get-ListItemAttachmentMetadata -Item $Item
|
|
FieldValues = Get-ListItemFieldValueMap -Item $Item
|
|
FieldTextValues = Get-ListItemFieldValueMap -Item $Item -AsText
|
|
Fields = Get-ListItemFieldMetadata -Item $Item
|
|
}
|
|
}
|
|
|
|
function Get-FileMetadataObject {
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[Microsoft.SharePoint.SPWeb]$Web,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[Microsoft.SharePoint.SPList]$List,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[Microsoft.SharePoint.SPFile]$File
|
|
)
|
|
|
|
$item = $File.Item
|
|
|
|
return [PSCustomObject]@{
|
|
ExportedAtUtc = [System.DateTime]::UtcNow.ToString("o")
|
|
Web = [PSCustomObject]@{
|
|
Title = $Web.Title
|
|
Url = $Web.Url
|
|
ServerRelativeUrl = $Web.ServerRelativeUrl
|
|
Id = $Web.ID.ToString()
|
|
}
|
|
Library = [PSCustomObject]@{
|
|
Title = $List.Title
|
|
Id = $List.ID.ToString()
|
|
RootFolderUrl = $List.RootFolder.ServerRelativeUrl
|
|
BaseTemplate = [int]$List.BaseTemplate
|
|
}
|
|
File = [PSCustomObject]@{
|
|
Name = $File.Name
|
|
Url = $File.Url
|
|
ServerRelativeUrl = $File.ServerRelativeUrl
|
|
UniqueId = $File.UniqueId.ToString()
|
|
Length = $File.Length
|
|
TimeCreated = $File.TimeCreated.ToString("o")
|
|
TimeLastModified = $File.TimeLastModified.ToString("o")
|
|
CheckOutType = $File.CheckOutType.ToString()
|
|
Level = $File.Level.ToString()
|
|
MajorVersion = $File.MajorVersion
|
|
MinorVersion = $File.MinorVersion
|
|
}
|
|
Item = if ($null -ne $item) {
|
|
Get-ListItemMetadataObject -Item $item
|
|
}
|
|
else {
|
|
$null
|
|
}
|
|
}
|
|
}
|
|
|
|
function Write-MetadataJson {
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
$MetadataObject,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$Path
|
|
)
|
|
|
|
$json = $MetadataObject | ConvertTo-Json -Depth 10
|
|
[System.IO.File]::WriteAllText($Path, $json, [System.Text.Encoding]::UTF8)
|
|
}
|
|
|
|
function Write-ManifestRow {
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[pscustomobject]$Row,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$ManifestPath
|
|
)
|
|
|
|
$append = [System.IO.File]::Exists($ManifestPath)
|
|
$Row | Export-Csv -Path $ManifestPath -NoTypeInformation -Delimiter ";" -Encoding UTF8 -Append:$append
|
|
}
|
|
|
|
function New-ManifestRow {
|
|
param(
|
|
[string]$RecordType = "",
|
|
[string]$ObjectType = "",
|
|
[string]$SourceWebUrl = "",
|
|
[string]$SourceTitle = "",
|
|
[string]$TargetTitle = "",
|
|
[string]$BaseType = "",
|
|
[string]$BaseTemplate = "",
|
|
[string]$RootFolderUrl = "",
|
|
[string]$SourceServerRelativeUrl = "",
|
|
[string]$FileName = "",
|
|
[string]$FileUniqueId = "",
|
|
[string]$FileLength = "",
|
|
[string]$LocalFilePath = "",
|
|
[string]$LocalMetadataPath = "",
|
|
[string]$ExportedAtUtc = ""
|
|
)
|
|
|
|
return [PSCustomObject]@{
|
|
RecordType = $RecordType
|
|
ObjectType = $ObjectType
|
|
SourceWebUrl = $SourceWebUrl
|
|
SourceTitle = $SourceTitle
|
|
TargetTitle = $TargetTitle
|
|
BaseType = $BaseType
|
|
BaseTemplate = $BaseTemplate
|
|
RootFolderUrl = $RootFolderUrl
|
|
SourceServerRelativeUrl = $SourceServerRelativeUrl
|
|
FileName = $FileName
|
|
FileUniqueId = $FileUniqueId
|
|
FileLength = $FileLength
|
|
LocalFilePath = $LocalFilePath
|
|
LocalMetadataPath = $LocalMetadataPath
|
|
ExportedAtUtc = $ExportedAtUtc
|
|
}
|
|
}
|
|
|
|
function Write-ContainerManifestRow {
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[Microsoft.SharePoint.SPWeb]$Web,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[Microsoft.SharePoint.SPList]$List,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$ManifestPath
|
|
)
|
|
|
|
$objectType = if ($List.BaseType -eq [Microsoft.SharePoint.SPBaseType]::DocumentLibrary) { "DocumentLibrary" } else { "List" }
|
|
|
|
$manifestRow = New-ManifestRow `
|
|
-RecordType "Container" `
|
|
-ObjectType $objectType `
|
|
-SourceWebUrl $Web.Url `
|
|
-SourceTitle $List.Title `
|
|
-TargetTitle "" `
|
|
-BaseType $List.BaseType.ToString() `
|
|
-BaseTemplate ([string][int]$List.BaseTemplate) `
|
|
-RootFolderUrl $List.RootFolder.ServerRelativeUrl `
|
|
-SourceServerRelativeUrl $List.RootFolder.ServerRelativeUrl `
|
|
-ExportedAtUtc ([System.DateTime]::UtcNow.ToString("o"))
|
|
|
|
Write-ManifestRow -Row $manifestRow -ManifestPath $ManifestPath
|
|
}
|
|
|
|
function Get-RelativeFilePathSegments {
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[Microsoft.SharePoint.SPList]$List,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[Microsoft.SharePoint.SPFile]$File
|
|
)
|
|
|
|
$rootUrl = $List.RootFolder.ServerRelativeUrl.TrimEnd("/")
|
|
$fileUrl = $File.ServerRelativeUrl
|
|
$relativeUrl = $fileUrl.Substring($rootUrl.Length).TrimStart("/")
|
|
|
|
return @($relativeUrl.Split("/") | ForEach-Object { Get-SafePathSegment $_ })
|
|
}
|
|
|
|
function Get-SPListItemsRecursive {
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[Microsoft.SharePoint.SPList]$List
|
|
)
|
|
|
|
$query = New-Object Microsoft.SharePoint.SPQuery
|
|
$query.Query = ""
|
|
$query.Folder = $List.RootFolder
|
|
$query.ViewAttributes = "Scope='RecursiveAll'"
|
|
$query.RowLimit = 0
|
|
$query.ViewFieldsOnly = $false
|
|
|
|
return @($List.GetItems($query))
|
|
}
|
|
|
|
function Export-SPFile {
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[Microsoft.SharePoint.SPWeb]$Web,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[Microsoft.SharePoint.SPList]$List,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[Microsoft.SharePoint.SPFile]$File,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$FilesRootPath,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$ManifestPath
|
|
)
|
|
|
|
$relativeSegments = @(Get-RelativeFilePathSegments -List $List -File $File)
|
|
$relativeDirectorySegments = @()
|
|
|
|
if ($relativeSegments.Length -gt 1) {
|
|
$relativeDirectorySegments = $relativeSegments[0..($relativeSegments.Length - 2)]
|
|
}
|
|
|
|
$safeLibraryName = Get-SafePathSegment $List.Title
|
|
$fileDirectory = Combine-PathSegments -BasePath ([System.IO.Path]::Combine($FilesRootPath, $safeLibraryName)) -Segments $relativeDirectorySegments
|
|
|
|
Ensure-Directory -Path $fileDirectory
|
|
|
|
if ($relativeSegments.Length -eq 0) {
|
|
throw ("Konnte keinen relativen Dateipfad fuer '{0}' ermitteln." -f $File.ServerRelativeUrl)
|
|
}
|
|
|
|
$fileName = $relativeSegments[-1]
|
|
$localFilePath = [System.IO.Path]::Combine($fileDirectory, $fileName)
|
|
$metadataPath = [System.IO.Path]::Combine($fileDirectory, "$fileName.properties.json")
|
|
|
|
[System.IO.File]::WriteAllBytes($localFilePath, $File.OpenBinary())
|
|
|
|
$metadata = Get-FileMetadataObject -Web $Web -List $List -File $File
|
|
Write-MetadataJson -MetadataObject $metadata -Path $metadataPath
|
|
|
|
$manifestRow = New-ManifestRow `
|
|
-RecordType "File" `
|
|
-ObjectType "DocumentLibrary" `
|
|
-SourceWebUrl $Web.Url `
|
|
-SourceTitle $List.Title `
|
|
-TargetTitle "" `
|
|
-BaseType $List.BaseType.ToString() `
|
|
-BaseTemplate ([string][int]$List.BaseTemplate) `
|
|
-RootFolderUrl $List.RootFolder.ServerRelativeUrl `
|
|
-SourceServerRelativeUrl $File.ServerRelativeUrl `
|
|
-FileName $File.Name `
|
|
-FileUniqueId $File.UniqueId.ToString() `
|
|
-FileLength ([string]$File.Length) `
|
|
-LocalFilePath $localFilePath `
|
|
-LocalMetadataPath $metadataPath `
|
|
-ExportedAtUtc ([System.DateTime]::UtcNow.ToString("o"))
|
|
|
|
Write-ManifestRow -Row $manifestRow -ManifestPath $ManifestPath
|
|
}
|
|
|
|
function Export-SPFolder {
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[Microsoft.SharePoint.SPWeb]$Web,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[Microsoft.SharePoint.SPList]$List,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[Microsoft.SharePoint.SPFolder]$Folder,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$FilesRootPath,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$ManifestPath,
|
|
|
|
[ref]$FileCount
|
|
)
|
|
|
|
foreach ($file in $Folder.Files) {
|
|
Export-SPFile -Web $Web -List $List -File $file -FilesRootPath $FilesRootPath -ManifestPath $ManifestPath
|
|
$FileCount.Value++
|
|
}
|
|
|
|
foreach ($subFolder in $Folder.SubFolders) {
|
|
if ($subFolder.Name -eq "Forms") {
|
|
continue
|
|
}
|
|
|
|
Export-SPFolder -Web $Web -List $List -Folder $subFolder -FilesRootPath $FilesRootPath -ManifestPath $ManifestPath -FileCount $FileCount
|
|
}
|
|
}
|
|
|
|
function Export-SPDocumentLibrary {
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[Microsoft.SharePoint.SPWeb]$Web,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[Microsoft.SharePoint.SPList]$List,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$FilesRootPath,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$ManifestPath
|
|
)
|
|
|
|
Write-Host ("Exportiere Bibliothek: {0}" -f $List.Title)
|
|
Write-ContainerManifestRow -Web $Web -List $List -ManifestPath $ManifestPath
|
|
$fileCount = 0
|
|
|
|
Export-SPFolder -Web $Web -List $List -Folder $List.RootFolder -FilesRootPath $FilesRootPath -ManifestPath $ManifestPath -FileCount ([ref]$fileCount)
|
|
|
|
Write-Host (" Dateien exportiert: {0}" -f $fileCount)
|
|
}
|
|
|
|
function Export-SPList {
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[Microsoft.SharePoint.SPWeb]$Web,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[Microsoft.SharePoint.SPList]$List,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$ListsRootPath,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$ManifestPath
|
|
)
|
|
|
|
Write-Host ("Exportiere Liste: {0}" -f $List.Title)
|
|
Write-ContainerManifestRow -Web $Web -List $List -ManifestPath $ManifestPath
|
|
|
|
$safeListName = Get-SafePathSegment $List.Title
|
|
$listPath = [System.IO.Path]::Combine($ListsRootPath, "$safeListName.json")
|
|
$items = @()
|
|
|
|
foreach ($item in @(Get-SPListItemsRecursive -List $List)) {
|
|
$items += Get-ListItemMetadataObject -Item $item
|
|
}
|
|
|
|
$listExport = [PSCustomObject]@{
|
|
ExportedAtUtc = [System.DateTime]::UtcNow.ToString("o")
|
|
Web = [PSCustomObject]@{
|
|
Title = $Web.Title
|
|
Url = $Web.Url
|
|
ServerRelativeUrl = $Web.ServerRelativeUrl
|
|
Id = $Web.ID.ToString()
|
|
}
|
|
List = [PSCustomObject]@{
|
|
Title = $List.Title
|
|
Id = $List.ID.ToString()
|
|
BaseType = $List.BaseType.ToString()
|
|
BaseTemplate = [int]$List.BaseTemplate
|
|
DefaultViewUrl = $List.DefaultViewUrl
|
|
RootFolderUrl = $List.RootFolder.ServerRelativeUrl
|
|
ItemCount = $List.ItemCount
|
|
Hidden = $List.Hidden
|
|
}
|
|
Items = $items
|
|
}
|
|
|
|
Write-MetadataJson -MetadataObject $listExport -Path $listPath
|
|
|
|
Write-Host (" Listeneintraege exportiert: {0}" -f $items.Length)
|
|
}
|
|
|
|
function Get-ObjectPropertyValue {
|
|
param(
|
|
$Object,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$PropertyName,
|
|
|
|
$DefaultValue = $null
|
|
)
|
|
|
|
if ($null -eq $Object) {
|
|
return $DefaultValue
|
|
}
|
|
|
|
$property = $Object.PSObject.Properties[$PropertyName]
|
|
if ($null -eq $property) {
|
|
return $DefaultValue
|
|
}
|
|
|
|
return $property.Value
|
|
}
|
|
|
|
function Read-ManifestRows {
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$ManifestPath
|
|
)
|
|
|
|
if (-not [System.IO.File]::Exists($ManifestPath)) {
|
|
return @()
|
|
}
|
|
|
|
return @(Import-Csv -Path $ManifestPath -Delimiter ";")
|
|
}
|
|
|
|
function Get-ContainerManifestEntryKey {
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$ObjectType,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$SourceTitle
|
|
)
|
|
|
|
return ("{0}|{1}" -f $ObjectType.Trim(), $SourceTitle.Trim()).ToLowerInvariant()
|
|
}
|
|
|
|
function Get-ContainerManifestMap {
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[object[]]$ManifestRows
|
|
)
|
|
|
|
$containerMap = @{}
|
|
|
|
foreach ($row in $ManifestRows) {
|
|
$recordType = [string](Get-ObjectPropertyValue -Object $row -PropertyName "RecordType")
|
|
$sourceTitle = [string](Get-ObjectPropertyValue -Object $row -PropertyName "SourceTitle")
|
|
$objectType = [string](Get-ObjectPropertyValue -Object $row -PropertyName "ObjectType")
|
|
|
|
if ($recordType -ne "Container" -or [string]::IsNullOrWhiteSpace($sourceTitle) -or [string]::IsNullOrWhiteSpace($objectType)) {
|
|
continue
|
|
}
|
|
|
|
$key = Get-ContainerManifestEntryKey -ObjectType $objectType -SourceTitle $sourceTitle
|
|
$containerMap[$key] = $row
|
|
}
|
|
|
|
return $containerMap
|
|
}
|
|
|
|
function Get-TargetContainerTitle {
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[hashtable]$ContainerManifestMap,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$ObjectType,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$SourceTitle
|
|
)
|
|
|
|
$key = Get-ContainerManifestEntryKey -ObjectType $ObjectType -SourceTitle $SourceTitle
|
|
$manifestEntry = $ContainerManifestMap[$key]
|
|
|
|
if ($null -eq $manifestEntry) {
|
|
return $SourceTitle
|
|
}
|
|
|
|
$targetTitle = [string](Get-ObjectPropertyValue -Object $manifestEntry -PropertyName "TargetTitle")
|
|
if ([string]::IsNullOrWhiteSpace($targetTitle)) {
|
|
return $SourceTitle
|
|
}
|
|
|
|
return $targetTitle.Trim()
|
|
}
|
|
|
|
function Test-ContainerHasExplicitTargetMapping {
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[hashtable]$ContainerManifestMap,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$ObjectType,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$SourceTitle
|
|
)
|
|
|
|
$key = Get-ContainerManifestEntryKey -ObjectType $ObjectType -SourceTitle $SourceTitle
|
|
$manifestEntry = $ContainerManifestMap[$key]
|
|
|
|
if ($null -eq $manifestEntry) {
|
|
return $false
|
|
}
|
|
|
|
$targetTitle = [string](Get-ObjectPropertyValue -Object $manifestEntry -PropertyName "TargetTitle")
|
|
return -not [string]::IsNullOrWhiteSpace($targetTitle)
|
|
}
|
|
|
|
function Test-ObjectHasProperty {
|
|
param(
|
|
$Object,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$PropertyName
|
|
)
|
|
|
|
if ($null -eq $Object) {
|
|
return $false
|
|
}
|
|
|
|
return $null -ne $Object.PSObject.Properties[$PropertyName]
|
|
}
|
|
|
|
function Read-JsonFile {
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$Path
|
|
)
|
|
|
|
return Get-Content -Path $Path -Raw -Encoding UTF8 | ConvertFrom-Json
|
|
}
|
|
|
|
function Resolve-SPField {
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[Microsoft.SharePoint.SPFieldCollection]$Fields,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$InternalName
|
|
)
|
|
|
|
try {
|
|
return $Fields.GetFieldByInternalName($InternalName)
|
|
}
|
|
catch {
|
|
}
|
|
|
|
try {
|
|
return $Fields.GetFieldByStaticName($InternalName)
|
|
}
|
|
catch {
|
|
}
|
|
|
|
foreach ($field in $Fields) {
|
|
if ($field.InternalName -eq $InternalName -or $field.StaticName -eq $InternalName) {
|
|
return $field
|
|
}
|
|
}
|
|
|
|
return $null
|
|
}
|
|
|
|
function Get-FieldMapping {
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$Path
|
|
)
|
|
|
|
$rows = Import-Csv -Path $Path -Delimiter ";"
|
|
$mapping = [ordered]@{}
|
|
|
|
foreach ($row in $rows) {
|
|
$sourceInternalName = [string](Get-ObjectPropertyValue -Object $row -PropertyName "SourceInternalName")
|
|
$targetInternalName = [string](Get-ObjectPropertyValue -Object $row -PropertyName "TargetInternalName")
|
|
|
|
if ([string]::IsNullOrWhiteSpace($sourceInternalName) -or [string]::IsNullOrWhiteSpace($targetInternalName)) {
|
|
continue
|
|
}
|
|
|
|
$mapping[$sourceInternalName.Trim()] = $targetInternalName.Trim()
|
|
}
|
|
|
|
return $mapping
|
|
}
|
|
|
|
function Convert-ToBoolean {
|
|
param(
|
|
$RawValue,
|
|
$TextValue
|
|
)
|
|
|
|
if ($RawValue -is [bool]) {
|
|
return $RawValue
|
|
}
|
|
|
|
$candidate = $RawValue
|
|
if ($null -eq $candidate -or [string]::IsNullOrWhiteSpace([string]$candidate)) {
|
|
$candidate = $TextValue
|
|
}
|
|
|
|
if ($null -eq $candidate -or [string]::IsNullOrWhiteSpace([string]$candidate)) {
|
|
return $null
|
|
}
|
|
|
|
return [System.Convert]::ToBoolean($candidate)
|
|
}
|
|
|
|
function Convert-ToInt32 {
|
|
param(
|
|
$RawValue,
|
|
$TextValue
|
|
)
|
|
|
|
$candidate = $RawValue
|
|
if ($null -eq $candidate -or [string]::IsNullOrWhiteSpace([string]$candidate)) {
|
|
$candidate = $TextValue
|
|
}
|
|
|
|
if ($null -eq $candidate -or [string]::IsNullOrWhiteSpace([string]$candidate)) {
|
|
return $null
|
|
}
|
|
|
|
return [int]$candidate
|
|
}
|
|
|
|
function Convert-ToDouble {
|
|
param(
|
|
$RawValue,
|
|
$TextValue
|
|
)
|
|
|
|
$candidate = $RawValue
|
|
if ($null -eq $candidate -or [string]::IsNullOrWhiteSpace([string]$candidate)) {
|
|
$candidate = $TextValue
|
|
}
|
|
|
|
if ($null -eq $candidate -or [string]::IsNullOrWhiteSpace([string]$candidate)) {
|
|
return $null
|
|
}
|
|
|
|
return [double]::Parse(
|
|
[string]$candidate,
|
|
[System.Globalization.NumberStyles]::Any,
|
|
[System.Globalization.CultureInfo]::InvariantCulture
|
|
)
|
|
}
|
|
|
|
function Convert-ToDateTimeValue {
|
|
param(
|
|
$RawValue,
|
|
$TextValue
|
|
)
|
|
|
|
$candidate = $RawValue
|
|
if ($null -eq $candidate -or [string]::IsNullOrWhiteSpace([string]$candidate)) {
|
|
$candidate = $TextValue
|
|
}
|
|
|
|
if ($null -eq $candidate -or [string]::IsNullOrWhiteSpace([string]$candidate)) {
|
|
return $null
|
|
}
|
|
|
|
return [datetime]::Parse(
|
|
[string]$candidate,
|
|
[System.Globalization.CultureInfo]::InvariantCulture,
|
|
[System.Globalization.DateTimeStyles]::RoundtripKind
|
|
)
|
|
}
|
|
|
|
function Resolve-SPUser {
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[Microsoft.SharePoint.SPWeb]$Web,
|
|
|
|
$RawUserValue,
|
|
|
|
[string]$TextValue
|
|
)
|
|
|
|
$candidates = @()
|
|
|
|
if ($null -ne $RawUserValue) {
|
|
$loginName = Get-ObjectPropertyValue -Object $RawUserValue -PropertyName "LoginName"
|
|
$email = Get-ObjectPropertyValue -Object $RawUserValue -PropertyName "Email"
|
|
$lookupValue = Get-ObjectPropertyValue -Object $RawUserValue -PropertyName "LookupValue"
|
|
|
|
if (-not [string]::IsNullOrWhiteSpace([string]$loginName)) {
|
|
$candidates += [string]$loginName
|
|
}
|
|
|
|
if (-not [string]::IsNullOrWhiteSpace([string]$email)) {
|
|
$candidates += [string]$email
|
|
}
|
|
|
|
if (-not [string]::IsNullOrWhiteSpace([string]$lookupValue)) {
|
|
$candidates += [string]$lookupValue
|
|
}
|
|
}
|
|
|
|
if (-not [string]::IsNullOrWhiteSpace([string]$TextValue)) {
|
|
$candidates += [string]$TextValue
|
|
}
|
|
|
|
foreach ($candidate in $candidates | Select-Object -Unique) {
|
|
try {
|
|
return $Web.EnsureUser($candidate)
|
|
}
|
|
catch {
|
|
}
|
|
}
|
|
|
|
return $null
|
|
}
|
|
|
|
function Convert-ToUserFieldValue {
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[Microsoft.SharePoint.SPListItem]$Item,
|
|
|
|
$RawValue,
|
|
|
|
[string]$TextValue
|
|
)
|
|
|
|
$user = Resolve-SPUser -Web $Item.Web -RawUserValue $RawValue -TextValue $TextValue
|
|
if ($null -eq $user) {
|
|
return $null
|
|
}
|
|
|
|
return New-Object Microsoft.SharePoint.SPFieldUserValue($Item.Web, $user.ID, $user.LoginName)
|
|
}
|
|
|
|
function Convert-ToUserMultiFieldValue {
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[Microsoft.SharePoint.SPListItem]$Item,
|
|
|
|
$RawValue,
|
|
|
|
[string]$TextValue
|
|
)
|
|
|
|
$collection = New-Object Microsoft.SharePoint.SPFieldUserValueCollection
|
|
$rawUsers = @($RawValue)
|
|
|
|
if (($rawUsers.Length -eq 1) -and $null -eq $rawUsers[0] -and -not [string]::IsNullOrWhiteSpace($TextValue)) {
|
|
$rawUsers = @($TextValue.Split(";", [System.StringSplitOptions]::RemoveEmptyEntries))
|
|
}
|
|
|
|
foreach ($rawUser in $rawUsers) {
|
|
$userValue = Convert-ToUserFieldValue -Item $Item -RawValue $rawUser -TextValue ([string]$rawUser)
|
|
if ($null -ne $userValue) {
|
|
[void]$collection.Add($userValue)
|
|
}
|
|
}
|
|
|
|
return $collection
|
|
}
|
|
|
|
function Convert-ToUrlFieldValue {
|
|
param(
|
|
$RawValue,
|
|
|
|
[string]$TextValue
|
|
)
|
|
|
|
$url = Get-ObjectPropertyValue -Object $RawValue -PropertyName "Url"
|
|
$description = Get-ObjectPropertyValue -Object $RawValue -PropertyName "Description"
|
|
|
|
if (-not [string]::IsNullOrWhiteSpace([string]$url)) {
|
|
$fieldValue = New-Object Microsoft.SharePoint.SPFieldUrlValue
|
|
$fieldValue.Url = [string]$url
|
|
$fieldValue.Description = [string]$description
|
|
return $fieldValue
|
|
}
|
|
|
|
if (-not [string]::IsNullOrWhiteSpace([string]$TextValue)) {
|
|
$fieldValue = New-Object Microsoft.SharePoint.SPFieldUrlValue
|
|
try {
|
|
$fieldValue.FromString([string]$TextValue)
|
|
return $fieldValue
|
|
}
|
|
catch {
|
|
}
|
|
}
|
|
|
|
return $null
|
|
}
|
|
|
|
function Set-SPItemFieldValue {
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[Microsoft.SharePoint.SPListItem]$Item,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$TargetInternalName,
|
|
|
|
$RawValue,
|
|
|
|
[string]$TextValue
|
|
)
|
|
|
|
$field = Resolve-SPField -Fields $Item.Fields -InternalName $TargetInternalName
|
|
if ($null -eq $field) {
|
|
Write-Warning ("Zielfeld nicht gefunden: {0}" -f $TargetInternalName)
|
|
return
|
|
}
|
|
|
|
if ($field.ReadOnlyField -or $field.Sealed) {
|
|
Write-Warning ("Zielfeld ist schreibgeschuetzt und wird uebersprungen: {0}" -f $TargetInternalName)
|
|
return
|
|
}
|
|
|
|
try {
|
|
switch ($field.TypeAsString) {
|
|
"Boolean" {
|
|
$Item[$field.InternalName] = Convert-ToBoolean -RawValue $RawValue -TextValue $TextValue
|
|
return
|
|
}
|
|
"Integer" {
|
|
$Item[$field.InternalName] = Convert-ToInt32 -RawValue $RawValue -TextValue $TextValue
|
|
return
|
|
}
|
|
"Counter" {
|
|
return
|
|
}
|
|
"Number" {
|
|
$Item[$field.InternalName] = Convert-ToDouble -RawValue $RawValue -TextValue $TextValue
|
|
return
|
|
}
|
|
"Currency" {
|
|
$Item[$field.InternalName] = Convert-ToDouble -RawValue $RawValue -TextValue $TextValue
|
|
return
|
|
}
|
|
"DateTime" {
|
|
$Item[$field.InternalName] = Convert-ToDateTimeValue -RawValue $RawValue -TextValue $TextValue
|
|
return
|
|
}
|
|
"URL" {
|
|
$Item[$field.InternalName] = Convert-ToUrlFieldValue -RawValue $RawValue -TextValue $TextValue
|
|
return
|
|
}
|
|
"User" {
|
|
$Item[$field.InternalName] = Convert-ToUserFieldValue -Item $Item -RawValue $RawValue -TextValue $TextValue
|
|
return
|
|
}
|
|
"UserMulti" {
|
|
$Item[$field.InternalName] = Convert-ToUserMultiFieldValue -Item $Item -RawValue $RawValue -TextValue $TextValue
|
|
return
|
|
}
|
|
default {
|
|
if ($null -eq $RawValue) {
|
|
$Item[$field.InternalName] = $TextValue
|
|
}
|
|
else {
|
|
$Item[$field.InternalName] = $RawValue
|
|
}
|
|
|
|
return
|
|
}
|
|
}
|
|
}
|
|
catch {
|
|
if (-not [string]::IsNullOrWhiteSpace($TextValue)) {
|
|
try {
|
|
$field.ParseAndSetValue($Item, $TextValue)
|
|
return
|
|
}
|
|
catch {
|
|
}
|
|
}
|
|
|
|
throw ("Konnte Feld '{0}' nicht setzen. {1}" -f $TargetInternalName, $_.Exception.Message)
|
|
}
|
|
}
|
|
|
|
function Apply-FieldMappingToItem {
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[Microsoft.SharePoint.SPListItem]$Item,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[System.Collections.IDictionary]$FieldMapping,
|
|
|
|
$SourceFieldValues,
|
|
|
|
$SourceFieldTextValues
|
|
)
|
|
|
|
foreach ($sourceInternalName in $FieldMapping.Keys) {
|
|
$targetInternalName = [string]$FieldMapping[$sourceInternalName]
|
|
|
|
$hasRawValue = Test-ObjectHasProperty -Object $SourceFieldValues -PropertyName $sourceInternalName
|
|
$hasTextValue = Test-ObjectHasProperty -Object $SourceFieldTextValues -PropertyName $sourceInternalName
|
|
|
|
if (-not $hasRawValue -and -not $hasTextValue) {
|
|
continue
|
|
}
|
|
|
|
$rawValue = if ($hasRawValue) {
|
|
Get-ObjectPropertyValue -Object $SourceFieldValues -PropertyName $sourceInternalName
|
|
}
|
|
else {
|
|
$null
|
|
}
|
|
|
|
$textValue = if ($hasTextValue) {
|
|
[string](Get-ObjectPropertyValue -Object $SourceFieldTextValues -PropertyName $sourceInternalName)
|
|
}
|
|
else {
|
|
$null
|
|
}
|
|
|
|
Set-SPItemFieldValue -Item $Item -TargetInternalName $targetInternalName -RawValue $rawValue -TextValue $textValue
|
|
}
|
|
}
|
|
|
|
function Save-SPListItem {
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[Microsoft.SharePoint.SPListItem]$Item
|
|
)
|
|
|
|
try {
|
|
$Item.UpdateOverwriteVersion()
|
|
return
|
|
}
|
|
catch {
|
|
}
|
|
|
|
$Item.Update()
|
|
}
|
|
|
|
function Get-RelativeSegmentsFromMetadataPath {
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$MetadataFilePath,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$FilesRootPath
|
|
)
|
|
|
|
$relativePath = $MetadataFilePath.Substring($FilesRootPath.Length).TrimStart("\")
|
|
return @($relativePath.Split("\") | Where-Object { -not [string]::IsNullOrWhiteSpace($_) })
|
|
}
|
|
|
|
function Ensure-SPFolderHierarchy {
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[Microsoft.SharePoint.SPList]$List,
|
|
|
|
[string[]]$FolderSegments = @()
|
|
)
|
|
|
|
$currentFolder = $List.RootFolder
|
|
|
|
foreach ($folderSegment in $FolderSegments) {
|
|
$nextFolder = $null
|
|
|
|
foreach ($existingFolder in $currentFolder.SubFolders) {
|
|
if ($existingFolder.Name -eq $folderSegment) {
|
|
$nextFolder = $existingFolder
|
|
break
|
|
}
|
|
}
|
|
|
|
if ($null -eq $nextFolder) {
|
|
$nextFolder = $currentFolder.SubFolders.Add($folderSegment)
|
|
}
|
|
|
|
$currentFolder = $nextFolder
|
|
}
|
|
|
|
return $currentFolder
|
|
}
|
|
|
|
function Import-SPDocumentLibraries {
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[Microsoft.SharePoint.SPWeb]$Web,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$FilesRootPath,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[System.Collections.IDictionary]$FieldMapping,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[hashtable]$ContainerManifestMap,
|
|
|
|
[switch]$OverwriteFiles
|
|
)
|
|
|
|
if (-not [System.IO.Directory]::Exists($FilesRootPath)) {
|
|
Write-Warning ("Kein Files-Ordner gefunden: {0}" -f $FilesRootPath)
|
|
return
|
|
}
|
|
|
|
$metadataFiles = @(Get-ChildItem -Path $FilesRootPath -Recurse -File -Filter *.properties.json)
|
|
Write-Host ("Gefundene Datei-Metadaten: {0}" -f $metadataFiles.Length)
|
|
|
|
foreach ($metadataFile in $metadataFiles) {
|
|
$sourceFilePath = $metadataFile.FullName.Substring(0, $metadataFile.FullName.Length - ".properties.json".Length)
|
|
if (-not [System.IO.File]::Exists($sourceFilePath)) {
|
|
Write-Warning ("Quelldatei zur Metadatei nicht gefunden: {0}" -f $metadataFile.FullName)
|
|
continue
|
|
}
|
|
|
|
$metadata = Read-JsonFile -Path $metadataFile.FullName
|
|
$libraryMetadata = Get-ObjectPropertyValue -Object $metadata -PropertyName "Library"
|
|
$itemMetadata = Get-ObjectPropertyValue -Object $metadata -PropertyName "Item"
|
|
$sourceLibraryTitle = [string](Get-ObjectPropertyValue -Object $libraryMetadata -PropertyName "Title")
|
|
|
|
if ([string]::IsNullOrWhiteSpace($sourceLibraryTitle)) {
|
|
Write-Warning ("Bibliothekstitel fehlt in: {0}" -f $metadataFile.FullName)
|
|
continue
|
|
}
|
|
|
|
$targetLibraryTitle = Get-TargetContainerTitle -ContainerManifestMap $ContainerManifestMap -ObjectType "DocumentLibrary" -SourceTitle $sourceLibraryTitle
|
|
$targetLibrary = $Web.Lists.TryGetList($targetLibraryTitle)
|
|
if ($null -eq $targetLibrary) {
|
|
if (Test-ContainerHasExplicitTargetMapping -ContainerManifestMap $ContainerManifestMap -ObjectType "DocumentLibrary" -SourceTitle $sourceLibraryTitle) {
|
|
Write-Warning ("Zielbibliothek '{0}' fuer Quellbibliothek '{1}' nicht gefunden. Bitte diese Bibliothek im Ziel manuell anlegen." -f $targetLibraryTitle, $sourceLibraryTitle)
|
|
}
|
|
else {
|
|
Write-Warning ("Zielbibliothek '{0}' nicht gefunden und kein TargetTitle im manifest.csv gepflegt. Bitte Bibliothek manuell anlegen oder TargetTitle im Manifest setzen." -f $sourceLibraryTitle)
|
|
}
|
|
continue
|
|
}
|
|
|
|
if ($targetLibrary.BaseType -ne [Microsoft.SharePoint.SPBaseType]::DocumentLibrary) {
|
|
Write-Warning ("Zielliste ist keine Dokumentbibliothek: {0}" -f $targetLibraryTitle)
|
|
continue
|
|
}
|
|
|
|
$relativeSegments = @(Get-RelativeSegmentsFromMetadataPath -MetadataFilePath $metadataFile.FullName -FilesRootPath $FilesRootPath)
|
|
if ($relativeSegments.Length -lt 2) {
|
|
Write-Warning ("Dateipfad konnte nicht relativ zur Bibliothek ermittelt werden: {0}" -f $metadataFile.FullName)
|
|
continue
|
|
}
|
|
|
|
$folderSegments = @()
|
|
if ($relativeSegments.Length -gt 2) {
|
|
$folderSegments = $relativeSegments[1..($relativeSegments.Length - 2)]
|
|
}
|
|
|
|
$targetFolder = Ensure-SPFolderHierarchy -List $targetLibrary -FolderSegments $folderSegments
|
|
$fileName = [System.IO.Path]::GetFileName($sourceFilePath)
|
|
$fileBytes = [System.IO.File]::ReadAllBytes($sourceFilePath)
|
|
|
|
Write-Host ("Importiere Datei: {0} -> {1}" -f $sourceFilePath, $targetLibrary.Title)
|
|
|
|
$spFile = $targetFolder.Files.Add($fileName, $fileBytes, $OverwriteFiles.IsPresent)
|
|
$spItem = $spFile.Item
|
|
|
|
if ($null -ne $itemMetadata) {
|
|
Apply-FieldMappingToItem -Item $spItem -FieldMapping $FieldMapping -SourceFieldValues (Get-ObjectPropertyValue -Object $itemMetadata -PropertyName "FieldValues") -SourceFieldTextValues (Get-ObjectPropertyValue -Object $itemMetadata -PropertyName "FieldTextValues")
|
|
Save-SPListItem -Item $spItem
|
|
}
|
|
}
|
|
}
|
|
|
|
function Import-SPLists {
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[Microsoft.SharePoint.SPWeb]$Web,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$ListsRootPath,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[System.Collections.IDictionary]$FieldMapping,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[hashtable]$ContainerManifestMap
|
|
)
|
|
|
|
if (-not [System.IO.Directory]::Exists($ListsRootPath)) {
|
|
Write-Warning ("Kein Lists-Ordner gefunden: {0}" -f $ListsRootPath)
|
|
return
|
|
}
|
|
|
|
$listFiles = @(Get-ChildItem -Path $ListsRootPath -File -Filter *.json)
|
|
Write-Host ("Gefundene Listen-JSONs: {0}" -f $listFiles.Length)
|
|
|
|
foreach ($listFile in $listFiles) {
|
|
$listExport = Read-JsonFile -Path $listFile.FullName
|
|
$listMetadata = Get-ObjectPropertyValue -Object $listExport -PropertyName "List"
|
|
$items = @(Get-ObjectPropertyValue -Object $listExport -PropertyName "Items" -DefaultValue @())
|
|
$sourceListTitle = [string](Get-ObjectPropertyValue -Object $listMetadata -PropertyName "Title")
|
|
|
|
if ([string]::IsNullOrWhiteSpace($sourceListTitle)) {
|
|
Write-Warning ("Listentitel fehlt in: {0}" -f $listFile.FullName)
|
|
continue
|
|
}
|
|
|
|
$targetListTitle = Get-TargetContainerTitle -ContainerManifestMap $ContainerManifestMap -ObjectType "List" -SourceTitle $sourceListTitle
|
|
$targetList = $Web.Lists.TryGetList($targetListTitle)
|
|
if ($null -eq $targetList) {
|
|
if (Test-ContainerHasExplicitTargetMapping -ContainerManifestMap $ContainerManifestMap -ObjectType "List" -SourceTitle $sourceListTitle) {
|
|
Write-Warning ("Zielliste '{0}' fuer Quellliste '{1}' nicht gefunden. Bitte diese Liste im Ziel manuell anlegen." -f $targetListTitle, $sourceListTitle)
|
|
}
|
|
else {
|
|
Write-Warning ("Zielliste '{0}' nicht gefunden und kein TargetTitle im manifest.csv gepflegt. Bitte Liste manuell anlegen oder TargetTitle im Manifest setzen." -f $sourceListTitle)
|
|
}
|
|
continue
|
|
}
|
|
|
|
if ($targetList.BaseType -eq [Microsoft.SharePoint.SPBaseType]::DocumentLibrary) {
|
|
Write-Warning ("Liste ist eine Dokumentbibliothek und wird im Listenimport uebersprungen: {0}" -f $targetListTitle)
|
|
continue
|
|
}
|
|
|
|
Write-Host ("Importiere Liste: {0}" -f $targetListTitle)
|
|
|
|
foreach ($sourceItem in $items) {
|
|
$fileSystemObjectType = [string](Get-ObjectPropertyValue -Object $sourceItem -PropertyName "FileSystemObjectType")
|
|
if ($fileSystemObjectType -eq "Folder") {
|
|
Write-Warning ("Ordner in normalen Listen werden in dieser Version uebersprungen: {0}" -f $targetListTitle)
|
|
continue
|
|
}
|
|
|
|
if ((Get-ObjectPropertyValue -Object $sourceItem -PropertyName "HasAttachments" -DefaultValue $false)) {
|
|
Write-Warning ("Listenanlagen wurden im Export nicht physisch gesichert und werden uebersprungen. Liste: {0}, ItemId: {1}" -f $targetListTitle, (Get-ObjectPropertyValue -Object $sourceItem -PropertyName "Id"))
|
|
}
|
|
|
|
$targetItem = $targetList.Items.Add()
|
|
Apply-FieldMappingToItem -Item $targetItem -FieldMapping $FieldMapping -SourceFieldValues (Get-ObjectPropertyValue -Object $sourceItem -PropertyName "FieldValues") -SourceFieldTextValues (Get-ObjectPropertyValue -Object $sourceItem -PropertyName "FieldTextValues")
|
|
Save-SPListItem -Item $targetItem
|
|
}
|
|
}
|
|
}
|
|
|
|
Initialize-SharePointPowerShell
|
|
|
|
$resolvedOutputPath = [System.IO.Path]::GetFullPath($OutputPath)
|
|
$filesRootPath = [System.IO.Path]::Combine($resolvedOutputPath, "Files")
|
|
$listsRootPath = [System.IO.Path]::Combine($resolvedOutputPath, "Lists")
|
|
$manifestPath = [System.IO.Path]::Combine($resolvedOutputPath, "manifest.csv")
|
|
|
|
$importConfigurationProvided =
|
|
(-not [string]::IsNullOrWhiteSpace($TargetWebUrl)) -or
|
|
(-not [string]::IsNullOrWhiteSpace($MappingCsvPath)) -or
|
|
$ImportFiles -or
|
|
$ImportLists -or
|
|
$OverwriteFiles
|
|
|
|
if ($ExportOnly -and $ImportOnly) {
|
|
throw "ExportOnly und ImportOnly koennen nicht gleichzeitig gesetzt werden."
|
|
}
|
|
|
|
if ($ImportOnly) {
|
|
if ([string]::IsNullOrWhiteSpace($TargetWebUrl) -or [string]::IsNullOrWhiteSpace($MappingCsvPath)) {
|
|
throw "Fuer ImportOnly muessen TargetWebUrl und MappingCsvPath angegeben werden."
|
|
}
|
|
|
|
Invoke-MigrationImport -InputPath $resolvedOutputPath -TargetWebUrl $TargetWebUrl -MappingCsvPath $MappingCsvPath -ImportFiles:$ImportFiles -ImportLists:$ImportLists -OverwriteFiles:$OverwriteFiles
|
|
return
|
|
}
|
|
|
|
if ([string]::IsNullOrWhiteSpace($WebUrl)) {
|
|
throw "Fuer den Export muss WebUrl angegeben werden."
|
|
}
|
|
|
|
Ensure-Directory -Path $resolvedOutputPath
|
|
Ensure-Directory -Path $filesRootPath
|
|
Ensure-Directory -Path $listsRootPath
|
|
|
|
if ([System.IO.File]::Exists($manifestPath)) {
|
|
[System.IO.File]::Delete($manifestPath)
|
|
}
|
|
|
|
$web = $null
|
|
|
|
try {
|
|
$web = Get-SPWeb -Identity $WebUrl -ErrorAction Stop
|
|
|
|
$documentLibraries = @(
|
|
$web.Lists | Where-Object {
|
|
$_.BaseType -eq [Microsoft.SharePoint.SPBaseType]::DocumentLibrary -and
|
|
($IncludeHiddenLibraries -or -not $_.Hidden) -and
|
|
-not (Test-IsCatalogList -List $_)
|
|
}
|
|
)
|
|
|
|
$lists = @(
|
|
$web.Lists | Where-Object {
|
|
$_.BaseType -ne [Microsoft.SharePoint.SPBaseType]::DocumentLibrary -and
|
|
($IncludeHiddenLists -or -not $_.Hidden) -and
|
|
-not (Test-IsCatalogList -List $_)
|
|
}
|
|
)
|
|
|
|
Write-Host ("Gefundene Bibliotheken: {0}" -f $documentLibraries.Length)
|
|
Write-Host ("Gefundene Listen: {0}" -f $lists.Length)
|
|
|
|
foreach ($library in $documentLibraries) {
|
|
Export-SPDocumentLibrary -Web $web -List $library -FilesRootPath $filesRootPath -ManifestPath $manifestPath
|
|
}
|
|
|
|
foreach ($list in $lists) {
|
|
Export-SPList -Web $web -List $list -ListsRootPath $listsRootPath -ManifestPath $manifestPath
|
|
}
|
|
|
|
if ($documentLibraries.Length -eq 0 -and $lists.Length -eq 0) {
|
|
Write-Warning ("Keine exportierbaren Bibliotheken oder Listen im Web gefunden: {0}" -f $WebUrl)
|
|
return
|
|
}
|
|
|
|
Write-Host ("Export abgeschlossen. Ausgabe: {0}" -f $resolvedOutputPath)
|
|
|
|
if ($ExportOnly) {
|
|
Write-Host "ExportOnly ist gesetzt. Import wird uebersprungen."
|
|
return
|
|
}
|
|
|
|
if (-not $importConfigurationProvided) {
|
|
return
|
|
}
|
|
|
|
if ([string]::IsNullOrWhiteSpace($TargetWebUrl) -or [string]::IsNullOrWhiteSpace($MappingCsvPath)) {
|
|
throw "Fuer den automatischen Import muessen TargetWebUrl und MappingCsvPath angegeben werden."
|
|
}
|
|
|
|
Write-Host ("Starte Import nach Export. Zielweb: {0}" -f $TargetWebUrl)
|
|
Invoke-MigrationImport -InputPath $resolvedOutputPath -TargetWebUrl $TargetWebUrl -MappingCsvPath $MappingCsvPath -ImportFiles:$ImportFiles -ImportLists:$ImportLists -OverwriteFiles:$OverwriteFiles
|
|
}
|
|
finally {
|
|
if ($null -ne $web) {
|
|
$web.Dispose()
|
|
}
|
|
}
|