SharePoint 데이터베이스로 부터 모든 문서를 백업 및 추출하기

개요

필자는 SharePoint 서버 제품을 이용해서 문서를 관리해 왔다. SharePoint를 이용하면 수 천개의 문서를 종류별로 분류하고 데이터베이스화할 수 있다. 문서의 종류와 문서의 내용도 인덱싱(indexing)되므로 문서 내용과 다양한 메타 데이터로 문서를 검색할 수 있다는 점 때문에 많은 문서를 쉽게 관리하고 검색할 수 있다는 장점이 있다.

SharePoint의 장점을 나열하지면 많겠지만, 모바일 트랜드 시대에서는 에버노트가 최고이지 쉽다. 필자의 에버노트와 DropBox는 땡전 한푼 안들이고 프리미엄 서비스를 받고 있는데, 필자가 문서를 사용하고 관리하는 패턴에선 SharePoint 보다는 에버노트DropBox 조합이 더 접근성이 좋고 사용하기도 편하다. 데스크탑은 물론이고 브라우저, 다양한 모바일 기기에서 에버노트 클리핑과 DropBox 동기화 등을 지원하기 때문이다.

그래서 이번에 필자가 가지고 있는 수 천개의 모든 문서를 이전하고자 SharePoint의 모든 파일을 추출해야 했다. 여기에서 여러 Site Collections/Sites/Doc Libs의 각각의 문서를 한 번에 추출하는 작업을 진행했다.

1. WSS_Content 데이터베이스 연결

원하는 툴을 이용해서 SharePoint가 사용하는 데이터베이스에 연결한다. SharePoint에 저장된 문서가 많을 수록 데이터베이스에 연결해야 하는 시간이 늘어난다. 그러므로 Timeout이 발생하지 않도록 주의해야 한다. 필자는 여기에서 SSMS(Sql Server Management Studio) 2012 버전을 사용했다.

2. 파일 추출하기

2.1. 데이터베이스 구성 변경 쿼리 실행

sp_configure 'show advanced options', 1;  
GO

RECONFIGURE;  
GO

sp_configure 'Ole Automation Procedures', 1;  
GO

RECONFIGURE;  
GO

2.2. 데이터베이스 추출 쿼리 실행

아래의 쿼리는 이 사이트의 링크[1]를 참고하였으나, 일부 오류가 발생하여 필자가 수정한 부분이 있으니 이점 참고하기 바란다.

그리고 SharePoint에 저장되는 파일들은 다양한 타입이 존재한다. 가령, 메타데이터의 Binary 파일, _private 폴더, *.aspx, 시스템에 필요한 파일 등 필자가 저장한 문서와 상관 없는 찌꺼기 들도 함께 저장이 된다.

파일의 다양한 플래그 값은 MSDN의 Document Store Type, Doc Flags 문서[2]를 참고 하면 된다.


  
[그림1] WSS_Content 데이터베이스의 모든 문서를 파일 시스템으로 추출한 결과 화면


USE WSS_CONTENT;  

DECLARE @PATH_PREFIX  NVARCHAR(1024);  
SET @PATH_PREFIX = 'C:\BACKUP\';  -- 이곳에 백업할 경로를 입력, 반드시 뒤에 '\' 문자 추가하셈'


--DECLARING THE CURSOR, THIS IS THE ITEMS YOU WANT TO RUN THE EXTRACTING ON  
DECLARE CURSOR_Images CURSOR FOR (SELECT Id FROM [dbo].[AllDocs])  

--DECLARE THE TYPE OF THE COLUMN YOU SELECTED ABOVE  
DECLARE @ImageID uniqueidentifier;  

--START THE CURSOR AND RUN THROUGH ALL THE ITEMS IN CURSOR_Images  
OPEN CURSOR_Images  
FETCH NEXT FROM CURSOR_Images INTO @ImageID  
WHILE (@@FETCH_STATUS <> -1)  
BEGIN  
  --DECLARE THE VARIABLE THAT WILL KEEP THE BINARY DATA  
  DECLARE @ImageData varbinary(MAX);  
  --SELECT THE BINARY DATA AND SET IT TO @ImageData.  THE BINARY DATA FOR ALLDOCS ARE LOCATED IN ALLDOCSTREAMS  
  --AND THE ID IS THE SAME AS IN ALLDOCS  
  SELECT @ImageData = (SELECT TOP 1 CONVERT(varbinary(MAX), Content, 1) FROM [dbo].[AllDocStreams] WHERE Id = @ImageID ORDER BY InternalVersion ASC);

  --GET THE LOCATION OF THE DIRECTORY THE FILES WAS SAVED IN AND CHANGE REPLACE THE / WITH \ TO BE USED IN FILESYSTEM  
  DECLARE @DIRPATH NVARCHAR(MAX);  
  SET @DIRPATH = REPLACE((SELECT  DirName FROM [dbo].[AllDocs]  WHERE Id = @ImageID),'/','\');

  --SET THE PATH  
  DECLARE @Path nvarchar(1024);  
  --SELECT @Path = 'C:\Export\' + @DIRPATH + '\';  
  SELECT @Path = @PATH_PREFIX + @DIRPATH + '\';
-- '\

  --CREATE THE DIRECTORIES  
  EXEC master.dbo.xp_create_subdir @Path;

  --GET THE FILE NAME OF THE FILE FROM LEAFNAME  
  DECLARE @Filename NVARCHAR(1024);  
  DECLARE @DocFlags INT;  
  DECLARE @Type     TINYINT;  
  SELECT @Filename = (SELECT LeafName FROM [dbo].[AllDocs] WHERE id = @ImageID);  
  SELECT @DocFlags = (SELECT DocFlags FROM [dbo].[AllDocs] WHERE id = @ImageID);  
  SELECT @Type     = (SELECT [Type]    FROM [dbo].[AllDocs] WHERE id = @ImageID);

  -- 폴더를 0바이트 파일로 생성하므로 파일이 아닌 경우 파일 저장 루틴 진입 금지  
  IF (@Type = 1 AND @DocFlags = 0) OR (@DocFlags & 0x100) <> 0x100 BEGIN  
CONTINUE;  
  END   
  ELSE BEGIN

  --SET THE FULL PATH FOR WHERE THE FILES WILL BE STORED  
  DECLARE @FullPathToOutputFile NVARCHAR(2048);  
  SELECT @FullPathToOutputFile = @Path + '\' + @Filename;

  --SAVE THE FILE TO THE FILE SYSTEM  -'
  DECLARE @ObjectToken INT  
  EXEC sp_OACreate 'ADODB.Stream', @ObjectToken OUTPUT;  
  EXEC sp_OASetProperty @ObjectToken, 'TYPE', 1;  
  EXEC sp_OAMethod @ObjectToken, 'OPEN';  
  EXEC sp_OAMethod @ObjectToken, 'WRITE', NULL, @ImageData;  
  EXEC sp_OAMethod @ObjectToken, 'SaveToFile', NULL, @FullPathToOutputFile, 2;  
  EXEC sp_OAMethod @ObjectToken, 'Close';  
  EXEC sp_OADestroy @ObjectToken;

  END

  --LOOP TO THE NEXT ENTRY IN THE CURSOR  
  FETCH NEXT FROM CURSOR_Images INTO @ImageID  
END  
CLOSE CURSOR_Images  
DEALLOCATE CURSOR_Images  

2.3. 참고 사항

위의 쿼리는 다양한 메타데이터와 시스템 파일(*.aspx, _private 등..)을 모두 저장한다. 이런 쓰레기 데이터를 파일로 저장하지 않길 원한다면 아래의 쿼리를 이용해서 조건절을 추가해 주면 된다.

각각의 플래그 값의 의미는 Document Store Type 문서를 참고하면 된다. 그러면 여러분이 원하는 데이터만 파일 시스템으로 추출하여 저장하도록 커스터마이징이 될 것이다.

SELECT LeafName, DocFlags  
  FROM [dbo].[AllDocs]  
 WHERE (DocFlags & 0x100) = 0x100
   AND (DocFlags & 0xFFFF0000) <> 0xFFFF0000
   AND (DocFlags & 0x80) <> 0x80
   AND (DocFlags & 0x10) <> 0x10
   AND (DocFlags & 0x8) <> 0x8  

결론

만약 SharePoint에 저장되었던 많은 파일 또는 데이터를 전혀 다른 솔루션으로 이전하고 싶은 경우가 있다. SharePoint는 Microsft SQL Server 데이터베이스에 바이너리를 저장하는데 파일 시스템을 단일 데이터베이스에 저장한다는 것이 좀 아이러니 한 구조이다.

많은 기업내 담당자들의 SharePoint에 대한 피드백을 물어보면 빠지지 않는 것은 ‘느리다’ 라는 것인데, 기하급수적으로 늘어나는 데이터베이스 용량과 웹 응용 프로그램의 SPSites/DocLibs 등이 생성되면서 시간이 지날 수록 점점 느려지는 것은 어쩔 수 없는 구조인 듯 하다. 더불어 SharePoint는 과거의 아키텍처가 현재까지도 트랜드의 변화에 대응되지 못하고 전반적으로 과거와 동일한 아키텍처에 새로운 기능만 계속 붙여나가다 보니 솔루션 자체의 구조적인 면에서 악순환이 되풀이 되는 형세이다.

하지만, 이 아티클을 통해 SharePoint 데이터베이스에서 직접 파일을 추출하여 파일 시스템으로 저장할 수 있다. 이 방법을 통해 추출된 다량의 파일을 다른 솔루션으로 옮기거나 업로드하면 끝이다.


Posted by 땡초 POWERUMC

댓글을 달아 주세요

  1. 억사마 2014.02.03 18:00 신고 Address Modify/Delete Reply

    안녕하세요~ 연락처가 어디 없으셔서 이렇게 댓글 남깁니다. SharePoint를 파일시스템에 백업을 받아야하는 급박한 회사업무가 생겼습니다. 좀 도움을 얻을수 있을까요? 부탁드리겠습니다. 혹시 몰라 제 이메일 주소를 남깁니다. e.joe@samsung.com 연락 부탁드리겠습니다. 감사합니다.

  2. 2014.02.03 18:14 Address Modify/Delete Reply

    비밀댓글입니다

일전에 모 xx 의 제안서 작업을 하기 위해 많은 양의 프레젠테이션을 만들었습니다. 제안서 총 페이지는 수백 페이지에 달할 만큼 굉장히 큰 규모의 프로젝트였고, 제안서에 포함되는 콘텐트의 양은 말할 것도 없었습니다. 그러는 중 프레젠테이션의 목차를 만들어달라는 요청이 들어왔고, 순간 나는 눈앞이 캄캄해졌습니다.

"이 많은 걸 언제 목차로 만들지??? OTL"   

저에게는 딱 두 가지 방법이 떠올랐습니다. 첫 번째는 손수 목차에 페이지의 제목과 페이지 번호를 직접 타이핑하는 방법이고, 두 번째는 뭔지는 모르겠지만 자동화 도구를 이용하는 방법입니다. 일단 시작하는 마음은 무겁지만 최대한 즐겁다고 스스로 주문을 외운 뒤에 하나 하나 목차를 타이핑하여 만들어 가기 시작했으나, 이게 왠 끝이 보이지 않는 겁니다. ㅠ

제안서를 마무리 해야 할 시간은 점점 다가오고, "에라 모르겠다 VSTO 든 스크립트로 하던,,, 도저히 손으로는 못하겠다"    

각설하고, 많은 양의 프레젠테이션의 목차를 만드는 방법을 알려드리지요.

   

파워포인트로 프레젠테이션 목차 만들기

PowerPoint 옵션의 리본 메뉴에 숨어있던 개발 도구 탭 을 활성화

그럼 리본 메뉴에 "개발 도구" 항목이 생깁니다. Visual Basic 을 클릭하여 VBAProject 에서 새로운 사용자 폼을 추가 합니다. 

그리고 대충 아래와 같이 화면을 디자인 하고, Button 을 더블 클릭하여 클릭 이벤트에 코드를 넣습니다. 텍스트박스의 속성 중 MultiLine 을 True 로 지정합니다.

 

   

Private Sub CommandButton1_Click()

Dim title As String
  For i = 1 To ActivePresentation.Slides.Count
    If ActivePresentation.Slides(i).Shapes.HasTitle Then
      If ActivePresentation.Slides(i).Shapes.title.HasTextFrame Then
        If ActivePresentation.Slides(i).Shapes.title.TextFrame.HasText Then
          title = title + ActivePresentation.Slides(i).Shapes.title.TextEffect.Text & " .......... " & ActivePresentation.Slides(i).SlideNumber & vbCrLf
        End If 
      End If
    End If
  Next

Me.TextBox1.Text = title

End Sub    

그리고 스크립트를 실행하면 아래와 같이 멋진 결과를 얻을 수 있다. 보안상 이미지를 흐리게 처리하였습니다.

그리고 위의 결과로 프레젠테이션을 조금만 다듬으면 아래와 같이 멋진 결과를 얻을 수 있다.

   

Posted by 땡초 POWERUMC

댓글을 달아 주세요

  1. 박중석 2009.10.23 11:45 Address Modify/Delete Reply

    와우.. 이거 정말 멋지군요. 게다가 UserForm1 의 압박!

  2. 씩씩한강냉이 2010.08.11 13:08 Address Modify/Delete Reply

    >와, 유용한데요. 감사합니다^^

  3. 황가 2011.11.01 13:17 Address Modify/Delete Reply

    완전 지대!! 유용한 글 감사

  4. 이상균 2015.10.16 14:38 Address Modify/Delete Reply

    안녕하세요
    작성하신 내용 보고 적용 하다 궁금해서 글 남깁니다

    제안서 내용중 하단 부분 중간에 목차가 I-1, I-2 ..... IV-3 이런식으로 들어가는데(바닥글에 넣은건 아니고 페이지 번호 #<#> 부분을 마스터에서 중간으로 변경하여 적용 한것입니다) 해당 부분은
    title = title + ActivePresentation.Slides(i).Shapes.title.TextEffect.Text & " .......... " & 이후 부분을 어떻게 처리 하면 될까요??