1 minute read

서론

Microsoft 365의 Exchange Online의 경우 EWS뿐 아니라 Graph API를 제공하기 때문에 사용자 사서함에 일괄 작업을 하기가 Exchange Server와 비교했을 때 더 다양한 선택지가 있습니다.
Exchange Server의 사서함에 일괄 작업을 하기 위해서는 EWS에 익숙해져야 할 필요가 있습니다. Applicationimpersonation 역할을 가진 계정으로 일괄 작업을 위한 인증 과정을 정리해봅니다.

사전 준비

  1. EWS managed API 다운로드
  2. Applicationimpersonation 역할 할당

EWS Managed API 다운로드

아래 링크에서 다운로드 받을 수 있습니다.
NuGet Gallery | Exchange.WebServices.Managed.Api

패키지 관리자를 이용하거나, 직접 파일을 다운로드 받을 수 있습니다.
ews-download

ZIP 파일을 압축해제 후 lib 폴더를 보면 필요한 파일들이 담겨있습니다.
Microsoft.Exchange.WebServices.dll를 사용합니다.
ews-download

Applicationimpersonation 역할 할당

ECP 또는 PowerShell을 통해 진행합니다.

ECP를 이용해 역할 할당

ECP에서 permissions -> Admin roles 메뉴로 이동 후 새로운 역할 그룹을 추가합니다.
추가한 그룹에는 Applicationimpersonation 역할을 넣어줍니다.
구성원으로는 작업에 사용할 서비스 계정을 넣어줍니다.
Applicationimpersonation 역할은 Exchange에서 3rd party 메일 서비스로 마이그레이션 작업 시 사용하기도 합니다.

ecp-role

PowerShell을 이용해 역할 할당

간단하게 한줄로 생성과 구성원 추가를 해줄 수 있습니다.

New-RoleGroup -Name "Application impersonation" -Roles "Applicationimpersonation" -Members "admin@3namu.shop"

연결

PowerShell을 이용합니다.

다운로드 받은 EWS managed API 라이브러리를 가져옵니다.
경로는 상황에 맞게 변경해주세요.

Import-Module "C:\Users\ho\Downloads\microsoft.exchange.webservices.2.2.0\lib\40\Microsoft.Exchange.WebServices.dll"

연결할 대상 사서함을 지정합니다.

$MailboxName ="on@3namu.shop"

자격증명 입력. 서비스 계정의 자격증명을 입력받습니다.

$PSCredential = Get-Credential

EWS 서비스 개체를 생성하고 필요한 생성한 자격증명과, URL을 넣어줍니다.
어플리케이션 (스크립트)이 본인의 사서함에 어떤 작업을 진행하는 경우에는 여기까지만 진행해도 사서함에 접근이 가능합니다.

$Service = [Microsoft.Exchange.WebServices.Data.ExchangeService]::new()
$Service.Credentials = New-Object System.Net.NetworkCredential($PSCredential.UserName.ToString(),$PSCredential.GetNetworkCredential().password.ToString())
$Service.Url = "https://mail.3namu.shop/EWS/Exchange.asmx"

다만, 다른 사용자의 사서함에 접근한 경우에는 아래와 같은 오류가 발생합니다.

대상 사서함의 받은 편지함 연결을 시도한 경우,

$folderid= new-object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Inbox ,$MailboxName)
$folder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($service,$folderid)

아래와 같은 권한 오류가 발생합니다.

"2"개의 인수가 있는 "Bind"을(를) 호출하는 동안 예외가 발생했습니다. "The specified object was not found in the store."
위치 줄:1 문자:1
+ $folder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($service ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : ServiceResponseException

Impersonated 된 권한을 사용하기 위해서는 생성한 서비스 객체에 ImpersonatedUserId 값을 채워줘야합니다.

$ImpersonatedUserId = New-Object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SMTPAddress,$MailboxName)
$service.ImpersonatedUserId = $ImpersonatedUserId

다시한번 받은 편지함 연결을 시도해 보면 정상적으로 연결됩니다.
mailbox-connected

활용

한가지 예시를 들어보자면, Get-Mailbox로 가져온 사서함 목록을 이용해 모든 사용자의 RecipientCache 폴더를 비워주는 작업을 생각해 볼 수 있습니다.

$mailboxes = Get-Mailbox -Resultsize Unlimited

$mailboxes | %{
  $MailboxName = $_.WindowsEmailAddress
  $ImpersonatedUserId = New-Object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SMTPAddress,$MailboxName)
  $service.ImpersonatedUserId = $ImpersonatedUserId
  $folderid= new-object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::RecipientCache, $MailboxName)
  $folder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($service, $folderid)
  $folder.Empty([Microsoft.Exchange.WebServices.Data.DeleteMode]::HardDelete, $true)
}