You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Microsoft Graph API的C# SharePoint站点备份异常求助

SharePoint站点批量备份失败排查求助

我开发了一款C#应用,通过Microsoft Graph API备份SharePoint站点管理员区域的所有文件。目前有多个SharePoint项目站点,其中近130个站点备份成功,但有200个站点无法被识别或备份失败。

环境信息

  • 开发工具:Visual Studio Community
  • NuGet包:Microsoft.Graph、Azure.Identity
  • 认证方式:ClientSecretCredential
  • Graph API版本:使用最新版
  • 目标目录:文件下载至D:\DownloadedFiles

问题详情

  • 多数失败站点无明确错误提示,仅文件未被下载
  • 失败发生在驱动器项检索或处理阶段,但日志未捕获到具体错误信息
  • 已对比正常与异常站点的配置XML、home.aspx文件,仅ID存在差异;确认两类站点权限设置、访问用户一致,所有列表均存在

已采取的排查步骤

  • 验证站点设置:对比正常与异常站点的XML配置及home.aspx文件,仅ID不同
  • 检查权限:确认两类站点权限配置、访问用户完全一致(包含管理员中心与SharePoint直接设置)
  • 确认列表:验证所有列表在两类站点中均存在
  • 错误日志:已实现详细错误日志,但未捕获到具体错误内容

核心代码

using Azure.Identity;
using Microsoft.Graph;
using Microsoft.Graph.Models;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;

class Program
{
    private static string clientId = "anonymized";
    private static string tenantId = "anonymized";
    private static string clientSecret = "anonymized";
    private static string downloadPath = @"D:\DownloadedFiles\";

    static async Task Main(string[] args)
    {
        try
        {
            var clientSecretCredential = new ClientSecretCredential(tenantId, clientId, clientSecret);
            var graphClient = new GraphServiceClient(clientSecretCredential);

            // Testing connection
            Console.WriteLine("Testing connection to SharePoint...");
            var sites = await graphClient.Sites.GetAsync();

            if (sites != null)
            {
                Console.WriteLine("Connected to SharePoint. Listing all active sites...");

                foreach (var site in sites.Value)
                {
                    if (site.WebUrl.Contains("sharepoint.com") && !site.WebUrl.Contains("personal"))
                    {
                        Console.WriteLine($"Site: {site.DisplayName}, URL: {site.WebUrl}, ID: {site.Id}");
                        string sitePath = Path.Combine(downloadPath, site.DisplayName ?? site.Id);
                        Directory.CreateDirectory(sitePath);

                        // Processing site contents
                        await ProcessSite(graphClient, site.Id, sitePath);
                    }
                }
            }
            else
            {
                Console.WriteLine("Failed to connect to SharePoint or no sites found.");
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error: {ex.Message}");
        }
    }

    static async Task ProcessSite(GraphServiceClient graphClient, string siteId, string path)
    {
        try
        {
            // Processing drives of the site
            await ProcessDrives(graphClient, siteId, path);

            // Retrieving subsites
            var subSites = await graphClient.Sites[siteId].Sites.GetAsync();
            if (subSites.Value != null && subSites.Value.Count > 0)
            {
                foreach (var subSite in subSites.Value)
                {
                    Console.WriteLine($"Processing Sub-Site: {subSite.DisplayName}");
                    string subSitePath = Path.Combine(path, subSite.DisplayName ?? subSite.Id);
                    Directory.CreateDirectory(subSitePath);

                    // Recursively processing subsites
                    await ProcessSite(graphClient, subSite.Id, subSitePath);
                }
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error processing site with ID {siteId}: {ex.Message}");
        }
    }

    static async Task ProcessDrives(GraphServiceClient graphClient, string siteId, string path)
    {
        Console.WriteLine($"Processing drives for site with ID: {siteId}");

        var drives = await graphClient.Sites[siteId].Drives.GetAsync();
        if (drives.Value != null && drives.Value.Count > 0)
        {
            foreach (var drive in drives.Value)
            {
                Console.WriteLine($"Processing Drive: {drive.Name}");
                string drivePath = Path.Combine(path, drive.Name ?? string.Empty);
                Directory.CreateDirectory(drivePath);

                await ProcessDriveItems(graphClient, drive.Id, drivePath);
            }
        }
        else
        {
            Console.WriteLine("No drives found.");
        }
    }

    static async Task ProcessDriveItems(GraphServiceClient graphClient, string driveId, string path)
    {
        try
        {
            var rootItems = await graphClient.Drives[driveId].Root.GetAsync();
            if (rootItems.Folder != null)
            {
                var children = await graphClient.Drives[driveId].Items[rootItems.Id].Children.GetAsync();
                await ProcessItems(graphClient, driveId, children.Value, path);
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error processing drive items: {ex.Message}");
        }
    }

    static async Task ProcessItems(GraphServiceClient graphClient, string driveId, IList<DriveItem> items, string path)
    {
        if (items != null)
        {
            foreach (var item in items)
            {
                var itemPath = Path.Combine(path, item.Name ?? string.Empty);
                if (item.Folder != null) // It's a folder
                {
                    Directory.CreateDirectory(itemPath);
                    var folderItems = await graphClient.Drives[driveId].Items[item.Id].Children.GetAsync();
                    await ProcessItems(graphClient, driveId, folderItems.Value, itemPath);
                }
                else if (item.File != null) // It's a file
                {
                    var fileContent = await graphClient.Drives[driveId].Items[item.Id].Content.GetAsync();
                    using (var fileStream = new FileStream(itemPath, FileMode.Create, FileAccess.Write))
                    {
                        await fileContent.CopyToAsync(fileStream);
                    }
                    Console.WriteLine($"Downloaded {item.Name} to {itemPath}");

                    // Saving meta-information
                    var fileMetaInfo = new
                    {
                        item.Name,
                        item.CreatedDateTime,
                        item.LastModifiedDateTime,
                        CreatedBy = item.CreatedBy?.User?.DisplayName,
                        LastModifiedBy = item.LastModifiedBy?.User?.DisplayName
                    };
                    var metaInfoPath = $"{itemPath}.meta.json";
                    await File.WriteAllTextAsync(metaInfoPath, System.Text.Json.JsonSerializer.Serialize(fileMetaInfo));
                }
            }
        }
    }
}

求助请求

  • 分析备份失败的可能原因
  • 提供额外的排查步骤或调试技巧
  • 指出可能遗漏的SharePoint隐藏配置

内容的提问来源于stack exchange,提问作者IonDOne

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 22:32:33