465 lines
13 KiB
PowerShell
465 lines
13 KiB
PowerShell
[CmdletBinding()]
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$WebUrl,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$OutputPath,
|
|
|
|
[switch]$IncludeHiddenLibraries
|
|
)
|
|
|
|
Set-StrictMode -Version Latest
|
|
$ErrorActionPreference = "Stop"
|
|
|
|
function Initialize-SharePointPowerShell {
|
|
if (-not (Get-PSSnapin -Name Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue)) {
|
|
Add-PSSnapin Microsoft.SharePoint.PowerShell
|
|
}
|
|
}
|
|
|
|
function Ensure-Directory {
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$Path
|
|
)
|
|
|
|
if (-not [System.IO.Directory]::Exists($Path)) {
|
|
[System.IO.Directory]::CreateDirectory($Path) | Out-Null
|
|
}
|
|
}
|
|
|
|
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 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
|
|
)
|
|
|
|
if (-not $Item.Fields.ContainsField($InternalName)) {
|
|
return $null
|
|
}
|
|
|
|
return Get-FieldTextValue -Field $Item.Fields[$InternalName] -RawValue $Item[$InternalName]
|
|
}
|
|
|
|
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
|
|
$fieldMetadata = @()
|
|
|
|
if ($null -ne $item) {
|
|
foreach ($field in $item.Fields) {
|
|
$rawValue = $item[$field.InternalName]
|
|
|
|
$fieldMetadata += [PSCustomObject]@{
|
|
InternalName = $field.InternalName
|
|
Title = $field.Title
|
|
TypeAsString = $field.TypeAsString
|
|
TextValue = Get-FieldTextValue -Field $field -RawValue $rawValue
|
|
Value = Convert-SPFieldValue $rawValue
|
|
}
|
|
}
|
|
}
|
|
|
|
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) {
|
|
[PSCustomObject]@{
|
|
Id = $item.ID
|
|
UniqueId = $item.UniqueId.ToString()
|
|
ContentTypeId = $item.ContentTypeId.ToString()
|
|
ContentTypeName = $item.ContentType.Name
|
|
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"
|
|
Fields = $fieldMetadata
|
|
}
|
|
}
|
|
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 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 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]$MetadataRootPath,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$ManifestPath
|
|
)
|
|
|
|
$relativeSegments = Get-RelativeFilePathSegments -List $List -File $File
|
|
$relativeDirectorySegments = @()
|
|
|
|
if ($relativeSegments.Count -gt 1) {
|
|
$relativeDirectorySegments = $relativeSegments[0..($relativeSegments.Count - 2)]
|
|
}
|
|
|
|
$safeLibraryName = Get-SafePathSegment $List.Title
|
|
$fileDirectory = Combine-PathSegments -BasePath ([System.IO.Path]::Combine($FilesRootPath, $safeLibraryName)) -Segments $relativeDirectorySegments
|
|
$metadataDirectory = Combine-PathSegments -BasePath ([System.IO.Path]::Combine($MetadataRootPath, $safeLibraryName)) -Segments $relativeDirectorySegments
|
|
|
|
Ensure-Directory -Path $fileDirectory
|
|
Ensure-Directory -Path $metadataDirectory
|
|
|
|
$fileName = $relativeSegments[-1]
|
|
$localFilePath = [System.IO.Path]::Combine($fileDirectory, $fileName)
|
|
$metadataPath = [System.IO.Path]::Combine($metadataDirectory, "$fileName.metadata.json")
|
|
|
|
[System.IO.File]::WriteAllBytes($localFilePath, $File.OpenBinary())
|
|
|
|
$metadata = Get-FileMetadataObject -Web $Web -List $List -File $File
|
|
Write-MetadataJson -MetadataObject $metadata -Path $metadataPath
|
|
|
|
$manifestRow = [PSCustomObject]@{
|
|
WebUrl = $Web.Url
|
|
LibraryTitle = $List.Title
|
|
FileName = $File.Name
|
|
FileServerRelativeUrl = $File.ServerRelativeUrl
|
|
FileUniqueId = $File.UniqueId.ToString()
|
|
FileLength = $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]$MetadataRootPath,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$ManifestPath,
|
|
|
|
[ref]$FileCount
|
|
)
|
|
|
|
foreach ($file in $Folder.Files) {
|
|
Export-SPFile -Web $Web -List $List -File $file -FilesRootPath $FilesRootPath -MetadataRootPath $MetadataRootPath -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 -MetadataRootPath $MetadataRootPath -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]$MetadataRootPath,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$ManifestPath
|
|
)
|
|
|
|
Write-Host ("Exportiere Bibliothek: {0}" -f $List.Title)
|
|
$fileCount = 0
|
|
|
|
Export-SPFolder -Web $Web -List $List -Folder $List.RootFolder -FilesRootPath $FilesRootPath -MetadataRootPath $MetadataRootPath -ManifestPath $ManifestPath -FileCount ([ref]$fileCount)
|
|
|
|
Write-Host (" Dateien exportiert: {0}" -f $fileCount)
|
|
}
|
|
|
|
Initialize-SharePointPowerShell
|
|
|
|
$resolvedOutputPath = [System.IO.Path]::GetFullPath($OutputPath)
|
|
$filesRootPath = [System.IO.Path]::Combine($resolvedOutputPath, "Files")
|
|
$metadataRootPath = [System.IO.Path]::Combine($resolvedOutputPath, "Metadata")
|
|
$manifestPath = [System.IO.Path]::Combine($resolvedOutputPath, "manifest.csv")
|
|
|
|
Ensure-Directory -Path $resolvedOutputPath
|
|
Ensure-Directory -Path $filesRootPath
|
|
Ensure-Directory -Path $metadataRootPath
|
|
|
|
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 $_.IsCatalog
|
|
}
|
|
)
|
|
|
|
if ($documentLibraries.Count -eq 0) {
|
|
Write-Warning ("Keine Dokumentbibliotheken im Web gefunden: {0}" -f $WebUrl)
|
|
return
|
|
}
|
|
|
|
Write-Host ("Gefundene Bibliotheken: {0}" -f $documentLibraries.Count)
|
|
|
|
foreach ($library in $documentLibraries) {
|
|
Export-SPDocumentLibrary -Web $web -List $library -FilesRootPath $filesRootPath -MetadataRootPath $metadataRootPath -ManifestPath $manifestPath
|
|
}
|
|
|
|
Write-Host ("Export abgeschlossen. Ausgabe: {0}" -f $resolvedOutputPath)
|
|
}
|
|
finally {
|
|
if ($null -ne $web) {
|
|
$web.Dispose()
|
|
}
|
|
}
|