version 1.0

This commit is contained in:
2026-04-15 13:26:45 +02:00
parent e5f5a61841
commit 6cbe860731

View File

@@ -0,0 +1,464 @@
[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()
}
}