이 방법을 사용하면 Teams에서 이루어진 사용자별 파일 관련 활동만을 확인할 수 있습니다.

Purview 포털 감사로그에서 시도한 방법들

Purview 포털에서 Teams 내 사용자의 파일 활동만을 검색할 수 있는지 확인하기 위해 시도한 방법은 다음과 같습니다.

 

시도한 방법 1) Activities - friendly names: Accessd file, Downloaded file, Uploaded file / Workloads: MicrosoftTeams

처음에는 Teams에서 발생한 파일 활동이므로 Workload가 MicrosoftTeams일 것이라고 생각하고, 파일 관련 활동을 선택했습니다.

 

결과: Total results = 0

 

이후 시도한 방법부터는 우선 Teams 내 파일 활동의 속성 값이 어떤 값을 가지는지 확인하기 위한 검색을 시도했습니다.

 

 

 


시도한 방법2) Activites - friendly names: Accessed file / Workloads: SharePoint, OneDrive

Workload가 MicrosoftTeams가 아니라면 SharePoint나 OneDrive일 것으로 판단하고, 결과 수를 줄이기 위해 Accessed file만 선택했습니다.

 

결과: Total results = 45

 

결과 리스트에서 RecordType 값이 SharePointFileOperation임을 확인했습니다.


시도한 방법3) Record Types: SharePointFileOpeartion

방법 2에서 확인한 RecordType을 기준으로 다시 검색했습니다.
로그 결과를 Export한 파일을 Excel에서 확인해 보니 FileAccessed를 포함한 다양한 활동이 있었지만, 다음과 같은 활동은 제외할 필요가 있었습니다.

  • Teams 외부 활동(FileModified 등)
  • 시스템 활동(FileSensitivityLabelApplied 등)
  • 파일과 무관한 활동(FolderCreated)

 

Teams 내 파일 활동만 보려면 AuditData 객체의 ApplicationDisplayName을 활용해야 될 것으로 보였습니다.

(CLient App


시도한 방법4) Activites - operation names: FileDownloaded,FileAccessed,FileUploaded,FilePreviewed / Record Types: SharePointFileOpeartion / Keyword Search: Microsoft Teams

 

 

방법 3에서 확인한 SharePointFileOperation 중 Teams에서 발생 가능한 파일 활동을 지정하고, Keyword Search에는 Microsoft Teams를 입력했습니다. Keyword를 지정한 이유는 ApplicationDisplayName 값이 Microsoft Teams 또는 Microsoft Teams Web Client인 항목을 찾기 위해서 입니다.

 

결과적으로, 목표했던 Microsoft Teams 또는 Microsoft Teams Web Client에서 발생한 사용자별 파일 활동을 성공적으로 검색할 수 있었습니다.

 

다만, Microsoft Teams를 키워드로 사용했기 때문에, 파일 이름 등에 해당 키워드가 포함되어 있으면 실제 Teams 내 파일 활동이 아니더라도 검색 결과에 포함될 가능성이 있었습니다.


PowerShell에서 Teams 내 파일 활동 로그 검색

Purview 포털에서는 Microsoft Teams 앱에서 발생한 파일 활동만을 검색하기에는 어려워 보였습니다. 그래서 PowerShell을 사용해 Exchange Online의 감사 로그를 조회하고, Teams 관련 이벤트만 추출한 뒤 CSV로 저장하는 방식을 구현했습니다.

Connect-ExchangeOnline

# Base path 설정
$basePath   = "/Users/"
$outputFile = "$basePath\AuditLogRecords.csv"

# 검색 기간
$start = "10/14/2025"
$end   = "10/15/2025"

# RecordType 및 Operations
$record = "SharePointFileOperation"
$ops    = @("FileDownloaded","FileUploaded","FileAccessed","FilePreviewed")

# 페이지 크기
$resultSize = 5000

# 감사 로그 추출 및 CSV로 저장
Search-UnifiedAuditLog -StartDate $start -EndDate $end -RecordType $record -Operations $ops -ResultSize $resultSize |
    Where-Object { $_.AuditData -like '*"ApplicationDisplayName":"Microsoft Teams*' } |
    Export-Csv -Path $outputFile

 

Exchange Online 모듈의 Search-UnifiedAuditLog cmdlet을 사용하여 감사 로그를 조회한 뒤, Where-Object를 통해 AuditData 속성에서 ApplicationDisplayName 값이 Microsoft Teams로 시작하는 레코드만 필터링했습니다. 마지막으로, 필터링된 결과를 CSV 형식으로 내보냈습니다.


하지만 결과 파일을 확인해 보니, Identity 값이 중복된 레코드가 전체의 절반가량을 차지했습니다.

 

PowerShell에서 Teams 내 파일 활동 로그 검색 - 레코드 중복 제거

Search-UnifiedAuditLog cmdlet 실행 시 중복이 발생하는 원인은 확인하지 못했습니다. 그래서 결과에서 중복된 Identity 값을 제거하는 방식으로 처리했습니다.

Connect-ExchangeOnline

# Base path 설정
$basePath   = "/Users/"
$outputFile = "$basePath\AuditLogRecords.csv"

# 검색 기간
$start = "10/14/2025"
$end   = "10/15/2025"

# RecordType 및 Operations
$record = "SharePointFileOperation"
$ops    = @("FileDownloaded","FileUploaded","FileAccessed","FilePreviewed")

# 페이지 크기
$resultSize = 5000

# 감사 로그 추출 및 CSV로 저장
Search-UnifiedAuditLog -StartDate $start -EndDate $end -RecordType $record -Operations $ops -ResultSize $resultSize |
    Where-Object { $_.AuditData -like '*"ApplicationDisplayName":"Microsoft Teams*' } |
    Export-Csv -Path $outputFile
    
# CSV 로드 → Identity 기준 중복 제거 → 동일 파일로 덮어쓰기
$rows = Import-Csv -Path $outputFile

$seen = @{}
$deduped = foreach ($row in $rows) {
    $keyRaw = $row.Identity
    if ($null -eq $keyRaw -or ($keyRaw -is [string] -and $keyRaw.Trim() -eq '')) {
        $row
        continue
    }

    $key = ($keyRaw -as [string]).Trim().ToLower()

    if (-not $seen.ContainsKey($key)) {
        $seen[$key] = $true
        $row
    }
}

$deduped | Export-Csv -Path $outputFile

 

$rows 변수에는 $outputFile 경로의 CSV 파일을 읽어 각 행을 PowerShell 객체 배열로 저장했습니다.

$rows = Import-Csv -Path $outputFile

 

$seen 변수는 중복 여부를 확인하기 위해, 순회 중 발견한 Identity 값을 기록하는 해시테이블로 초기화했습니다.

$seen = @{}

 

$deduped 변수에는 동일한 Identity 값을 가진 레코드 중 첫 번째 항목만 남겨 중복을 제거한 결과를 담았습니다.

$deduped = foreach ($row in $rows) {
    $keyRaw = $row.Identity
    if ($null -eq $keyRaw -or ($keyRaw -is [string] -and $keyRaw.Trim() -eq '')) {
        $row
        continue
    }

    $key = ($keyRaw -as [string]).Trim().ToLower()

    if (-not $seen.ContainsKey($key)) {
        $seen[$key] = $true
        $row
    }
}

 

 

마지막으로, 중복 제거된 결과를 기존 CSV 파일에 덮어썼습니다.

$deduped | Export-Csv -Path $outputFile

 

 

최종적으로, 목표했던 Teams 내 사용자별 파일 활동 로그를 중복 없이 얻을 수 있었습니다.


참고문서

 

Office 365 Management Activity API schema

The Office 365 Management Activity API schema is provided as a data service in two layers - Common schema and service-specific schema.

learn.microsoft.com

 

Use a PowerShell script to search the audit log

Use a PowerShell script that runs the Search-UnifiedAuditLog cmdlet in Exchange Online to search the audit log. This script is optimized to return a large set of audit records each time you run it. The script exports these records to a CSV file that you ca

learn.microsoft.com

본 글의 내용은 공식 문서, 실제 테스트 경험, 그리고 작성자의 개인적인 해석을 바탕으로 작성되었습니다.

환경이나 정책 그리고 시점에 따라 다르게 적용될 수 있으므로 참고용으로 활용해 주세요.

The structure described in this guide is used when there is a security requirement to restrict document access to all users except the document owner.

 

There are two methods for creating sensitivity labels based on this encryption configuration: one is somewhat complex, while the other is very straightforward. This guide walks through both approaches.


Related Concepts

IPC_USER_ID_OWNER:
A reserved user ID that represents the document owner.
(*IPC: Information Protection and Control)


Method 1: Using Rights Definition Objects

Step 1: Create a Rights Definition Object for Owner-Only Access

First, connect to the Azure Information Protection service and create a rights definition object:

Connect-AipService
$rights_definition = New-AipServiceRightsDefinition -EmailAddress "IPC_USER_ID_OWNER" -Rights "OWNER"

 

The `New-AipServiceRightsDefinition` cmdlet creates an object within your PowerShell session. The rights definition object stored in the `$rights_definition` variable will have the following structure:

JSON:

{ "Identity": "IPC_USER_ID_OWNER", "Rights": [ "OWNER" ] }

 

Step 2: Define Protection Template Names and Descriptions

Define the template name and description variables using hash tables for multi-language support:

$names = @{}
$names[1033] = "Template Name in English"
$names[1042] = "템플릿 이름 (한국어)"

$descriptions = @{}
$descriptions[1033] = "Description in English"
$descriptions[1042] = "설명 (한국어)"

When creating a protection template with New-AipServiceTemplate, the Names and Descriptions parameters must be specified as hash tables. First, create an empty hash table (@{}), then map the template name and description by using the appropriate LCID (Windows Language Code Identifier) as the key.

 

Step 3: Create a Protection Template

$protection_template = Add-AipServiceTemplate `
-Names $names `
-Descriptions $descriptions `
-RightsDefinitions $rights_definition `
-Status Published

 

The creation result of the protection template stored in the $protection_template variable is as follows.

Store the template ID from the created protection template in a variable for later use:

$id = $protection_template.TemplateId.ToString()

 

Step 4: Create a Sensitivity Label

New-Label `
    -Name "Label Name" `
    -DisplayName "Label Display Name" `
    -Tooltip "Tooltip Text" `
    -Comment "Description" `
    -EncryptionEnabled $true `
    -EncryptionProtectionType Template `
    -EncryptionTemplateId $TemplateId

Method 2: Using the EncryptionEnabled Parameter

For a simpler approach, you can create a sensitivity label directly using the New-Label cmdlet with the EncryptionEnabled parameter enabled.
New-Label `
    -Name "Label Name" `
    -DisplayName "Label Display Name" `
    -Tooltip "Tooltip Text" `
    -Comment "Label Description" `
    -EncryptionEnabled $true

Results

Both methods produce identical results. When you view the encryption permissions of the created sensitivity label in the Purview portal, you will see that Full Control permissions are assigned to IPC_USER_ID_OWNER.

 

You can verify this in PowerShell by running the Get-Label command. The rightsdefinitions key value will contain the rights definition object:

LabelActions                    : {{"Type":"encrypt","SubType":null,"Settings":[{"Key":"disabled","Value":"false"},{"Ke
                                  y":"protectiontype","Value":"template"},{"Key":"templateid","Value":""},{"Key":"templatearchived","Value":"False"},{"Key":"linkedtempl
                                  ateid","Value":""},{"Key":"contentexpiredondatein
                                  daysornever","Value":"Never"},{"Key":"offlineaccessdays","Value":"0"},{"Key":"rightsd
                                  efinitions","Value":"[{\"Identity\":\"IPC_USER_ID_OWNER\",\"Rights\":\"OWNER\"}]"}]}}

Reference Documentation

This article is based on official Microsoft documentation, practical testing experience, and the author's personal interpretation. Implementation may vary depending on your environment, policies, and timing. Please use this guide as a reference.

이 구성은 문서 소유자 외 모든 사용자 접근을 차단해야 하는 보안 요구사항이 있을 때 사용합니다.

 

이 암호화 구성을 기반으로 민감도 레이블을 만드는 방법은 두 가지가 있습니다.
하나는 조금 복잡한 방식, 다른 하나는 매우 간단한 방식입니다.


관련 개념

IPC_USER_ID_OWNER:

문서의 소유자를 나타내는 예약된 사용자 ID

(*IPC: Information Protection and Control의 약자)


권한 정의 개체를 이용한 방법 

1) 나만 볼 수 있는 권한 정의 개체(Rights definition object) 생성

Connect-AipService
$rights_definition = New-AipServiceRightsDefinition -EmailAddress "IPC_USER_ID_OWNER" -Rights "OWNER"

New-AipServiceRightsDefinition cmdlet을 사용하면 PowerShell 세션에서 객체를 만들어 줍니다.

$rights_definition 변수에 저장된 권한 정의 개체는 다음과 같습니다.

JSON 구조로 보면 다음과 같습니다.

{ "Identity": "IPC_USER_ID_OWNER", "Rights": [ "OWNER" ] }

 

2) 보호 템플릿 이름, 설명 변수 정의

$names = @{}
$names[1033] = "Template Name in English"
$names[1042] = "템플릿 이름 (한국어)"

$descriptions = @{}
$descriptions[1033] = "Description in English"
$descriptions[1042] = "설명 (한국어)"

New-AipServiceTemplate으로 보호 템플릿을 생성할 때, Names와 Descriptions 파라미터는 해시 테이블 형태로 지정해야 합니다.

따라서 먼저 빈 해시 테이블(@{})을 생성한 후, 표시할 언어에 해당하는 LCID(Windows Language Code Identifier)를 키로 이름과 설명을 매핑해 줍니다.

 

3) 보호 템플릿(Protection template) 생성

$protection_template = Add-AipServiceTemplate `
-Names $names `
-Descriptions $descriptions `
-RightsDefinitions $rights_definition `
-Status Published

$protection_template 변수에 저장된 보호 템플릿 생성 결과는 다음과 같습니다.

 

생성된 보호 템플릿의 GUID 값은 $id 변수에 저장합니다.

$id = $protection_template.TemplateId.ToString()

4) 민감도 레이블 생성

New-Label `
    -Name "레이블 이름" `
    -DisplayName "레이블 표시 이름" `
    -Tooltip "툴팁 내용" `
    -Comment "설명" `
    -EncryptionEnabled $true `
    -EncryptionProtectionType Template `
    -EncryptionTemplateId $TemplateId

EncryptionEnabled 파라미터를 이용한 방법

New-Label을 사용해서 민감도 레이블을 만들 때, 암호화를 활성해 주면 됩니다.
New-Label `
    -Name "레이블 이름" `
    -DisplayName "레이블 표시 이름" `
    -Tooltip "툴팁 내용" `
    -Comment "레이블 설명" `
    -EncryptionEnabled $true

결과

Purview 포털에서 생성된 민감도 레이블의 암호화 권한을 확인해 보면 IPC_USER_ID_OWNER에게 Full Control 권한이 설정되어 있는 것을 확인할 수 있습니다. 두 가지 방법 모두 결과는 동일합니다.

PowerShell에서 Get-Label 명령어로 확인해 보면 rightsdefinitions Key 값에 {\"Identity\":\"IPC_USER_ID_OWNER\",\"Rights\":\"OWNER\"} 권한 정의 개체가 들어가 있는 걸 확인할 수 있습니다.

LabelActions                    : {{"Type":"encrypt","SubType":null,"Settings":[{"Key":"disabled","Value":"false"},{"Ke
                                  y":"protectiontype","Value":"template"},{"Key":"templateid","Value":""},{"Key":"templatearchived","Value":"False"},{"Key":"linkedtempl
                                  ateid","Value":""},{"Key":"contentexpiredondatein
                                  daysornever","Value":"Never"},{"Key":"offlineaccessdays","Value":"0"},{"Key":"rightsd
                                  efinitions","Value":"[{\"Identity\":\"IPC_USER_ID_OWNER\",\"Rights\":\"OWNER\"}]"}]}}

참고문서

본 글의 내용은 공식 문서, 실제 테스트 경험, 그리고 작성자의 개인적인 해석을 바탕으로 작성되었습니다.

환경이나 정책 그리고 시점에 따라 다르게 적용될 수 있으므로 참고용으로 활용해 주세요.

+ Recent posts