Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
337 changes: 337 additions & 0 deletions code-tests/test-assessments/Test-Assessment.35002.Tests.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,337 @@
Describe "Test-Assessment-35002" {
BeforeAll {
$here = $PSScriptRoot
$srcRoot = Join-Path $here "../../src/powershell"
<#
# Import required module functions
@(
"private/core/Add-ZtTestResultDetail.ps1"
"public/Invoke-ZtGraphRequest.ps1"
"private/core/Write-ZtProgress.ps1"
"private/core/Get-ZtTestStatus.ps1"
"private/core/Get-SafeMarkdown.ps1"
) | ForEach-Object { . (Join-Path $srcRoot $_) }
#>
# Mock external module dependencies
if (-not (Get-Command Write-PSFMessage -ErrorAction SilentlyContinue)) {
function Write-PSFMessage {}
}

# Load the class
$classPath = Join-Path $srcRoot "classes/ZtTest.ps1"
if (-not ("ZtTest" -as [type])) {
. $classPath
}

# Load the SUT
$sut = Join-Path $srcRoot "tests/Test-Assessment.35002.ps1"
. $sut

# Setup output file
$script:outputFile = Join-Path $here "../TestResults/Report-Test-Assessment.35002.md"
$outputDir = Split-Path $script:outputFile
if (-not (Test-Path $outputDir)) { New-Item -ItemType Directory -Path $outputDir | Out-Null }
"# Test Results for 35002`n" | Set-Content $script:outputFile
}

BeforeEach {
Mock Write-PSFMessage {}
Mock Write-ZtProgress {}
Mock Get-SafeMarkdown { param($Text) return $Text }
$script:defaultPolicyResponse = $null
$script:partnersResponse = @()
}

Context "When Default Policy allows RMS" {
It "Should pass when Inbound and Outbound allow RMS explicitly" {
$script:defaultPolicyResponse = [PSCustomObject]@{
b2bCollaborationInbound = [PSCustomObject]@{
applications = [PSCustomObject]@{
accessType = "allowed"
targets = @([PSCustomObject]@{ target = "00000012-0000-0000-c000-000000000000" })
}
}
b2bCollaborationOutbound = [PSCustomObject]@{
applications = [PSCustomObject]@{
accessType = "allowed"
targets = @([PSCustomObject]@{ target = "00000012-0000-0000-c000-000000000000" })
}
}
}
$script:partnersResponse = @()

Mock Invoke-ZtGraphRequest {
if ($RelativeUri -match "default") { return $script:defaultPolicyResponse }
if ($RelativeUri -match "partners") { return $script:partnersResponse }
}

Mock Add-ZtTestResultDetail {
param($TestId, $Title, $Status, $Result)
"## Scenario: Default Allowed Explicitly`n`n$Result`n" | Add-Content $script:outputFile
}

Test-Assessment-35002

Should -Invoke Add-ZtTestResultDetail -ParameterFilter {
$Status -eq $true -and $Result -match "RMS application is allowed"
}
}

It "Should pass when Inbound and Outbound allow All Apps" {
$script:defaultPolicyResponse = [PSCustomObject]@{
Copy link

Copilot AI Dec 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inconsistent indentation: the variable assignment uses extra leading spaces (6 spaces instead of the standard 12 spaces for this level). This should be aligned with the indentation used in other test cases in this file.

Suggested change
$script:defaultPolicyResponse = [PSCustomObject]@{
$script:defaultPolicyResponse = [PSCustomObject]@{

Copilot uses AI. Check for mistakes.
b2bCollaborationInbound = [PSCustomObject]@{
applications = [PSCustomObject]@{
accessType = "allowed"
targets = @([PSCustomObject]@{ target = "AllApplications" })
}
}
b2bCollaborationOutbound = [PSCustomObject]@{
applications = [PSCustomObject]@{
accessType = "allowed"
targets = @([PSCustomObject]@{ target = "AllApplications" })
}
}
}
$script:partnersResponse = @()

Mock Invoke-ZtGraphRequest {
if ($RelativeUri -match "default") { return $script:defaultPolicyResponse }
if ($RelativeUri -match "partners") { return $script:partnersResponse }
}

Mock Add-ZtTestResultDetail {
param($TestId, $Title, $Status, $Result)
"## Scenario: Default Allowed All Apps`n`n$Result`n" | Add-Content $script:outputFile
}

Test-Assessment-35002

Should -Invoke Add-ZtTestResultDetail -ParameterFilter {
$Status -eq $true
}
}

It "Should pass when Inbound and Outbound Block specific apps but NOT RMS (Implicit Allow)" {
$script:defaultPolicyResponse = [PSCustomObject]@{
Copy link

Copilot AI Dec 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inconsistent indentation: the variable assignment uses extra leading spaces (6 spaces instead of the standard 12 spaces for this level). This should be aligned with the indentation used in other test cases in this file.

Copilot uses AI. Check for mistakes.
b2bCollaborationInbound = [PSCustomObject]@{
applications = [PSCustomObject]@{
accessType = "blocked"
targets = @([PSCustomObject]@{ target = "some-other-app-id" })
}
}
b2bCollaborationOutbound = [PSCustomObject]@{
applications = [PSCustomObject]@{
accessType = "blocked"
targets = @([PSCustomObject]@{ target = "some-other-app-id" })
}
}
}
$script:partnersResponse = @()

Mock Invoke-ZtGraphRequest {
if ($RelativeUri -match "default") { return $script:defaultPolicyResponse }
if ($RelativeUri -match "partners") { return $script:partnersResponse }
}

Mock Add-ZtTestResultDetail {
param($TestId, $Title, $Status, $Result)
"## Scenario: Default Implicit Allow`n`n$Result`n" | Add-Content $script:outputFile
}

Test-Assessment-35002

Should -Invoke Add-ZtTestResultDetail -ParameterFilter {
$Status -eq $true
}
}
}

Context "When Default Policy blocks RMS" {
It "Should fail when Inbound explicitly blocks RMS" {
$script:defaultPolicyResponse = [PSCustomObject]@{
b2bCollaborationInbound = [PSCustomObject]@{
applications = [PSCustomObject]@{
accessType = "blocked"
targets = @([PSCustomObject]@{ target = "00000012-0000-0000-c000-000000000000" })
}
}
b2bCollaborationOutbound = [PSCustomObject]@{
applications = [PSCustomObject]@{
accessType = "allowed"
targets = @([PSCustomObject]@{ target = "AllApplications" })
}
}
}
$script:partnersResponse = @()

Mock Invoke-ZtGraphRequest {
if ($RelativeUri -match "default") { return $script:defaultPolicyResponse }
if ($RelativeUri -match "partners") { return $script:partnersResponse }
}

$script:capturedResult = $null
Mock Add-ZtTestResultDetail {
param($TestId, $Title, $Status, $Result)
$script:capturedResult = $Result
"## Scenario: Default Inbound Blocked Explicitly`n`n$Result`n" | Add-Content $script:outputFile
}

Test-Assessment-35002

Should -Invoke Add-ZtTestResultDetail -ParameterFilter {
$Status -eq $false
}
$script:capturedResult | Should -Match "Blocked \(Explicit\)"
}

It "Should fail when Inbound allows specific apps but NOT RMS (Implicit Block)" {
$script:defaultPolicyResponse = [PSCustomObject]@{
b2bCollaborationInbound = [PSCustomObject]@{
applications = [PSCustomObject]@{
accessType = "allowed"
targets = @([PSCustomObject]@{ target = "some-other-app-id" })
}
}
b2bCollaborationOutbound = [PSCustomObject]@{
applications = [PSCustomObject]@{
accessType = "allowed"
targets = @([PSCustomObject]@{ target = "AllApplications" })
}
}
}
$script:partnersResponse = @()

Mock Invoke-ZtGraphRequest {
if ($RelativeUri -match "default") { return $script:defaultPolicyResponse }
if ($RelativeUri -match "partners") { return $script:partnersResponse }
}

$script:capturedResult = $null
Mock Add-ZtTestResultDetail {
param($TestId, $Title, $Status, $Result)
$script:capturedResult = $Result
"## Scenario: Default Inbound Blocked Implicitly`n`n$Result`n" | Add-Content $script:outputFile
}

Test-Assessment-35002

Should -Invoke Add-ZtTestResultDetail -ParameterFilter {
$Status -eq $false
}
$script:capturedResult | Should -Match "Blocked \(Implicit\)"
}
}

Context "When Partner Policies exist" {
It "Should fail if a Partner Policy blocks RMS" {
$script:defaultPolicyResponse = [PSCustomObject]@{
b2bCollaborationInbound = [PSCustomObject]@{
applications = [PSCustomObject]@{
accessType = "allowed"
targets = @([PSCustomObject]@{ target = "AllApplications" })
}
}
b2bCollaborationOutbound = [PSCustomObject]@{
applications = [PSCustomObject]@{
accessType = "allowed"
targets = @([PSCustomObject]@{ target = "AllApplications" })
}
}
}
$script:partnersResponse = @(
[PSCustomObject]@{
tenantId = "partner-tenant-id"
b2bCollaborationInbound = [PSCustomObject]@{
applications = [PSCustomObject]@{
accessType = "blocked"
targets = @([PSCustomObject]@{ target = "00000012-0000-0000-c000-000000000000" })
}
}
}
)

Mock Invoke-ZtGraphRequest {
if ($RelativeUri -match "default") { return $script:defaultPolicyResponse }
if ($RelativeUri -match "partners") { return $script:partnersResponse }
}

$script:capturedResult = $null
Mock Add-ZtTestResultDetail {
param($TestId, $Title, $Status, $Result)
$script:capturedResult = $Result
"## Scenario: Partner Blocked`n`n$Result`n" | Add-Content $script:outputFile
}

Test-Assessment-35002

Should -Invoke Add-ZtTestResultDetail -ParameterFilter {
$Status -eq $false
}
$script:capturedResult | Should -Match "Partner \(partner-tenant-id\)"
$script:capturedResult | Should -Match "Blocked \(Explicit\)"
}

It "Should ignore inherited partner settings" {
$script:defaultPolicyResponse = [PSCustomObject]@{
Copy link

Copilot AI Dec 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inconsistent indentation: the variable assignment uses extra leading spaces (6 spaces instead of the standard 12 spaces for this level). This should be aligned with the indentation used in other test cases in this file.

Suggested change
$script:defaultPolicyResponse = [PSCustomObject]@{
$script:defaultPolicyResponse = [PSCustomObject]@{

Copilot uses AI. Check for mistakes.
b2bCollaborationInbound = [PSCustomObject]@{
applications = [PSCustomObject]@{
accessType = "allowed"
targets = @([PSCustomObject]@{ target = "AllApplications" })
}
}
b2bCollaborationOutbound = [PSCustomObject]@{
applications = [PSCustomObject]@{
accessType = "allowed"
targets = @([PSCustomObject]@{ target = "AllApplications" })
}
}
}
# Partner with null/empty settings implies inheritance
$script:partnersResponse = @(
[PSCustomObject]@{
tenantId = "partner-tenant-id"
b2bCollaborationInbound = $null
b2bCollaborationOutbound = [PSCustomObject]@{
applications = $null
}
}
)

Mock Invoke-ZtGraphRequest {
if ($RelativeUri -match "default") { return $script:defaultPolicyResponse }
if ($RelativeUri -match "partners") { return $script:partnersResponse }
}

Mock Add-ZtTestResultDetail {
param($TestId, $Title, $Status, $Result)
"## Scenario: Partner Inherited`n`n$Result`n" | Add-Content $script:outputFile
}

Test-Assessment-35002

Should -Invoke Add-ZtTestResultDetail -ParameterFilter {
$Status -eq $true
}
}
}

Context "Error Handling" {
It "Should handle Graph API errors" {
Mock Invoke-ZtGraphRequest { throw "Graph API Error" }

$script:capturedResult = $null
Mock Add-ZtTestResultDetail {
param($TestId, $Title, $Status, $Result)
$script:capturedResult = $Result
"## Scenario: Error Handling`n`n$Result`n" | Add-Content $script:outputFile
}

Test-Assessment-35002

Should -Invoke Add-ZtTestResultDetail -ParameterFilter {
$Status -eq $false
}
$script:capturedResult | Should -Match "Cross-tenant access policy settings cannot be determined"
}
}
}
18 changes: 18 additions & 0 deletions src/powershell/tests/Test-Assessment.35002.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
Cross-tenant access policies (XTAP) in Microsoft Entra ID control how users in your organization collaborate with external organizations. When users share encrypted content across organizational boundaries or receive encrypted documents from external partners, the Microsoft Rights Management Service (RMS) must authenticate users from both organizations to enforce encryption permissions. If cross-tenant access settings block or restrict the RMS application (App ID: `00000012-0000-0000-c000-000000000000`), users will encounter "Access is blocked by your organization" or "Access is blocked by the organization" error messages when attempting to open encrypted emails or documents from external organizations. This prevents legitimate cross-organizational collaboration on protected content. Organizations should configure both inbound and outbound cross-tenant access settings to explicitly allow the RMS application, ensuring that external users can open encrypted content shared by your organization (inbound) and your users can open encrypted content received from external partners (outbound). Without proper XTAP configuration, encrypted content sharing fails even when users have appropriate permissions assigned through sensitivity label encryption settings.

**Remediation action**

To configure cross-tenant access settings to allow RMS:
1. Navigate to [Microsoft Entra admin center > External Identities > Cross-tenant access settings](https://entra.microsoft.com/#view/Microsoft_AAD_IAM/CompanyRelationshipsMenuBlade/~/CrossTenantAccessSettings)
2. Select "Default settings" or a specific organizational setting
3. Under "Inbound access", select "B2B collaboration"
4. Select "Applications" tab
5. Choose "Allow access" and add "Microsoft Rights Management Services" (App ID: `00000012-0000-0000-c000-000000000000`)
6. Repeat for "Outbound access" settings
7. Save changes

- [Cross-tenant access settings and encrypted content](https://learn.microsoft.com/purview/encryption-azure-ad-configuration#cross-tenant-access-settings-and-encrypted-content)
- [Configure cross-tenant access settings for B2B collaboration](https://learn.microsoft.com/entra/external-id/cross-tenant-access-settings-b2b-collaboration)

<!--- Results --->
%TestResult%
Loading