param(
    [ValidateSet("Debug", "Release")]
    [string]$Configuration = "Release",

    [string]$ServiceName = "SyncVisionServer",

    [ValidateSet("LocalSystem", "LocalService", "NetworkService")]
    [string]$ServiceAccount = "NetworkService",

    [string]$InstallDir = (Join-Path $env:ProgramFiles "SyncVision\Server"),

    [string]$DataDir = (Join-Path $env:ProgramData "SyncVision\Server"),

    [string]$Listen = "0.0.0.0:38580",

    [string]$Token = "",

    [string]$DeviceTokensFile = "",

    [string]$LogFile = "",

    [UInt64]$LogMaxBytes = 10485760,

    [UInt32]$LogRetainedFiles = 5,

    [string]$DiscoveryListen = "0.0.0.0:38581",

    [string]$Advertise = "",

    [switch]$Lan,

    [switch]$AllowUnsafePublicRelay,

    [ValidateSet("disabled", "optional", "required")]
    [string]$TransportEncryption = "disabled",

    [string]$TransportSecret = "",

    [string]$TransportSecretFile = "",

    [UInt32]$FirstFrameTimeoutMs = 5000,

    [UInt32]$IdleTimeoutMs = 15000,

    [UInt32]$HeartbeatTtlMs = 30000,

    [UInt32]$MaxSessions = 128,

    [UInt32]$MaxPendingFirstFrames = 64,

    [switch]$ConfigureFirewall,

    [string]$FirewallRemoteAddress = "",

    [UInt32]$ServiceRecoveryRestartDelayMs = 5000,

    [switch]$NoServiceRecovery,

    [switch]$NoDiscovery,

    [switch]$Start,

    [switch]$VerifyInstall,

    [UInt32]$VerifyTimeoutMs = 10000,

    [switch]$RevealGeneratedToken,

    [switch]$WhatIf,

    [switch]$SkipBuild,

    [string]$ExpectedManifestSha256 = "",

    [switch]$AllowUntrustedPackageManifestForLocalDevelopment,

    [switch]$AllowSourceCheckoutSkipBuildForLocalDevelopment,

    [switch]$TestMode
)

Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"

function Test-SyncVisionAdministrator {
    $identity = [Security.Principal.WindowsIdentity]::GetCurrent()
    $principal = [Security.Principal.WindowsPrincipal]::new($identity)
    return $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
}

function Assert-SyncVisionTrustedWindowsPathBoundary {
    param(
        [Parameter(Mandatory = $true)][string]$Path,
        [Parameter(Mandatory = $true)][string]$Context
    )

    $windowsRoot = [IO.Directory]::GetParent([Environment]::SystemDirectory).FullName.TrimEnd('\', '/')
    $trustedSids = @(
        "S-1-5-18",
        "S-1-5-32-544",
        "S-1-5-80-956008885-3418522649-1831038044-1853292631-2271478464"
    )
    $contentMutation = Get-SyncVisionContentMutationRights
    $destructive = Get-SyncVisionDestructiveAncestorRights
    $current = Get-Item -LiteralPath (Resolve-Path -LiteralPath $Path).Path -Force
    while ($null -ne $current) {
        if (($current.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
            throw "$Context contains a reparse-point path component: $($current.FullName)"
        }
        $acl = Get-Acl -LiteralPath $current.FullName
        $owner = $acl.GetOwner([Security.Principal.SecurityIdentifier]).Value
        if ($trustedSids -notcontains $owner) {
            throw "$Context has an untrusted owner SID $owner at $($current.FullName)."
        }
        $normalized = $current.FullName.TrimEnd('\', '/')
        $rightsToReject = if ($normalized.StartsWith($windowsRoot + [IO.Path]::DirectorySeparatorChar, [StringComparison]::OrdinalIgnoreCase) -or
            [string]::Equals($normalized, $windowsRoot, [StringComparison]::OrdinalIgnoreCase)) {
            $contentMutation
        }
        else {
            $destructive
        }
        foreach ($rule in $acl.GetAccessRules($true, $true, [Security.Principal.SecurityIdentifier])) {
            $applies = ($rule.PropagationFlags -band [Security.AccessControl.PropagationFlags]::InheritOnly) -eq 0
            if ($applies -and
                $rule.AccessControlType -eq [Security.AccessControl.AccessControlType]::Allow -and
                $trustedSids -notcontains $rule.IdentityReference.Value -and
                ($rule.FileSystemRights -band $rightsToReject) -ne 0) {
                throw "$Context grants an untrusted SID write, delete, or ACL-control rights at $($current.FullName)."
            }
        }
        $current = if ($current -is [IO.DirectoryInfo]) { $current.Parent } else { $current.Directory }
    }
}

function Resolve-SyncVisionTrustedWindowsTool {
    param(
        [Parameter(Mandatory = $true)][string]$RelativePath,
        [Parameter(Mandatory = $true)][string]$Context
    )

    $canonicalRelativePaths = @(
        "System32\sc.exe",
        "System32\WindowsPowerShell\v1.0\powershell.exe"
    )
    if ($canonicalRelativePaths -cnotcontains $RelativePath -or
        [IO.Path]::IsPathRooted($RelativePath) -or
        $RelativePath -match '(^|\\)\.\.(\\|$)') {
        throw "$Context requested an unreviewed Windows tool path: $RelativePath"
    }
    $windowsRoot = [IO.Directory]::GetParent([Environment]::SystemDirectory).FullName
    $path = [IO.Path]::GetFullPath((Join-Path $windowsRoot $RelativePath))
    $windowsPrefix = $windowsRoot.TrimEnd('\', '/') + [IO.Path]::DirectorySeparatorChar
    if (-not $path.StartsWith($windowsPrefix, [StringComparison]::OrdinalIgnoreCase) -or
        -not (Test-Path -LiteralPath $path -PathType Leaf)) {
        throw "$Context was not found under the canonical Windows root: $path"
    }
    Assert-SyncVisionTrustedWindowsPathBoundary -Path $path -Context $Context
    $item = Get-Item -LiteralPath $path -Force
    $signature = Get-AuthenticodeSignature -LiteralPath $item.FullName
    if ($signature.Status -ne [Management.Automation.SignatureStatus]::Valid -or
        $null -eq $signature.SignerCertificate -or
        $signature.SignerCertificate.Subject -notmatch '(^|, )O=Microsoft Corporation(,|$)') {
        throw "$Context does not have a valid Microsoft Authenticode identity: $($signature.Status)."
    }
    return [pscustomobject]@{
        Path = $item.FullName
        RelativePath = $RelativePath
        Hash = (Get-FileHash -LiteralPath $item.FullName -Algorithm SHA256).Hash.ToLowerInvariant()
        Version = [string]$item.VersionInfo.FileVersion
        Length = [Int64]$item.Length
        LastWriteTimeUtcTicks = $item.LastWriteTimeUtc.Ticks
        SignerThumbprint = $signature.SignerCertificate.Thumbprint.ToUpperInvariant()
        SignerSubject = $signature.SignerCertificate.Subject
    }
}

function Assert-SyncVisionTrustedWindowsToolIdentity {
    param(
        [Parameter(Mandatory = $true)][object]$Identity,
        [Parameter(Mandatory = $true)][string]$Context
    )

    $current = Resolve-SyncVisionTrustedWindowsTool -RelativePath $Identity.RelativePath -Context $Context
    foreach ($propertyName in @("Path", "Hash", "Version", "Length", "LastWriteTimeUtcTicks", "SignerThumbprint", "SignerSubject")) {
        if ([string]$current.$propertyName -cne [string]$Identity.$propertyName) {
            throw "$Context identity changed before trusted use: $propertyName"
        }
    }
    return $current
}

function New-SyncVisionServiceBinPath {
    param(
        [Parameter(Mandatory = $true)]
        [string]$ServerExe,

        [Parameter(Mandatory = $true)]
        [string]$ConfigPath,

        [Parameter(Mandatory = $true)]
        [string]$ServiceName
    )

    return "`"$ServerExe`" --service --service-name `"$ServiceName`" --config `"$ConfigPath`""
}

function Resolve-SyncVisionServiceAccountIdentity {
    param(
        [ValidateSet("LocalSystem", "LocalService", "NetworkService")]
        [string]$ServiceAccount = "NetworkService"
    )

    switch ($ServiceAccount) {
        "LocalService" { return "NT AUTHORITY\LocalService" }
        "NetworkService" { return "NT AUTHORITY\NetworkService" }
        default { return "LocalSystem" }
    }
}

function New-SyncVisionServiceCreateArguments {
    param(
        [Parameter(Mandatory = $true)]
        [string]$ServiceName,

        [Parameter(Mandatory = $true)]
        [string]$BinPath,

        [ValidateSet("LocalSystem", "LocalService", "NetworkService")]
        [string]$ServiceAccount = "NetworkService"
    )

    $arguments = @(
        "create",
        $ServiceName,
        "binPath=",
        $BinPath,
        "start=",
        "auto",
        "DisplayName=",
        "SyncVision Server"
    )

    $identity = Resolve-SyncVisionServiceAccountIdentity -ServiceAccount $ServiceAccount
    if ($identity -ne "LocalSystem") {
        $arguments += @("obj=", $identity)
    }

    return $arguments
}

function New-SyncVisionServiceConfigArguments {
    param(
        [Parameter(Mandatory = $true)][string]$ServiceName,
        [Parameter(Mandatory = $true)][string]$BinPath,
        [ValidateSet("LocalSystem", "LocalService", "NetworkService")]
        [string]$ServiceAccount = "NetworkService"
    )

    return @(
        "config",
        $ServiceName,
        "binPath=",
        $BinPath,
        "start=",
        "auto",
        "obj=",
        (Resolve-SyncVisionServiceAccountIdentity -ServiceAccount $ServiceAccount)
    )
}

function New-SyncVisionServerConfigText {
    param(
        [Parameter(Mandatory = $true)]
        [string]$Listen,

        [Parameter(Mandatory = $true)]
        [string]$TokenFile,

        [string]$DeviceTokensFile = "",

        [Parameter(Mandatory = $true)]
        [string]$LogFile,

        [Parameter(Mandatory = $true)]
        [UInt64]$LogMaxBytes,

        [Parameter(Mandatory = $true)]
        [UInt32]$LogRetainedFiles,

        [Parameter(Mandatory = $true)]
        [string]$DiscoveryListen,

        [string]$Advertise = "",

        [Parameter(Mandatory = $true)]
        [bool]$DiscoveryEnabled,

        [Parameter(Mandatory = $true)]
        [UInt32]$FirstFrameTimeoutMs,

        [Parameter(Mandatory = $true)]
        [UInt32]$IdleTimeoutMs,

        [Parameter(Mandatory = $true)]
        [UInt32]$HeartbeatTtlMs,

        [Parameter(Mandatory = $true)]
        [UInt32]$MaxSessions,

        [Parameter(Mandatory = $true)]
        [UInt32]$MaxPendingFirstFrames,

        [ValidateSet("disabled", "optional", "required")]
        [string]$TransportEncryption = "disabled",

        [AllowEmptyString()]
        [string]$TransportSecret = "",

        [AllowEmptyString()]
        [string]$TransportSecretFile = "",

        [Parameter(Mandatory = $true)]
        [bool]$AllowUnsafePublicRelay
    )

    $lines = @(
        "listen=$Listen",
        "token_file=$TokenFile",
        "log_file=$LogFile",
        "log_max_bytes=$LogMaxBytes",
        "log_retained_files=$LogRetainedFiles",
        "discovery_listen=$DiscoveryListen"
    )

    if ($DeviceTokensFile) {
        $lines += "device_tokens_file=$DeviceTokensFile"
    }

    if ($Advertise) {
        $lines += "advertise=$Advertise"
    }

    $lines += "discovery_enabled=$(if ($DiscoveryEnabled) { "true" } else { "false" })"
    $lines += "first_frame_timeout_ms=$FirstFrameTimeoutMs"
    $lines += "idle_timeout_ms=$IdleTimeoutMs"
    $lines += "heartbeat_ttl_ms=$HeartbeatTtlMs"
    $lines += "max_sessions=$MaxSessions"
    $lines += "max_pending_first_frames=$MaxPendingFirstFrames"
    if ($TransportEncryption -ne "disabled") {
        if ([string]::IsNullOrWhiteSpace($TransportSecret) -and [string]::IsNullOrWhiteSpace($TransportSecretFile)) {
            throw "TransportSecretFile cannot be empty when TransportEncryption is optional or required."
        }
        if (-not [string]::IsNullOrWhiteSpace($TransportSecret) -and -not [string]::IsNullOrWhiteSpace($TransportSecretFile)) {
            throw "Pass either TransportSecret or TransportSecretFile, not both."
        }
        $lines += "transport_encryption=$TransportEncryption"
        if (-not [string]::IsNullOrWhiteSpace($TransportSecretFile)) {
            $lines += "transport_secret_file=$TransportSecretFile"
        }
        else {
            $lines += "transport_secret=$TransportSecret"
        }
    }
    if ($AllowUnsafePublicRelay) {
        $lines += "allow_unsafe_public_relay=true"
    }
    return $lines -join [Environment]::NewLine
}

function Redact-SyncVisionServerConfigText {
    param(
        [Parameter(Mandatory = $true)]
        [string]$Text
    )

    $redactedLines = foreach ($line in ($Text -split "`r?`n")) {
        if ($line -match '^\s*token\s*=') {
            "token=<redacted>"
        }
        elseif ($line -match '^\s*transport_secret\s*=') {
            "transport_secret=<redacted>"
        }
        else {
            $line
        }
    }

    return $redactedLines -join [Environment]::NewLine
}

function Test-SyncVisionLocalSystemServiceAccount {
    param(
        [AllowEmptyString()]
        [string]$ServiceAccount = ""
    )

    $normalized = $ServiceAccount.Trim()
    return [string]::IsNullOrWhiteSpace($normalized) `
        -or $normalized -eq "LocalSystem" `
        -or $normalized -eq ".\LocalSystem" `
        -or $normalized -eq "SYSTEM" `
        -or $normalized -eq "NT AUTHORITY\SYSTEM"
}

function New-SyncVisionTokenFileAcl {
    param(
        [AllowEmptyString()]
        [string]$ServiceAccount = ""
    )

    $acl = New-Object System.Security.AccessControl.FileSecurity
    $acl.SetAccessRuleProtection($true, $false)

    $allow = [Security.AccessControl.AccessControlType]::Allow
    $noInheritance = [Security.AccessControl.InheritanceFlags]::None
    $noPropagation = [Security.AccessControl.PropagationFlags]::None
    $administratorsSid = [Security.Principal.SecurityIdentifier]::new([Security.Principal.WellKnownSidType]::BuiltinAdministratorsSid, $null)
    $systemSid = [Security.Principal.SecurityIdentifier]::new([Security.Principal.WellKnownSidType]::LocalSystemSid, $null)

    $acl.AddAccessRule([Security.AccessControl.FileSystemAccessRule]::new(
            $administratorsSid,
            [Security.AccessControl.FileSystemRights]::FullControl,
            $noInheritance,
            $noPropagation,
            $allow))
    $acl.AddAccessRule([Security.AccessControl.FileSystemAccessRule]::new(
            $systemSid,
            [Security.AccessControl.FileSystemRights]::FullControl,
            $noInheritance,
            $noPropagation,
            $allow))

    if (-not (Test-SyncVisionLocalSystemServiceAccount -ServiceAccount $ServiceAccount)) {
        $serviceIdentity = [Security.Principal.NTAccount]::new($ServiceAccount.Trim())
        $acl.AddAccessRule([Security.AccessControl.FileSystemAccessRule]::new(
                $serviceIdentity,
                [Security.AccessControl.FileSystemRights]::ReadAndExecute,
                $noInheritance,
                $noPropagation,
                $allow))
    }

    return $acl
}

function Set-SyncVisionTokenFileAcl {
    param(
        [Parameter(Mandatory = $true)]
        [string]$Path,

        [AllowEmptyString()]
        [string]$ServiceAccount = ""
    )

    $acl = New-SyncVisionTokenFileAcl -ServiceAccount $ServiceAccount
    Set-Acl -LiteralPath $Path -AclObject $acl
}

function Get-SyncVisionCurrentFileSystemProviderPath {
    $location = Get-Location
    if ($null -eq $location.Provider -or
        -not [string]::Equals($location.Provider.Name, "FileSystem", [StringComparison]::OrdinalIgnoreCase) -or
        [string]::IsNullOrWhiteSpace([string]$location.ProviderPath)) {
        throw "SyncVision user paths require the current PowerShell location to use the FileSystem provider."
    }
    $providerPath = [string]$location.ProviderPath
    if (-not [IO.Path]::IsPathRooted($providerPath)) {
        throw "The current PowerShell FileSystem ProviderPath is not rooted: $providerPath"
    }
    return [IO.Path]::GetFullPath($providerPath)
}

function Resolve-SyncVisionUserFileSystemPath {
    param(
        [Parameter(Mandatory = $true)][string]$Path,
        [Parameter(Mandatory = $true)][string]$BasePath,
        [Parameter(Mandatory = $true)][string]$Context
    )

    if ([string]::IsNullOrWhiteSpace($Path)) {
        throw "$Context must not be empty."
    }
    try {
        if ($BasePath -match '^[A-Za-z]:(?:$|[^\\/])' -or
            -not [IO.Path]::IsPathRooted($BasePath)) {
            throw "The explicit ProviderPath base must be fully qualified."
        }
        $canonicalBase = [IO.Path]::GetFullPath($BasePath)
        $isExtended = $Path.StartsWith('\\?\', [StringComparison]::Ordinal)
        $isUnc = -not $isExtended -and $Path.StartsWith('\\', [StringComparison]::Ordinal)
        $isDriveAbsolute = $Path -match '^[A-Za-z]:[\\/]'
        $isDriveRelative = $Path -match '^[A-Za-z]:(?:$|[^\\/])'
        $isSingleRooted = -not $isUnc -and -not $isExtended -and
            ($Path.StartsWith('\', [StringComparison]::Ordinal) -or
                $Path.StartsWith('/', [StringComparison]::Ordinal))

        if ($isDriveRelative) {
            throw "$Context rejects drive-relative path '$Path' because it depends on hidden per-drive current-directory state. Use a fully-qualified path such as C:\foo."
        }

        $combined = if ($isExtended -or $isUnc) {
            $qualifiedRoot = [IO.Path]::GetPathRoot($Path)
            $hasQualifiedStructure = if ($isExtended) {
                $Path -match '^\\\\\?\\(?:[A-Za-z]:[\\/]|UNC\\[^\\]+\\[^\\]+(?:\\|$)|Volume\{[0-9A-Fa-f-]+\}\\)'
            }
            else {
                $Path -match '^\\\\[^\\]+\\[^\\]+(?:\\|$)'
            }
            if ([string]::IsNullOrWhiteSpace($qualifiedRoot) -or -not $hasQualifiedStructure) {
                throw "$Context requires a fully-qualified UNC or extended path: $Path"
            }
            $Path
        }
        elseif ($isDriveAbsolute) {
            $Path
        }
        elseif ($isSingleRooted) {
            $providerDriveRoot = [IO.Path]::GetPathRoot($canonicalBase)
            if ($providerDriveRoot -notmatch '^[A-Za-z]:[\\/]$') {
                throw "$Context cannot resolve a single-root path because the current ProviderPath is not on a drive: $canonicalBase"
            }
            Join-Path `
                -Path $providerDriveRoot `
                -ChildPath $Path.TrimStart([char[]]@('\', '/'))
        }
        else {
            Join-Path -Path $canonicalBase -ChildPath $Path
        }
        if (-not [IO.Path]::IsPathRooted($combined)) {
            throw "The path was not rooted after applying the explicit ProviderPath base."
        }
        return [IO.Path]::GetFullPath($combined)
    }
    catch {
        throw "$Context could not be resolved from PowerShell ProviderPath base '$BasePath': $($_.Exception.Message)"
    }
}

function Assert-SyncVisionExistingPathChainNoReparse {
    param(
        [Parameter(Mandatory = $true)][string]$Path,
        [Parameter(Mandatory = $true)][string]$Context
    )

    $basePath = Get-SyncVisionCurrentFileSystemProviderPath
    $fullPath = (Resolve-SyncVisionUserFileSystemPath `
            -Path $Path `
            -BasePath $basePath `
            -Context $Context).TrimEnd('\', '/')
    $existingPath = $fullPath
    while (-not (Test-Path -LiteralPath $existingPath)) {
        $parent = Split-Path -Parent $existingPath
        if ([string]::IsNullOrWhiteSpace($parent) -or $parent -eq $existingPath) {
            throw "$Context has no existing path ancestor: $fullPath"
        }
        $existingPath = $parent
    }
    $current = Get-Item -LiteralPath $existingPath -Force
    while ($null -ne $current) {
        if (($current.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
            throw "$Context contains a reparse-point path component: $($current.FullName)"
        }
        $current = $current.Parent
    }
}

function Write-SyncVisionProtectedTextFile {
    param(
        [Parameter(Mandatory = $true)][string]$Path,
        [Parameter(Mandatory = $true)][string]$Text,
        [Parameter(Mandatory = $true)][Security.AccessControl.FileSecurity]$Security,
        [Parameter(Mandatory = $true)][string]$Context
    )

    $basePath = Get-SyncVisionCurrentFileSystemProviderPath
    $fullPath = Resolve-SyncVisionUserFileSystemPath `
        -Path $Path `
        -BasePath $basePath `
        -Context $Context
    $parentPath = Split-Path -Parent $fullPath
    if (-not (Test-Path -LiteralPath $parentPath -PathType Container)) {
        throw "$Context parent directory was not found: $parentPath"
    }
    Assert-SyncVisionExistingPathChainNoReparse -Path $parentPath -Context "$Context parent"
    if (Test-Path -LiteralPath $fullPath) {
        $targetItem = Get-Item -LiteralPath $fullPath -Force
        if ($targetItem.PSIsContainer -or
            ($targetItem.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
            throw "$Context target must be a non-reparse file: $fullPath"
        }
    }

    $temporaryPath = Join-Path $parentPath (".$([IO.Path]::GetFileName($fullPath)).write-" + [Guid]::NewGuid().ToString("N"))
    try {
        $bytes = [Text.UTF8Encoding]::new($false).GetBytes($Text)
        $stream = [IO.File]::Create($temporaryPath, 4096, [IO.FileOptions]::WriteThrough, $Security)
        try {
            $stream.Write($bytes, 0, $bytes.Length)
            $stream.Flush($true)
        }
        finally {
            $stream.Dispose()
        }
        Assert-SyncVisionExistingPathChainNoReparse -Path $parentPath -Context "$Context parent"
        if (Test-Path -LiteralPath $fullPath) {
            $targetItem = Get-Item -LiteralPath $fullPath -Force
            if ($targetItem.PSIsContainer -or
                ($targetItem.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
                throw "$Context target changed to a directory or reparse point: $fullPath"
            }
        }
        Move-Item -LiteralPath $temporaryPath -Destination $fullPath -Force
    }
    finally {
        if (Test-Path -LiteralPath $temporaryPath -PathType Leaf) {
            Assert-SyncVisionExistingPathChainNoReparse -Path $parentPath -Context "$Context cleanup parent"
            Remove-Item -LiteralPath $temporaryPath -Force -ErrorAction Stop
        }
    }
}

function Write-SyncVisionTokenFile {
    param(
        [Parameter(Mandatory = $true)]
        [string]$Path,

        [Parameter(Mandatory = $true)]
        [string]$Token,

        [AllowEmptyString()]
        [string]$ServiceAccount = ""
    )

    Write-SyncVisionProtectedTextFile `
        -Path $Path `
        -Text ($Token + [Environment]::NewLine) `
        -Security (New-SyncVisionTokenFileAcl -ServiceAccount $ServiceAccount) `
        -Context "SyncVision token file"
}

function Set-SyncVisionTransportSecretFileAcl {
    param(
        [Parameter(Mandatory = $true)]
        [string]$Path,

        [AllowEmptyString()]
        [string]$ServiceAccount = ""
    )

    Set-SyncVisionTokenFileAcl -Path $Path -ServiceAccount $ServiceAccount
}

function Write-SyncVisionTransportSecretFile {
    param(
        [Parameter(Mandatory = $true)]
        [string]$Path,

        [Parameter(Mandatory = $true)]
        [string]$Secret,

        [AllowEmptyString()]
        [string]$ServiceAccount = ""
    )

    Write-SyncVisionProtectedTextFile `
        -Path $Path `
        -Text ($Secret + [Environment]::NewLine) `
        -Security (New-SyncVisionTokenFileAcl -ServiceAccount $ServiceAccount) `
        -Context "SyncVision transport secret file"
}

function Resolve-SyncVisionInstallTransportSecret {
    param(
        [ValidateSet("disabled", "optional", "required")]
        [string]$TransportEncryption = "disabled",

        [AllowEmptyString()]
        [string]$TransportSecret = "",

        [AllowEmptyString()]
        [string]$TransportSecretFile = ""
    )

    if ($TransportEncryption -eq "disabled") {
        return ""
    }
    if (-not [string]::IsNullOrWhiteSpace($TransportSecret) -and
        -not [string]::IsNullOrWhiteSpace($TransportSecretFile)) {
        throw "Pass either -TransportSecret or -TransportSecretFile, not both."
    }
    if (-not [string]::IsNullOrWhiteSpace($TransportSecretFile)) {
        if (-not (Test-Path -LiteralPath $TransportSecretFile -PathType Leaf)) {
            throw "TransportSecretFile was not found: $TransportSecretFile"
        }

        $secretFromFile = ([IO.File]::ReadAllText($TransportSecretFile)).Trim()
        if ([string]::IsNullOrWhiteSpace($secretFromFile)) {
            throw "TransportSecretFile must not be empty: $TransportSecretFile"
        }

        return $secretFromFile
    }
    if ([string]::IsNullOrWhiteSpace($TransportSecret)) {
        return New-SyncVisionTransportSecret
    }

    return $TransportSecret
}

function Set-SyncVisionLogDirectoryAcl {
    param(
        [Parameter(Mandatory = $true)]
        [string]$Path,

        [AllowEmptyString()]
        [string]$ServiceAccount = ""
    )

    if (Test-SyncVisionLocalSystemServiceAccount -ServiceAccount $ServiceAccount) {
        return
    }

    $acl = Get-Acl -LiteralPath $Path
    $serviceIdentity = [Security.Principal.NTAccount]::new($ServiceAccount.Trim())
    $acl.AddAccessRule([Security.AccessControl.FileSystemAccessRule]::new(
            $serviceIdentity,
            [Security.AccessControl.FileSystemRights]::Modify,
            [Security.AccessControl.InheritanceFlags]"ContainerInherit, ObjectInherit",
            [Security.AccessControl.PropagationFlags]::None,
            [Security.AccessControl.AccessControlType]::Allow))
    Set-Acl -LiteralPath $Path -AclObject $acl
}

function Get-SyncVisionRequiredVcRuntimeDlls {
    return @(
        "VCRUNTIME140.dll",
        "VCRUNTIME140_1.dll",
        "MSVCP140.dll",
        "MSVCP140_ATOMIC_WAIT.dll"
    )
}

function Get-SyncVisionMissingVcRuntimeDlls {
    param(
        [AllowEmptyString()]
        [string]$WindowsDirectory = $env:WINDIR,

        [AllowEmptyString()]
        [string]$RuntimeDirectory = ""
    )

    if (-not [string]::IsNullOrWhiteSpace($RuntimeDirectory)) {
        $missingLocal = @()
        foreach ($dll in (Get-SyncVisionRequiredVcRuntimeDlls)) {
            if (-not (Test-Path -LiteralPath (Join-Path $RuntimeDirectory $dll) -PathType Leaf)) {
                $missingLocal += $dll
            }
        }
        if ($missingLocal.Count -eq 0) {
            return @()
        }
        if ($missingLocal.Count -ne @(Get-SyncVisionRequiredVcRuntimeDlls).Count) {
            return $missingLocal
        }
    }

    if ([string]::IsNullOrWhiteSpace($WindowsDirectory)) {
        return @(Get-SyncVisionRequiredVcRuntimeDlls)
    }

    $system32 = Join-Path $WindowsDirectory "System32"
    $missing = @()
    foreach ($dll in (Get-SyncVisionRequiredVcRuntimeDlls)) {
        $path = Join-Path $system32 $dll
        if (-not (Test-Path -LiteralPath $path -PathType Leaf)) {
            $missing += $dll
        }
    }

    return $missing
}

function Assert-SyncVisionVcRuntimeAvailable {
    param(
        [AllowEmptyString()]
        [string]$WindowsDirectory = $env:WINDIR,

        [AllowEmptyString()]
        [string]$RuntimeDirectory = ""
    )

    $missing = @(Get-SyncVisionMissingVcRuntimeDlls `
        -WindowsDirectory $WindowsDirectory `
        -RuntimeDirectory $RuntimeDirectory)
    if ($missing.Count -eq 0) {
        return
    }

    if (-not [string]::IsNullOrWhiteSpace($RuntimeDirectory)) {
        $presentLocalCount = @(
            Get-SyncVisionRequiredVcRuntimeDlls |
                Where-Object {
                    Test-Path -LiteralPath (Join-Path $RuntimeDirectory $_) -PathType Leaf
                }
        ).Count
        if ($presentLocalCount -ne 0) {
            throw "The app-local Microsoft Visual C++ x64 runtime set is incomplete under ${RuntimeDirectory}: $($missing -join ', '). Refusing to mix package-local and System32 runtime versions."
        }
    }

    $system32 = if ([string]::IsNullOrWhiteSpace($WindowsDirectory)) {
        "%WINDIR%\System32"
    }
    else {
        Join-Path $WindowsDirectory "System32"
    }
    throw "Microsoft Visual C++ Redistributable x64 is required to run SyncVisionServer.exe. Missing runtime DLL(s) under ${system32}: $($missing -join ', '). Install the latest Microsoft Visual C++ Redistributable x64 and rerun scripts\install-server.ps1."
}

function New-SyncVisionAccessToken {
    $bytes = New-Object byte[] 32
    $rng = [Security.Cryptography.RandomNumberGenerator]::Create()
    try {
        $rng.GetBytes($bytes)
    }
    finally {
        $rng.Dispose()
    }

    return [Convert]::ToBase64String($bytes).TrimEnd("=").Replace("+", "-").Replace("/", "_")
}

function New-SyncVisionTransportSecret {
    return New-SyncVisionAccessToken
}

function Test-SyncVisionLoopbackListen {
    param(
        [Parameter(Mandatory = $true)]
        [string]$Listen
    )

    $separator = $Listen.LastIndexOf(":")
    $hostPart = if ($separator -gt 0) { $Listen.Substring(0, $separator) } else { $Listen }
    return $hostPart -eq "localhost" -or $hostPart -eq "127.0.0.1" -or $hostPart.StartsWith("127.")
}

function Resolve-SyncVisionInstallToken {
    param(
        [AllowEmptyString()]
        [string]$Token,

        [Parameter(Mandatory = $true)]
        [string]$Listen
    )

    if ([string]::IsNullOrWhiteSpace($Token)) {
        return New-SyncVisionAccessToken
    }

    if ($Token -eq "dev-token" -and -not (Test-SyncVisionLoopbackListen -Listen $Listen)) {
        throw "The default dev-token is only allowed for loopback installs. Omit -Token to generate a secure token, or pass a non-default -Token."
    }

    return $Token
}

function Get-SyncVisionEndpointHost {
    param(
        [Parameter(Mandatory = $true)]
        [string]$Endpoint
    )

    $separator = $Endpoint.LastIndexOf(":")
    if ($separator -le 0) {
        return $Endpoint
    }

    return $Endpoint.Substring(0, $separator)
}

function Test-SyncVisionWildcardHost {
    param(
        [Parameter(Mandatory = $true)]
        [string]$HostName
    )

    return $HostName -eq "0.0.0.0" -or $HostName -eq "::" -or $HostName -eq "*" -or [string]::IsNullOrWhiteSpace($HostName)
}

function Get-SyncVisionLocalIPv4Addresses {
    $addresses = New-Object System.Collections.Generic.List[string]
    foreach ($adapter in [System.Net.NetworkInformation.NetworkInterface]::GetAllNetworkInterfaces()) {
        if ($adapter.OperationalStatus -ne [System.Net.NetworkInformation.OperationalStatus]::Up) {
            continue
        }
        if ($adapter.NetworkInterfaceType -eq [System.Net.NetworkInformation.NetworkInterfaceType]::Loopback -or
            $adapter.NetworkInterfaceType -eq [System.Net.NetworkInformation.NetworkInterfaceType]::Tunnel) {
            continue
        }

        foreach ($unicast in $adapter.GetIPProperties().UnicastAddresses) {
            if ($unicast.Address.AddressFamily -eq [System.Net.Sockets.AddressFamily]::InterNetwork) {
                $addresses.Add($unicast.Address.ToString())
            }
        }
    }

    return $addresses
}

function Test-SyncVisionUsableLanIPv4Address {
    param(
        [Parameter(Mandatory = $true)]
        [string]$AddressText
    )

    $address = [System.Net.IPAddress]::None
    if (-not [System.Net.IPAddress]::TryParse($AddressText.Trim(), [ref]$address)) {
        return $false
    }
    if ($address.AddressFamily -ne [System.Net.Sockets.AddressFamily]::InterNetwork) {
        return $false
    }
    if ([System.Net.IPAddress]::IsLoopback($address) -or
        $address.Equals([System.Net.IPAddress]::Any) -or
        $address.Equals([System.Net.IPAddress]::Broadcast) -or
        $address.Equals([System.Net.IPAddress]::None)) {
        return $false
    }

    $bytes = $address.GetAddressBytes()
    return -not ($bytes[0] -eq 169 -and $bytes[1] -eq 254)
}

function Resolve-SyncVisionDefaultAdvertise {
    param(
        [Parameter(Mandatory = $true)]
        [string]$Listen,

        [string[]]$LocalAddresses = @()
    )

    $addresses = @($LocalAddresses)
    if ($addresses.Count -eq 0) {
        $addresses = @(Get-SyncVisionLocalIPv4Addresses)
    }

    foreach ($address in $addresses) {
        if (Test-SyncVisionUsableLanIPv4Address -AddressText $address) {
            $port = Get-SyncVisionEndpointPort -Endpoint $Listen
            return "${address}:$port"
        }
    }

    throw "LAN mode could not find a non-loopback IPv4 address to advertise. Pass -Advertise <reachable-host:port> explicitly."
}

function Resolve-SyncVisionInstallAdvertise {
    param(
        [Parameter(Mandatory = $true)]
        [string]$Listen,

        [AllowEmptyString()]
        [string]$Advertise,

        [Parameter(Mandatory = $true)]
        [bool]$DiscoveryEnabled,

        [switch]$Lan,

        [string[]]$LocalAddresses = @()
    )

    if (-not $DiscoveryEnabled) {
        return $Advertise
    }

    if (-not [string]::IsNullOrWhiteSpace($Advertise)) {
        return $Advertise
    }

    if ($Lan) {
        return Resolve-SyncVisionDefaultAdvertise -Listen $Listen -LocalAddresses $LocalAddresses
    }

    $listenHost = Get-SyncVisionEndpointHost -Endpoint $Listen
    if (Test-SyncVisionWildcardHost -HostName $listenHost) {
        throw "LAN discovery cannot advertise wildcard listen address '$Listen'. Pass -Advertise <reachable-host:port>, or pass -NoDiscovery for explicit public relay use."
    }

    return $Listen
}

function Resolve-SyncVisionInstallDiscoveryEnabled {
    param(
        [Parameter(Mandatory = $true)]
        [string]$Listen,

        [AllowEmptyString()]
        [string]$Advertise,

        [Parameter(Mandatory = $true)]
        [bool]$NoDiscovery,

        [switch]$Lan
    )

    if ($NoDiscovery) {
        return $false
    }

    if ($Lan) {
        return $true
    }

    if (-not [string]::IsNullOrWhiteSpace($Advertise)) {
        return $true
    }

    $listenHost = Get-SyncVisionEndpointHost -Endpoint $Listen
    return -not (Test-SyncVisionWildcardHost -HostName $listenHost)
}

function Assert-SyncVisionUnsafePublicRelayAcknowledged {
    param(
        [Parameter(Mandatory = $true)]
        [string]$Listen,

        [Parameter(Mandatory = $true)]
        [bool]$AllowUnsafePublicRelay
    )

    if (-not (Test-SyncVisionLoopbackListen -Listen $Listen) -and -not $AllowUnsafePublicRelay) {
        throw "Non-loopback raw TCP relay requires -AllowUnsafePublicRelay. Use a trusted network, VPN, or TLS tunnel before exposing SyncVision publicly."
    }
}

function Assert-SyncVisionPublicFirewallRemoteAddressRestricted {
    param(
        [Parameter(Mandatory = $true)]
        [string]$Listen,

        [Parameter(Mandatory = $true)]
        [bool]$ConfigureFirewall,

        [AllowEmptyString()]
        [string]$FirewallRemoteAddress
    )

    if ($ConfigureFirewall -and
        -not (Test-SyncVisionLoopbackListen -Listen $Listen) -and
        [string]::IsNullOrWhiteSpace($FirewallRemoteAddress)) {
        throw "Non-loopback firewall rules require -FirewallRemoteAddress <trusted-client-cidr-or-ip> before SyncVision opens the relay port. Use LocalSubnet for LAN-only installs."
    }
}

function Get-SyncVisionEndpointPort {
    param(
        [Parameter(Mandatory = $true)]
        [string]$Endpoint
    )

    $separator = $Endpoint.LastIndexOf(":")
    if ($separator -le 0 -or $separator -eq $Endpoint.Length - 1) {
        throw "Endpoint must use host:port: $Endpoint"
    }

    $portText = $Endpoint.Substring($separator + 1)
    $port = 0
    if (-not [int]::TryParse($portText, [ref]$port) -or $port -le 0 -or $port -gt 65535) {
        throw "Endpoint has an invalid port: $Endpoint"
    }

    return $port
}

function Get-SyncVisionManagedFirewallIdentity {
    param([Parameter(Mandatory = $true)][string]$ServiceName)

    if ([string]::IsNullOrWhiteSpace($ServiceName)) {
        throw "Managed firewall identity requires a non-empty service name."
    }
    $normalized = $ServiceName.Normalize([Text.NormalizationForm]::FormC).ToUpperInvariant()
    $sha256 = [Security.Cryptography.SHA256]::Create()
    try {
        $hash = ([BitConverter]::ToString(
                $sha256.ComputeHash([Text.UTF8Encoding]::new($false).GetBytes($normalized))
            )).Replace("-", "").ToLowerInvariant()
    }
    finally { $sha256.Dispose() }
    return [pscustomobject]@{
        Key = $hash.Substring(0, 32)
        RelayName = "SyncVision.Managed.$($hash.Substring(0, 32)).Relay"
        DiscoveryName = "SyncVision.Managed.$($hash.Substring(0, 32)).Discovery"
        Group = "SyncVision Managed $($hash.Substring(0, 32))"
    }
}

function New-SyncVisionFirewallRulePlans {
    param(
        [Parameter(Mandatory = $true)]
        [string]$ServiceName,

        [Parameter(Mandatory = $true)]
        [string]$Listen,

        [Parameter(Mandatory = $true)]
        [string]$DiscoveryListen,

        [Parameter(Mandatory = $true)]
        [bool]$DiscoveryEnabled,

        [Parameter(Mandatory = $true)]
        [string]$Program,

        [AllowEmptyString()]
        [string]$RemoteAddress = ""
    )

    $relayPort = Get-SyncVisionEndpointPort -Endpoint $Listen
    $identity = Get-SyncVisionManagedFirewallIdentity -ServiceName $ServiceName
    $rules = New-Object System.Collections.Generic.List[object]
    $rules.Add([pscustomobject]@{
        Name = $identity.RelayName
        Group = $identity.Group
        DisplayName = "SyncVision Relay ($ServiceName) TCP $relayPort"
        Protocol = "TCP"
        LocalPort = $relayPort
        Program = $Program
        RemoteAddress = $RemoteAddress
    })

    if ($DiscoveryEnabled) {
        $discoveryPort = Get-SyncVisionEndpointPort -Endpoint $DiscoveryListen
        $rules.Add([pscustomobject]@{
            Name = $identity.DiscoveryName
            Group = $identity.Group
            DisplayName = "SyncVision Discovery ($ServiceName) UDP $discoveryPort"
            Protocol = "UDP"
            LocalPort = $discoveryPort
            Program = $Program
            RemoteAddress = $RemoteAddress
        })
    }

    return $rules
}

function Format-SyncVisionPowerShellArgument {
    param(
        [AllowNull()]
        [string]$Value
    )

    if ($null -eq $Value) {
        return '""'
    }

    if ($Value.IndexOfAny([char[]]" `t`"()") -ge 0) {
        return '"' + ($Value -replace '"', '\"') + '"'
    }

    return $Value
}

function Format-SyncVisionFirewallRuleCommand {
    param(
        [Parameter(Mandatory = $true)]
        $Rule
    )

    $parts = @(
        "New-NetFirewallRule",
        "-Name",
        (Format-SyncVisionPowerShellArgument -Value $Rule.Name),
        "-Group",
        (Format-SyncVisionPowerShellArgument -Value $Rule.Group),
        "-DisplayName",
        (Format-SyncVisionPowerShellArgument -Value $Rule.DisplayName),
        "-Direction",
        "Inbound",
        "-Action",
        "Allow",
        "-Protocol",
        $Rule.Protocol,
        "-LocalPort",
        [string]$Rule.LocalPort,
        "-Program",
        (Format-SyncVisionPowerShellArgument -Value $Rule.Program)
    )

    if ($Rule.RemoteAddress) {
        $parts += @(
            "-RemoteAddress",
            (Format-SyncVisionPowerShellArgument -Value $Rule.RemoteAddress)
        )
    }

    return $parts -join " "
}

function Format-SyncVisionCommandLine {
    param(
        [Parameter(Mandatory = $true)]
        [string]$Command,

        [Parameter(Mandatory = $true)]
        [string[]]$Arguments
    )

    $parts = @($Command)
    foreach ($argument in $Arguments) {
        $parts += Format-SyncVisionPowerShellArgument -Value $argument
    }

    return $parts -join " "
}

function Invoke-SyncVisionFirewallRulePlans {
    param(
        [Parameter(Mandatory = $true)]
        [object[]]$Rules
    )

    if (-not (Get-Command New-NetFirewallRule -ErrorAction SilentlyContinue)) {
        throw "New-NetFirewallRule is unavailable. Install or enable the Windows NetSecurity module, or omit -ConfigureFirewall and create firewall rules manually."
    }

    foreach ($rule in $Rules) {
        $parameters = @{
            Name = $rule.Name
            Group = $rule.Group
            DisplayName = $rule.DisplayName
            Direction = "Inbound"
            Action = "Allow"
            Protocol = $rule.Protocol
            LocalPort = $rule.LocalPort
            Program = $rule.Program
        }
        if ($rule.RemoteAddress) {
            $parameters.RemoteAddress = $rule.RemoteAddress
        }

        New-NetFirewallRule @parameters | Out-Null
    }
}

function Test-SyncVisionLegacyAnyAddressFirewallRule {
    param(
        [Parameter(Mandatory = $true)]$FirewallRule,
        [Parameter(Mandatory = $true)][string]$ServiceName,
        [Parameter(Mandatory = $true)][object[]]$Rules
    )

    if ($Rules.Count -eq 0 -or
        -not [string]::IsNullOrWhiteSpace([string]$FirewallRule.Group) -or
        [string]$FirewallRule.Direction -ine "Inbound" -or
        [string]$FirewallRule.Action -ine "Allow") {
        return $false
    }

    $displayNamePattern = '^SyncVision (?<Kind>Relay|Discovery) \(' +
        [regex]::Escape($ServiceName) +
        '\) (?<Protocol>TCP|UDP) (?<Port>[0-9]+)$'
    $displayNameMatch = [regex]::Match(
        [string]$FirewallRule.DisplayName,
        $displayNamePattern,
        ([Text.RegularExpressions.RegexOptions]::IgnoreCase -bor
            [Text.RegularExpressions.RegexOptions]::CultureInvariant))
    if (-not $displayNameMatch.Success) {
        return $false
    }

    $kind = $displayNameMatch.Groups["Kind"].Value
    $protocol = $displayNameMatch.Groups["Protocol"].Value
    if (($kind -ieq "Relay" -and $protocol -ine "TCP") -or
        ($kind -ieq "Discovery" -and $protocol -ine "UDP")) {
        return $false
    }

    $expectedPrograms = @($Rules | ForEach-Object { [string]$_.Program } |
            Where-Object { -not [string]::IsNullOrWhiteSpace($_) } |
            Sort-Object -Unique)
    $expectedProgramFileNames = @($expectedPrograms | ForEach-Object {
            [IO.Path]::GetFileName($_)
        } | Sort-Object -Unique)
    $applicationFilters = @(Get-NetFirewallApplicationFilter `
            -AssociatedNetFirewallRule $FirewallRule `
            -ErrorAction Stop)
    $programMatches = $false
    foreach ($applicationFilter in $applicationFilters) {
        foreach ($expectedProgram in $expectedPrograms) {
            if (Test-SyncVisionFirewallFilterValue `
                    -Actual $applicationFilter.Program `
                    -Expected $expectedProgram) {
                $programMatches = $true
                break
            }
        }
        if (-not $programMatches) {
            foreach ($actualProgram in @(ConvertTo-SyncVisionFirewallFilterValues -Value $applicationFilter.Program)) {
                if ($expectedProgramFileNames -icontains [IO.Path]::GetFileName($actualProgram)) {
                    $programMatches = $true
                    break
                }
            }
        }
        if ($programMatches) { break }
    }
    if (-not $programMatches) {
        return $false
    }

    $portFilters = @(Get-NetFirewallPortFilter `
            -AssociatedNetFirewallRule $FirewallRule `
            -ErrorAction Stop)
    $portMatches = @($portFilters | Where-Object {
            (Test-SyncVisionFirewallFilterValue -Actual $_.Protocol -Expected $protocol) -and
            (Test-SyncVisionFirewallFilterValue `
                -Actual $_.LocalPort `
                -Expected $displayNameMatch.Groups["Port"].Value)
        }).Count -ne 0
    if (-not $portMatches) {
        return $false
    }

    $addressFilters = @(Get-NetFirewallAddressFilter `
            -AssociatedNetFirewallRule $FirewallRule `
            -ErrorAction Stop)
    if ($addressFilters.Count -eq 0) {
        return $false
    }
    foreach ($addressFilter in $addressFilters) {
        $remoteAddresses = @(ConvertTo-SyncVisionFirewallFilterValues -Value $addressFilter.RemoteAddress)
        if ($remoteAddresses.Count -ne 0 -and
            @($remoteAddresses | Where-Object {
                    $_ -in @("Any", "*", "0.0.0.0/0", "::/0")
                }).Count -ne $remoteAddresses.Count) {
            return $false
        }
    }

    return $true
}

function Get-SyncVisionManagedFirewallRules {
    param(
        [Parameter(Mandatory = $true)][string]$ServiceName,
        [object[]]$Rules = @()
    )

    $identity = Get-SyncVisionManagedFirewallIdentity -ServiceName $ServiceName
    $ownedNames = @($identity.RelayName, $identity.DiscoveryName)
    return @(Get-NetFirewallRule -ErrorAction Stop | Where-Object {
            ($ownedNames -icontains [string]$_.Name) -or
            (Test-SyncVisionLegacyAnyAddressFirewallRule `
                -FirewallRule $_ `
                -ServiceName $ServiceName `
                -Rules $Rules)
        })
}

function Get-SyncVisionFirewallTransactionSnapshot {
    param(
        [Parameter(Mandatory = $true)][object[]]$Rules,
        [AllowEmptyString()][string]$ServiceName = ""
    )

    Assert-SyncVisionFirewallTransactionCapabilities
    if ([string]::IsNullOrWhiteSpace($ServiceName)) {
        $firstDisplayName = [string]$Rules[0].DisplayName
        if ($firstDisplayName -notmatch '^SyncVision (?:Relay|Discovery) \((.+)\) (?:TCP|UDP) [0-9]+$') {
            throw "Firewall transaction could not derive the managed service name from its rule plans."
        }
        $ServiceName = $Matches[1]
    }
    $snapshots = New-Object "System.Collections.Generic.List[object]"
    $seenRuleNames = New-Object "System.Collections.Generic.HashSet[string]" ([StringComparer]::OrdinalIgnoreCase)
    foreach ($rule in @(Get-SyncVisionManagedFirewallRules -ServiceName $ServiceName -Rules $Rules)) {
            if (-not $seenRuleNames.Add([string]$rule.Name)) { continue }
            $portFilters = @(Get-NetFirewallPortFilter -AssociatedNetFirewallRule $rule -ErrorAction Stop)
            $addressFilters = @(Get-NetFirewallAddressFilter -AssociatedNetFirewallRule $rule -ErrorAction Stop)
            $applicationFilters = @(Get-NetFirewallApplicationFilter -AssociatedNetFirewallRule $rule -ErrorAction Stop)
            $serviceFilters = @(Get-NetFirewallServiceFilter -AssociatedNetFirewallRule $rule -ErrorAction Stop)
            $interfaceFilters = @(Get-NetFirewallInterfaceFilter -AssociatedNetFirewallRule $rule -ErrorAction Stop)
            $interfaceTypeFilters = @(Get-NetFirewallInterfaceTypeFilter -AssociatedNetFirewallRule $rule -ErrorAction Stop)
            $securityFilters = @(Get-NetFirewallSecurityFilter -AssociatedNetFirewallRule $rule -ErrorAction Stop)
            foreach ($filterSet in @(
                    [pscustomobject]@{ Name = "port"; Values = $portFilters },
                    [pscustomobject]@{ Name = "address"; Values = $addressFilters },
                    [pscustomobject]@{ Name = "application"; Values = $applicationFilters },
                    [pscustomobject]@{ Name = "service"; Values = $serviceFilters },
                    [pscustomobject]@{ Name = "interface"; Values = $interfaceFilters },
                    [pscustomobject]@{ Name = "interface type"; Values = $interfaceTypeFilters },
                    [pscustomobject]@{ Name = "security"; Values = $securityFilters })) {
                if ($filterSet.Values.Count -ne 1) {
                    throw "Firewall transaction cannot snapshot rule '$($rule.Name)': expected exactly one $($filterSet.Name) filter, found $($filterSet.Values.Count)."
                }
            }
            $port = $portFilters[0]
            $address = $addressFilters[0]
            $application = $applicationFilters[0]
            $service = $serviceFilters[0]
            $interface = $interfaceFilters[0]
            $interfaceType = $interfaceTypeFilters[0]
            $security = $securityFilters[0]
            $snapshots.Add([pscustomobject]@{
                    Name = [string]$rule.Name
                    DisplayName = [string]$rule.DisplayName
                    Description = [string]$rule.Description
                    Group = [string]$rule.Group
                    Enabled = [string]$rule.Enabled
                    Profile = [string]$rule.Profile
                    Platform = @($rule.Platform | ForEach-Object { [string]$_ })
                    Direction = [string]$rule.Direction
                    Action = [string]$rule.Action
                    EdgeTraversalPolicy = [string]$rule.EdgeTraversalPolicy
                    LooseSourceMapping = [bool]$rule.LooseSourceMapping
                    LocalOnlyMapping = [bool]$rule.LocalOnlyMapping
                    Owner = [string]$rule.Owner
                    PolicyAppId = [string]$rule.PolicyAppId
                    RemoteDynamicKeywordAddresses = @($rule.RemoteDynamicKeywordAddresses | ForEach-Object { [string]$_ })
                    Protocol = [string]$port.Protocol
                    LocalPort = @($port.LocalPort | ForEach-Object { [string]$_ })
                    RemotePort = @($port.RemotePort | ForEach-Object { [string]$_ })
                    IcmpType = @($port.IcmpType | ForEach-Object { [string]$_ })
                    DynamicTarget = [string]$port.DynamicTarget
                    LocalAddress = @($address.LocalAddress | ForEach-Object { [string]$_ })
                    RemoteAddress = @($address.RemoteAddress | ForEach-Object { [string]$_ })
                    Program = [string]$application.Program
                    Package = [string]$application.Package
                    Service = [string]$service.Service
                    InterfaceAlias = @($interface.InterfaceAlias | ForEach-Object { [string]$_ })
                    InterfaceType = [string]$interfaceType.InterfaceType
                    LocalUser = [string]$security.LocalUser
                    RemoteUser = [string]$security.RemoteUser
                    RemoteMachine = [string]$security.RemoteMachine
                    Authentication = [string]$security.Authentication
                    Encryption = [string]$security.Encryption
                    OverrideBlockRules = [bool]$security.OverrideBlockRules
                    PolicyStoreSource = [string]$rule.PolicyStoreSource
                    PolicyStoreSourceType = [string]$rule.PolicyStoreSourceType
                })
    }
    $snapshot = [pscustomobject]@{
        ServiceName = $ServiceName
        Plans = $Rules
        Rules = @($snapshots.ToArray() | Sort-Object -Property Name)
    }
    Assert-SyncVisionFirewallTransactionCapabilities -Snapshot $snapshot
    return $snapshot
}

function Remove-SyncVisionManagedFirewallRules {
    param(
        [Parameter(Mandatory = $true)][object[]]$Rules,
        [AllowEmptyString()][string]$ServiceName = ""
    )

    if ([string]::IsNullOrWhiteSpace($ServiceName)) {
        $firstDisplayName = [string]$Rules[0].DisplayName
        if ($firstDisplayName -notmatch '^SyncVision (?:Relay|Discovery) \((.+)\) (?:TCP|UDP) [0-9]+$') {
            throw "Firewall cleanup could not derive the managed service name from its rule plans."
        }
        $ServiceName = $Matches[1]
    }
    Get-SyncVisionManagedFirewallRules -ServiceName $ServiceName -Rules $Rules |
        Remove-NetFirewallRule -ErrorAction Stop
}

function Restore-SyncVisionFirewallTransactionSnapshot {
    param([Parameter(Mandatory = $true)][object]$Snapshot)

    Assert-SyncVisionFirewallTransactionCapabilities -Snapshot $Snapshot
    Remove-SyncVisionManagedFirewallRules -Rules $Snapshot.Plans -ServiceName ([string]$Snapshot.ServiceName)
    foreach ($rule in $Snapshot.Rules) {
        $parameters = @{
            Name = $rule.Name
            DisplayName = $rule.DisplayName
            Direction = $rule.Direction
            Action = $rule.Action
            Enabled = $rule.Enabled
            Profile = $rule.Profile
            Platform = $rule.Platform
            LooseSourceMapping = $rule.LooseSourceMapping
            LocalOnlyMapping = $rule.LocalOnlyMapping
            Protocol = $rule.Protocol
            LocalPort = $rule.LocalPort
            RemotePort = $rule.RemotePort
            IcmpType = $rule.IcmpType
            DynamicTarget = $rule.DynamicTarget
            LocalAddress = $rule.LocalAddress
            RemoteAddress = $rule.RemoteAddress
            Program = $rule.Program
            Package = $rule.Package
            Service = $rule.Service
            InterfaceAlias = $rule.InterfaceAlias
            InterfaceType = $rule.InterfaceType
            LocalUser = $rule.LocalUser
            RemoteUser = $rule.RemoteUser
            RemoteMachine = $rule.RemoteMachine
            Authentication = $rule.Authentication
            Encryption = $rule.Encryption
            OverrideBlockRules = $rule.OverrideBlockRules
            RemoteDynamicKeywordAddresses = $rule.RemoteDynamicKeywordAddresses
        }
        foreach ($name in @("Description", "Group", "EdgeTraversalPolicy", "Owner", "PolicyAppId")) {
            if (-not [string]::IsNullOrWhiteSpace([string]$rule.$name)) {
                $parameters[$name] = $rule.$name
            }
        }
        foreach ($name in @("Platform", "LocalPort", "RemotePort", "IcmpType", "LocalAddress", "RemoteAddress", "InterfaceAlias", "RemoteDynamicKeywordAddresses")) {
            if (@($rule.$name).Count -eq 0) { [void]$parameters.Remove($name) }
        }
        foreach ($name in @("Program", "Package", "Service", "LocalUser", "RemoteUser", "RemoteMachine", "Authentication", "Encryption", "InterfaceType", "DynamicTarget")) {
            if ([string]::IsNullOrWhiteSpace([string]$rule.$name)) { [void]$parameters.Remove($name) }
        }
        New-NetFirewallRule @parameters | Out-Null
    }
    Assert-SyncVisionFirewallTransactionSnapshotRestored -Snapshot $Snapshot
}

function Set-SyncVisionFirewallRulePlansTransactional {
    param(
        [Parameter(Mandatory = $true)][object[]]$Rules,
        [AllowNull()][object]$Snapshot
    )

    Assert-SyncVisionFirewallTransactionCapabilities -Snapshot $Snapshot
    if ($null -ne $Snapshot) {
        Assert-SyncVisionFirewallTransactionSnapshotRestored -Snapshot $Snapshot -Context "Pre-mutation firewall rule set"
    }
    $serviceName = if ($null -ne $Snapshot) { [string]$Snapshot.ServiceName } else { "" }
    Remove-SyncVisionManagedFirewallRules -Rules $Rules -ServiceName $serviceName
    Invoke-SyncVisionFirewallRulePlans -Rules $Rules
}

function Assert-SyncVisionFirewallTransactionCapabilities {
    param([AllowNull()][object]$Snapshot)

    $requiredCommands = @(
        "Get-NetFirewallRule",
        "Get-NetFirewallPortFilter",
        "Get-NetFirewallAddressFilter",
        "Get-NetFirewallApplicationFilter",
        "Get-NetFirewallServiceFilter",
        "Get-NetFirewallInterfaceFilter",
        "Get-NetFirewallInterfaceTypeFilter",
        "Get-NetFirewallSecurityFilter",
        "New-NetFirewallRule",
        "Remove-NetFirewallRule")
    foreach ($commandName in $requiredCommands) {
        if ($null -eq (Get-Command $commandName -ErrorAction SilentlyContinue)) {
            throw "Firewall transaction cannot preserve and restore complete rules because $commandName is unavailable."
        }
    }

    $requiredCommandParameters = [ordered]@{
        "Get-NetFirewallRule" = @("DisplayName")
        "Get-NetFirewallPortFilter" = @("AssociatedNetFirewallRule")
        "Get-NetFirewallAddressFilter" = @("AssociatedNetFirewallRule")
        "Get-NetFirewallApplicationFilter" = @("AssociatedNetFirewallRule")
        "Get-NetFirewallServiceFilter" = @("AssociatedNetFirewallRule")
        "Get-NetFirewallInterfaceFilter" = @("AssociatedNetFirewallRule")
        "Get-NetFirewallInterfaceTypeFilter" = @("AssociatedNetFirewallRule")
        "Get-NetFirewallSecurityFilter" = @("AssociatedNetFirewallRule")
        "Remove-NetFirewallRule" = @("InputObject")
    }
    foreach ($commandName in $requiredCommandParameters.Keys) {
        $command = Get-Command $commandName -ErrorAction Stop
        foreach ($parameterName in $requiredCommandParameters[$commandName]) {
            if (-not $command.Parameters.ContainsKey($parameterName)) {
                throw "Firewall transaction cannot preserve and restore complete rules because $commandName lacks -$parameterName."
            }
        }
    }

    $newRuleCommand = Get-Command New-NetFirewallRule -ErrorAction Stop
    $requiredParameters = @(
        "Name", "DisplayName", "Description", "Group", "Enabled", "Profile", "Platform", "Direction", "Action",
        "EdgeTraversalPolicy", "LooseSourceMapping", "LocalOnlyMapping", "Owner", "PolicyAppId",
        "RemoteDynamicKeywordAddresses", "Protocol", "LocalPort", "RemotePort", "IcmpType", "DynamicTarget",
        "LocalAddress", "RemoteAddress", "Program", "Package", "Service", "InterfaceAlias", "InterfaceType",
        "LocalUser", "RemoteUser", "RemoteMachine", "Authentication", "Encryption", "OverrideBlockRules")
    foreach ($parameterName in $requiredParameters) {
        if (-not $newRuleCommand.Parameters.ContainsKey($parameterName)) {
            throw "Firewall transaction cannot preserve and restore complete rules because New-NetFirewallRule lacks -$parameterName."
        }
    }

    if ($null -eq $Snapshot) { return }
    $seenNames = New-Object "System.Collections.Generic.HashSet[string]" ([StringComparer]::OrdinalIgnoreCase)
    foreach ($rule in @($Snapshot.Rules)) {
        if ([string]::IsNullOrWhiteSpace([string]$rule.Name) -or -not $seenNames.Add([string]$rule.Name)) {
            throw "Firewall transaction snapshot contains a missing or duplicate rule Name and cannot be restored exactly."
        }
        if ([string]$rule.PolicyStoreSourceType -cne "Local" -or [string]$rule.PolicyStoreSource -cne "PersistentStore") {
            throw "Firewall transaction refuses to mutate non-local or non-persistent rule '$($rule.Name)' because its policy-store ownership cannot be recreated exactly."
        }
    }
}

function ConvertTo-SyncVisionCanonicalFirewallTransactionSnapshot {
    param([Parameter(Mandatory = $true)][object]$Snapshot)

    $arrayFields = @(
        "Platform", "RemoteDynamicKeywordAddresses", "LocalPort", "RemotePort", "IcmpType",
        "LocalAddress", "RemoteAddress", "InterfaceAlias")
    $scalarFields = @(
        "Name", "DisplayName", "Description", "Group", "Enabled", "Profile", "Direction", "Action",
        "EdgeTraversalPolicy", "LooseSourceMapping", "LocalOnlyMapping", "Owner", "PolicyAppId", "Protocol",
        "DynamicTarget", "Program", "Package", "Service", "InterfaceType", "LocalUser", "RemoteUser",
        "RemoteMachine", "Authentication", "Encryption", "OverrideBlockRules", "PolicyStoreSource",
        "PolicyStoreSourceType")
    $rules = foreach ($rule in @($Snapshot.Rules | Sort-Object -Property Name)) {
        $model = [ordered]@{}
        foreach ($name in $scalarFields) { $model[$name] = $rule.$name }
        foreach ($name in $arrayFields) {
            $model[$name] = @($rule.$name | ForEach-Object { [string]$_ } | Sort-Object)
        }
        [pscustomobject]$model
    }
    return @($rules) | ConvertTo-Json -Compress -Depth 20
}

function Assert-SyncVisionFirewallTransactionSnapshotRestored {
    param(
        [Parameter(Mandatory = $true)][object]$Snapshot,
        [string]$Context = "Restored firewall rule set"
    )

    $actual = Get-SyncVisionFirewallTransactionSnapshot `
        -Rules $Snapshot.Plans `
        -ServiceName ([string]$Snapshot.ServiceName)
    $expectedModel = ConvertTo-SyncVisionCanonicalFirewallTransactionSnapshot -Snapshot $Snapshot
    $actualModel = ConvertTo-SyncVisionCanonicalFirewallTransactionSnapshot -Snapshot $actual
    if ($actualModel -cne $expectedModel) {
        throw "$Context does not match the complete rule and advanced-filter snapshot."
    }
}

function ConvertTo-SyncVisionFirewallFilterValues {
    param(
        [AllowNull()]
        $Value
    )

    if ($null -eq $Value) {
        return @()
    }

    $values = @()
    foreach ($item in @($Value)) {
        if ($null -eq $item) {
            continue
        }

        foreach ($part in ([string]$item -split ",")) {
            $trimmed = $part.Trim()
            if (-not [string]::IsNullOrWhiteSpace($trimmed)) {
                $values += $trimmed
            }
        }
    }

    return $values
}

function Test-SyncVisionFirewallFilterValue {
    param(
        [AllowNull()]
        $Actual,

        [AllowEmptyString()]
        [string]$Expected,

        [switch]$AllowAnyWhenExpectedEmpty
    )

    $actualValues = @(ConvertTo-SyncVisionFirewallFilterValues -Value $Actual)
    if ([string]::IsNullOrWhiteSpace($Expected)) {
        if (-not $AllowAnyWhenExpectedEmpty) {
            return $actualValues.Count -eq 0
        }

        return $actualValues.Count -eq 0 -or
            @($actualValues | Where-Object { $_ -eq "Any" -or $_ -eq "*" }).Count -gt 0
    }

    foreach ($actualValue in $actualValues) {
        if ($actualValue -eq $Expected) {
            return $true
        }
    }

    return $false
}

function Test-SyncVisionFirewallRuleMatchesPlan {
    param(
        [Parameter(Mandatory = $true)]
        $ExpectedRule,

        [Parameter(Mandatory = $true)]
        $FirewallRule
    )

    if (($null -ne $ExpectedRule.PSObject.Properties["Name"] -and
            [string]$FirewallRule.Name -cne [string]$ExpectedRule.Name) -or
        ($null -ne $ExpectedRule.PSObject.Properties["Group"] -and
            [string]$FirewallRule.Group -cne [string]$ExpectedRule.Group) -or
        $FirewallRule.Direction -ne "Inbound" -or
        $FirewallRule.Action -ne "Allow" -or
        $FirewallRule.Enabled -ne "True") {
        return $false
    }

    $portFilters = @(Get-NetFirewallPortFilter -AssociatedNetFirewallRule $FirewallRule)
    if ($portFilters.Count -eq 0) {
        return $false
    }

    $addressFilters = @(Get-NetFirewallAddressFilter -AssociatedNetFirewallRule $FirewallRule)
    if ($addressFilters.Count -eq 0) {
        return $false
    }

    $applicationFilters = @(Get-NetFirewallApplicationFilter -AssociatedNetFirewallRule $FirewallRule)
    if ($applicationFilters.Count -eq 0) {
        return $false
    }

    $matchingApplicationFilters = @($applicationFilters | Where-Object {
            Test-SyncVisionFirewallFilterValue -Actual $_.Program -Expected $ExpectedRule.Program
        })
    if ($matchingApplicationFilters.Count -eq 0) {
        return $false
    }

    $expectedProtocol = [string]$ExpectedRule.Protocol
    $expectedLocalPort = [string]$ExpectedRule.LocalPort
    foreach ($portFilter in $portFilters) {
        if (-not (Test-SyncVisionFirewallFilterValue -Actual $portFilter.Protocol -Expected $expectedProtocol)) {
            continue
        }
        if (-not (Test-SyncVisionFirewallFilterValue -Actual $portFilter.LocalPort -Expected $expectedLocalPort)) {
            continue
        }

        foreach ($addressFilter in $addressFilters) {
            if (Test-SyncVisionFirewallFilterValue `
                    -Actual $addressFilter.RemoteAddress `
                    -Expected $ExpectedRule.RemoteAddress `
                    -AllowAnyWhenExpectedEmpty) {
                return $true
            }
        }
    }

    return $false
}

function Invoke-SyncVisionScCommand {
    param([Parameter(Mandatory = $true)][string[]]$Arguments, [Parameter(Mandatory = $true)][string]$Context)

    $sc = Resolve-SyncVisionTrustedWindowsTool -RelativePath "System32\sc.exe" -Context "Windows Service Controller"
    $sc = Assert-SyncVisionTrustedWindowsToolIdentity -Identity $sc -Context "Windows Service Controller"
    & $sc.Path @Arguments
    if ($LASTEXITCODE -ne 0) {
        throw "$Context failed with sc.exe exit code $LASTEXITCODE."
    }
}

function Copy-SyncVisionRegistryValueData {
    param(
        [AllowNull()]$Value,
        [Parameter(Mandatory = $true)][Microsoft.Win32.RegistryValueKind]$Kind
    )

    if ($null -eq $Value) { return $null }
    switch ($Kind) {
        ([Microsoft.Win32.RegistryValueKind]::Binary) { return ,([byte[]]([byte[]]$Value).Clone()) }
        ([Microsoft.Win32.RegistryValueKind]::None) { return ,([byte[]]([byte[]]$Value).Clone()) }
        ([Microsoft.Win32.RegistryValueKind]::MultiString) { return ,([string[]]([string[]]$Value).Clone()) }
        ([Microsoft.Win32.RegistryValueKind]::DWord) { return [int]$Value }
        ([Microsoft.Win32.RegistryValueKind]::QWord) { return [long]$Value }
        default { return [string]$Value }
    }
}

function Get-SyncVisionRegistryTreeSnapshot {
    param([Parameter(Mandatory = $true)][Microsoft.Win32.RegistryKey]$Key)

    $sections = [Security.AccessControl.AccessControlSections]::Owner -bor
        [Security.AccessControl.AccessControlSections]::Group -bor
        [Security.AccessControl.AccessControlSections]::Access
    $values = New-Object "System.Collections.Generic.List[object]"
    $valueNames = [string[]]$Key.GetValueNames()
    [Array]::Sort($valueNames, [StringComparer]::Ordinal)
    foreach ($name in $valueNames) {
        $kind = $Key.GetValueKind($name)
        $value = $Key.GetValue($name, $null, [Microsoft.Win32.RegistryValueOptions]::DoNotExpandEnvironmentNames)
        $values.Add([pscustomobject]@{
                Name = $name
                Kind = [string]$kind
                Value = Copy-SyncVisionRegistryValueData -Value $value -Kind $kind
            })
    }

    $subKeys = New-Object "System.Collections.Generic.List[object]"
    $subKeyNames = [string[]]$Key.GetSubKeyNames()
    [Array]::Sort($subKeyNames, [StringComparer]::Ordinal)
    foreach ($name in $subKeyNames) {
        $subKey = $Key.OpenSubKey($name, $false)
        if ($null -eq $subKey) { throw "Service registry snapshot could not open subkey '$($Key.Name)\$name'." }
        try {
            $subKeys.Add([pscustomobject]@{
                    Name = $name
                    Tree = Get-SyncVisionRegistryTreeSnapshot -Key $subKey
                })
        }
        finally { $subKey.Dispose() }
    }

    $security = $Key.GetAccessControl($sections)
    return [pscustomobject]@{
        SecurityDescriptor = $security.GetSecurityDescriptorSddlForm($sections)
        Values = $values.ToArray()
        SubKeys = $subKeys.ToArray()
    }
}

function ConvertTo-SyncVisionCanonicalRegistrySecurityModel {
    param([Parameter(Mandatory = $true)][string]$SecurityDescriptor)

    $raw = [Security.AccessControl.RawSecurityDescriptor]::new($SecurityDescriptor)
    $daclPresent = ($raw.ControlFlags -band [Security.AccessControl.ControlFlags]::DiscretionaryAclPresent) -ne 0
    $daclProtected = ($raw.ControlFlags -band [Security.AccessControl.ControlFlags]::DiscretionaryAclProtected) -ne 0
    $aces = New-Object "System.Collections.Generic.List[string]"
    if ($null -ne $raw.DiscretionaryAcl) {
        foreach ($ace in $raw.DiscretionaryAcl) {
            $bytes = New-Object byte[] $ace.BinaryLength
            $ace.GetBinaryForm($bytes, 0)
            $aces.Add([Convert]::ToBase64String($bytes))
        }
    }

    return [pscustomobject]([ordered]@{
            owner = if ($null -eq $raw.Owner) { $null } else { $raw.Owner.Value }
            group = if ($null -eq $raw.Group) { $null } else { $raw.Group.Value }
            dacl_present = $daclPresent
            dacl_protected = $daclProtected
            dacl_revision = if ($null -eq $raw.DiscretionaryAcl) { $null } else { [int]$raw.DiscretionaryAcl.Revision }
            dacl_aces = $aces.ToArray()
        })
}

function ConvertTo-SyncVisionCanonicalRegistryTreeModel {
    param([Parameter(Mandatory = $true)][object]$Snapshot)

    $values = foreach ($value in @($Snapshot.Values)) {
        $kind = [Microsoft.Win32.RegistryValueKind][Enum]::Parse(
            [Microsoft.Win32.RegistryValueKind],
            [string]$value.Kind,
            $false)
        $encodedValue = switch ($kind) {
            ([Microsoft.Win32.RegistryValueKind]::Binary) { [Convert]::ToBase64String([byte[]]$value.Value); break }
            ([Microsoft.Win32.RegistryValueKind]::None) { [Convert]::ToBase64String([byte[]]$value.Value); break }
            ([Microsoft.Win32.RegistryValueKind]::MultiString) { @([string[]]$value.Value); break }
            ([Microsoft.Win32.RegistryValueKind]::DWord) { [int]$value.Value; break }
            ([Microsoft.Win32.RegistryValueKind]::QWord) { [long]$value.Value; break }
            default { [string]$value.Value }
        }
        [pscustomobject]([ordered]@{
                name = [string]$value.Name
                kind = [string]$value.Kind
                value = $encodedValue
            })
    }
    $subKeys = foreach ($subKey in @($Snapshot.SubKeys)) {
        [pscustomobject]([ordered]@{
                name = [string]$subKey.Name
                tree = ConvertTo-SyncVisionCanonicalRegistryTreeModel -Snapshot $subKey.Tree
            })
    }
    return [pscustomobject]([ordered]@{
            security = ConvertTo-SyncVisionCanonicalRegistrySecurityModel -SecurityDescriptor ([string]$Snapshot.SecurityDescriptor)
            values = @($values)
            subkeys = @($subKeys)
        })
}

function Assert-SyncVisionRegistryTreeSnapshot {
    param(
        [Parameter(Mandatory = $true)][Microsoft.Win32.RegistryKey]$Key,
        [Parameter(Mandatory = $true)][object]$Snapshot,
        [Parameter(Mandatory = $true)][string]$Context
    )

    $expected = ConvertTo-SyncVisionCanonicalRegistryTreeModel -Snapshot $Snapshot | ConvertTo-Json -Compress -Depth 100
    $actualSnapshot = Get-SyncVisionRegistryTreeSnapshot -Key $Key
    $actual = ConvertTo-SyncVisionCanonicalRegistryTreeModel -Snapshot $actualSnapshot | ConvertTo-Json -Compress -Depth 100
    if ($actual -cne $expected) {
        throw "$Context does not match the complete recursive registry value, subkey, and ACL snapshot."
    }
    return $actualSnapshot
}

function Restore-SyncVisionRegistryTreeSnapshot {
    param(
        [Parameter(Mandatory = $true)][Microsoft.Win32.RegistryKey]$Key,
        [Parameter(Mandatory = $true)][object]$Snapshot
    )

    $expectedValues = New-Object "System.Collections.Generic.HashSet[string]" ([StringComparer]::Ordinal)
    foreach ($value in @($Snapshot.Values)) { [void]$expectedValues.Add([string]$value.Name) }
    foreach ($name in $Key.GetValueNames()) {
        if (-not $expectedValues.Contains([string]$name)) { $Key.DeleteValue($name, $false) }
    }
    foreach ($value in @($Snapshot.Values)) {
        $kind = [Microsoft.Win32.RegistryValueKind][Enum]::Parse(
            [Microsoft.Win32.RegistryValueKind],
            [string]$value.Kind,
            $false)
        $data = Copy-SyncVisionRegistryValueData -Value $value.Value -Kind $kind
        $Key.SetValue([string]$value.Name, $data, $kind)
    }

    $expectedSubKeys = New-Object "System.Collections.Generic.HashSet[string]" ([StringComparer]::Ordinal)
    foreach ($subKey in @($Snapshot.SubKeys)) { [void]$expectedSubKeys.Add([string]$subKey.Name) }
    foreach ($name in $Key.GetSubKeyNames()) {
        if (-not $expectedSubKeys.Contains([string]$name)) { $Key.DeleteSubKeyTree($name, $false) }
    }
    foreach ($subKeySnapshot in @($Snapshot.SubKeys)) {
        $subKey = $Key.CreateSubKey(
            [string]$subKeySnapshot.Name,
            [Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree)
        if ($null -eq $subKey) { throw "Service registry restore could not create subkey '$($Key.Name)\$($subKeySnapshot.Name)'." }
        try { Restore-SyncVisionRegistryTreeSnapshot -Key $subKey -Snapshot $subKeySnapshot.Tree }
        finally { $subKey.Dispose() }
    }

    $sections = [Security.AccessControl.AccessControlSections]::Owner -bor
        [Security.AccessControl.AccessControlSections]::Group -bor
        [Security.AccessControl.AccessControlSections]::Access
    $security = [Security.AccessControl.RegistrySecurity]::new()
    $security.SetSecurityDescriptorSddlForm([string]$Snapshot.SecurityDescriptor, $sections)
    $Key.SetAccessControl($security)
}

function Assert-SyncVisionRegistryTreeFullControl {
    param([Parameter(Mandatory = $true)][Microsoft.Win32.RegistryKey]$Key)

    foreach ($name in $Key.GetSubKeyNames()) {
        $subKey = $Key.OpenSubKey(
            $name,
            [Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree,
            [Security.AccessControl.RegistryRights]::FullControl)
        if ($null -eq $subKey) { throw "Service registry transaction cannot obtain full control for '$($Key.Name)\$name'." }
        try { Assert-SyncVisionRegistryTreeFullControl -Key $subKey }
        finally { $subKey.Dispose() }
    }
}

function Assert-SyncVisionServiceRegistryTransactionCapabilities {
    param(
        [Parameter(Mandatory = $true)][object]$Snapshot,
        [switch]$RequireSnapshotMatch
    )

    $servicesPath = "SYSTEM\CurrentControlSet\Services"
    $servicesKey = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey(
        $servicesPath,
        [Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree,
        [Security.AccessControl.RegistryRights]::FullControl)
    if ($null -eq $servicesKey) {
        throw "Service registry transaction cannot obtain FullControl on HKLM\$servicesPath before mutation."
    }
    try {
        if (-not $Snapshot.Exists) { return }
        $serviceKey = $servicesKey.OpenSubKey(
            [string]$Snapshot.ServiceName,
            [Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree,
            [Security.AccessControl.RegistryRights]::FullControl)
        if ($null -eq $serviceKey) {
            if ($RequireSnapshotMatch) {
                throw "Service registry transaction cannot obtain FullControl on the existing service subtree before mutation."
            }
            return
        }
        try {
            Assert-SyncVisionRegistryTreeFullControl -Key $serviceKey
            if ($RequireSnapshotMatch) {
                Assert-SyncVisionRegistryTreeSnapshot -Key $serviceKey -Snapshot $Snapshot.RegistryTree -Context "Pre-mutation service registry subtree" | Out-Null
            }
        }
        finally { $serviceKey.Dispose() }
    }
    finally { $servicesKey.Dispose() }
}

function Get-SyncVisionServiceRegistryValues {
    param([Parameter(Mandatory = $true)][string]$ServiceName)

    $path = "SYSTEM\CurrentControlSet\Services\$ServiceName"
    $key = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey($path, $false)
    if ($null -eq $key) { return @() }
    try {
        return @(
            foreach ($name in $key.GetValueNames()) {
                [pscustomobject]@{
                    Name = $name
                    Kind = [string]$key.GetValueKind($name)
                    Value = $key.GetValue($name, $null, [Microsoft.Win32.RegistryValueOptions]::DoNotExpandEnvironmentNames)
                }
            })
    }
    finally { $key.Dispose() }
}

function Get-SyncVisionServiceTransactionSnapshot {
    param([Parameter(Mandatory = $true)][string]$ServiceName)

    $service = Get-Service -Name $ServiceName -ErrorAction SilentlyContinue
    if ($null -eq $service) {
        return [pscustomobject]@{ Exists = $false; ServiceName = $ServiceName; Running = $false; Cim = $null; RegistryValues = @(); RegistryTree = $null; Sddl = "" }
    }
    $cim = Get-CimInstance Win32_Service -Filter "Name='$($ServiceName.Replace("'", "''"))'" -ErrorAction Stop
    $sddlOutput = @(Invoke-SyncVisionScCommand -Arguments @("sdshow", $ServiceName) -Context "Service security snapshot")
    $sddl = [string](@($sddlOutput | Where-Object { $_ -match '^[OGDS]:' } | Select-Object -Last 1)[0])
    if ([string]::IsNullOrWhiteSpace($sddl)) { throw "Service security snapshot did not return SDDL for '$ServiceName'." }
    $registryPath = "SYSTEM\CurrentControlSet\Services\$ServiceName"
    $registryKey = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey($registryPath, $false)
    if ($null -eq $registryKey) { throw "Service registry snapshot could not open HKLM\$registryPath." }
    try { $registryTree = Get-SyncVisionRegistryTreeSnapshot -Key $registryKey }
    finally { $registryKey.Dispose() }
    return [pscustomobject]@{
        Exists = $true
        ServiceName = $ServiceName
        Running = $service.Status -ne [System.ServiceProcess.ServiceControllerStatus]::Stopped
        Cim = [pscustomobject]@{
            PathName = [string]$cim.PathName
            StartName = [string]$cim.StartName
            StartMode = [string]$cim.StartMode
            DisplayName = [string]$cim.DisplayName
            Description = [string]$cim.Description
        }
        RegistryValues = @(Get-SyncVisionServiceRegistryValues -ServiceName $ServiceName)
        RegistryTree = $registryTree
        Sddl = $sddl.Trim()
    }
}

function Assert-SyncVisionServiceRollbackCredentialSafe {
    param([Parameter(Mandatory = $true)][object]$Snapshot)

    if (-not $Snapshot.Exists) { return }
    if ($null -eq $Snapshot.Cim -or [string]::IsNullOrWhiteSpace([string]$Snapshot.Cim.StartName)) {
        throw "Service rollback credential preflight could not determine the existing service account."
    }

    $startName = ([string]$Snapshot.Cim.StartName).Trim()
    $passwordlessAccounts = @(
        "LocalSystem",
        ".\LocalSystem",
        "SYSTEM",
        "NT AUTHORITY\SYSTEM",
        "NT AUTHORITY\LocalService",
        "NT AUTHORITY\NetworkService")
    if ($passwordlessAccounts -notcontains $startName) {
        throw "Service rollback credential preflight rejected '$startName' for '$($Snapshot.ServiceName)': Windows cannot export the existing service password, so destructive service recreation cannot be rolled back safely. Reconfigure the service to a built-in passwordless account before upgrading."
    }
}

function Wait-SyncVisionServiceAbsent {
    param([Parameter(Mandatory = $true)][string]$ServiceName, [int]$TimeoutSeconds = 30)

    $deadline = [DateTime]::UtcNow.AddSeconds($TimeoutSeconds)
    while ($null -ne (Get-Service -Name $ServiceName -ErrorAction SilentlyContinue) -and [DateTime]::UtcNow -lt $deadline) {
        Start-Sleep -Milliseconds 200
    }
    if ($null -ne (Get-Service -Name $ServiceName -ErrorAction SilentlyContinue)) {
        throw "Service '$ServiceName' was not deleted within $TimeoutSeconds seconds."
    }
}

function Restore-SyncVisionServiceRegistryValues {
    param([Parameter(Mandatory = $true)][string]$ServiceName, [Parameter(Mandatory = $true)][object[]]$Values)

    $path = "SYSTEM\CurrentControlSet\Services\$ServiceName"
    $key = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey($path, $true)
    if ($null -eq $key) { throw "Restored service registry key was not found: $path" }
    try {
        $expectedNames = @($Values | ForEach-Object { $_.Name })
        foreach ($name in $key.GetValueNames()) {
            if ($expectedNames -cnotcontains $name) { $key.DeleteValue($name, $false) }
        }
        foreach ($value in $Values) {
            $kind = [Microsoft.Win32.RegistryValueKind][Enum]::Parse(
                [Microsoft.Win32.RegistryValueKind],
                [string]$value.Kind,
                $false)
            $key.SetValue([string]$value.Name, $value.Value, $kind)
        }
    }
    finally { $key.Dispose() }
}

function Restore-SyncVisionServiceRunningState {
    param([Parameter(Mandatory = $true)][object]$Snapshot)

    if (-not [bool]$Snapshot.Exists -or -not [bool]$Snapshot.Running) { return }
    $serviceName = [string]$Snapshot.ServiceName
    $disabledWhileRunning = [string]$Snapshot.Cim.StartMode -ceq "Disabled"
    if (-not $disabledWhileRunning) {
        Start-Service -Name $serviceName -ErrorAction Stop
        return
    }

    Invoke-SyncVisionScCommand `
        -Arguments @("config", $serviceName, "start=", "demand") `
        -Context "Temporarily enable restored disabled service for running-state recovery"
    $startFailure = $null
    try { Start-Service -Name $serviceName -ErrorAction Stop }
    catch { $startFailure = $_ }
    $modeFailure = $null
    try {
        Invoke-SyncVisionScCommand `
            -Arguments @("config", $serviceName, "start=", "disabled") `
            -Context "Restore disabled start mode after running-state recovery"
    }
    catch { $modeFailure = $_ }
    if ($null -ne $startFailure -and $null -ne $modeFailure) {
        throw "Restored disabled service could not be started and its disabled start mode could not be re-applied. Start: $($startFailure.Exception.Message) StartMode: $($modeFailure.Exception.Message)"
    }
    if ($null -ne $modeFailure) { throw $modeFailure }
    if ($null -ne $startFailure) { throw $startFailure }
}

function Restore-SyncVisionServiceTransactionSnapshot {
    param(
        [Parameter(Mandatory = $true)][object]$Snapshot,
        [switch]$DeferStart
    )

    Assert-SyncVisionServiceRegistryTransactionCapabilities -Snapshot $Snapshot
    $current = Get-Service -Name $Snapshot.ServiceName -ErrorAction SilentlyContinue
    if ($null -ne $current) {
        if ($current.Status -ne [System.ServiceProcess.ServiceControllerStatus]::Stopped) {
            Stop-Service -Name $Snapshot.ServiceName -Force -ErrorAction Stop
            (Get-Service -Name $Snapshot.ServiceName -ErrorAction Stop).WaitForStatus(
                [System.ServiceProcess.ServiceControllerStatus]::Stopped,
                [TimeSpan]::FromSeconds(30))
        }
        Invoke-SyncVisionScCommand -Arguments @("delete", $Snapshot.ServiceName) -Context "Delete current service during rollback"
        Wait-SyncVisionServiceAbsent -ServiceName $Snapshot.ServiceName
    }
    if (-not $Snapshot.Exists) { return }

    $startMode = switch ($Snapshot.Cim.StartMode) {
        "Auto" { "auto" }
        "Manual" { "demand" }
        "Disabled" { "disabled" }
        default { "demand" }
    }
    $arguments = @("create", $Snapshot.ServiceName, "binPath=", $Snapshot.Cim.PathName, "start=", $startMode, "obj=", $Snapshot.Cim.StartName, "DisplayName=", $Snapshot.Cim.DisplayName)
    Invoke-SyncVisionScCommand -Arguments $arguments -Context "Recreate previous service during rollback"
    $registryPath = "SYSTEM\CurrentControlSet\Services\$($Snapshot.ServiceName)"
    $registryKey = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey(
        $registryPath,
        [Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree,
        [Security.AccessControl.RegistryRights]::FullControl)
    if ($null -eq $registryKey) { throw "Restored service registry subtree was not available for exact rollback: HKLM\$registryPath" }
    try { Restore-SyncVisionRegistryTreeSnapshot -Key $registryKey -Snapshot $Snapshot.RegistryTree }
    finally { $registryKey.Dispose() }
    Invoke-SyncVisionScCommand -Arguments @("sdset", $Snapshot.ServiceName, $Snapshot.Sddl) -Context "Restore previous service security"
    if (-not [string]::IsNullOrWhiteSpace($Snapshot.Cim.Description)) {
        Invoke-SyncVisionScCommand -Arguments @("description", $Snapshot.ServiceName, $Snapshot.Cim.Description) -Context "Restore previous service description"
    }
    $registryKey = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey($registryPath, $false)
    if ($null -eq $registryKey) { throw "Restored service registry subtree disappeared before exact verification: HKLM\$registryPath" }
    try { Assert-SyncVisionRegistryTreeSnapshot -Key $registryKey -Snapshot $Snapshot.RegistryTree -Context "Restored service registry subtree" | Out-Null }
    finally { $registryKey.Dispose() }
    if (-not $DeferStart) { Restore-SyncVisionServiceRunningState -Snapshot $Snapshot }
}

function New-SyncVisionServiceRecoveryCommands {
    param(
        [Parameter(Mandatory = $true)]
        [string]$ServiceName,

        [Parameter(Mandatory = $true)]
        [UInt32]$RestartDelayMs
    )

    return @(
        "sc.exe failure $ServiceName reset= 86400 actions= restart/$RestartDelayMs/restart/$RestartDelayMs/`"`"/0",
        "sc.exe failureflag $ServiceName 1"
    )
}

function Invoke-SyncVisionServiceRecovery {
    param(
        [Parameter(Mandatory = $true)]
        [string]$ServiceName,

        [Parameter(Mandatory = $true)]
        [UInt32]$RestartDelayMs
    )

    $actions = "restart/$RestartDelayMs/restart/$RestartDelayMs/`"`"/0"
    Invoke-SyncVisionScCommand `
        -Arguments @("failure", $ServiceName, "reset=", "86400", "actions=", $actions) `
        -Context "Configure service recovery actions"
    Invoke-SyncVisionScCommand `
        -Arguments @("failureflag", $ServiceName, "1") `
        -Context "Configure service recovery failure flag"
}

function Resolve-SyncVisionInstallProbeEndpoint {
    param(
        [Parameter(Mandatory = $true)]
        [string]$Listen
    )

    $hostPart = Get-SyncVisionEndpointHost -Endpoint $Listen
    $port = Get-SyncVisionEndpointPort -Endpoint $Listen
    if (Test-SyncVisionWildcardHost -HostName $hostPart) {
        return "127.0.0.1:$port"
    }

    return $Listen
}

function New-SyncVisionInstallVerificationPlan {
    param(
        [Parameter(Mandatory = $true)]
        [string]$ServiceName,

        [Parameter(Mandatory = $true)]
        [string]$ServerExe,

        [Parameter(Mandatory = $true)]
        [string]$ConfigPath,

        [Parameter(Mandatory = $true)]
        [string]$TokenPath,

        [Parameter(Mandatory = $true)]
        [string]$ProbeEndpoint,

        [Parameter(Mandatory = $true)]
        [bool]$StartRequested,

        [Parameter(Mandatory = $true)]
        [bool]$ConfigureFirewall,

        [object[]]$FirewallRules = @()
    )

    $plan = New-Object System.Collections.Generic.List[string]
    $plan.Add("Verify service '$ServiceName' exists.")
    $plan.Add("Verify copied server binary: $ServerExe")
    $plan.Add("Verify server config: $ConfigPath")
    $plan.Add("Verify server token file: $TokenPath")
    if ($StartRequested) {
        $plan.Add("Probe live server at $ProbeEndpoint.")
    }
    else {
        $plan.Add("Skip live protocol probe because -Start was not passed.")
    }

    if ($ConfigureFirewall) {
        foreach ($rule in $FirewallRules) {
            $plan.Add("Verify Windows Firewall rule: $($rule.DisplayName)")
        }
    }
    else {
        $plan.Add("Skip firewall rule verification because -ConfigureFirewall was not passed.")
    }

    return $plan
}

function Get-SyncVisionManagedServerInstallFileNames {
    return @(
        "SyncVisionServer.exe",
        "SyncVisionServer.pdb",
        "vcruntime140.dll",
        "vcruntime140_1.dll",
        "msvcp140.dll",
        "msvcp140_atomic_wait.dll",
        "datachannel.dll",
        "srtp2.dll",
        "libssl-3-x64.dll",
        "libcrypto-3-x64.dll"
    )
}

function Get-SyncVisionServerInstallFiles {
    param(
        [Parameter(Mandatory = $true)]
        [string]$ReleaseDir
    )

    $files = New-Object System.Collections.Generic.List[object]
    foreach ($name in @("SyncVisionServer.exe", "SyncVisionServer.pdb")) {
        $path = Join-Path $ReleaseDir $name
        if (Test-Path -LiteralPath $path -PathType Leaf) {
            $item = Get-Item -LiteralPath $path -Force
            if (($item.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
                throw "Server install input must not be a reparse point: $path"
            }
            $files.Add($item)
        }
    }

    $vcRuntimeNames = @(Get-SyncVisionRequiredVcRuntimeDlls)
    $presentVcRuntimeNames = @(
        $vcRuntimeNames |
            Where-Object {
                Test-Path -LiteralPath (Join-Path $ReleaseDir $_) -PathType Leaf
            }
    )
    if ($presentVcRuntimeNames.Count -ne 0 -and
        $presentVcRuntimeNames.Count -ne $vcRuntimeNames.Count) {
        $missingVcRuntimeNames = @(
            $vcRuntimeNames |
                Where-Object { $presentVcRuntimeNames -notcontains $_ }
        )
        throw "Server install app-local VC runtime set is incomplete: $($missingVcRuntimeNames -join ', ')"
    }
    foreach ($name in $presentVcRuntimeNames) {
        $path = Join-Path $ReleaseDir $name
        $item = Get-Item -LiteralPath $path -Force
        if (($item.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
            throw "Server install VC runtime DLL must not be a reparse point: $path"
        }
        $files.Add($item)
    }

    $buildFlavorPath = Join-Path $ReleaseDir "SyncVisionBuildFlavor.json"
    if (Test-Path -LiteralPath $buildFlavorPath -PathType Leaf) {
        try {
            $buildFlavor = Get-Content -LiteralPath $buildFlavorPath -Raw | ConvertFrom-Json
        }
        catch {
            throw "Server install build flavor manifest is invalid JSON: $buildFlavorPath. $($_.Exception.Message)"
        }
        if ($null -eq $buildFlavor.runtime_dll_sha256 -or $buildFlavor.runtime_dll_sha256 -isnot [pscustomobject]) {
            throw "Server install build flavor manifest must contain runtime_dll_sha256: $buildFlavorPath"
        }
        $managedRuntimeNames = @((Get-SyncVisionManagedServerInstallFileNames) | Where-Object { $_ -like "*.dll" })
        foreach ($property in $buildFlavor.runtime_dll_sha256.PSObject.Properties) {
            $name = $property.Name
            if ($managedRuntimeNames -cnotcontains $name -or [string]$property.Value -cnotmatch '^[0-9a-f]{64}$') {
                throw "Server install build flavor manifest contains an unapproved runtime DLL: $name"
            }
            $path = Join-Path $ReleaseDir $name
            if (-not (Test-Path -LiteralPath $path -PathType Leaf)) {
                throw "Server install build flavor runtime DLL was not found: $path"
            }
            $item = Get-Item -LiteralPath $path -Force
            if (($item.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
                throw "Server install runtime DLL must not be a reparse point: $path"
            }
            $actualHash = (Get-FileHash -LiteralPath $path -Algorithm SHA256).Hash.ToLowerInvariant()
            if ($actualHash -cne [string]$property.Value) {
                throw "Server install build flavor runtime DLL hash mismatch: $name"
            }
            $files.Add($item)
        }
    }

    return $files
}

function ConvertTo-SyncVisionPackageManifestRelativePath {
    param(
        [Parameter(Mandatory = $true)]
        [string]$RelativePath,

        [Parameter(Mandatory = $true)]
        [string]$Context
    )

    $candidate = $RelativePath.Trim()
    if ($candidate.StartsWith("*")) {
        $candidate = $candidate.Substring(1)
    }
    if ([string]::IsNullOrWhiteSpace($candidate)) {
        throw "Package manifest verification failed: $Context has an empty relative path."
    }

    $normalized = $candidate -replace '/', '\'
    if ([IO.Path]::IsPathRooted($normalized) -or $normalized.StartsWith('\')) {
        throw "Package manifest verification failed: $Context must be relative to the package root: $RelativePath"
    }

    $segments = @($normalized -split '\\')
    if ($segments.Count -eq 0 -or @($segments | Where-Object {
            [string]::IsNullOrWhiteSpace($_) -or $_ -eq '.' -or $_ -eq '..'
        }).Count -ne 0) {
        throw "Package manifest verification failed: $Context is not a canonical package-relative path: $RelativePath"
    }

    return ($segments -join '\')
}

function Assert-SyncVisionPackageTreeSnapshot {
    param(
        [Parameter(Mandatory = $true)]
        [string]$RootPath,

        [Parameter(Mandatory = $true)]
        [string]$ManifestPath,

        [Parameter(Mandatory = $true)]
        [object]$ManifestEntries
    )

    $resolvedRoot = (Resolve-Path -LiteralPath $RootPath).Path.TrimEnd('\', '/')
    $rootItem = Get-Item -LiteralPath $resolvedRoot -Force
    if (($rootItem.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
        throw "Package manifest verification failed: reparse-point package root: $resolvedRoot"
    }

    $resolvedManifest = [IO.Path]::GetFullPath($ManifestPath)
    $rootPrefix = $resolvedRoot + "\"
    $observedManifestEntries = New-Object "System.Collections.Generic.HashSet[string]" ([StringComparer]::OrdinalIgnoreCase)
    $pendingDirectories = New-Object "System.Collections.Generic.Stack[string]"
    $pendingDirectories.Push($resolvedRoot)

    while ($pendingDirectories.Count -ne 0) {
        $directoryPath = $pendingDirectories.Pop()
        foreach ($item in (Get-ChildItem -LiteralPath $directoryPath -Force)) {
            $itemPath = $item.FullName
            if (-not $itemPath.StartsWith($rootPrefix, [StringComparison]::OrdinalIgnoreCase)) {
                throw "Package manifest verification failed: package item is outside the package root: $itemPath"
            }

            if ($item.PSIsContainer) {
                if (($item.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
                    throw "Package manifest verification failed: reparse-point package directory: $itemPath"
                }
                $pendingDirectories.Push($itemPath)
                continue
            }

            if ($itemPath -ieq $resolvedManifest) {
                Assert-SyncVisionFileTrustMetadata `
                    -Path $itemPath `
                    -Context "Package manifest verification" | Out-Null
                continue
            }
            if (($item.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
                throw "Package manifest verification failed: reparse-point package file: $itemPath"
            }
            Assert-SyncVisionFileTrustMetadata `
                -Path $itemPath `
                -Context "Package manifest verification" | Out-Null

            $relativePath = ConvertTo-SyncVisionPackageManifestRelativePath `
                -RelativePath $itemPath.Substring($rootPrefix.Length) `
                -Context "package file"
            if (-not $ManifestEntries.ContainsKey($relativePath)) {
                throw "Package manifest verification failed: unmanifested package file: $relativePath"
            }

            $expectedHash = $ManifestEntries[$relativePath]
            $actualHash = (Get-FileHash -LiteralPath $itemPath -Algorithm SHA256).Hash.ToLowerInvariant()
            if ($actualHash -ne $expectedHash) {
                throw "Checksum mismatch for $relativePath. Expected $expectedHash, got $actualHash."
            }
            [void]$observedManifestEntries.Add($relativePath)
        }
    }

    foreach ($relativePath in $ManifestEntries.Keys) {
        if (-not $observedManifestEntries.Contains($relativePath)) {
            throw "Package manifest verification failed: SHA256SUMS.txt references missing file: $relativePath"
        }
    }
}

function Get-SyncVisionPackageInstallInputs {
    param(
        [Parameter(Mandatory = $true)]
        [string]$RootPath,

        [Parameter(Mandatory = $true)]
        [string]$ReleaseDir,

        [Parameter(Mandatory = $true)]
        [object]$ManifestEntries
    )

    $configuration = Split-Path -Leaf $ReleaseDir
    $releasePrefix = "build\x64\$configuration\"
    $serverRelativePath = $releasePrefix + "SyncVisionServer.exe"
    $serverPdbRelativePath = $releasePrefix + "SyncVisionServer.pdb"
    $installInputs = New-Object System.Collections.Generic.List[object]
    $hasServerExecutable = $false

    foreach ($relativePath in @($ManifestEntries.Keys | Sort-Object)) {
        $leafName = [IO.Path]::GetFileName($relativePath)
        $isServerExecutable = [string]::Equals($relativePath, $serverRelativePath, [StringComparison]::OrdinalIgnoreCase)
        $isServerPdb = [string]::Equals($relativePath, $serverPdbRelativePath, [StringComparison]::OrdinalIgnoreCase)
        $isRuntimeDll = $relativePath.StartsWith($releasePrefix, [StringComparison]::OrdinalIgnoreCase) -and
            [string]::Equals([IO.Path]::GetExtension($leafName), ".dll", [StringComparison]::OrdinalIgnoreCase)
        if (-not ($isServerExecutable -or $isServerPdb -or $isRuntimeDll)) {
            continue
        }

        $installInputs.Add([pscustomobject]@{
                RelativePath = $relativePath
                SourcePath = Join-Path $RootPath $relativePath
                DestinationName = $leafName
                ExpectedHash = $ManifestEntries[$relativePath]
            })
        if ($isServerExecutable) {
            $hasServerExecutable = $true
        }
    }

    if (-not $hasServerExecutable) {
        throw "Package manifest verification failed: SHA256SUMS.txt does not contain required install input: $serverRelativePath"
    }

    return $installInputs.ToArray()
}

function Assert-SyncVisionStagedPackageInstallInputs {
    param(
        [Parameter(Mandatory = $true)]
        [object[]]$StagedInputs
    )

    if ($StagedInputs.Count -eq 0) {
        throw "Package manifest verification failed: staged server install set is empty."
    }
    $stagingDirectory = Split-Path -Parent $StagedInputs[0].Path
    $expectedNames = New-Object "System.Collections.Generic.HashSet[string]" ([StringComparer]::OrdinalIgnoreCase)
    $hasServerExecutable = $false
    foreach ($stagedInput in $StagedInputs) {
        if (-not [string]::Equals((Split-Path -Parent $stagedInput.Path), $stagingDirectory, [StringComparison]::OrdinalIgnoreCase)) {
            throw "Package manifest verification failed: staged server inputs must share one flat staging directory."
        }
        $destinationName = if ($null -ne $stagedInput.PSObject.Properties["DestinationName"]) {
            [string]$stagedInput.DestinationName
        }
        else {
            Split-Path -Leaf $stagedInput.Path
        }
        if (-not $expectedNames.Add($destinationName)) {
            throw "Package manifest verification failed: duplicate staged install input name: $destinationName"
        }
        if ($destinationName -ieq "SyncVisionServer.exe") {
            $hasServerExecutable = $true
        }
        if (-not (Test-Path -LiteralPath $stagedInput.Path -PathType Leaf)) {
            throw "Package manifest verification failed: staged package input was not found: $($stagedInput.RelativePath)"
        }
        $item = Get-Item -LiteralPath $stagedInput.Path -Force
        if (($item.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
            throw "Package manifest verification failed: staged package input is a reparse point: $($stagedInput.RelativePath)"
        }
        Assert-SyncVisionFileTrustMetadata `
            -Path $item.FullName `
            -Context "Staged package input verification" | Out-Null
        if ($null -eq $stagedInput.PSObject.Properties["ExpectedLength"] -or
            [int64]$stagedInput.ExpectedLength -lt 0 -or
            $item.Length -ne [int64]$stagedInput.ExpectedLength) {
            throw "Package manifest verification failed: staged package input length changed: $($stagedInput.RelativePath)"
        }
        $actualHash = (Get-FileHash -LiteralPath $stagedInput.Path -Algorithm SHA256).Hash.ToLowerInvariant()
        if ($actualHash -ne $stagedInput.ExpectedHash) {
            throw "Checksum mismatch for staged package input $($stagedInput.RelativePath). Expected $($stagedInput.ExpectedHash), got $actualHash."
        }
    }
    if (-not $hasServerExecutable) {
        throw "Package manifest verification failed: staged server install set is missing SyncVisionServer.exe."
    }
    foreach ($item in (Get-ChildItem -LiteralPath $stagingDirectory -Force)) {
        if (($item.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
            throw "Package manifest verification failed: staged install tree contains a reparse point: $($item.FullName)"
        }
        if ($item.PSIsContainer -or -not $expectedNames.Contains($item.Name)) {
            throw "Package manifest verification failed: staged install tree contains an unexpected entry: $($item.Name)"
        }
    }
    if (@(Get-ChildItem -LiteralPath $stagingDirectory -File -Force).Count -ne $expectedNames.Count) {
        throw "Package manifest verification failed: staged install tree is not an exact file set."
    }
}

function Copy-SyncVisionInstallInputsToStaging {
    param(
        [Parameter(Mandatory = $true)][object[]]$InstallInputs,
        [Parameter(Mandatory = $true)][string]$StagingDirectory
    )

    if (-not (Test-Path -LiteralPath $StagingDirectory -PathType Container)) {
        New-Item -ItemType Directory -Path $StagingDirectory | Out-Null
    }
    $stagingItem = Get-Item -LiteralPath $StagingDirectory -Force
    if (($stagingItem.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0 -or
        @(Get-ChildItem -LiteralPath $StagingDirectory -Force).Count -ne 0) {
        throw "Package manifest verification failed: install staging directory must be a fresh empty non-reparse directory."
    }

    $managedNames = New-Object "System.Collections.Generic.HashSet[string]" ([StringComparer]::OrdinalIgnoreCase)
    foreach ($name in (Get-SyncVisionManagedServerInstallFileNames)) {
        [void]$managedNames.Add($name)
    }
    $stagedInputs = New-Object System.Collections.Generic.List[object]
    $stagedNames = New-Object "System.Collections.Generic.HashSet[string]" ([StringComparer]::OrdinalIgnoreCase)
    foreach ($installInput in $InstallInputs) {
        $destinationName = [string]$installInput.DestinationName
        if (-not $managedNames.Contains($destinationName)) {
            throw "Package manifest verification failed: unmanaged server install input name: $destinationName"
        }
        if (-not $stagedNames.Add($destinationName)) {
            throw "Package manifest verification failed: duplicate staged install input name: $destinationName"
        }
        if (-not (Test-Path -LiteralPath $installInput.SourcePath -PathType Leaf)) {
            throw "Package manifest verification failed: server install input was not found: $($installInput.SourcePath)"
        }
        $sourceItem = Get-Item -LiteralPath $installInput.SourcePath -Force
        if (($sourceItem.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
            throw "Package manifest verification failed: server install input is a reparse point: $($installInput.SourcePath)"
        }
        Assert-SyncVisionFileTrustMetadata `
            -Path $sourceItem.FullName `
            -Context "Server install input verification" | Out-Null
        $expectedHash = [string]$installInput.ExpectedHash
        $sourceHash = (Get-FileHash -LiteralPath $sourceItem.FullName -Algorithm SHA256).Hash.ToLowerInvariant()
        if ($sourceHash -cne $expectedHash) {
            throw "Checksum mismatch for server install input $($installInput.RelativePath). Expected $expectedHash, got $sourceHash."
        }
        $stagedPath = Join-Path $StagingDirectory $destinationName
        [IO.File]::Copy($sourceItem.FullName, $stagedPath, $false)
        $stagedInputs.Add([pscustomobject]@{
                Path = $stagedPath
                RelativePath = $installInput.RelativePath
                DestinationName = $destinationName
                ExpectedLength = [int64]$sourceItem.Length
                ExpectedHash = $expectedHash
            })
    }
    $result = $stagedInputs.ToArray()
    Assert-SyncVisionStagedPackageInstallInputs -StagedInputs $result
    return $result
}

function Get-SyncVisionSourceInstallInputs {
    param([Parameter(Mandatory = $true)][string]$ReleaseDir)

    $inputs = foreach ($file in (Get-SyncVisionServerInstallFiles -ReleaseDir $ReleaseDir)) {
        [pscustomobject]@{
            RelativePath = $file.Name
            SourcePath = $file.FullName
            DestinationName = $file.Name
            ExpectedHash = (Get-FileHash -LiteralPath $file.FullName -Algorithm SHA256).Hash.ToLowerInvariant()
        }
    }
    if (@($inputs | Where-Object { $_.DestinationName -ieq "SyncVisionServer.exe" }).Count -ne 1) {
        throw "Source server install inputs must contain exactly one SyncVisionServer.exe."
    }
    return @($inputs)
}

function Copy-SyncVisionPackageInstallInputsToStaging {
    param(
        [Parameter(Mandatory = $true)]
        [object]$PackageManifest,

        [Parameter(Mandatory = $true)]
        [string]$StagingDirectory
    )

    if (-not $PackageManifest.IsPackage) {
        throw "Package manifest verification failed: only validated package inputs can be staged."
    }

    Assert-SyncVisionPackageTreeSnapshot `
        -RootPath $PackageManifest.RootPath `
        -ManifestPath $PackageManifest.ManifestPath `
        -ManifestEntries $PackageManifest.ManifestEntries

    $stagedInputs = @(Copy-SyncVisionInstallInputsToStaging `
        -InstallInputs @($PackageManifest.InstallInputs) `
        -StagingDirectory $StagingDirectory)
    Assert-SyncVisionPackageTreeSnapshot `
        -RootPath $PackageManifest.RootPath `
        -ManifestPath $PackageManifest.ManifestPath `
        -ManifestEntries $PackageManifest.ManifestEntries
    Assert-SyncVisionStagedPackageInstallInputs -StagedInputs $stagedInputs
    return $stagedInputs
}

function Resolve-SyncVisionServiceAccountSid {
    param([AllowEmptyString()][string]$ServiceAccount = "")

    $normalized = $ServiceAccount.Trim()
    if ([string]::IsNullOrWhiteSpace($normalized) -or
        $normalized -in @("LocalSystem", ".\LocalSystem", "SYSTEM", "NT AUTHORITY\SYSTEM")) {
        return [Security.Principal.SecurityIdentifier]::new(
            [Security.Principal.WellKnownSidType]::LocalSystemSid,
            $null)
    }
    if ($normalized -in @("LocalService", ".\LocalService", "NT AUTHORITY\LOCAL SERVICE")) {
        return [Security.Principal.SecurityIdentifier]::new(
            [Security.Principal.WellKnownSidType]::LocalServiceSid,
            $null)
    }
    if ($normalized -in @("NetworkService", ".\NetworkService", "NT AUTHORITY\NETWORK SERVICE")) {
        return [Security.Principal.SecurityIdentifier]::new(
            [Security.Principal.WellKnownSidType]::NetworkServiceSid,
            $null)
    }
    throw "Unsupported SyncVision service account identity: $ServiceAccount"
}

function Get-SyncVisionContentMutationRights {
    return [Security.AccessControl.FileSystemRights]::WriteData -bor
        [Security.AccessControl.FileSystemRights]::AppendData -bor
        [Security.AccessControl.FileSystemRights]::WriteExtendedAttributes -bor
        [Security.AccessControl.FileSystemRights]::WriteAttributes -bor
        [Security.AccessControl.FileSystemRights]::DeleteSubdirectoriesAndFiles -bor
        [Security.AccessControl.FileSystemRights]::Delete -bor
        [Security.AccessControl.FileSystemRights]::ChangePermissions -bor
        [Security.AccessControl.FileSystemRights]::TakeOwnership
}

function Get-SyncVisionDestructiveAncestorRights {
    return [Security.AccessControl.FileSystemRights]::DeleteSubdirectoriesAndFiles -bor
        [Security.AccessControl.FileSystemRights]::Delete -bor
        [Security.AccessControl.FileSystemRights]::ChangePermissions -bor
        [Security.AccessControl.FileSystemRights]::TakeOwnership
}

function New-SyncVisionProtectedInstallDirectorySecurity {
    param(
        [AllowEmptyString()][string]$ServiceAccount = "",
        [switch]$ServiceModify
    )

    $acl = New-Object Security.AccessControl.DirectorySecurity
    $acl.SetAccessRuleProtection($true, $false)
    $inheritance = [Security.AccessControl.InheritanceFlags]"ContainerInherit, ObjectInherit"
    $propagation = [Security.AccessControl.PropagationFlags]::None
    $allow = [Security.AccessControl.AccessControlType]::Allow
    $administratorsSid = [Security.Principal.SecurityIdentifier]::new(
        [Security.Principal.WellKnownSidType]::BuiltinAdministratorsSid,
        $null)
    $systemSid = [Security.Principal.SecurityIdentifier]::new(
        [Security.Principal.WellKnownSidType]::LocalSystemSid,
        $null)
    $serviceSid = Resolve-SyncVisionServiceAccountSid -ServiceAccount $ServiceAccount
    $acl.SetOwner($administratorsSid)
    foreach ($sid in @($administratorsSid, $systemSid)) {
        $acl.AddAccessRule([Security.AccessControl.FileSystemAccessRule]::new(
                $sid,
                [Security.AccessControl.FileSystemRights]::FullControl,
                $inheritance,
                $propagation,
                $allow)) | Out-Null
    }
    if ($serviceSid.Value -ne $systemSid.Value) {
        $serviceRights = if ($ServiceModify) {
            [Security.AccessControl.FileSystemRights]::Modify
        }
        else {
            [Security.AccessControl.FileSystemRights]"ReadAndExecute, Synchronize"
        }
        $acl.AddAccessRule([Security.AccessControl.FileSystemAccessRule]::new(
                $serviceSid,
                $serviceRights,
                $inheritance,
                $propagation,
                $allow)) | Out-Null
    }
    return $acl
}

function Assert-SyncVisionInstallAncestorBoundary {
    param(
        [Parameter(Mandatory = $true)][string]$Path,
        [Parameter(Mandatory = $true)][string]$Context,
        [AllowEmptyString()][string]$ServiceAccount = "",
        [switch]$AllowProgramDataAtomicCreate
    )

    $trustedSids = @(
        "S-1-5-18",
        "S-1-5-32-544",
        "S-1-5-80-956008885-3418522649-1831038044-1853292631-2271478464"
    )
    $programData = [IO.Path]::GetFullPath(
        [Environment]::GetFolderPath([Environment+SpecialFolder]::CommonApplicationData)).TrimEnd('\', '/')
    $programFilesRoots = @(
        [Environment]::GetFolderPath([Environment+SpecialFolder]::ProgramFiles),
        [Environment]::GetFolderPath([Environment+SpecialFolder]::ProgramFilesX86)
    ) | Where-Object { -not [string]::IsNullOrWhiteSpace($_) } | ForEach-Object { [IO.Path]::GetFullPath($_).TrimEnd('\', '/') }
    $leafPath = (Resolve-Path -LiteralPath $Path).Path.TrimEnd('\', '/')
    $stopPath = ""
    if ($leafPath.StartsWith($programData + [IO.Path]::DirectorySeparatorChar, [StringComparison]::OrdinalIgnoreCase) -or
        [string]::Equals($leafPath, $programData, [StringComparison]::OrdinalIgnoreCase)) {
        $stopPath = $programData
    }
    else {
        foreach ($root in $programFilesRoots) {
            if ($leafPath.StartsWith($root + [IO.Path]::DirectorySeparatorChar, [StringComparison]::OrdinalIgnoreCase) -or
                [string]::Equals($leafPath, $root, [StringComparison]::OrdinalIgnoreCase)) {
                $stopPath = $root
                break
            }
        }
    }
    $current = Get-Item -LiteralPath $leafPath -Force
    while ($null -ne $current) {
        if ($current -isnot [IO.DirectoryInfo] -or
            ($current.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
            throw "$Context contains a non-directory or reparse-point component: $($current.FullName)"
        }
        try {
            $acl = Get-Acl -LiteralPath $current.FullName -ErrorAction Stop
        }
        catch {
            throw "$Context uses an unsupported ACL provider or unreadable ACL at $($current.FullName): $($_.Exception.Message)"
        }
        if ($acl -isnot [Security.AccessControl.DirectorySecurity]) {
            throw "$Context uses an unsupported ACL provider at $($current.FullName)."
        }
        $ownerSid = $acl.GetOwner([Security.Principal.SecurityIdentifier]).Value
        if ($trustedSids -notcontains $ownerSid) {
            throw "$Context has an untrusted owner SID $ownerSid at $($current.FullName)."
        }
        $isAtomicProgramDataLeaf = $AllowProgramDataAtomicCreate -and
            [string]::Equals($current.FullName.TrimEnd('\', '/'), $programData, [StringComparison]::OrdinalIgnoreCase)
        $dangerousRights = if ($isAtomicProgramDataLeaf) {
            Get-SyncVisionDestructiveAncestorRights
        }
        else {
            Get-SyncVisionContentMutationRights
        }
        foreach ($rule in $acl.GetAccessRules($true, $true, [Security.Principal.SecurityIdentifier])) {
            $applies = ($rule.PropagationFlags -band [Security.AccessControl.PropagationFlags]::InheritOnly) -eq 0
            if ($applies -and
                $rule.AccessControlType -eq [Security.AccessControl.AccessControlType]::Allow -and
                $trustedSids -notcontains $rule.IdentityReference.Value -and
                ($rule.FileSystemRights -band $dangerousRights) -ne 0) {
                throw "$Context grants unprivileged SID $($rule.IdentityReference.Value) write, modify, delete, or ACL-control rights at $($current.FullName)."
            }
        }
        if (-not [string]::IsNullOrWhiteSpace($stopPath) -and
            [string]::Equals($current.FullName.TrimEnd('\', '/'), $stopPath, [StringComparison]::OrdinalIgnoreCase)) {
            break
        }
        $current = $current.Parent
    }
}

function Resolve-SyncVisionInstallDirectoryCreationBoundary {
    param(
        [Parameter(Mandatory = $true)][string]$Path,
        [AllowEmptyString()][string]$ServiceAccount = "",
        [Parameter(Mandatory = $true)][string]$Context
    )

    $basePath = Get-SyncVisionCurrentFileSystemProviderPath
    $fullPath = (Resolve-SyncVisionUserFileSystemPath `
            -Path $Path `
            -BasePath $basePath `
            -Context $Context).TrimEnd('\', '/')
    $volumeRoot = [IO.Path]::GetPathRoot($fullPath).TrimEnd('\', '/')
    if ([string]::Equals($fullPath, $volumeRoot, [StringComparison]::OrdinalIgnoreCase)) {
        throw "$Context must be a non-root directory path: $fullPath"
    }

    $missingPaths = New-Object "System.Collections.Generic.List[string]"
    $existingPath = $fullPath
    while (-not (Test-Path -LiteralPath $existingPath)) {
        $missingPaths.Add($existingPath)
        $parent = Split-Path -Parent $existingPath
        if ([string]::IsNullOrWhiteSpace($parent) -or $parent -eq $existingPath) {
            throw "$Context has no existing directory ancestor: $fullPath"
        }
        $existingPath = $parent
    }

    $existingItem = Get-Item -LiteralPath $existingPath -Force
    if (-not $existingItem.PSIsContainer) {
        throw "$Context existing path component is not a directory: $($existingItem.FullName)"
    }
    if (($existingItem.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
        throw "$Context contains a reparse-point path component: $($existingItem.FullName)"
    }
    $resolvedExistingPath = $existingItem.FullName.TrimEnd('\', '/')
    if ($missingPaths.Count -ne 0) {
        Assert-SyncVisionInstallAncestorBoundary `
            -Path $resolvedExistingPath `
            -Context "$Context atomic-creation ancestor" `
            -ServiceAccount $ServiceAccount `
            -AllowProgramDataAtomicCreate
    }

    return [pscustomobject]@{
        Path = $fullPath
        Existed = $missingPaths.Count -eq 0
        ExistingPath = $resolvedExistingPath
        MissingPaths = $missingPaths.ToArray()
    }
}

function Assert-SyncVisionProtectedInstallDirectory {
    param(
        [Parameter(Mandatory = $true)][string]$Path,
        [AllowEmptyString()][string]$ServiceAccount = "",
        [switch]$ServiceModify,
        [Parameter(Mandatory = $true)][string]$Context
    )

    if (-not (Test-Path -LiteralPath $Path -PathType Container)) {
        throw "$Context was not found: $Path"
    }
    $item = Get-Item -LiteralPath $Path -Force
    if (($item.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
        throw "$Context must not be a reparse point: $($item.FullName)"
    }
    $acl = Get-Acl -LiteralPath $item.FullName
    if (-not $acl.AreAccessRulesProtected) {
        throw "$Context must have protected ACL inheritance: $($item.FullName)"
    }
    $administratorsSid = [Security.Principal.SecurityIdentifier]::new(
        [Security.Principal.WellKnownSidType]::BuiltinAdministratorsSid,
        $null)
    $systemSid = [Security.Principal.SecurityIdentifier]::new(
        [Security.Principal.WellKnownSidType]::LocalSystemSid,
        $null)
    $serviceSid = Resolve-SyncVisionServiceAccountSid -ServiceAccount $ServiceAccount
    $ownerSid = $acl.GetOwner([Security.Principal.SecurityIdentifier]).Value
    if (@($administratorsSid.Value, $systemSid.Value) -notcontains $ownerSid) {
        throw "$Context has an untrusted owner SID $ownerSid at $($item.FullName)."
    }
    $expected = [ordered]@{
        $administratorsSid.Value = [Security.AccessControl.FileSystemRights]::FullControl
        $systemSid.Value = [Security.AccessControl.FileSystemRights]::FullControl
    }
    if ($serviceSid.Value -ne $systemSid.Value) {
        $expected[$serviceSid.Value] = if ($ServiceModify) {
            [Security.AccessControl.FileSystemRights]"Modify, Synchronize"
        }
        else {
            [Security.AccessControl.FileSystemRights]"ReadAndExecute, Synchronize"
        }
    }
    $rules = @($acl.GetAccessRules($true, $true, [Security.Principal.SecurityIdentifier]))
    if ($rules.Count -ne $expected.Count) {
        throw "$Context contains an unprivileged or unexpected ACL rule at $($item.FullName)."
    }
    $expectedInheritance = [Security.AccessControl.InheritanceFlags]"ContainerInherit, ObjectInherit"
    foreach ($rule in $rules) {
        $sid = $rule.IdentityReference.Value
        if (-not $expected.Contains($sid) -or
            $rule.AccessControlType -ne [Security.AccessControl.AccessControlType]::Allow -or
            $rule.FileSystemRights -ne $expected[$sid] -or
            $rule.InheritanceFlags -ne $expectedInheritance -or
            $rule.PropagationFlags -ne [Security.AccessControl.PropagationFlags]::None -or
            $rule.IsInherited) {
            throw "$Context contains an unprivileged, writable, or non-exact ACL rule at $($item.FullName)."
        }
    }
    return $item.FullName
}

function Initialize-SyncVisionProtectedInstallDirectory {
    param(
        [Parameter(Mandatory = $true)][string]$Path,
        [AllowEmptyString()][string]$ServiceAccount = "",
        [switch]$ServiceModify,
        [Parameter(Mandatory = $true)][string]$Context,
        [AllowNull()][scriptblock]$TestPhaseHook
    )

    $boundary = Resolve-SyncVisionInstallDirectoryCreationBoundary `
        -Path $Path `
        -ServiceAccount $ServiceAccount `
        -Context $Context
    $fullPath = $boundary.Path
    $missing = New-Object "System.Collections.Generic.Stack[string]"
    foreach ($missingPath in @($boundary.MissingPaths)) {
        $missing.Push([string]$missingPath)
    }
    if ($missing.Count -eq 0) {
        $resolved = Assert-SyncVisionProtectedInstallDirectory `
            -Path $fullPath `
            -ServiceAccount $ServiceAccount `
            -ServiceModify:$ServiceModify `
            -Context $Context
        Assert-SyncVisionInstallAncestorBoundary `
            -Path (Split-Path -Parent $resolved) `
            -Context "$Context ancestor" `
            -ServiceAccount $ServiceAccount `
            -AllowProgramDataAtomicCreate
        return $resolved
    }

    while ($missing.Count -ne 0) {
        $nextPath = $missing.Pop()
        $isLeaf = [string]::Equals($nextPath, $fullPath, [StringComparison]::OrdinalIgnoreCase)
        $nextServiceModify = [bool]($ServiceModify -and $isLeaf)
        if (-not (Test-Path -LiteralPath $nextPath)) {
            [IO.Directory]::CreateDirectory(
                $nextPath,
                (New-SyncVisionProtectedInstallDirectorySecurity `
                    -ServiceAccount $ServiceAccount `
                    -ServiceModify:$nextServiceModify)) | Out-Null
            if ($null -ne $TestPhaseHook) {
                & $TestPhaseHook "AfterProtectedInstallDirectoryComponentCreated" ([pscustomobject]@{
                        Path = $fullPath
                        CreatedPath = $nextPath
                        ServiceModify = $nextServiceModify
                    })
            }
        }
        Assert-SyncVisionProtectedInstallDirectory `
            -Path $nextPath `
            -ServiceAccount $ServiceAccount `
            -ServiceModify:$nextServiceModify `
            -Context $Context | Out-Null
    }
    Assert-SyncVisionInstallAncestorBoundary `
        -Path (Split-Path -Parent $fullPath) `
        -Context "$Context ancestor" `
        -ServiceAccount $ServiceAccount `
        -AllowProgramDataAtomicCreate
    return (Resolve-Path -LiteralPath $fullPath).Path
}

function Get-SyncVisionTrustedDestinationSids {
    return @(
        "S-1-5-18",
        "S-1-5-32-544",
        "S-1-5-80-956008885-3418522649-1831038044-1853292631-2271478464"
    )
}

function Assert-SyncVisionServerInstallPathAcl {
    param(
        [Parameter(Mandatory = $true)][string]$Path,
        [Parameter(Mandatory = $true)][bool]$RejectWrite,
        [Parameter(Mandatory = $true)][string]$Context
    )

    $item = Get-Item -LiteralPath $Path -Force
    if (($item.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
        throw "$Context is a reparse point: $($item.FullName)"
    }
    $trustedSids = @(Get-SyncVisionTrustedDestinationSids)
    $acl = Get-Acl -LiteralPath $item.FullName
    $ownerSid = $acl.GetOwner([Security.Principal.SecurityIdentifier]).Value
    if ($trustedSids -notcontains $ownerSid) {
        throw "$Context has an untrusted owner SID $ownerSid at $($item.FullName)."
    }
    $dangerousRights = [Security.AccessControl.FileSystemRights]::DeleteSubdirectoriesAndFiles -bor
        [Security.AccessControl.FileSystemRights]::Delete -bor
        [Security.AccessControl.FileSystemRights]::ChangePermissions -bor
        [Security.AccessControl.FileSystemRights]::TakeOwnership
    if ($RejectWrite) {
        $dangerousRights = $dangerousRights -bor
            [Security.AccessControl.FileSystemRights]::WriteData -bor
            [Security.AccessControl.FileSystemRights]::AppendData -bor
            [Security.AccessControl.FileSystemRights]::WriteAttributes -bor
            [Security.AccessControl.FileSystemRights]::WriteExtendedAttributes
    }
    foreach ($rule in $acl.GetAccessRules($true, $true, [Security.Principal.SecurityIdentifier])) {
        $applies = ($rule.PropagationFlags -band [Security.AccessControl.PropagationFlags]::InheritOnly) -eq 0
        if ($applies -and
            $rule.AccessControlType -eq [Security.AccessControl.AccessControlType]::Allow -and
            $trustedSids -notcontains $rule.IdentityReference.Value -and
            ($rule.FileSystemRights -band $dangerousRights) -ne 0) {
            $rightClass = if ($RejectWrite) { "write, modify, delete, or ACL-control" } else { "delete or ACL-control" }
            throw "$Context grants unprivileged SID $($rule.IdentityReference.Value) $rightClass rights at $($item.FullName)."
        }
    }
    return $item.FullName
}

function New-SyncVisionProtectedServerPublicationDirectorySecurity {
    $acl = New-Object System.Security.AccessControl.DirectorySecurity
    $acl.SetAccessRuleProtection($true, $false)
    $inheritance = [Security.AccessControl.InheritanceFlags]"ContainerInherit, ObjectInherit"
    $propagation = [Security.AccessControl.PropagationFlags]::None
    $allow = [Security.AccessControl.AccessControlType]::Allow
    $administratorsSid = [Security.Principal.SecurityIdentifier]::new(
        [Security.Principal.WellKnownSidType]::BuiltinAdministratorsSid,
        $null)
    $systemSid = [Security.Principal.SecurityIdentifier]::new(
        [Security.Principal.WellKnownSidType]::LocalSystemSid,
        $null)
    $usersSid = [Security.Principal.SecurityIdentifier]::new(
        [Security.Principal.WellKnownSidType]::BuiltinUsersSid,
        $null)
    $acl.SetOwner($administratorsSid)
    foreach ($sid in @($administratorsSid, $systemSid)) {
        $acl.AddAccessRule([Security.AccessControl.FileSystemAccessRule]::new(
                $sid,
                [Security.AccessControl.FileSystemRights]::FullControl,
                $inheritance,
                $propagation,
                $allow)) | Out-Null
    }
    $acl.AddAccessRule([Security.AccessControl.FileSystemAccessRule]::new(
            $usersSid,
            [Security.AccessControl.FileSystemRights]"ReadAndExecute, Synchronize",
            $inheritance,
            $propagation,
            $allow)) | Out-Null
    return $acl
}

function Assert-SyncVisionServerInstallDestinationBoundary {
    param([Parameter(Mandatory = $true)][string]$InstallDir)

    $basePath = Get-SyncVisionCurrentFileSystemProviderPath
    $installPath = (Resolve-SyncVisionUserFileSystemPath `
            -Path $InstallDir `
            -BasePath $basePath `
            -Context "Server install destination").TrimEnd('\', '/')
    if ($installPath.StartsWith('\\?\UNC\', [StringComparison]::OrdinalIgnoreCase) -or
        ($installPath.StartsWith('\\', [StringComparison]::Ordinal) -and
            -not $installPath.StartsWith('\\?\', [StringComparison]::Ordinal))) {
        throw "Server install destination must be a local filesystem path; UNC paths are rejected before mutation: $installPath"
    }
    if ($installPath -match '^[A-Za-z]:\\') {
        $drive = Get-PSDrive -Name $installPath.Substring(0, 1) -PSProvider FileSystem -ErrorAction SilentlyContinue
        if ($null -ne $drive -and
            -not [string]::IsNullOrWhiteSpace([string]$drive.DisplayRoot) -and
            [string]$drive.DisplayRoot.StartsWith('\\', [StringComparison]::Ordinal)) {
            throw "Server install destination must not use a mapped network drive; use a local volume path: $installPath"
        }
    }
    $volumeRoot = [IO.Path]::GetPathRoot($installPath).TrimEnd('\', '/')
    if ([string]::IsNullOrWhiteSpace((Split-Path -Leaf $installPath)) -or
        [string]::Equals($installPath, $volumeRoot, [StringComparison]::OrdinalIgnoreCase)) {
        throw "Server install destination must be a non-root directory path: $installPath"
    }

    $existingAncestor = $installPath
    while (-not (Test-Path -LiteralPath $existingAncestor)) {
        $parent = Split-Path -Parent $existingAncestor
        if ([string]::IsNullOrWhiteSpace($parent) -or $parent -eq $existingAncestor) {
            throw "Server install destination has no existing ancestor: $installPath"
        }
        $existingAncestor = $parent
    }
    $existingItem = Get-Item -LiteralPath $existingAncestor -Force
    if (-not $existingItem.PSIsContainer) {
        throw "Server install destination existing ancestor is not a directory: $existingAncestor"
    }
    $mutationBoundaryPaths = New-Object "System.Collections.Generic.HashSet[string]" ([StringComparer]::OrdinalIgnoreCase)
    $programDataPath = [IO.Path]::GetFullPath(
        [Environment]::GetFolderPath([Environment+SpecialFolder]::CommonApplicationData)).TrimEnd('\', '/')
    $atomicProgramDataCreate = -not (Test-Path -LiteralPath $installPath) -and
        [string]::Equals($existingItem.FullName.TrimEnd('\', '/'), $programDataPath, [StringComparison]::OrdinalIgnoreCase)
    if (-not $atomicProgramDataCreate) {
        [void]$mutationBoundaryPaths.Add($existingItem.FullName.TrimEnd('\', '/'))
    }
    if (Test-Path -LiteralPath $installPath -PathType Container) {
        [void]$mutationBoundaryPaths.Add((Split-Path -Parent $installPath).TrimEnd('\', '/'))
        [void]$mutationBoundaryPaths.Add($installPath)
    }
    $current = $existingItem
    while ($null -ne $current) {
        Assert-SyncVisionServerInstallPathAcl `
            -Path $current.FullName `
            -RejectWrite ($mutationBoundaryPaths.Contains($current.FullName.TrimEnd('\', '/'))) `
            -Context "Server install destination ancestor" | Out-Null
        $current = $current.Parent
    }

    if (-not (Test-Path -LiteralPath $installPath)) {
        return $installPath
    }
    if (-not (Test-Path -LiteralPath $installPath -PathType Container)) {
        throw "Server install destination exists and is not a directory: $installPath"
    }
    Assert-SyncVisionServerInstallPathAcl -Path $installPath -RejectWrite $true -Context "Server install destination" | Out-Null

    $managedNames = New-Object "System.Collections.Generic.HashSet[string]" ([StringComparer]::OrdinalIgnoreCase)
    foreach ($name in (Get-SyncVisionManagedServerInstallFileNames)) {
        [void]$managedNames.Add($name)
    }
    foreach ($item in (Get-ChildItem -LiteralPath $installPath -Force)) {
        if (($item.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
            throw "Server install destination contains a reparse entry: $($item.Name)"
        }
        if ($item.PSIsContainer -or -not $managedNames.Contains($item.Name)) {
            throw "Server install destination contains an unexpected unmanaged entry: $($item.Name)"
        }
    }
    return $installPath
}

function Initialize-SyncVisionServerInstallParentBoundary {
    param([Parameter(Mandatory = $true)][string]$InstallDir)

    $installPath = Assert-SyncVisionServerInstallDestinationBoundary -InstallDir $InstallDir
    $parentPath = Split-Path -Parent $installPath
    $boundary = Resolve-SyncVisionInstallDirectoryCreationBoundary `
        -Path $parentPath `
        -Context "Server install publication parent"
    $missing = New-Object "System.Collections.Generic.Stack[string]"
    foreach ($path in @($boundary.MissingPaths)) { $missing.Push([string]$path) }
    while ($missing.Count -ne 0) {
        $next = $missing.Pop()
        if (-not (Test-Path -LiteralPath $next)) {
            [IO.Directory]::CreateDirectory(
                $next,
                (New-SyncVisionProtectedServerPublicationDirectorySecurity)) | Out-Null
        }
        Assert-SyncVisionServerInstallPathAcl `
            -Path $next `
            -RejectWrite $true `
            -Context "Server install publication parent" | Out-Null
    }
    Assert-SyncVisionServerInstallDestinationBoundary -InstallDir $installPath | Out-Null
    return (Resolve-Path -LiteralPath $parentPath).ProviderPath
}

function Assert-SyncVisionExactServerInstallTree {
    param(
        [Parameter(Mandatory = $true)][string]$InstallDir,
        [Parameter(Mandatory = $true)][object[]]$StagedInputs
    )

    $installPath = Assert-SyncVisionServerInstallDestinationBoundary -InstallDir $InstallDir
    if (-not (Test-Path -LiteralPath $installPath -PathType Container)) {
        throw "Exact server install destination was not found: $installPath"
    }
    $expected = New-Object "System.Collections.Generic.Dictionary[string,object]" ([StringComparer]::OrdinalIgnoreCase)
    foreach ($input in $StagedInputs) {
        $name = if ($null -ne $input.PSObject.Properties["DestinationName"]) {
            [string]$input.DestinationName
        }
        else {
            Split-Path -Leaf $input.Path
        }
        if ($expected.ContainsKey($name)) {
            throw "Exact server install verification found a duplicate expected name: $name"
        }
        if ($null -eq $input.PSObject.Properties["ExpectedLength"] -or [int64]$input.ExpectedLength -lt 0) {
            throw "Exact server install verification is missing a reviewed file length for: $name"
        }
        $expected.Add($name, [pscustomobject]@{
                Length = [int64]$input.ExpectedLength
                Hash = [string]$input.ExpectedHash
            })
    }
    $observed = @(Get-ChildItem -LiteralPath $installPath -Force)
    if ($observed.Count -ne $expected.Count) {
        throw "Exact server install verification found an unexpected destination entry count. Expected $($expected.Count), got $($observed.Count)."
    }
    foreach ($file in $observed) {
        if ($file.PSIsContainer -or ($file.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
            throw "Exact server install verification found a non-regular destination entry: $($file.Name)"
        }
        Assert-SyncVisionFileTrustMetadata `
            -Path $file.FullName `
            -Context "Exact server install verification" | Out-Null
        if (-not $expected.ContainsKey($file.Name)) {
            throw "Exact server install verification found an unexpected destination entry: $($file.Name)"
        }
        $expectedIdentity = $expected[$file.Name]
        if ($file.Length -ne [int64]$expectedIdentity.Length) {
            throw "Exact server install verification length mismatch for $($file.Name). Expected $($expectedIdentity.Length), got $($file.Length)."
        }
        $actualHash = (Get-FileHash -LiteralPath $file.FullName -Algorithm SHA256).Hash.ToLowerInvariant()
        if ($actualHash -cne [string]$expectedIdentity.Hash) {
            throw "Exact server install verification hash mismatch for $($file.Name). Expected $($expectedIdentity.Hash), got $actualHash."
        }
    }
    foreach ($name in $expected.Keys) {
        if (-not (Test-Path -LiteralPath (Join-Path $installPath $name) -PathType Leaf)) {
            throw "Exact server install verification is missing destination file: $name"
        }
    }
    return $installPath
}

function Get-SyncVisionServerInstallJournalResourceIdentity {
    param([Parameter(Mandatory = $true)][string]$InstallDir)

    $installPath = Assert-SyncVisionServerInstallDestinationBoundary -InstallDir $InstallDir
    $parentPath = Split-Path -Parent $installPath
    if (-not (Test-Path -LiteralPath $parentPath -PathType Container)) {
        throw "Server install transaction journal requires the immediate install parent to exist before mutation: $parentPath"
    }
    $parentItem = Get-Item -LiteralPath $parentPath -Force
    if (($parentItem.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
        throw "Server install transaction journal parent is a reparse point: $($parentItem.FullName)"
    }

    $requestedLeaf = Split-Path -Leaf $installPath
    $canonicalLeaf = $requestedLeaf
    if (Test-Path -LiteralPath $installPath) {
        $installItem = Get-Item -LiteralPath $installPath -Force
        $canonicalTargetPath = Get-SyncVisionInstallCanonicalDirectoryPath -Path $installItem.FullName
        $canonicalLeaf = $canonicalTargetPath.Substring($canonicalTargetPath.LastIndexOf('\') + 1)
        if (-not [string]::Equals($requestedLeaf, $canonicalLeaf, [StringComparison]::OrdinalIgnoreCase)) {
            throw "Server install destination leaf aliases such as 8.3 short names are rejected before mutation; use the canonical directory name '$canonicalLeaf'."
        }
    }
    if ([string]::IsNullOrWhiteSpace($canonicalLeaf) -or
        -not [string]::Equals((Split-Path -Leaf $canonicalLeaf), $canonicalLeaf, [StringComparison]::Ordinal)) {
        throw "Server install transaction journal has an invalid canonical destination leaf: $canonicalLeaf"
    }

    $parentIdentity = Get-SyncVisionInstallFileSystemIdentity -Path $parentItem.FullName
    $lockResources = @(Get-SyncVisionInstallPathLockResources -Path $installPath)
    if ($lockResources -cnotcontains "PathIdentity|$parentIdentity") {
        throw "Server install transaction journal identity diverged from the install transaction lock resource."
    }
    return "ServerInstall|$parentIdentity|$($canonicalLeaf.ToUpperInvariant())"
}

function Get-SyncVisionServerInstallJournalBasePath {
    $commonApplicationData = [Environment]::GetFolderPath([Environment+SpecialFolder]::CommonApplicationData)
    if ([string]::IsNullOrWhiteSpace($commonApplicationData)) {
        throw "Server install transaction journal failed: CommonApplicationData is unavailable."
    }
    return Join-Path $commonApplicationData "SyncVisionInstallTransactions"
}

function Initialize-SyncVisionServerInstallJournalBase {
    $basePath = Get-SyncVisionServerInstallJournalBasePath
    $parentPath = Split-Path -Parent $basePath
    Assert-SyncVisionStagingAncestorChain -Path $parentPath
    if (Test-Path -LiteralPath $basePath) {
        if (-not (Test-Path -LiteralPath $basePath -PathType Container)) {
            throw "Server install transaction journal base is not a directory: $basePath"
        }
        Assert-SyncVisionTrustedStagingDirectory -Path $basePath -Context "server install transaction journal base" | Out-Null
        Assert-SyncVisionStagingAncestorChain -Path $basePath
        return (Resolve-Path -LiteralPath $basePath).ProviderPath
    }

    [IO.Directory]::CreateDirectory(
        $basePath,
        (New-SyncVisionProtectedInstallStagingDirectorySecurity)) | Out-Null
    Assert-SyncVisionTrustedStagingDirectory -Path $basePath -Context "new server install transaction journal base" | Out-Null
    Assert-SyncVisionStagingAncestorChain -Path $basePath
    return (Resolve-Path -LiteralPath $basePath).ProviderPath
}

function Get-SyncVisionServerInstallJournalPath {
    param([Parameter(Mandatory = $true)][string]$InstallDir)

    $resourceIdentity = Get-SyncVisionServerInstallJournalResourceIdentity -InstallDir $InstallDir
    $resourceHash = Get-SyncVisionServerInstallJournalSha256 `
        -Bytes ([Text.UTF8Encoding]::new($false).GetBytes($resourceIdentity))
    return Join-Path (Initialize-SyncVisionServerInstallJournalBase) ("server-$resourceHash.journal")
}

function Get-SyncVisionServerInstallIntentPath {
    param([Parameter(Mandatory = $true)][string]$InstallDir)

    $journalPath = Get-SyncVisionServerInstallJournalPath -InstallDir $InstallDir
    return [IO.Path]::ChangeExtension($journalPath, ".intent")
}

function Get-SyncVisionServerInstallIntentTemporaryPath {
    param([Parameter(Mandatory = $true)][string]$InstallDir)

    return (Get-SyncVisionServerInstallIntentPath -InstallDir $InstallDir) + ".tmp"
}

function Get-SyncVisionServerInstallJournalTemporaryPath {
    param([Parameter(Mandatory = $true)][string]$InstallDir)

    return (Get-SyncVisionServerInstallJournalPath -InstallDir $InstallDir) + ".tmp"
}

function Get-SyncVisionServerInstallResourceStateTemporaryPath {
    param(
        [Parameter(Mandatory = $true)][string]$InstallDir,
        [Parameter(Mandatory = $true)][string]$TransactionId
    )

    return (Get-SyncVisionServerInstallResourceStatePath `
            -InstallDir $InstallDir `
            -TransactionId $TransactionId) + ".tmp"
}

function Get-SyncVisionInstallIntentCanonicalPath {
    param([Parameter(Mandatory = $true)][string]$Path)

    $fullPath = [IO.Path]::GetFullPath($Path)
    $root = [IO.Path]::GetPathRoot($fullPath)
    if ([string]::Equals($fullPath, $root, [StringComparison]::OrdinalIgnoreCase)) {
        return $root
    }
    return $fullPath.TrimEnd('\', '/')
}

function Assert-SyncVisionIntentObjectProperties {
    param(
        [Parameter(Mandatory = $true)][object]$Object,
        [Parameter(Mandatory = $true)][string[]]$Expected,
        [string[]]$Optional = @(),
        [Parameter(Mandatory = $true)][string]$Context
    )

    $actual = @($Object.PSObject.Properties | ForEach-Object Name | Sort-Object)
    $orderedExpected = @($Expected | Sort-Object)
    $allowed = @($Expected + $Optional | Sort-Object -Unique)
    if (@($orderedExpected | Where-Object { $actual -cnotcontains $_ }).Count -ne 0 -or
        @($actual | Where-Object { $allowed -cnotcontains $_ }).Count -ne 0) {
        throw "$Context contains missing, duplicate, or unknown properties."
    }
}

function Assert-SyncVisionServerInstallIntent {
    param(
        [Parameter(Mandatory = $true)][object]$Intent,
        [AllowEmptyString()][string]$ExpectedInstallDir = ""
    )

    Assert-SyncVisionIntentObjectProperties `
        -Object $Intent `
        -Expected @(
            "Version", "Mode", "TransactionId", "InstallPath", "IntentPath",
            "JournalPath", "ResourceStatePath", "ServiceAccount", "WorkPaths",
            "LockResources", "FreshBoundaries") `
        -Optional @("IntentFileIdentity", "IntentSha256") `
        -Context "Server install transaction intent"
    if ($Intent.Version -isnot [int] -or [int]$Intent.Version -ne 1) {
        throw "Server install transaction intent has an unsupported version."
    }
    $mode = [string]$Intent.Mode
    if (@("Preparing", "Cleanup") -cnotcontains $mode) {
        throw "Server install transaction intent has an unsupported mode: $mode"
    }
    $transactionId = [string]$Intent.TransactionId
    if ($transactionId -cnotmatch '^[0-9a-f]{32}$') {
        throw "Server install transaction intent has an invalid transaction ID."
    }
    $installPath = Assert-SyncVisionServerInstallDestinationBoundary -InstallDir ([string]$Intent.InstallPath)
    if (-not [string]::IsNullOrWhiteSpace($ExpectedInstallDir)) {
        $expectedPath = Assert-SyncVisionServerInstallDestinationBoundary -InstallDir $ExpectedInstallDir
        if ((Get-SyncVisionServerInstallJournalResourceIdentity -InstallDir $installPath) -cne
            (Get-SyncVisionServerInstallJournalResourceIdentity -InstallDir $expectedPath)) {
            throw "Server install transaction intent belongs to a different canonical install resource."
        }
    }
    $expectedIntentPath = Get-SyncVisionServerInstallIntentPath -InstallDir $installPath
    $expectedJournalPath = Get-SyncVisionServerInstallJournalPath -InstallDir $installPath
    $expectedResourceStatePath = Get-SyncVisionServerInstallResourceStatePath `
        -InstallDir $installPath `
        -TransactionId $transactionId
    foreach ($pathCheck in @(
            [pscustomobject]@{ Name = "IntentPath"; Actual = [string]$Intent.IntentPath; Expected = $expectedIntentPath },
            [pscustomobject]@{ Name = "JournalPath"; Actual = [string]$Intent.JournalPath; Expected = $expectedJournalPath },
            [pscustomobject]@{ Name = "ResourceStatePath"; Actual = [string]$Intent.ResourceStatePath; Expected = $expectedResourceStatePath })) {
        if (-not [string]::Equals(
                (Get-SyncVisionInstallIntentCanonicalPath -Path $pathCheck.Actual),
                (Get-SyncVisionInstallIntentCanonicalPath -Path $pathCheck.Expected),
                [StringComparison]::OrdinalIgnoreCase)) {
            throw "Server install transaction intent $($pathCheck.Name) escaped its canonical boundary."
        }
    }

    $serviceAccount = [string]$Intent.ServiceAccount
    if ([string]::IsNullOrWhiteSpace($serviceAccount) -or $serviceAccount.Length -gt 256) {
        throw "Server install transaction intent has an invalid service account identity."
    }
    $stagingBase = Get-SyncVisionTrustedPackageStagingBasePath
    $expectedWorkLeaves = @(
        "txn-$transactionId-package",
        "txn-$transactionId-status",
        "txn-$transactionId-snapshot")
    $workPaths = @($Intent.WorkPaths | ForEach-Object {
            Get-SyncVisionInstallIntentCanonicalPath -Path ([string]$_)
        } | Sort-Object)
    if ($workPaths.Count -ne $expectedWorkLeaves.Count -or
        @($workPaths | Select-Object -Unique).Count -ne $workPaths.Count) {
        throw "Server install transaction intent has an invalid deterministic work-path set."
    }
    foreach ($workPath in $workPaths) {
        if (-not [string]::Equals(
                (Split-Path -Parent $workPath),
                (Get-SyncVisionInstallIntentCanonicalPath -Path $stagingBase),
                [StringComparison]::OrdinalIgnoreCase) -or
            $expectedWorkLeaves -cnotcontains (Split-Path -Leaf $workPath)) {
            throw "Server install transaction intent work path escaped its protected staging base: $workPath"
        }
    }

    $lockResources = @($Intent.LockResources | ForEach-Object { [string]$_ } | Sort-Object)
    if ($lockResources.Count -eq 0 -or
        $lockResources.Count -gt 512 -or
        @($lockResources | Select-Object -Unique).Count -ne $lockResources.Count) {
        throw "Server install transaction intent has an invalid lock-resource set."
    }
    foreach ($resource in $lockResources) {
        if ([string]::IsNullOrWhiteSpace($resource) -or $resource.Length -gt 32768) {
            throw "Server install transaction intent contains an invalid lock resource."
        }
        Get-SyncVisionInstallMutexName -Resource $resource | Out-Null
    }

    $boundaries = New-Object "System.Collections.Generic.List[object]"
    $roles = New-Object "System.Collections.Generic.HashSet[string]" ([StringComparer]::Ordinal)
    foreach ($boundary in @($Intent.FreshBoundaries)) {
        Assert-SyncVisionIntentObjectProperties `
            -Object $boundary `
            -Expected @("Role", "Path", "Existed", "ExistingPath", "ExistingIdentity", "ServiceModify", "MissingPaths") `
            -Context "Server install transaction intent fresh boundary"
        $role = [string]$boundary.Role
        if (@("data", "log") -cnotcontains $role -or -not $roles.Add($role)) {
            throw "Server install transaction intent has a duplicate or invalid fresh-boundary role: $role"
        }
        if ($boundary.Existed -isnot [bool] -or $boundary.ServiceModify -isnot [bool]) {
            throw "Server install transaction intent fresh-boundary flags must be Boolean."
        }
        $path = Get-SyncVisionInstallIntentCanonicalPath -Path ([string]$boundary.Path)
        $existingPath = Get-SyncVisionInstallIntentCanonicalPath -Path ([string]$boundary.ExistingPath)
        $existingIdentity = [string]$boundary.ExistingIdentity
        if ($existingIdentity -cnotmatch '^[0-9a-f]{8}:[0-9a-f]{16}$' -or
            -not (Test-Path -LiteralPath $existingPath -PathType Container) -or
            (Get-SyncVisionInstallFileSystemIdentity -Path $existingPath) -cne $existingIdentity) {
            throw "Server install transaction intent fresh-boundary ancestor identity changed: $existingPath"
        }
        $missingPaths = @($boundary.MissingPaths | ForEach-Object {
                Get-SyncVisionInstallIntentCanonicalPath -Path ([string]$_)
            })
        if ([bool]$boundary.Existed) {
            if ($missingPaths.Count -ne 0 -or
                -not [string]::Equals($path, $existingPath, [StringComparison]::OrdinalIgnoreCase)) {
                throw "Existing server install intent boundary contains missing path components."
            }
        }
        else {
            if ($missingPaths.Count -eq 0 -or
                -not [string]::Equals($missingPaths[0], $path, [StringComparison]::OrdinalIgnoreCase)) {
                throw "Fresh server install intent boundary is missing its target component chain."
            }
            for ($index = 0; $index -lt $missingPaths.Count; ++$index) {
                $expectedParent = if ($index + 1 -lt $missingPaths.Count) {
                    $missingPaths[$index + 1]
                }
                else { $existingPath }
                if (-not [string]::Equals(
                        (Split-Path -Parent $missingPaths[$index]),
                        $expectedParent,
                        [StringComparison]::OrdinalIgnoreCase)) {
                    throw "Fresh server install intent boundary contains a non-contiguous path chain."
                }
            }
        }
        $boundaries.Add([pscustomobject]@{
                Role = $role
                Path = $path
                Existed = [bool]$boundary.Existed
                ExistingPath = $existingPath
                ExistingIdentity = $existingIdentity
                ServiceModify = [bool]$boundary.ServiceModify
                MissingPaths = $missingPaths
            })
    }
    if ($roles.Count -ne 2) {
        throw "Server install transaction intent requires exact data and log fresh-boundary records."
    }

    $validated = [pscustomobject]@{
        Version = 1
        Mode = $mode
        TransactionId = $transactionId
        InstallPath = $installPath
        IntentPath = $expectedIntentPath
        JournalPath = $expectedJournalPath
        ResourceStatePath = $expectedResourceStatePath
        ServiceAccount = $serviceAccount
        WorkPaths = $workPaths
        LockResources = $lockResources
        FreshBoundaries = @($boundaries.ToArray() | Sort-Object Role)
    }
    foreach ($propertyName in @("IntentFileIdentity", "IntentSha256")) {
        if ($null -eq $Intent.PSObject.Properties[$propertyName] -or
            [string]::IsNullOrWhiteSpace([string]$Intent.$propertyName)) {
            continue
        }
        $value = [string]$Intent.$propertyName
        $pattern = if ($propertyName -ceq "IntentFileIdentity") {
            '^[0-9a-f]{8}:[0-9a-f]{16}$'
        }
        else { '^[0-9a-f]{64}$' }
        if ($value -cnotmatch $pattern) {
            throw "Server install transaction intent has an invalid in-memory $propertyName."
        }
        $validated | Add-Member -NotePropertyName $propertyName -NotePropertyValue $value
    }
    return $validated
}

function New-SyncVisionServerInstallIntent {
    param(
        [Parameter(Mandatory = $true)][string]$InstallDir,
        [Parameter(Mandatory = $true)][string]$TransactionId,
        [Parameter(Mandatory = $true)][string]$ServiceAccount,
        [Parameter(Mandatory = $true)][string[]]$WorkPaths,
        [Parameter(Mandatory = $true)][string[]]$LockResources,
        [Parameter(Mandatory = $true)][object[]]$FreshBoundaries,
        [ValidateSet("Preparing", "Cleanup")][string]$Mode = "Preparing"
    )

    $installPath = Assert-SyncVisionServerInstallDestinationBoundary -InstallDir $InstallDir
    $boundaryRecords = foreach ($entry in $FreshBoundaries) {
        [pscustomobject]@{
            Role = [string]$entry.Role
            Path = [string]$entry.Boundary.Path
            Existed = [bool]$entry.Boundary.Existed
            ExistingPath = [string]$entry.Boundary.ExistingPath
            ExistingIdentity = Get-SyncVisionInstallFileSystemIdentity -Path ([string]$entry.Boundary.ExistingPath)
            ServiceModify = [bool]$entry.ServiceModify
            MissingPaths = @($entry.Boundary.MissingPaths)
        }
    }
    return Assert-SyncVisionServerInstallIntent -Intent ([pscustomobject]@{
            Version = 1
            Mode = $Mode
            TransactionId = $TransactionId
            InstallPath = $installPath
            IntentPath = Get-SyncVisionServerInstallIntentPath -InstallDir $installPath
            JournalPath = Get-SyncVisionServerInstallJournalPath -InstallDir $installPath
            ResourceStatePath = Get-SyncVisionServerInstallResourceStatePath -InstallDir $installPath -TransactionId $TransactionId
            ServiceAccount = $ServiceAccount
            WorkPaths = $WorkPaths
            LockResources = $LockResources
            FreshBoundaries = @($boundaryRecords)
        })
}

function ConvertTo-SyncVisionServerInstallIntentPayload {
    param([Parameter(Mandatory = $true)][object]$Intent)

    $state = Assert-SyncVisionServerInstallIntent -Intent $Intent
    $payload = [ordered]@{
        Version = $state.Version
        Mode = $state.Mode
        TransactionId = $state.TransactionId
        InstallPath = $state.InstallPath
        IntentPath = $state.IntentPath
        JournalPath = $state.JournalPath
        ResourceStatePath = $state.ResourceStatePath
        ServiceAccount = $state.ServiceAccount
        WorkPaths = @($state.WorkPaths)
        LockResources = @($state.LockResources)
        FreshBoundaries = @($state.FreshBoundaries | ForEach-Object {
                [ordered]@{
                    Role = $_.Role
                    Path = $_.Path
                    Existed = $_.Existed
                    ExistingPath = $_.ExistingPath
                    ExistingIdentity = $_.ExistingIdentity
                    ServiceModify = $_.ServiceModify
                    MissingPaths = @($_.MissingPaths)
                }
            })
    }
    return ($payload | ConvertTo-Json -Compress -Depth 20)
}

function ConvertTo-SyncVisionServerInstallIntentText {
    param([Parameter(Mandatory = $true)][object]$Intent)

    $payload = ConvertTo-SyncVisionServerInstallIntentPayload -Intent $Intent
    $payloadBytes = [Text.UTF8Encoding]::new($false).GetBytes($payload)
    return @(
        "SYNCVISION_SERVER_INSTALL_INTENT",
        "version=1",
        "payload_b64=$([Convert]::ToBase64String($payloadBytes))",
        "payload_sha256=$(Get-SyncVisionServerInstallJournalSha256 -Bytes $payloadBytes)",
        "") -join "`n"
}

function ConvertFrom-SyncVisionServerInstallIntentText {
    param(
        [Parameter(Mandatory = $true)][string]$Text,
        [Parameter(Mandatory = $true)][string]$ExpectedInstallDir
    )

    if ($Text.Length -le 0 -or $Text.Length -gt 1048576 -or
        $Text[0] -eq [char]0xfeff -or $Text.IndexOf("`r") -ge 0 -or
        $Text.IndexOf([char]0) -ge 0 -or -not $Text.EndsWith("`n", [StringComparison]::Ordinal)) {
        throw "Server install transaction intent encoding or size is invalid."
    }
    $lines = $Text.Split([char]10)
    if ($lines.Count -ne 5 -or $lines[0] -cne "SYNCVISION_SERVER_INSTALL_INTENT" -or
        $lines[1] -cne "version=1" -or $lines[4] -cne "" -or
        -not $lines[2].StartsWith("payload_b64=", [StringComparison]::Ordinal) -or
        $lines[3] -cnotmatch '^payload_sha256=([0-9a-f]{64})$') {
        throw "Server install transaction intent envelope is invalid."
    }
    $expectedSha256 = $Matches[1]
    try { $payloadBytes = [Convert]::FromBase64String($lines[2].Substring("payload_b64=".Length)) }
    catch { throw "Server install transaction intent payload base64 is invalid: $($_.Exception.Message)" }
    if ([Convert]::ToBase64String($payloadBytes) -cne $lines[2].Substring("payload_b64=".Length) -or
        (Get-SyncVisionServerInstallJournalSha256 -Bytes $payloadBytes) -cne $expectedSha256) {
        throw "Server install transaction intent payload digest or canonical base64 is invalid."
    }
    try {
        $payloadText = [Text.UTF8Encoding]::new($false, $true).GetString($payloadBytes)
        $document = $payloadText | ConvertFrom-Json -ErrorAction Stop
    }
    catch { throw "Server install transaction intent JSON is invalid: $($_.Exception.Message)" }
    $intent = Assert-SyncVisionServerInstallIntent -Intent $document -ExpectedInstallDir $ExpectedInstallDir
    if ((ConvertTo-SyncVisionServerInstallIntentPayload -Intent $intent) -cne $payloadText) {
        throw "Server install transaction intent JSON is not in the exact canonical form."
    }
    return $intent
}

function Assert-SyncVisionServerInstallDurableFileVersionCurrent {
    param(
        [Parameter(Mandatory = $true)][string]$Path,
        [Parameter(Mandatory = $true)][string]$ExpectedIdentity,
        [Parameter(Mandatory = $true)][string]$ExpectedSha256,
        [Parameter(Mandatory = $true)][string]$Context
    )

    if ($ExpectedIdentity -cnotmatch '^[0-9a-f]{8}:[0-9a-f]{16}$' -or
        $ExpectedSha256 -cnotmatch '^[0-9a-f]{64}$') {
        throw "$Context update requires the File ID and SHA-256 returned by its protected read or write."
    }
    if ($null -eq (Get-SyncVisionServerInstallSiblingItem -Path $Path)) {
        throw "$Context disappeared before its compare-and-swap update."
    }
    $validatedPath = Assert-SyncVisionServerInstallJournalFileSecurity -Path $Path
    Assert-SyncVisionFileTrustMetadata -Path $validatedPath -Context $Context | Out-Null
    Initialize-SyncVisionInstallFileIdentityType
    if ([SyncVisionTask19FileIdentity]::GetLinkCount($validatedPath) -ne [uint32]1) {
        throw "$Context has an unsupported hard-link count before its compare-and-swap update."
    }
    $stream = [IO.File]::Open(
        $validatedPath,
        [IO.FileMode]::Open,
        [IO.FileAccess]::Read,
        [IO.FileShare]::Read)
    try {
        $identity = Get-SyncVisionInstallRegularFileIdentity -Path $validatedPath
        if ($stream.Length -le 0 -or $stream.Length -gt 1048576) {
            throw "$Context size is invalid before its compare-and-swap update."
        }
        $bytes = New-Object byte[] ([int]$stream.Length)
        $offset = 0
        while ($offset -lt $bytes.Length) {
            $read = $stream.Read($bytes, $offset, $bytes.Length - $offset)
            if ($read -le 0) { throw "$Context read ended early before its compare-and-swap update." }
            $offset += $read
        }
        $sha256 = Get-SyncVisionServerInstallJournalSha256 -Bytes $bytes
        if ($identity -cne $ExpectedIdentity -or $sha256 -cne $ExpectedSha256 -or
            (Get-SyncVisionInstallRegularFileIdentity -Path $validatedPath) -cne $identity) {
            throw "$Context File ID or SHA-256 changed before its compare-and-swap update."
        }
    }
    finally { $stream.Dispose() }
    return $validatedPath
}

function Write-SyncVisionServerInstallIntent {
    param(
        [Parameter(Mandatory = $true)][object]$Intent,
        [switch]$Replace,
        [AllowNull()][scriptblock]$TestPhaseHook
    )

    $state = Assert-SyncVisionServerInstallIntent -Intent $Intent
    $path = $state.IntentPath
    $temporaryPath = Get-SyncVisionServerInstallIntentTemporaryPath -InstallDir $state.InstallPath
    $existing = Get-SyncVisionServerInstallSiblingItem -Path $path
    $expectedIdentity = ""
    $expectedSha256 = ""
    if ($Replace) {
        if ($null -eq $existing) { throw "Server install transaction intent disappeared before its atomic mode update." }
        if ($null -eq $state.PSObject.Properties["IntentFileIdentity"] -or
            $null -eq $state.PSObject.Properties["IntentSha256"]) {
            throw "Server install transaction intent replacement requires its protected read version."
        }
        $expectedIdentity = [string]$state.IntentFileIdentity
        $expectedSha256 = [string]$state.IntentSha256
        Assert-SyncVisionServerInstallDurableFileVersionCurrent `
            -Path $path `
            -ExpectedIdentity $expectedIdentity `
            -ExpectedSha256 $expectedSha256 `
            -Context "Server install transaction intent" | Out-Null
    }
    elseif ($null -ne $existing) {
        throw "A server install transaction intent already exists for this install resource."
    }
    if ($null -ne (Get-SyncVisionServerInstallSiblingItem -Path $temporaryPath)) {
        throw "Server install transaction intent temporary file already exists; recovery must inspect it first."
    }
    $text = ConvertTo-SyncVisionServerInstallIntentText -Intent $state
    $bytes = [Text.UTF8Encoding]::new($false).GetBytes($text)
    try {
        $stream = [IO.File]::Create(
            $temporaryPath,
            4096,
            [IO.FileOptions]::WriteThrough,
            (New-SyncVisionServerInstallJournalFileSecurity))
        try {
            if ($null -ne $TestPhaseHook) { & $TestPhaseHook "AfterIntentTemporaryCreated" $state }
            $stream.Write($bytes, 0, $bytes.Length)
            $stream.Flush($true)
        }
        finally { $stream.Dispose() }
        if ($null -ne $TestPhaseHook) { & $TestPhaseHook "AfterIntentTemporaryFlushed" $state }
        Assert-SyncVisionExistingPathChainNoReparse -Path (Split-Path -Parent $path) -Context "Server install intent publication parent"
        Initialize-SyncVisionServerInstallJournalAtomicType
        if ($Replace) {
            Assert-SyncVisionServerInstallDurableFileVersionCurrent `
                -Path $path `
                -ExpectedIdentity $expectedIdentity `
                -ExpectedSha256 $expectedSha256 `
                -Context "Server install transaction intent" | Out-Null
            [SyncVisionServerInstallJournalAtomic]::Replace($temporaryPath, $path)
        }
        else {
            [SyncVisionServerInstallJournalAtomic]::PublishNew($temporaryPath, $path)
        }
        $validatedPath = Assert-SyncVisionServerInstallJournalFileSecurity -Path $path
        Assert-SyncVisionFileTrustMetadata -Path $validatedPath -Context "Server install transaction intent" | Out-Null
        Initialize-SyncVisionInstallFileIdentityType
        if ([SyncVisionTask19FileIdentity]::GetLinkCount($validatedPath) -ne [uint32]1) {
            throw "Server install transaction intent has an unsupported hard-link count."
        }
        $state | Add-Member -NotePropertyName IntentFileIdentity -NotePropertyValue (Get-SyncVisionInstallRegularFileIdentity -Path $validatedPath) -Force
        $state | Add-Member -NotePropertyName IntentSha256 -NotePropertyValue (Get-SyncVisionServerInstallJournalSha256 -Bytes $bytes) -Force
        if ($null -ne $TestPhaseHook) { & $TestPhaseHook "AfterIntentPublished" $state }
        return $state
    }
    finally {
        if (Test-Path -LiteralPath $temporaryPath -PathType Leaf) {
            $temporary = Assert-SyncVisionServerInstallJournalFileSecurity -Path $temporaryPath
            $temporaryIdentity = Get-SyncVisionInstallRegularFileIdentity -Path $temporary
            Initialize-SyncVisionServerInstallJournalAtomicType
            [SyncVisionServerInstallJournalAtomic]::DeleteIfIdentity($temporary, $temporaryIdentity)
        }
    }
}

function Read-SyncVisionServerInstallIntent {
    param(
        [Parameter(Mandatory = $true)][string]$InstallDir,
        [switch]$AllowMissing
    )

    $path = Get-SyncVisionServerInstallIntentPath -InstallDir $InstallDir
    if ($null -eq (Get-SyncVisionServerInstallSiblingItem -Path $path)) {
        if ($AllowMissing) { return $null }
        throw "Server install transaction intent was not found: $path"
    }
    $validatedPath = Assert-SyncVisionServerInstallJournalFileSecurity -Path $path
    Assert-SyncVisionFileTrustMetadata -Path $validatedPath -Context "Server install transaction intent" | Out-Null
    Initialize-SyncVisionInstallFileIdentityType
    if ([SyncVisionTask19FileIdentity]::GetLinkCount($validatedPath) -ne [uint32]1) {
        throw "Server install transaction intent has an unsupported hard-link count."
    }
    $stream = [IO.File]::Open($validatedPath, [IO.FileMode]::Open, [IO.FileAccess]::Read, [IO.FileShare]::Read)
    try {
        $identity = Get-SyncVisionInstallRegularFileIdentity -Path $validatedPath
        if ($stream.Length -le 0 -or $stream.Length -gt 1048576) {
            throw "Server install transaction intent size is invalid."
        }
        $bytes = New-Object byte[] ([int]$stream.Length)
        $offset = 0
        while ($offset -lt $bytes.Length) {
            $read = $stream.Read($bytes, $offset, $bytes.Length - $offset)
            if ($read -le 0) { throw "Server install transaction intent read ended early." }
            $offset += $read
        }
        try { $text = [Text.UTF8Encoding]::new($false, $true).GetString($bytes) }
        catch { throw "Server install transaction intent is not strict UTF-8: $($_.Exception.Message)" }
        $intent = ConvertFrom-SyncVisionServerInstallIntentText -Text $text -ExpectedInstallDir $InstallDir
        if ((Get-SyncVisionInstallRegularFileIdentity -Path $validatedPath) -cne $identity) {
            throw "Server install transaction intent identity changed while it was read."
        }
        $intent | Add-Member -NotePropertyName IntentFileIdentity -NotePropertyValue $identity -Force
        $intent | Add-Member -NotePropertyName IntentSha256 -NotePropertyValue (Get-SyncVisionServerInstallJournalSha256 -Bytes $bytes) -Force
        return $intent
    }
    finally { $stream.Dispose() }
}

function Set-SyncVisionServerInstallIntentMode {
    param(
        [Parameter(Mandatory = $true)][object]$Intent,
        [ValidateSet("Preparing", "Cleanup")][string]$Mode
    )

    $current = Read-SyncVisionServerInstallIntent -InstallDir ([string]$Intent.InstallPath)
    if ($current.TransactionId -cne [string]$Intent.TransactionId) {
        throw "Server install transaction intent changed transactions before its mode update."
    }
    if ($current.Mode -ceq $Mode) { return $current }
    if ($current.Mode -cne "Preparing" -or $Mode -cne "Cleanup") {
        throw "Server install transaction intent mode transition is invalid: $($current.Mode) -> $Mode"
    }
    $current.Mode = $Mode
    return Write-SyncVisionServerInstallIntent -Intent $current -Replace
}

function Remove-SyncVisionServerInstallIntent {
    param([Parameter(Mandatory = $true)][object]$Intent)

    $state = Assert-SyncVisionServerInstallIntent -Intent $Intent
    $current = Read-SyncVisionServerInstallIntent -InstallDir $state.InstallPath -AllowMissing
    if ($null -eq $current) { return }
    if ($current.TransactionId -cne $state.TransactionId) {
        throw "Refusing to remove a server install intent that changed transactions."
    }
    Initialize-SyncVisionServerInstallJournalAtomicType
    [SyncVisionServerInstallJournalAtomic]::DeleteIfIdentity($current.IntentPath, $current.IntentFileIdentity)
}

function Remove-SyncVisionServerInstallProtectedTemporaryFile {
    param(
        [Parameter(Mandatory = $true)][string]$Path,
        [Parameter(Mandatory = $true)][string]$Context
    )

    $item = Get-SyncVisionServerInstallSiblingItem -Path $Path
    if ($null -eq $item) { return }
    $expectedBase = Initialize-SyncVisionServerInstallJournalBase
    if (-not [string]::Equals(
            (Split-Path -Parent $item.FullName),
            $expectedBase,
            [StringComparison]::OrdinalIgnoreCase)) {
        throw "$Context escaped the protected transaction base."
    }
    $validatedPath = Assert-SyncVisionServerInstallJournalFileSecurity -Path $item.FullName
    Assert-SyncVisionFileTrustMetadata -Path $validatedPath -Context $Context | Out-Null
    Initialize-SyncVisionInstallFileIdentityType
    if ([SyncVisionTask19FileIdentity]::GetLinkCount($validatedPath) -ne [uint32]1) {
        throw "$Context has an unsupported hard-link count."
    }
    $identity = Get-SyncVisionInstallRegularFileIdentity -Path $validatedPath
    Initialize-SyncVisionServerInstallJournalAtomicType
    [SyncVisionServerInstallJournalAtomic]::DeleteIfIdentity($validatedPath, $identity)
}

function Remove-SyncVisionServerInstallIntentWorkPaths {
    param([Parameter(Mandatory = $true)][object]$Intent)

    $state = Assert-SyncVisionServerInstallIntent -Intent $Intent
    foreach ($workPath in $state.WorkPaths) {
        if (-not (Test-Path -LiteralPath $workPath)) { continue }
        $basePath = Initialize-SyncVisionTrustedPackageStagingBase
        $validatedPath = Assert-SyncVisionTrustedStagingPath `
            -BasePath $basePath `
            -StagingPath $workPath
        $parentLease = $null
        $workLease = $null
        try {
            $parentLease = Enter-SyncVisionInstallDirectoryLease `
                -Path $basePath `
                -ExpectedIdentity (Get-SyncVisionInstallFileSystemIdentity -Path $basePath)
            $workLease = Enter-SyncVisionInstallDirectoryLease `
                -Path $validatedPath `
                -ExpectedIdentity (Get-SyncVisionInstallFileSystemIdentity -Path $validatedPath) `
                -DeleteAccess
            $workLease.DeleteTree()
            Exit-SyncVisionInstallDirectoryLease -Lease $workLease
            $workLease = $null
            if (Test-Path -LiteralPath $validatedPath) {
                throw "Intent-owned protected work directory was replaced during cleanup: $validatedPath"
            }
        }
        finally {
            Exit-SyncVisionInstallDirectoryLease -Lease $workLease
            Exit-SyncVisionInstallDirectoryLease -Lease $parentLease
        }
    }
}

function Remove-SyncVisionServerInstallIntentFreshPaths {
    param([Parameter(Mandatory = $true)][object]$Intent)

    $state = Assert-SyncVisionServerInstallIntent -Intent $Intent
    if ($state.Mode -cne "Preparing") {
        throw "Fresh-path orphan cleanup is only valid before the complete journal boundary."
    }
    $planned = New-Object "System.Collections.Generic.Dictionary[string,bool]" ([StringComparer]::OrdinalIgnoreCase)
    foreach ($boundary in $state.FreshBoundaries) {
        if ((Get-SyncVisionInstallFileSystemIdentity -Path $boundary.ExistingPath) -cne $boundary.ExistingIdentity) {
            throw "Fresh-path cleanup ancestor identity changed: $($boundary.ExistingPath)"
        }
        if ($boundary.Existed) { continue }
        foreach ($missingPath in $boundary.MissingPaths) {
            if (-not $planned.ContainsKey($missingPath)) { $planned.Add($missingPath, $false) }
        }
        if ($boundary.ServiceModify -and $planned.ContainsKey($boundary.Path)) {
            $planned[$boundary.Path] = $true
        }
    }
    $roots = @($planned.Keys | Where-Object { -not $planned.ContainsKey((Split-Path -Parent $_)) } | Sort-Object)
    foreach ($root in $roots) {
        if (-not (Test-Path -LiteralPath $root)) { continue }
        $pending = New-Object "System.Collections.Generic.Stack[string]"
        $pending.Push($root)
        while ($pending.Count -ne 0) {
            $currentPath = $pending.Pop()
            $item = Get-Item -LiteralPath $currentPath -Force
            if (-not $item.PSIsContainer -or
                ($item.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0 -or
                -not $planned.ContainsKey($item.FullName.TrimEnd('\', '/'))) {
                throw "Pre-journal fresh-path cleanup found an unplanned or reparse entry: $($item.FullName)"
            }
            Assert-SyncVisionProtectedInstallDirectory `
                -Path $item.FullName `
                -ServiceAccount $state.ServiceAccount `
                -ServiceModify:$planned[$item.FullName.TrimEnd('\', '/')] `
                -Context "Pre-journal transaction-owned fresh directory" | Out-Null
            foreach ($child in (Get-ChildItem -LiteralPath $item.FullName -Force)) {
                if (($child.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0 -or -not $child.PSIsContainer) {
                    throw "Pre-journal fresh-path cleanup found content outside the planned empty directory topology: $($child.FullName)"
                }
                $pending.Push($child.FullName)
            }
        }

        $parentPath = Split-Path -Parent $root
        $parentLease = $null
        $rootLease = $null
        try {
            $parentLease = Enter-SyncVisionInstallDirectoryLease `
                -Path $parentPath `
                -ExpectedIdentity (Get-SyncVisionInstallFileSystemIdentity -Path $parentPath)
            $rootIdentity = Get-SyncVisionInstallFileSystemIdentity -Path $root
            $rootLease = Enter-SyncVisionInstallDirectoryLease `
                -Path $root `
                -ExpectedIdentity $rootIdentity `
                -DeleteAccess
            $rootLease.DeleteTree()
            Exit-SyncVisionInstallDirectoryLease -Lease $rootLease
            $rootLease = $null
            if (Test-Path -LiteralPath $root) {
                throw "Pre-journal fresh-path cleanup found a replacement after deleting its exact owned root: $root"
            }
        }
        finally {
            Exit-SyncVisionInstallDirectoryLease -Lease $rootLease
            Exit-SyncVisionInstallDirectoryLease -Lease $parentLease
        }
    }
}

function Remove-SyncVisionServerInstallIntentResourceState {
    param([Parameter(Mandatory = $true)][object]$Intent)

    $state = Assert-SyncVisionServerInstallIntent -Intent $Intent
    $path = $state.ResourceStatePath
    if ($null -eq (Get-SyncVisionServerInstallSiblingItem -Path $path)) { return }
    $validatedPath = Assert-SyncVisionServerInstallJournalFileSecurity -Path $path
    Assert-SyncVisionFileTrustMetadata -Path $validatedPath -Context "Orphan durable resource state" | Out-Null
    Initialize-SyncVisionInstallFileIdentityType
    if ([SyncVisionTask19FileIdentity]::GetLinkCount($validatedPath) -ne [uint32]1) {
        throw "Orphan durable resource state has an unsupported hard-link count."
    }
    $identity = Get-SyncVisionInstallRegularFileIdentity -Path $validatedPath
    $stream = [IO.File]::Open($validatedPath, [IO.FileMode]::Open, [IO.FileAccess]::Read, [IO.FileShare]::Read)
    try {
        if ($stream.Length -le 0 -or $stream.Length -gt 16777216) {
            throw "Orphan durable resource-state size is invalid."
        }
        $bytes = New-Object byte[] ([int]$stream.Length)
        $offset = 0
        while ($offset -lt $bytes.Length) {
            $read = $stream.Read($bytes, $offset, $bytes.Length - $offset)
            if ($read -le 0) { throw "Orphan durable resource-state read ended early." }
            $offset += $read
        }
        try { $document = [Text.UTF8Encoding]::new($false, $true).GetString($bytes) | ConvertFrom-Json -ErrorAction Stop }
        catch { throw "Orphan durable resource-state JSON is invalid: $($_.Exception.Message)" }
        if ([int]$document.SchemaVersion -ne 1 -or
            [string]$document.TransactionId -cne $state.TransactionId -or
            [string]::IsNullOrWhiteSpace([string]$document.BackendKind) -or
            $null -eq $document.State) {
            throw "Orphan durable resource state does not match its protected transaction intent."
        }
    }
    finally { $stream.Dispose() }
    if ((Get-SyncVisionInstallRegularFileIdentity -Path $validatedPath) -cne $identity) {
        throw "Orphan durable resource-state identity changed before cleanup."
    }
    Initialize-SyncVisionServerInstallJournalAtomicType
    [SyncVisionServerInstallJournalAtomic]::DeleteIfIdentity($validatedPath, $identity)
}

function Invoke-SyncVisionServerInstallIntentOnlyRecovery {
    param([Parameter(Mandatory = $true)][object]$Intent)

    $state = Assert-SyncVisionServerInstallIntent -Intent $Intent
    if ($null -ne (Read-SyncVisionServerInstallJournal -InstallDir $state.InstallPath -AllowMissing)) {
        throw "Intent-only recovery found a complete journal and cannot use the pre-journal cleanup path."
    }
    Remove-SyncVisionServerInstallProtectedTemporaryFile `
        -Path (Get-SyncVisionServerInstallJournalTemporaryPath -InstallDir $state.InstallPath) `
        -Context "Server install journal temporary file"
    Remove-SyncVisionServerInstallProtectedTemporaryFile `
        -Path (Get-SyncVisionServerInstallResourceStateTemporaryPath `
            -InstallDir $state.InstallPath `
            -TransactionId $state.TransactionId) `
        -Context "Server install resource-state temporary file"
    Remove-SyncVisionServerInstallIntentWorkPaths -Intent $state
    if ($state.Mode -ceq "Preparing") {
        Remove-SyncVisionServerInstallIntentFreshPaths -Intent $state
    }
    Remove-SyncVisionServerInstallIntentResourceState -Intent $state
    $action = if ($state.Mode -ceq "Preparing") { "PreJournalCleanup" } else { "PostJournalCleanup" }
    $transactionId = $state.TransactionId
    Remove-SyncVisionServerInstallIntent -Intent $state
    return [pscustomobject]@{ Recovered = $true; Action = $action; TransactionId = $transactionId }
}

function Get-SyncVisionServerInstallJournalPhases {
    return @(
        "Prepared",
        "ServiceStopPending",
        "ServiceStopMutationStarted",
        "ServiceStopped",
        "DirectoriesPending",
        "DirectoriesApplied",
        "BackupMovePending",
        "BackupMoved",
        "PublishMovePending",
        "Published",
        "ConfigPending",
        "ConfigApplied",
        "ServiceDefinitionPending",
        "ServiceDefinitionMutationStarted",
        "ServiceDefinitionApplied",
        "FirewallPending",
        "FirewallMutationStarted",
        "FirewallApplied",
        "ServiceStartPending",
        "ServiceStarted",
        "VerificationPending",
        "Verified",
        "ForwardCommitted",
        "Committed")
}

function Get-SyncVisionServerInstallSiblingItem {
    param([Parameter(Mandatory = $true)][string]$Path)

    $fullPath = [IO.Path]::GetFullPath($Path).TrimEnd('\', '/')
    $parentPath = Split-Path -Parent $fullPath
    $leafName = Split-Path -Leaf $fullPath
    if (-not (Test-Path -LiteralPath $parentPath -PathType Container)) { return $null }
    $matches = @(Get-ChildItem -LiteralPath $parentPath -Force | Where-Object {
            [string]::Equals($_.Name, $leafName, [StringComparison]::OrdinalIgnoreCase)
        })
    if ($matches.Count -gt 1) {
        throw "Server install transaction boundary contains duplicate sibling names for: $fullPath"
    }
    if ($matches.Count -eq 0) { return $null }
    return $matches[0]
}

function New-SyncVisionServerInstallJournalFileSecurity {
    $security = [Security.AccessControl.FileSecurity]::new()
    $security.SetAccessRuleProtection($true, $false)
    $allow = [Security.AccessControl.AccessControlType]::Allow
    $noInheritance = [Security.AccessControl.InheritanceFlags]::None
    $noPropagation = [Security.AccessControl.PropagationFlags]::None
    $administratorsSid = [Security.Principal.SecurityIdentifier]::new(
        [Security.Principal.WellKnownSidType]::BuiltinAdministratorsSid,
        $null)
    $systemSid = [Security.Principal.SecurityIdentifier]::new(
        [Security.Principal.WellKnownSidType]::LocalSystemSid,
        $null)
    $security.SetOwner($administratorsSid)
    foreach ($sid in @($administratorsSid, $systemSid)) {
        $security.AddAccessRule([Security.AccessControl.FileSystemAccessRule]::new(
                $sid,
                [Security.AccessControl.FileSystemRights]::FullControl,
                $noInheritance,
                $noPropagation,
                $allow)) | Out-Null
    }
    return $security
}

function Initialize-SyncVisionServerInstallJournalAtomicType {
    if ("SyncVisionServerInstallJournalAtomic" -as [type]) { return }

    Add-Type -TypeDefinition @'
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;

public static class SyncVisionServerInstallJournalAtomic
{
    private const uint MOVEFILE_REPLACE_EXISTING = 0x00000001u;
    private const uint MOVEFILE_WRITE_THROUGH = 0x00000008u;
    private const uint DELETE = 0x00010000u;
    private const uint FILE_SHARE_READ = 0x00000001u;
    private const uint FILE_SHARE_WRITE = 0x00000002u;
    private const uint FILE_SHARE_DELETE = 0x00000004u;
    private const uint OPEN_EXISTING = 3u;
    private const uint FILE_FLAG_OPEN_REPARSE_POINT = 0x00200000u;
    private const uint FILE_ATTRIBUTE_DIRECTORY = 0x00000010u;
    private const uint FILE_ATTRIBUTE_REPARSE_POINT = 0x00000400u;

    [StructLayout(LayoutKind.Sequential)]
    private struct BY_HANDLE_FILE_INFORMATION
    {
        public uint FileAttributes;
        public System.Runtime.InteropServices.ComTypes.FILETIME CreationTime;
        public System.Runtime.InteropServices.ComTypes.FILETIME LastAccessTime;
        public System.Runtime.InteropServices.ComTypes.FILETIME LastWriteTime;
        public uint VolumeSerialNumber;
        public uint FileSizeHigh;
        public uint FileSizeLow;
        public uint NumberOfLinks;
        public uint FileIndexHigh;
        public uint FileIndexLow;
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct FILE_DISPOSITION_INFO
    {
        [MarshalAs(UnmanagedType.U1)]
        public bool DeleteFile;
    }

    [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    private static extern bool MoveFileEx(string existingFileName, string newFileName, uint flags);

    [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    private static extern SafeFileHandle CreateFile(
        string fileName,
        uint desiredAccess,
        uint shareMode,
        IntPtr securityAttributes,
        uint creationDisposition,
        uint flagsAndAttributes,
        IntPtr templateFile);

    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern bool GetFileInformationByHandle(
        SafeFileHandle handle,
        out BY_HANDLE_FILE_INFORMATION information);

    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern bool SetFileInformationByHandle(
        SafeFileHandle handle,
        int fileInformationClass,
        ref FILE_DISPOSITION_INFO fileInformation,
        uint bufferSize);

    public static void Replace(string sourcePath, string destinationPath)
    {
        if (!MoveFileEx(
                sourcePath,
                destinationPath,
                MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH))
        {
            throw new Win32Exception(Marshal.GetLastWin32Error(), "Atomic journal replacement failed.");
        }
    }

    public static void PublishNew(string sourcePath, string destinationPath)
    {
        if (!MoveFileEx(sourcePath, destinationPath, MOVEFILE_WRITE_THROUGH))
        {
            throw new Win32Exception(
                Marshal.GetLastWin32Error(),
                "Atomic transaction-intent publication failed without replacement.");
        }
    }

    public static void DeleteIfIdentity(string path, string expectedIdentity)
    {
        using (SafeFileHandle handle = CreateFile(
            path,
            DELETE,
            FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
            IntPtr.Zero,
            OPEN_EXISTING,
            FILE_FLAG_OPEN_REPARSE_POINT,
            IntPtr.Zero))
        {
            if (handle.IsInvalid)
            {
                throw new Win32Exception(Marshal.GetLastWin32Error(), "Opening journal for identity-bound deletion failed.");
            }
            BY_HANDLE_FILE_INFORMATION information;
            if (!GetFileInformationByHandle(handle, out information))
            {
                throw new Win32Exception(Marshal.GetLastWin32Error(), "Reading journal identity before deletion failed.");
            }
            if ((information.FileAttributes & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT)) != 0)
            {
                throw new InvalidOperationException("Journal identity-bound deletion requires a regular non-reparse file.");
            }
            string actualIdentity = information.VolumeSerialNumber.ToString("x8") + ":" +
                information.FileIndexHigh.ToString("x8") + information.FileIndexLow.ToString("x8");
            if (!String.Equals(actualIdentity, expectedIdentity, StringComparison.Ordinal))
            {
                throw new InvalidOperationException("Journal file identity changed at final deletion use.");
            }
            FILE_DISPOSITION_INFO disposition = new FILE_DISPOSITION_INFO { DeleteFile = true };
            if (!SetFileInformationByHandle(
                handle,
                4,
                ref disposition,
                (uint)Marshal.SizeOf(typeof(FILE_DISPOSITION_INFO))))
            {
                throw new Win32Exception(Marshal.GetLastWin32Error(), "Identity-bound journal deletion failed.");
            }
        }
    }
}
'@
}

function Initialize-SyncVisionInstallDirectoryLeaseType {
    if ("SyncVisionInstallDirectoryLeaseV1" -as [type]) { return }

    Add-Type -TypeDefinition @'
using System;
using System.ComponentModel;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using Microsoft.Win32.SafeHandles;

public sealed class SyncVisionInstallDirectoryLeaseV1 : IDisposable
{
    private const uint DELETE = 0x00010000u;
    private const uint FILE_LIST_DIRECTORY = 0x00000001u;
    private const uint FILE_READ_ATTRIBUTES = 0x00000080u;
    private const uint FILE_WRITE_ATTRIBUTES = 0x00000100u;
    private const uint FILE_SHARE_READ = 0x00000001u;
    private const uint FILE_SHARE_WRITE = 0x00000002u;
    private const uint OPEN_EXISTING = 3u;
    private const uint FILE_FLAG_OPEN_REPARSE_POINT = 0x00200000u;
    private const uint FILE_FLAG_BACKUP_SEMANTICS = 0x02000000u;
    private const uint FILE_ATTRIBUTE_READONLY = 0x00000001u;
    private const uint FILE_ATTRIBUTE_DIRECTORY = 0x00000010u;
    private const uint FILE_ATTRIBUTE_NORMAL = 0x00000080u;
    private const uint FILE_ATTRIBUTE_REPARSE_POINT = 0x00000400u;
    private const int FILE_RENAME_INFO_CLASS = 3;
    private const int FILE_DISPOSITION_INFO_CLASS = 4;
    private const int FILE_DISPOSITION_INFO_EX_CLASS = 21;
    private const int FILE_BASIC_INFO_CLASS = 0;
    private const uint FILE_DISPOSITION_FLAG_DELETE = 0x00000001u;
    private const uint FILE_DISPOSITION_FLAG_IGNORE_READONLY_ATTRIBUTE = 0x00000010u;

    [StructLayout(LayoutKind.Sequential)]
    private struct BY_HANDLE_FILE_INFORMATION
    {
        public uint FileAttributes;
        public System.Runtime.InteropServices.ComTypes.FILETIME CreationTime;
        public System.Runtime.InteropServices.ComTypes.FILETIME LastAccessTime;
        public System.Runtime.InteropServices.ComTypes.FILETIME LastWriteTime;
        public uint VolumeSerialNumber;
        public uint FileSizeHigh;
        public uint FileSizeLow;
        public uint NumberOfLinks;
        public uint FileIndexHigh;
        public uint FileIndexLow;
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct FILE_DISPOSITION_INFO
    {
        [MarshalAs(UnmanagedType.U1)]
        public bool DeleteFile;
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct FILE_DISPOSITION_INFO_EX
    {
        public uint Flags;
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct FILE_BASIC_INFO
    {
        public long CreationTime;
        public long LastAccessTime;
        public long LastWriteTime;
        public long ChangeTime;
        public uint FileAttributes;
    }

    [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    private static extern SafeFileHandle CreateFile(
        string fileName,
        uint desiredAccess,
        uint shareMode,
        IntPtr securityAttributes,
        uint creationDisposition,
        uint flagsAndAttributes,
        IntPtr templateFile);

    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern bool GetFileInformationByHandle(
        SafeFileHandle handle,
        out BY_HANDLE_FILE_INFORMATION information);

    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern bool GetFileInformationByHandleEx(
        SafeFileHandle handle,
        int fileInformationClass,
        out FILE_BASIC_INFO information,
        uint bufferSize);

    [DllImport("kernel32.dll", SetLastError = true, EntryPoint = "SetFileInformationByHandle")]
    private static extern bool SetFileInformationByHandleBuffer(
        SafeFileHandle handle,
        int fileInformationClass,
        IntPtr information,
        uint bufferSize);

    [DllImport("kernel32.dll", SetLastError = true, EntryPoint = "SetFileInformationByHandle")]
    private static extern bool SetFileInformationByHandleDisposition(
        SafeFileHandle handle,
        int fileInformationClass,
        ref FILE_DISPOSITION_INFO information,
        uint bufferSize);

    [DllImport("kernel32.dll", SetLastError = true, EntryPoint = "SetFileInformationByHandle")]
    private static extern bool SetFileInformationByHandleDispositionEx(
        SafeFileHandle handle,
        int fileInformationClass,
        ref FILE_DISPOSITION_INFO_EX information,
        uint bufferSize);

    [DllImport("kernel32.dll", SetLastError = true, EntryPoint = "SetFileInformationByHandle")]
    private static extern bool SetFileInformationByHandleBasic(
        SafeFileHandle handle,
        int fileInformationClass,
        ref FILE_BASIC_INFO information,
        uint bufferSize);

    private SafeFileHandle handle;
    private string path;
    private readonly string identity;
    private readonly bool deleteAccess;
    private bool deletePending;

    public static bool ForceLegacyDispositionForTest { get; set; }

    private SyncVisionInstallDirectoryLeaseV1(
        SafeFileHandle handle,
        string path,
        string identity,
        bool deleteAccess)
    {
        this.handle = handle;
        this.path = path;
        this.identity = identity;
        this.deleteAccess = deleteAccess;
    }

    public string Path
    {
        get { return this.path; }
    }

    public string Identity
    {
        get { return this.identity; }
    }

    public static SyncVisionInstallDirectoryLeaseV1 Open(
        string path,
        string expectedIdentity,
        bool requireDelete)
    {
        if (String.IsNullOrWhiteSpace(path))
        {
            throw new ArgumentException("A directory lease requires a path.", "path");
        }
        if (String.IsNullOrWhiteSpace(expectedIdentity))
        {
            throw new ArgumentException("A directory lease requires an expected File ID.", "expectedIdentity");
        }
        string canonicalPath = CanonicalizePath(path);
        SafeFileHandle opened = OpenDirectoryHandle(canonicalPath, requireDelete);
        try
        {
            BY_HANDLE_FILE_INFORMATION information = ReadDirectoryInformation(opened, "directory lease");
            string actualIdentity = FormatIdentity(information);
            if (!String.Equals(actualIdentity, expectedIdentity, StringComparison.Ordinal))
            {
                throw new InvalidOperationException(
                    "Directory File ID changed before the no-follow handle lease was acquired.");
            }
            return new SyncVisionInstallDirectoryLeaseV1(
                opened,
                canonicalPath,
                actualIdentity,
                requireDelete);
        }
        catch
        {
            opened.Dispose();
            throw;
        }
    }

    public void AssertIdentity()
    {
        EnsureOpen();
        BY_HANDLE_FILE_INFORMATION information = ReadDirectoryInformation(this.handle, "directory lease revalidation");
        if (!String.Equals(FormatIdentity(information), this.identity, StringComparison.Ordinal))
        {
            throw new InvalidOperationException("Pinned directory File ID changed while leased.");
        }
    }

    public void RenameNoReplace(string destinationPath)
    {
        EnsureOpen();
        if (!this.deleteAccess)
        {
            throw new InvalidOperationException("The directory lease was not opened with rename access.");
        }
        string destination = CanonicalizePath(destinationPath);
        string sourceParent = System.IO.Path.GetDirectoryName(this.path);
        string destinationParent = System.IO.Path.GetDirectoryName(destination);
        if (String.IsNullOrEmpty(sourceParent) || String.IsNullOrEmpty(destinationParent) ||
            !String.Equals(sourceParent, destinationParent, StringComparison.OrdinalIgnoreCase))
        {
            throw new InvalidOperationException("Handle-bound directory rename requires one shared parent.");
        }
        string destinationLeaf = System.IO.Path.GetFileName(destination);
        if (String.IsNullOrWhiteSpace(destinationLeaf) ||
            destinationLeaf.IndexOf('\\') >= 0 || destinationLeaf.IndexOf('/') >= 0 ||
            destinationLeaf == "." || destinationLeaf == "..")
        {
            throw new InvalidOperationException("Handle-bound directory rename has an invalid destination leaf.");
        }

        string parentIdentity = GetDirectoryIdentity(destinationParent);
        using (SyncVisionInstallDirectoryLeaseV1 parentLease =
            Open(destinationParent, parentIdentity, false))
        {
            RenameHandleNoReplace(
                this.handle,
                destination,
                "Handle-bound directory rename");
        }
        this.path = destination;
        AssertIdentity();
    }

    public void DeleteTree()
    {
        EnsureOpen();
        if (!this.deleteAccess)
        {
            throw new InvalidOperationException("The directory lease was not opened with delete access.");
        }
        ClearContents();
        ClearReadOnly(this.handle);
        MarkDelete(this.handle, "pinned directory root");
        this.deletePending = true;
    }

    public void ClearContents()
    {
        EnsureOpen();
        AssertIdentity();
        bool emptied = false;
        for (int pass = 0; pass < 32; ++pass)
        {
            string[] children = Directory.GetFileSystemEntries(this.path);
            if (children.Length == 0)
            {
                emptied = true;
                break;
            }
            foreach (string child in children)
            {
                DeleteEntry(child);
            }
        }
        if (!emptied)
        {
            throw new IOException("Pinned directory could not reach a stable empty state.");
        }
        AssertIdentity();
    }

    public void MoveChildrenNoReplaceTo(SyncVisionInstallDirectoryLeaseV1 destination)
    {
        EnsureOpen();
        if (!this.deleteAccess)
        {
            throw new InvalidOperationException(
                "The source directory lease was not opened with child rename access.");
        }
        if (destination == null)
        {
            throw new ArgumentNullException("destination");
        }
        destination.EnsureOpen();
        AssertIdentity();
        destination.AssertIdentity();
        if (String.Equals(this.identity, destination.identity, StringComparison.Ordinal))
        {
            throw new InvalidOperationException(
                "Handle-bound child publication requires different source and destination directories.");
        }

        string[] children = Directory.GetFileSystemEntries(this.path);
        Array.Sort(children, StringComparer.Ordinal);
        foreach (string child in children)
        {
            MoveEntryNoReplace(child, destination.path);
        }
        if (Directory.GetFileSystemEntries(this.path).Length != 0)
        {
            throw new IOException(
                "Handle-bound child publication did not consume the complete staged tree.");
        }
        AssertIdentity();
        destination.AssertIdentity();
    }

    public void ApplyBasicMetadata(
        long creationTimeUtcTicks,
        long lastWriteTimeUtcTicks,
        int attributes)
    {
        EnsureOpen();
        uint requestedAttributes = unchecked((uint)attributes);
        if ((requestedAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0u ||
            (requestedAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0u)
        {
            throw new InvalidOperationException(
                "Pinned directory metadata requires non-reparse directory attributes.");
        }
        FILE_BASIC_INFO basic;
        if (!GetFileInformationByHandleEx(
            this.handle,
            FILE_BASIC_INFO_CLASS,
            out basic,
            (uint)Marshal.SizeOf(typeof(FILE_BASIC_INFO))))
        {
            throw new Win32Exception(
                Marshal.GetLastWin32Error(),
                "Reading pinned directory metadata failed.");
        }
        basic.CreationTime = new DateTime(
            creationTimeUtcTicks,
            DateTimeKind.Utc).ToFileTimeUtc();
        basic.LastWriteTime = new DateTime(
            lastWriteTimeUtcTicks,
            DateTimeKind.Utc).ToFileTimeUtc();
        basic.FileAttributes = requestedAttributes;
        if (!SetFileInformationByHandleBasic(
            this.handle,
            FILE_BASIC_INFO_CLASS,
            ref basic,
            (uint)Marshal.SizeOf(typeof(FILE_BASIC_INFO))))
        {
            throw new Win32Exception(
                Marshal.GetLastWin32Error(),
                "Writing pinned directory metadata failed.");
        }
        AssertIdentity();
    }

    public void Dispose()
    {
        if (this.handle != null)
        {
            this.handle.Dispose();
            this.handle = null;
        }
    }

    private static void DeleteEntry(string entryPath)
    {
        SafeFileHandle entry = CreateFile(
            entryPath,
            DELETE | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | FILE_LIST_DIRECTORY,
            FILE_SHARE_READ | FILE_SHARE_WRITE,
            IntPtr.Zero,
            OPEN_EXISTING,
            FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
            IntPtr.Zero);
        if (entry.IsInvalid)
        {
            int error = Marshal.GetLastWin32Error();
            entry.Dispose();
            if (error == 2 || error == 3) { return; }
            throw new Win32Exception(error, "Opening a pinned directory child for deletion failed.");
        }
        try
        {
            BY_HANDLE_FILE_INFORMATION information;
            if (!GetFileInformationByHandle(entry, out information))
            {
                throw new Win32Exception(
                    Marshal.GetLastWin32Error(),
                    "Reading a pinned directory child identity failed.");
            }
            if ((information.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0u)
            {
                throw new InvalidOperationException(
                    "Pinned directory deletion rejected a reparse-point child: " + entryPath);
            }
            if ((information.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0u)
            {
                string childIdentity = FormatIdentity(information);
                using (SyncVisionInstallDirectoryLeaseV1 childLease =
                    new SyncVisionInstallDirectoryLeaseV1(
                        entry,
                        CanonicalizePath(entryPath),
                        childIdentity,
                        true))
                {
                    entry = null;
                    childLease.DeleteTree();
                }
            }
            else
            {
                ClearReadOnly(entry);
                MarkDelete(entry, "pinned regular file");
            }
        }
        finally
        {
            if (entry != null) { entry.Dispose(); }
        }
    }

    private static void MoveEntryNoReplace(string entryPath, string destinationRoot)
    {
        SafeFileHandle entry = CreateFile(
            entryPath,
            DELETE | FILE_READ_ATTRIBUTES,
            FILE_SHARE_READ | FILE_SHARE_WRITE,
            IntPtr.Zero,
            OPEN_EXISTING,
            FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
            IntPtr.Zero);
        if (entry.IsInvalid)
        {
            int error = Marshal.GetLastWin32Error();
            entry.Dispose();
            throw new Win32Exception(
                error,
                "Opening a staged rollback child for handle-bound publication failed.");
        }
        try
        {
            BY_HANDLE_FILE_INFORMATION information;
            if (!GetFileInformationByHandle(entry, out information))
            {
                throw new Win32Exception(
                    Marshal.GetLastWin32Error(),
                    "Reading a staged rollback child identity failed.");
            }
            if ((information.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0u)
            {
                throw new InvalidOperationException(
                    "Handle-bound rollback publication rejected a reparse-point child: " +
                    entryPath);
            }
            string leaf = System.IO.Path.GetFileName(entryPath);
            if (String.IsNullOrWhiteSpace(leaf) || leaf == "." || leaf == "..")
            {
                throw new InvalidOperationException(
                    "Handle-bound rollback publication found an invalid child name.");
            }
            RenameHandleNoReplace(
                entry,
                System.IO.Path.Combine(destinationRoot, leaf),
                "Handle-bound rollback child publication");
        }
        finally
        {
            entry.Dispose();
        }
    }

    private static SafeFileHandle OpenDirectoryHandle(string path, bool requireDelete)
    {
        uint access = FILE_LIST_DIRECTORY | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES;
        if (requireDelete) { access |= DELETE; }
        SafeFileHandle opened = CreateFile(
            path,
            access,
            FILE_SHARE_READ | FILE_SHARE_WRITE,
            IntPtr.Zero,
            OPEN_EXISTING,
            FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
            IntPtr.Zero);
        if (opened.IsInvalid)
        {
            int error = Marshal.GetLastWin32Error();
            opened.Dispose();
            throw new Win32Exception(error, "Opening a no-follow directory lease failed.");
        }
        return opened;
    }

    private static BY_HANDLE_FILE_INFORMATION ReadDirectoryInformation(
        SafeFileHandle opened,
        string context)
    {
        BY_HANDLE_FILE_INFORMATION information;
        if (!GetFileInformationByHandle(opened, out information))
        {
            throw new Win32Exception(
                Marshal.GetLastWin32Error(),
                "Reading " + context + " File ID failed.");
        }
        if ((information.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0u ||
            (information.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0u)
        {
            throw new InvalidOperationException(context + " requires a non-reparse directory.");
        }
        return information;
    }

    private static string GetDirectoryIdentity(string path)
    {
        using (SafeFileHandle opened = OpenDirectoryHandle(path, false))
        {
            return FormatIdentity(ReadDirectoryInformation(opened, "rename parent"));
        }
    }

    private static void RenameHandleNoReplace(
        SafeFileHandle source,
        string destination,
        string context)
    {
        byte[] destinationBytes = Encoding.Unicode.GetBytes(destination);
        int rootOffset = IntPtr.Size == 8 ? 8 : 4;
        int lengthOffset = rootOffset + IntPtr.Size;
        int nameOffset = lengthOffset + 4;
        int bufferSize = nameOffset + destinationBytes.Length + 2;
        IntPtr buffer = Marshal.AllocHGlobal(bufferSize);
        try
        {
            for (int index = 0; index < bufferSize; ++index)
            {
                Marshal.WriteByte(buffer, index, 0);
            }
            Marshal.WriteByte(buffer, 0, 0);
            Marshal.WriteIntPtr(buffer, rootOffset, IntPtr.Zero);
            Marshal.WriteInt32(buffer, lengthOffset, destinationBytes.Length);
            Marshal.Copy(
                destinationBytes,
                0,
                IntPtr.Add(buffer, nameOffset),
                destinationBytes.Length);
            if (!SetFileInformationByHandleBuffer(
                source,
                FILE_RENAME_INFO_CLASS,
                buffer,
                (uint)bufferSize))
            {
                int error = Marshal.GetLastWin32Error();
                throw new Win32Exception(
                    error,
                    context + " failed with Win32 error " + error + ".");
            }
        }
        finally
        {
            Marshal.FreeHGlobal(buffer);
        }
    }

    private static string CanonicalizePath(string value)
    {
        string fullPath = System.IO.Path.GetFullPath(value);
        string root = System.IO.Path.GetPathRoot(fullPath);
        if (!String.IsNullOrEmpty(root) &&
            String.Equals(fullPath, root, StringComparison.OrdinalIgnoreCase))
        {
            return root;
        }
        return fullPath.TrimEnd('\\', '/');
    }

    private static string FormatIdentity(BY_HANDLE_FILE_INFORMATION information)
    {
        return information.VolumeSerialNumber.ToString("x8") + ":" +
            information.FileIndexHigh.ToString("x8") + information.FileIndexLow.ToString("x8");
    }

    private static void ClearReadOnly(SafeFileHandle entry)
    {
        FILE_BASIC_INFO basic;
        if (!GetFileInformationByHandleEx(
            entry,
            FILE_BASIC_INFO_CLASS,
            out basic,
            (uint)Marshal.SizeOf(typeof(FILE_BASIC_INFO))))
        {
            throw new Win32Exception(
                Marshal.GetLastWin32Error(),
                "Reading pinned filesystem attributes failed.");
        }
        if ((basic.FileAttributes & FILE_ATTRIBUTE_READONLY) == 0u) { return; }
        basic.FileAttributes &= ~FILE_ATTRIBUTE_READONLY;
        if (basic.FileAttributes == 0u)
        {
            basic.FileAttributes = FILE_ATTRIBUTE_NORMAL;
        }
        if (!SetFileInformationByHandleBasic(
            entry,
            FILE_BASIC_INFO_CLASS,
            ref basic,
            (uint)Marshal.SizeOf(typeof(FILE_BASIC_INFO))))
        {
            throw new Win32Exception(
                Marshal.GetLastWin32Error(),
                "Clearing a pinned read-only filesystem attribute failed.");
        }
    }

    private static void MarkDelete(SafeFileHandle entry, string context)
    {
        FILE_DISPOSITION_INFO_EX extendedDisposition = new FILE_DISPOSITION_INFO_EX
        {
            Flags = FILE_DISPOSITION_FLAG_DELETE |
                FILE_DISPOSITION_FLAG_IGNORE_READONLY_ATTRIBUTE
        };
        if (!ForceLegacyDispositionForTest &&
            SetFileInformationByHandleDispositionEx(
                entry,
                FILE_DISPOSITION_INFO_EX_CLASS,
                ref extendedDisposition,
                (uint)Marshal.SizeOf(typeof(FILE_DISPOSITION_INFO_EX))))
        {
            return;
        }
        int extendedError = ForceLegacyDispositionForTest ? 87 : Marshal.GetLastWin32Error();
        if (extendedError != 1 && extendedError != 50 && extendedError != 87)
        {
            throw new Win32Exception(
                extendedError,
                "Identity-bound extended deletion failed for " + context +
                " with Win32 error " + extendedError + ".");
        }

        FILE_DISPOSITION_INFO disposition = new FILE_DISPOSITION_INFO { DeleteFile = true };
        if (!SetFileInformationByHandleDisposition(
            entry,
            FILE_DISPOSITION_INFO_CLASS,
            ref disposition,
            (uint)Marshal.SizeOf(typeof(FILE_DISPOSITION_INFO))))
        {
            int error = Marshal.GetLastWin32Error();
            throw new Win32Exception(
                error,
                "Identity-bound deletion failed for " + context +
                " with Win32 error " + error +
                " after extended disposition was unavailable with Win32 error " +
                extendedError + ".");
        }
    }

    private void EnsureOpen()
    {
        if (this.handle == null || this.handle.IsClosed || this.handle.IsInvalid || this.deletePending)
        {
            throw new ObjectDisposedException("SyncVisionInstallDirectoryLeaseV1");
        }
    }
}
'@
}

function Enter-SyncVisionInstallDirectoryLease {
    param(
        [Parameter(Mandatory = $true)][string]$Path,
        [Parameter(Mandatory = $true)][string]$ExpectedIdentity,
        [switch]$DeleteAccess
    )

    Initialize-SyncVisionInstallDirectoryLeaseType
    return [SyncVisionInstallDirectoryLeaseV1]::Open(
        $Path,
        $ExpectedIdentity,
        [bool]$DeleteAccess)
}

function Exit-SyncVisionInstallDirectoryLease {
    param([AllowNull()]$Lease)

    if ($null -ne $Lease) { $Lease.Dispose() }
}

function Assert-SyncVisionServerInstallJournalFileSecurity {
    param([Parameter(Mandatory = $true)][string]$Path)

    $item = Get-SyncVisionServerInstallSiblingItem -Path $Path
    if ($null -eq $item -or $item.PSIsContainer) {
        throw "Server install transaction journal was not found as a regular file: $Path"
    }
    if (($item.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
        throw "Server install transaction journal is a reparse point: $($item.FullName)"
    }
    $expectedSids = @("S-1-5-18", "S-1-5-32-544") | Sort-Object
    $security = Get-Acl -LiteralPath $item.FullName
    $owner = $security.GetOwner([Security.Principal.SecurityIdentifier]).Value
    $rules = @($security.GetAccessRules($true, $true, [Security.Principal.SecurityIdentifier]))
    $actualSids = @($rules | ForEach-Object { $_.IdentityReference.Value } | Sort-Object -Unique)
    if (-not $security.AreAccessRulesProtected -or
        $expectedSids -notcontains $owner -or
        $rules.Count -ne $expectedSids.Count -or
        @(Compare-Object -CaseSensitive -ReferenceObject $expectedSids -DifferenceObject $actualSids).Count -ne 0) {
        throw "Server install transaction journal has an untrusted owner or non-exact DACL: $($item.FullName)"
    }
    foreach ($rule in $rules) {
        if ($rule.IsInherited -or
            $rule.AccessControlType -ne [Security.AccessControl.AccessControlType]::Allow -or
            $rule.FileSystemRights -ne [Security.AccessControl.FileSystemRights]::FullControl -or
            $rule.InheritanceFlags -ne [Security.AccessControl.InheritanceFlags]::None -or
            $rule.PropagationFlags -ne [Security.AccessControl.PropagationFlags]::None) {
            throw "Server install transaction journal contains a non-exact access rule: $($item.FullName)"
        }
    }
    return $item.FullName
}

function Get-SyncVisionServerInstallJournalSha256 {
    param([Parameter(Mandatory = $true)][byte[]]$Bytes)

    $sha256 = [Security.Cryptography.SHA256]::Create()
    try {
        return ([BitConverter]::ToString($sha256.ComputeHash($Bytes))).Replace("-", "").ToLowerInvariant()
    }
    finally { $sha256.Dispose() }
}

function ConvertTo-SyncVisionServerInstallJournalBase64 {
    param([AllowEmptyString()][string]$Value = "")

    return [Convert]::ToBase64String([Text.UTF8Encoding]::new($false).GetBytes($Value))
}

function ConvertFrom-SyncVisionServerInstallJournalBase64 {
    param(
        [AllowEmptyString()][string]$Value = "",
        [Parameter(Mandatory = $true)][string]$Context
    )

    try {
        $bytes = [Convert]::FromBase64String($Value)
        if ([Convert]::ToBase64String($bytes) -cne $Value) {
            throw "The base64 representation is not canonical."
        }
        $decoded = [Text.UTF8Encoding]::new($false, $true).GetString($bytes)
        if ($decoded.IndexOf([char]0) -ge 0) {
            throw "The decoded value contains a NUL character."
        }
        return $decoded
    }
    catch {
        throw "Server install transaction journal contains an invalid $Context value: $($_.Exception.Message)"
    }
}

function Get-SyncVisionServerInstallResourceStatePath {
    param(
        [Parameter(Mandatory = $true)][string]$InstallDir,
        [Parameter(Mandatory = $true)][string]$TransactionId
    )

    if ($TransactionId -cnotmatch '^[0-9a-f]{32}$') {
        throw "Server install durable resource state requires a valid transaction ID."
    }
    $journalPath = Get-SyncVisionServerInstallJournalPath -InstallDir $InstallDir
    return Join-Path (Split-Path -Parent $journalPath) ("server-$TransactionId.resources")
}

function Write-SyncVisionServerInstallResourceState {
    param(
        [Parameter(Mandatory = $true)][string]$InstallDir,
        [Parameter(Mandatory = $true)][string]$TransactionId,
        [Parameter(Mandatory = $true)][string]$BackendKind,
        [Parameter(Mandatory = $true)][object]$State,
        [AllowNull()][scriptblock]$TestPhaseHook
    )

    if ($BackendKind -cnotmatch '^[A-Za-z][A-Za-z0-9]{0,31}$') {
        throw "Server install durable resource state has an invalid backend kind."
    }
    $path = Get-SyncVisionServerInstallResourceStatePath `
        -InstallDir $InstallDir `
        -TransactionId $TransactionId
    $parentPath = Split-Path -Parent $path
    $payload = [ordered]@{
        SchemaVersion = 1
        TransactionId = $TransactionId
        BackendKind = $BackendKind
        State = $State
    } | ConvertTo-Json -Compress -Depth 100
    $bytes = [Text.UTF8Encoding]::new($false).GetBytes($payload + "`n")
    if ($bytes.Length -le 0 -or $bytes.Length -gt 16777216) {
        throw "Server install durable resource state encoding or size is invalid."
    }
    $temporaryPath = Get-SyncVisionServerInstallResourceStateTemporaryPath `
        -InstallDir $InstallDir `
        -TransactionId $TransactionId
    try {
        if ($null -ne (Get-SyncVisionServerInstallSiblingItem -Path $path)) {
            throw "Server install durable resource state already exists for transaction $TransactionId."
        }
        if ($null -ne (Get-SyncVisionServerInstallSiblingItem -Path $temporaryPath)) {
            throw "Server install durable resource-state temporary file already exists; recovery must inspect it first."
        }
        $stream = [IO.File]::Create(
            $temporaryPath,
            4096,
            [IO.FileOptions]::WriteThrough,
            (New-SyncVisionServerInstallJournalFileSecurity))
        try {
            if ($null -ne $TestPhaseHook) {
                & $TestPhaseHook "AfterResourceStateTemporaryCreated" ([pscustomobject]@{
                        TransactionId = $TransactionId
                        Path = $path
                        TemporaryPath = $temporaryPath
                    })
            }
            $stream.Write($bytes, 0, $bytes.Length)
            $stream.Flush($true)
        }
        finally { $stream.Dispose() }
        if ($null -ne $TestPhaseHook) {
            & $TestPhaseHook "AfterResourceStateTemporaryFlushed" ([pscustomobject]@{
                    TransactionId = $TransactionId
                    Path = $path
                    TemporaryPath = $temporaryPath
                })
        }
        Assert-SyncVisionExistingPathChainNoReparse -Path $parentPath -Context "Server install resource-state publication parent"
        Initialize-SyncVisionServerInstallJournalAtomicType
        [SyncVisionServerInstallJournalAtomic]::PublishNew($temporaryPath, $path)
        $validatedPath = Assert-SyncVisionServerInstallJournalFileSecurity -Path $path
        $result = [pscustomobject]@{
            Path = $validatedPath
            Identity = Get-SyncVisionInstallRegularFileIdentity -Path $validatedPath
            Sha256 = Get-SyncVisionServerInstallJournalSha256 -Bytes $bytes
            BackendKind = $BackendKind
        }
        if ($null -ne $TestPhaseHook) { & $TestPhaseHook "AfterResourceStatePublished" $result }
        return $result
    }
    finally {
        if (Test-Path -LiteralPath $temporaryPath -PathType Leaf) {
            Remove-Item -LiteralPath $temporaryPath -Force -ErrorAction Stop
        }
    }
}

function Read-SyncVisionServerInstallResourceState {
    param([Parameter(Mandatory = $true)][object]$Journal)

    $journalState = Assert-SyncVisionServerInstallJournal -Journal $Journal
    if ([string]::IsNullOrEmpty($journalState.ResourceStatePath)) { return $null }
    $validatedPath = Assert-SyncVisionServerInstallJournalFileSecurity -Path $journalState.ResourceStatePath
    $stream = [IO.File]::Open(
        $validatedPath,
        [IO.FileMode]::Open,
        [IO.FileAccess]::Read,
        [IO.FileShare]::Read)
    try {
        $identity = Get-SyncVisionInstallRegularFileIdentity -Path $validatedPath
        if ($identity -cne $journalState.ResourceStateIdentity) {
            throw "Server install durable resource-state file identity changed."
        }
        if ($stream.Length -le 0 -or $stream.Length -gt 16777216) {
            throw "Server install durable resource-state size is invalid."
        }
        $bytes = New-Object byte[] ([int]$stream.Length)
        $offset = 0
        while ($offset -lt $bytes.Length) {
            $read = $stream.Read($bytes, $offset, $bytes.Length - $offset)
            if ($read -le 0) { throw "Server install durable resource-state read ended early." }
            $offset += $read
        }
        if ((Get-SyncVisionServerInstallJournalSha256 -Bytes $bytes) -cne $journalState.ResourceStateSha256) {
            throw "Server install durable resource-state digest mismatch."
        }
        try { $text = [Text.UTF8Encoding]::new($false, $true).GetString($bytes) }
        catch { throw "Server install durable resource state is not strict UTF-8: $($_.Exception.Message)" }
        if ($text.IndexOf([char]0) -ge 0 -or $text.IndexOf("`r") -ge 0 -or -not $text.EndsWith("`n", [StringComparison]::Ordinal)) {
            throw "Server install durable resource-state encoding is invalid."
        }
        try { $document = $text | ConvertFrom-Json -ErrorAction Stop }
        catch { throw "Server install durable resource-state JSON is invalid: $($_.Exception.Message)" }
        if ([int]$document.SchemaVersion -ne 1 -or
            [string]$document.TransactionId -cne $journalState.TransactionId -or
            [string]$document.BackendKind -cne $journalState.ResourceBackendKind -or
            $null -eq $document.State) {
            throw "Server install durable resource state does not match its protected journal."
        }
        return $document.State
    }
    finally { $stream.Dispose() }
}

function Remove-SyncVisionServerInstallResourceState {
    param([Parameter(Mandatory = $true)][object]$Journal)

    $journalState = Assert-SyncVisionServerInstallJournal -Journal $Journal
    if ([string]::IsNullOrEmpty($journalState.ResourceStatePath) -or
        $null -eq (Get-SyncVisionServerInstallSiblingItem -Path $journalState.ResourceStatePath)) {
        return
    }
    $validatedPath = Assert-SyncVisionServerInstallJournalFileSecurity -Path $journalState.ResourceStatePath
    if ((Get-SyncVisionInstallRegularFileIdentity -Path $validatedPath) -cne $journalState.ResourceStateIdentity) {
        throw "Refusing to remove a server install resource state whose file identity changed."
    }
    Initialize-SyncVisionServerInstallJournalAtomicType
    [SyncVisionServerInstallJournalAtomic]::DeleteIfIdentity($validatedPath, $journalState.ResourceStateIdentity)
}

function ConvertTo-SyncVisionServerInstallJournalInputs {
    param(
        [AllowEmptyCollection()][object[]]$Inputs = @(),
        [Parameter(Mandatory = $true)][string]$Context,
        [switch]$RequireServerExecutable
    )

    if ($Inputs.Count -gt 64) {
        throw "$Context contains too many files."
    }
    $managedNames = New-Object "System.Collections.Generic.HashSet[string]" ([StringComparer]::OrdinalIgnoreCase)
    foreach ($name in (Get-SyncVisionManagedServerInstallFileNames)) {
        [void]$managedNames.Add($name)
    }
    $recordsByName = New-Object "System.Collections.Generic.Dictionary[string,object]" ([StringComparer]::OrdinalIgnoreCase)
    foreach ($input in $Inputs) {
        foreach ($propertyName in @("DestinationName", "ExpectedLength", "ExpectedHash")) {
            if ($null -eq $input -or $null -eq $input.PSObject.Properties[$propertyName]) {
                throw "$Context is missing required property $propertyName."
            }
        }
        $name = [string]$input.DestinationName
        if ([string]::IsNullOrWhiteSpace($name) -or
            -not [string]::Equals((Split-Path -Leaf $name), $name, [StringComparison]::Ordinal) -or
            $name.IndexOfAny([IO.Path]::GetInvalidFileNameChars()) -ge 0 -or
            -not $managedNames.Contains($name)) {
            throw "$Context contains an unmanaged or invalid destination name: $name"
        }
        if ($recordsByName.ContainsKey($name)) {
            throw "$Context contains a duplicate destination name: $name"
        }
        $lengthText = [string]$input.ExpectedLength
        $length = [int64]0
        if ($lengthText -notmatch '^(0|[1-9][0-9]{0,18})$' -or
            -not [int64]::TryParse(
                $lengthText,
                [Globalization.NumberStyles]::None,
                [Globalization.CultureInfo]::InvariantCulture,
                [ref]$length) -or
            $length -lt 0) {
            throw "$Context contains an invalid length for $name."
        }
        $hash = [string]$input.ExpectedHash
        if ($hash -cnotmatch '^[0-9a-f]{64}$') {
            throw "$Context contains an invalid lowercase SHA-256 for $name."
        }
        $recordsByName.Add($name, [pscustomobject]@{
                DestinationName = $name
                ExpectedLength = $length
                ExpectedHash = $hash
            })
    }
    if ($RequireServerExecutable -and -not $recordsByName.ContainsKey("SyncVisionServer.exe")) {
        throw "$Context is missing SyncVisionServer.exe."
    }
    [string[]]$orderedNames = @($recordsByName.Keys)
    [Array]::Sort($orderedNames, [StringComparer]::Ordinal)
    return @($orderedNames | ForEach-Object { $recordsByName[$_] })
}

function New-SyncVisionServerInstallJournal {
    param(
        [Parameter(Mandatory = $true)][string]$InstallDir,
        [Parameter(Mandatory = $true)][string]$TransactionId,
        [Parameter(Mandatory = $true)][bool]$HadPrevious,
        [AllowEmptyCollection()][object[]]$PreviousInputs = @(),
        [Parameter(Mandatory = $true)][object[]]$NewInputs,
        [AllowEmptyString()][string]$PreviousIdentity = "",
        [AllowEmptyString()][string]$CandidateIdentity = "",
        [AllowEmptyString()][string]$ResourceStatePath = "",
        [AllowEmptyString()][string]$ResourceStateIdentity = "",
        [AllowEmptyString()][string]$ResourceStateSha256 = "",
        [AllowEmptyString()][string]$ResourceBackendKind = "",
        [string]$Phase = "Prepared"
    )

    $installPath = Assert-SyncVisionServerInstallDestinationBoundary -InstallDir $InstallDir
    $parentPath = Split-Path -Parent $installPath
    $leafName = Split-Path -Leaf $installPath
    return [pscustomobject]@{
        Version = 2
        TransactionId = $TransactionId
        Phase = $Phase
        InstallPath = $installPath
        PublishPath = Join-Path $parentPath ("$leafName.publish-$TransactionId")
        BackupPath = Join-Path $parentPath ("$leafName.previous-$TransactionId")
        ParentPath = $parentPath
        JournalPath = Get-SyncVisionServerInstallJournalPath -InstallDir $installPath
        HadPrevious = $HadPrevious
        PreviousIdentity = $PreviousIdentity
        CandidateIdentity = $CandidateIdentity
        ResourceStatePath = $ResourceStatePath
        ResourceStateIdentity = $ResourceStateIdentity
        ResourceStateSha256 = $ResourceStateSha256
        ResourceBackendKind = $ResourceBackendKind
        PreviousInputs = @($PreviousInputs)
        NewInputs = @($NewInputs)
    }
}

function Assert-SyncVisionServerInstallJournal {
    param(
        [Parameter(Mandatory = $true)][object]$Journal,
        [AllowEmptyString()][string]$ExpectedInstallDir = ""
    )

    foreach ($propertyName in @(
            "Version", "TransactionId", "Phase", "InstallPath", "PublishPath", "BackupPath",
            "ParentPath", "JournalPath", "HadPrevious", "PreviousIdentity", "CandidateIdentity",
            "ResourceStatePath", "ResourceStateIdentity", "ResourceStateSha256", "ResourceBackendKind",
            "PreviousInputs", "NewInputs")) {
        if ($null -eq $Journal.PSObject.Properties[$propertyName]) {
            throw "Server install transaction journal is missing required field $propertyName."
        }
    }
    if ($Journal.Version -isnot [int] -or [int]$Journal.Version -ne 2) {
        throw "Server install transaction journal has an unsupported version."
    }
    $transactionId = [string]$Journal.TransactionId
    if ($transactionId -cnotmatch '^[0-9a-f]{32}$') {
        throw "Server install transaction journal has an invalid transaction ID."
    }
    $phase = [string]$Journal.Phase
    if (@(Get-SyncVisionServerInstallJournalPhases) -cnotcontains $phase) {
        throw "Server install transaction journal has an unsupported phase: $phase"
    }
    if ($Journal.HadPrevious -isnot [bool]) {
        throw "Server install transaction journal HadPrevious must be a Boolean."
    }

    $installPath = Assert-SyncVisionServerInstallDestinationBoundary -InstallDir ([string]$Journal.InstallPath)
    $requestedInstallPath = if ([string]::IsNullOrWhiteSpace($ExpectedInstallDir)) {
        $installPath
    }
    else {
        Assert-SyncVisionServerInstallDestinationBoundary -InstallDir $ExpectedInstallDir
    }
    $journalResourceIdentity = Get-SyncVisionServerInstallJournalResourceIdentity -InstallDir $installPath
    $requestedResourceIdentity = Get-SyncVisionServerInstallJournalResourceIdentity -InstallDir $requestedInstallPath
    if ($journalResourceIdentity -cne $requestedResourceIdentity) {
        throw "Server install transaction journal InstallPath does not match the requested canonical resource identity."
    }
    $parentPath = Split-Path -Parent $installPath
    $leafName = Split-Path -Leaf $installPath
    $expectedPublishPath = Join-Path $parentPath ("$leafName.publish-$transactionId")
    $expectedBackupPath = Join-Path $parentPath ("$leafName.previous-$transactionId")
    $expectedJournalPath = Get-SyncVisionServerInstallJournalPath -InstallDir $installPath
    foreach ($pathCheck in @(
            [pscustomobject]@{ Name = "ParentPath"; Actual = [string]$Journal.ParentPath; Expected = $parentPath },
            [pscustomobject]@{ Name = "PublishPath"; Actual = [string]$Journal.PublishPath; Expected = $expectedPublishPath },
            [pscustomobject]@{ Name = "BackupPath"; Actual = [string]$Journal.BackupPath; Expected = $expectedBackupPath },
            [pscustomobject]@{ Name = "JournalPath"; Actual = [string]$Journal.JournalPath; Expected = $expectedJournalPath })) {
        if (-not [string]::Equals($pathCheck.Actual, $pathCheck.Expected, [StringComparison]::OrdinalIgnoreCase)) {
            throw "Server install transaction journal $($pathCheck.Name) escaped its canonical transaction boundary."
        }
    }

    $previousIdentity = [string]$Journal.PreviousIdentity
    $candidateIdentity = [string]$Journal.CandidateIdentity
    if (-not [string]::IsNullOrEmpty($previousIdentity) -and
        $previousIdentity -cnotmatch '^[0-9a-f]{8}:[0-9a-f]{16}$') {
        throw "Server install transaction journal has an invalid previous directory identity."
    }
    if (-not [string]::IsNullOrEmpty($candidateIdentity) -and
        $candidateIdentity -cnotmatch '^[0-9a-f]{8}:[0-9a-f]{16}$') {
        throw "Server install transaction journal has an invalid candidate directory identity."
    }
    $previousInputs = @(ConvertTo-SyncVisionServerInstallJournalInputs `
            -Inputs @($Journal.PreviousInputs) `
            -Context "Server install transaction previous file set" `
            -RequireServerExecutable:([bool]$Journal.HadPrevious))
    $newInputs = @(ConvertTo-SyncVisionServerInstallJournalInputs `
            -Inputs @($Journal.NewInputs) `
            -Context "Server install transaction candidate file set" `
            -RequireServerExecutable)
    if ($Journal.HadPrevious) {
        if ([string]::IsNullOrEmpty($previousIdentity) -or $previousInputs.Count -eq 0) {
            throw "Server install transaction journal is missing the exact previous tree identity."
        }
    }
    elseif (-not [string]::IsNullOrEmpty($previousIdentity) -or $previousInputs.Count -ne 0) {
        throw "Server install transaction journal records a previous tree for a fresh install."
    }
    $candidateRequiredPhases = @(
        "BackupMovePending", "BackupMoved", "PublishMovePending", "Published",
        "ConfigPending", "ConfigApplied", "ServiceDefinitionPending", "ServiceDefinitionMutationStarted", "ServiceDefinitionApplied",
        "FirewallPending", "FirewallMutationStarted", "FirewallApplied", "ServiceStartPending", "ServiceStarted",
        "VerificationPending", "Verified", "ForwardCommitted", "Committed")
    if ($candidateRequiredPhases -ccontains $phase -and [string]::IsNullOrEmpty($candidateIdentity)) {
        throw "Server install transaction journal phase $phase is missing the candidate directory identity."
    }
    if (($phase -ceq "BackupMovePending" -or $phase -ceq "BackupMoved") -and -not $Journal.HadPrevious) {
        throw "Server install transaction journal uses a backup phase without a previous tree."
    }

    $resourceStatePath = [string]$Journal.ResourceStatePath
    $resourceStateIdentity = [string]$Journal.ResourceStateIdentity
    $resourceStateSha256 = [string]$Journal.ResourceStateSha256
    $resourceBackendKind = [string]$Journal.ResourceBackendKind
    $resourceFieldsPresent = @(
        -not [string]::IsNullOrEmpty($resourceStatePath),
        -not [string]::IsNullOrEmpty($resourceStateIdentity),
        -not [string]::IsNullOrEmpty($resourceStateSha256),
        -not [string]::IsNullOrEmpty($resourceBackendKind))
    if (@($resourceFieldsPresent | Where-Object { $_ }).Count -notin @(0, 4)) {
        throw "Server install transaction journal has an incomplete durable resource-state reference."
    }
    if ($resourceFieldsPresent[0]) {
        $expectedResourceStatePath = Join-Path `
            (Split-Path -Parent $expectedJournalPath) `
            ("server-$transactionId.resources")
        if (-not [string]::Equals($resourceStatePath, $expectedResourceStatePath, [StringComparison]::OrdinalIgnoreCase)) {
            throw "Server install transaction resource state escaped its protected central base."
        }
        if ($resourceStateIdentity -cnotmatch '^[0-9a-f]{8}:[0-9a-f]{16}$' -or
            $resourceStateSha256 -cnotmatch '^[0-9a-f]{64}$' -or
            $resourceBackendKind -cnotmatch '^[A-Za-z][A-Za-z0-9]{0,31}$') {
            throw "Server install transaction journal has an invalid durable resource-state identity."
        }
    }

    $validated = [pscustomobject]@{
        Version = 2
        TransactionId = $transactionId
        Phase = $phase
        InstallPath = $installPath
        PublishPath = $expectedPublishPath
        BackupPath = $expectedBackupPath
        ParentPath = $parentPath
        JournalPath = $expectedJournalPath
        HadPrevious = [bool]$Journal.HadPrevious
        PreviousIdentity = $previousIdentity
        CandidateIdentity = $candidateIdentity
        ResourceStatePath = $resourceStatePath
        ResourceStateIdentity = $resourceStateIdentity
        ResourceStateSha256 = $resourceStateSha256
        ResourceBackendKind = $resourceBackendKind
        PreviousInputs = $previousInputs
        NewInputs = $newInputs
    }
    if ($null -ne $Journal.PSObject.Properties["JournalFileIdentity"] -and
        -not [string]::IsNullOrEmpty([string]$Journal.JournalFileIdentity)) {
        if ([string]$Journal.JournalFileIdentity -cnotmatch '^[0-9a-f]{8}:[0-9a-f]{16}$') {
            throw "Server install transaction journal has an invalid in-memory file identity."
        }
        $validated | Add-Member -NotePropertyName JournalFileIdentity -NotePropertyValue ([string]$Journal.JournalFileIdentity)
    }
    if ($null -ne $Journal.PSObject.Properties["JournalSha256"] -and
        -not [string]::IsNullOrEmpty([string]$Journal.JournalSha256)) {
        if ([string]$Journal.JournalSha256 -cnotmatch '^[0-9a-f]{64}$') {
            throw "Server install transaction journal has an invalid in-memory SHA-256."
        }
        $validated | Add-Member -NotePropertyName JournalSha256 -NotePropertyValue ([string]$Journal.JournalSha256)
    }
    return $validated
}

function ConvertTo-SyncVisionServerInstallJournalText {
    param([Parameter(Mandatory = $true)][object]$Journal)

    $journalState = Assert-SyncVisionServerInstallJournal -Journal $Journal
    $lines = New-Object "System.Collections.Generic.List[string]"
    $lines.Add("SYNCVISION_SERVER_INSTALL_JOURNAL")
    $lines.Add("version=2")
    $lines.Add("transaction_id=$($journalState.TransactionId)")
    $lines.Add("phase=$($journalState.Phase)")
    foreach ($pathField in @(
            [pscustomobject]@{ Name = "install_path_b64"; Value = $journalState.InstallPath },
            [pscustomobject]@{ Name = "publish_path_b64"; Value = $journalState.PublishPath },
            [pscustomobject]@{ Name = "backup_path_b64"; Value = $journalState.BackupPath },
            [pscustomobject]@{ Name = "parent_path_b64"; Value = $journalState.ParentPath },
            [pscustomobject]@{ Name = "journal_path_b64"; Value = $journalState.JournalPath },
            [pscustomobject]@{ Name = "previous_identity_b64"; Value = $journalState.PreviousIdentity },
            [pscustomobject]@{ Name = "candidate_identity_b64"; Value = $journalState.CandidateIdentity },
            [pscustomobject]@{ Name = "resource_state_path_b64"; Value = $journalState.ResourceStatePath },
            [pscustomobject]@{ Name = "resource_state_identity_b64"; Value = $journalState.ResourceStateIdentity },
            [pscustomobject]@{ Name = "resource_state_sha256_b64"; Value = $journalState.ResourceStateSha256 },
            [pscustomobject]@{ Name = "resource_backend_kind_b64"; Value = $journalState.ResourceBackendKind })) {
        $lines.Add("$($pathField.Name)=$(ConvertTo-SyncVisionServerInstallJournalBase64 -Value $pathField.Value)")
    }
    $lines.Add("had_previous=$(if ($journalState.HadPrevious) { '1' } else { '0' })")
    $lines.Add("previous_count=$($journalState.PreviousInputs.Count)")
    for ($index = 0; $index -lt $journalState.PreviousInputs.Count; ++$index) {
        $record = $journalState.PreviousInputs[$index]
        $lines.Add("previous.$index.name_b64=$(ConvertTo-SyncVisionServerInstallJournalBase64 -Value $record.DestinationName)")
        $lines.Add("previous.$index.length=$($record.ExpectedLength.ToString([Globalization.CultureInfo]::InvariantCulture))")
        $lines.Add("previous.$index.sha256=$($record.ExpectedHash)")
    }
    $lines.Add("new_count=$($journalState.NewInputs.Count)")
    for ($index = 0; $index -lt $journalState.NewInputs.Count; ++$index) {
        $record = $journalState.NewInputs[$index]
        $lines.Add("new.$index.name_b64=$(ConvertTo-SyncVisionServerInstallJournalBase64 -Value $record.DestinationName)")
        $lines.Add("new.$index.length=$($record.ExpectedLength.ToString([Globalization.CultureInfo]::InvariantCulture))")
        $lines.Add("new.$index.sha256=$($record.ExpectedHash)")
    }
    $payload = ($lines.ToArray() -join "`n") + "`n"
    $payloadBytes = [Text.UTF8Encoding]::new($false).GetBytes($payload)
    return $payload + "payload_sha256=$(Get-SyncVisionServerInstallJournalSha256 -Bytes $payloadBytes)`n"
}

function Get-SyncVisionServerInstallJournalField {
    param(
        [Parameter(Mandatory = $true)][string[]]$Lines,
        [Parameter(Mandatory = $true)][ref]$Index,
        [Parameter(Mandatory = $true)][string]$Name
    )

    if ($Index.Value -ge $Lines.Count) {
        throw "Server install transaction journal ended before required field $Name."
    }
    $prefix = "$Name="
    $line = $Lines[$Index.Value]
    $Index.Value++
    if (-not $line.StartsWith($prefix, [StringComparison]::Ordinal)) {
        throw "Server install transaction journal expected field $Name but found '$line'."
    }
    return $line.Substring($prefix.Length)
}

function ConvertFrom-SyncVisionServerInstallJournalText {
    param(
        [Parameter(Mandatory = $true)][string]$Text,
        [Parameter(Mandatory = $true)][string]$ExpectedInstallDir
    )

    if ($Text.Length -eq 0 -or $Text.Length -gt 1048576 -or
        $Text[0] -eq [char]0xfeff -or $Text.IndexOf("`r") -ge 0 -or
        $Text.IndexOf([char]0) -ge 0 -or -not $Text.EndsWith("`n", [StringComparison]::Ordinal)) {
        throw "Server install transaction journal encoding or size is invalid."
    }
    [string[]]$allLines = $Text.Split([char]10)
    if ($allLines.Count -lt 3 -or $allLines[$allLines.Count - 1] -cne "") {
        throw "Server install transaction journal line termination is invalid."
    }
    [string[]]$lines = @($allLines[0..($allLines.Count - 2)])
    if ($lines[0] -cne "SYNCVISION_SERVER_INSTALL_JOURNAL") {
        throw "Server install transaction journal header is invalid."
    }
    $digestLine = $lines[$lines.Count - 1]
    if ($digestLine -cnotmatch '^payload_sha256=([0-9a-f]{64})$') {
        throw "Server install transaction journal digest field is invalid."
    }
    $expectedDigest = $Matches[1]
    $payload = ($lines[0..($lines.Count - 2)] -join "`n") + "`n"
    $actualDigest = Get-SyncVisionServerInstallJournalSha256 `
        -Bytes ([Text.UTF8Encoding]::new($false).GetBytes($payload))
    if ($actualDigest -cne $expectedDigest) {
        throw "Server install transaction journal digest mismatch."
    }

    $index = 1
    $versionText = Get-SyncVisionServerInstallJournalField -Lines $lines -Index ([ref]$index) -Name "version"
    if ($versionText -cne "2") {
        throw "Server install transaction journal has an unsupported version: $versionText"
    }
    $transactionId = Get-SyncVisionServerInstallJournalField -Lines $lines -Index ([ref]$index) -Name "transaction_id"
    $phase = Get-SyncVisionServerInstallJournalField -Lines $lines -Index ([ref]$index) -Name "phase"
    $installPath = ConvertFrom-SyncVisionServerInstallJournalBase64 `
        -Value (Get-SyncVisionServerInstallJournalField -Lines $lines -Index ([ref]$index) -Name "install_path_b64") `
        -Context "InstallPath"
    $publishPath = ConvertFrom-SyncVisionServerInstallJournalBase64 `
        -Value (Get-SyncVisionServerInstallJournalField -Lines $lines -Index ([ref]$index) -Name "publish_path_b64") `
        -Context "PublishPath"
    $backupPath = ConvertFrom-SyncVisionServerInstallJournalBase64 `
        -Value (Get-SyncVisionServerInstallJournalField -Lines $lines -Index ([ref]$index) -Name "backup_path_b64") `
        -Context "BackupPath"
    $parentPath = ConvertFrom-SyncVisionServerInstallJournalBase64 `
        -Value (Get-SyncVisionServerInstallJournalField -Lines $lines -Index ([ref]$index) -Name "parent_path_b64") `
        -Context "ParentPath"
    $journalPath = ConvertFrom-SyncVisionServerInstallJournalBase64 `
        -Value (Get-SyncVisionServerInstallJournalField -Lines $lines -Index ([ref]$index) -Name "journal_path_b64") `
        -Context "JournalPath"
    $previousIdentity = ConvertFrom-SyncVisionServerInstallJournalBase64 `
        -Value (Get-SyncVisionServerInstallJournalField -Lines $lines -Index ([ref]$index) -Name "previous_identity_b64") `
        -Context "PreviousIdentity"
    $candidateIdentity = ConvertFrom-SyncVisionServerInstallJournalBase64 `
        -Value (Get-SyncVisionServerInstallJournalField -Lines $lines -Index ([ref]$index) -Name "candidate_identity_b64") `
        -Context "CandidateIdentity"
    $resourceStatePath = ConvertFrom-SyncVisionServerInstallJournalBase64 `
        -Value (Get-SyncVisionServerInstallJournalField -Lines $lines -Index ([ref]$index) -Name "resource_state_path_b64") `
        -Context "ResourceStatePath"
    $resourceStateIdentity = ConvertFrom-SyncVisionServerInstallJournalBase64 `
        -Value (Get-SyncVisionServerInstallJournalField -Lines $lines -Index ([ref]$index) -Name "resource_state_identity_b64") `
        -Context "ResourceStateIdentity"
    $resourceStateSha256 = ConvertFrom-SyncVisionServerInstallJournalBase64 `
        -Value (Get-SyncVisionServerInstallJournalField -Lines $lines -Index ([ref]$index) -Name "resource_state_sha256_b64") `
        -Context "ResourceStateSha256"
    $resourceBackendKind = ConvertFrom-SyncVisionServerInstallJournalBase64 `
        -Value (Get-SyncVisionServerInstallJournalField -Lines $lines -Index ([ref]$index) -Name "resource_backend_kind_b64") `
        -Context "ResourceBackendKind"
    $hadPreviousText = Get-SyncVisionServerInstallJournalField -Lines $lines -Index ([ref]$index) -Name "had_previous"
    if ($hadPreviousText -cne "0" -and $hadPreviousText -cne "1") {
        throw "Server install transaction journal HadPrevious field is invalid."
    }

    $previousCountText = Get-SyncVisionServerInstallJournalField -Lines $lines -Index ([ref]$index) -Name "previous_count"
    if ($previousCountText -notmatch '^(0|[1-9][0-9]?)$') {
        throw "Server install transaction journal previous file count is invalid."
    }
    $previousCount = [int]$previousCountText
    $previousInputs = New-Object "System.Collections.Generic.List[object]"
    for ($recordIndex = 0; $recordIndex -lt $previousCount; ++$recordIndex) {
        $name = ConvertFrom-SyncVisionServerInstallJournalBase64 `
            -Value (Get-SyncVisionServerInstallJournalField -Lines $lines -Index ([ref]$index) -Name "previous.$recordIndex.name_b64") `
            -Context "previous file name"
        $length = Get-SyncVisionServerInstallJournalField -Lines $lines -Index ([ref]$index) -Name "previous.$recordIndex.length"
        $hash = Get-SyncVisionServerInstallJournalField -Lines $lines -Index ([ref]$index) -Name "previous.$recordIndex.sha256"
        $previousInputs.Add([pscustomobject]@{ DestinationName = $name; ExpectedLength = $length; ExpectedHash = $hash })
    }
    $newCountText = Get-SyncVisionServerInstallJournalField -Lines $lines -Index ([ref]$index) -Name "new_count"
    if ($newCountText -notmatch '^[1-9][0-9]?$') {
        throw "Server install transaction journal candidate file count is invalid."
    }
    $newCount = [int]$newCountText
    $newInputs = New-Object "System.Collections.Generic.List[object]"
    for ($recordIndex = 0; $recordIndex -lt $newCount; ++$recordIndex) {
        $name = ConvertFrom-SyncVisionServerInstallJournalBase64 `
            -Value (Get-SyncVisionServerInstallJournalField -Lines $lines -Index ([ref]$index) -Name "new.$recordIndex.name_b64") `
            -Context "candidate file name"
        $length = Get-SyncVisionServerInstallJournalField -Lines $lines -Index ([ref]$index) -Name "new.$recordIndex.length"
        $hash = Get-SyncVisionServerInstallJournalField -Lines $lines -Index ([ref]$index) -Name "new.$recordIndex.sha256"
        $newInputs.Add([pscustomobject]@{ DestinationName = $name; ExpectedLength = $length; ExpectedHash = $hash })
    }
    $parsedDigest = Get-SyncVisionServerInstallJournalField -Lines $lines -Index ([ref]$index) -Name "payload_sha256"
    if ($parsedDigest -cne $expectedDigest -or $index -ne $lines.Count) {
        throw "Server install transaction journal contains duplicate, unknown, or trailing fields."
    }

    return Assert-SyncVisionServerInstallJournal `
        -ExpectedInstallDir $ExpectedInstallDir `
        -Journal ([pscustomobject]@{
            Version = 2
            TransactionId = $transactionId
            Phase = $phase
            InstallPath = $installPath
            PublishPath = $publishPath
            BackupPath = $backupPath
            ParentPath = $parentPath
            JournalPath = $journalPath
            HadPrevious = ($hadPreviousText -ceq "1")
            PreviousIdentity = $previousIdentity
            CandidateIdentity = $candidateIdentity
            ResourceStatePath = $resourceStatePath
            ResourceStateIdentity = $resourceStateIdentity
            ResourceStateSha256 = $resourceStateSha256
            ResourceBackendKind = $resourceBackendKind
            PreviousInputs = $previousInputs.ToArray()
            NewInputs = $newInputs.ToArray()
        })
}

function Write-SyncVisionServerInstallJournal {
    param(
        [Parameter(Mandatory = $true)][object]$Journal,
        [AllowNull()][scriptblock]$TestPhaseHook
    )

    $journalState = Assert-SyncVisionServerInstallJournal -Journal $Journal
    $path = $journalState.JournalPath
    $parentPath = Split-Path -Parent $path
    $expectedBasePath = Initialize-SyncVisionServerInstallJournalBase
    if (-not [string]::Equals($parentPath, $expectedBasePath, [StringComparison]::OrdinalIgnoreCase)) {
        throw "Server install transaction journal escaped its protected central base."
    }
    Assert-SyncVisionExistingPathChainNoReparse -Path $parentPath -Context "Server install transaction journal parent"
    $existing = Get-SyncVisionServerInstallSiblingItem -Path $path
    $replace = $null -ne $existing
    $expectedIdentity = ""
    $expectedSha256 = ""
    if ($replace) {
        if ($null -eq $journalState.PSObject.Properties["JournalFileIdentity"] -or
            $null -eq $journalState.PSObject.Properties["JournalSha256"]) {
            throw "Server install transaction journal replacement requires its protected read version."
        }
        $expectedIdentity = [string]$journalState.JournalFileIdentity
        $expectedSha256 = [string]$journalState.JournalSha256
        Assert-SyncVisionServerInstallDurableFileVersionCurrent `
            -Path $path `
            -ExpectedIdentity $expectedIdentity `
            -ExpectedSha256 $expectedSha256 `
            -Context "Server install transaction journal" | Out-Null
    }
    $temporaryPath = Get-SyncVisionServerInstallJournalTemporaryPath -InstallDir $journalState.InstallPath
    if ($null -ne (Get-SyncVisionServerInstallSiblingItem -Path $temporaryPath)) {
        throw "Server install transaction journal temporary file already exists; recovery must inspect it first."
    }
    try {
        $text = ConvertTo-SyncVisionServerInstallJournalText -Journal $journalState
        $bytes = [Text.UTF8Encoding]::new($false).GetBytes($text)
        $stream = [IO.File]::Create(
            $temporaryPath,
            4096,
            [IO.FileOptions]::WriteThrough,
            (New-SyncVisionServerInstallJournalFileSecurity))
        try {
            if ($null -ne $TestPhaseHook) { & $TestPhaseHook "AfterJournalTemporaryCreated" $journalState }
            $stream.Write($bytes, 0, $bytes.Length)
            $stream.Flush($true)
        }
        finally { $stream.Dispose() }
        if ($null -ne $TestPhaseHook) { & $TestPhaseHook "AfterJournalTemporaryFlushed" $journalState }
        Assert-SyncVisionExistingPathChainNoReparse -Path $parentPath -Context "Server install transaction journal publication parent"
        Initialize-SyncVisionServerInstallJournalAtomicType
        if ($replace) {
            Assert-SyncVisionServerInstallDurableFileVersionCurrent `
                -Path $path `
                -ExpectedIdentity $expectedIdentity `
                -ExpectedSha256 $expectedSha256 `
                -Context "Server install transaction journal" | Out-Null
            [SyncVisionServerInstallJournalAtomic]::Replace($temporaryPath, $path)
        }
        else {
            [SyncVisionServerInstallJournalAtomic]::PublishNew($temporaryPath, $path)
        }
        Assert-SyncVisionServerInstallJournalFileSecurity -Path $path | Out-Null
        $journalState | Add-Member `
            -NotePropertyName JournalFileIdentity `
            -NotePropertyValue (Get-SyncVisionInstallRegularFileIdentity -Path $path) `
            -Force
        $journalState | Add-Member `
            -NotePropertyName JournalSha256 `
            -NotePropertyValue (Get-SyncVisionServerInstallJournalSha256 -Bytes $bytes) `
            -Force
        if ($null -ne $TestPhaseHook) { & $TestPhaseHook "AfterJournalPublished" $journalState }
        return $journalState
    }
    finally {
        if (Test-Path -LiteralPath $temporaryPath -PathType Leaf) {
            Assert-SyncVisionExistingPathChainNoReparse -Path $parentPath -Context "Server install transaction journal temporary cleanup parent"
            Remove-Item -LiteralPath $temporaryPath -Force -ErrorAction Stop
        }
    }
}

function Read-SyncVisionServerInstallJournal {
    param(
        [Parameter(Mandatory = $true)][string]$InstallDir,
        [switch]$AllowMissing
    )

    $journalPath = Get-SyncVisionServerInstallJournalPath -InstallDir $InstallDir
    if ($null -eq (Get-SyncVisionServerInstallSiblingItem -Path $journalPath)) {
        if ($AllowMissing) { return $null }
        throw "Server install transaction journal was not found: $journalPath"
    }
    $journalPath = Assert-SyncVisionServerInstallJournalFileSecurity -Path $journalPath
    $stream = [IO.File]::Open(
        $journalPath,
        [IO.FileMode]::Open,
        [IO.FileAccess]::Read,
        [IO.FileShare]::Read)
    try {
        $journalIdentity = Get-SyncVisionInstallRegularFileIdentity -Path $journalPath
        if ($stream.Length -le 0 -or $stream.Length -gt 1048576) {
            throw "Server install transaction journal size is invalid: $($stream.Length)"
        }
        $bytes = New-Object byte[] ([int]$stream.Length)
        $offset = 0
        while ($offset -lt $bytes.Length) {
            $read = $stream.Read($bytes, $offset, $bytes.Length - $offset)
            if ($read -le 0) { throw "Server install transaction journal read ended early." }
            $offset += $read
        }
        try { $text = [Text.UTF8Encoding]::new($false, $true).GetString($bytes) }
        catch { throw "Server install transaction journal is not strict UTF-8: $($_.Exception.Message)" }
        $journal = ConvertFrom-SyncVisionServerInstallJournalText -Text $text -ExpectedInstallDir $InstallDir
        if ((Get-SyncVisionInstallRegularFileIdentity -Path $journalPath) -cne $journalIdentity) {
            throw "Server install transaction journal identity changed while it was read."
        }
        $journal | Add-Member -NotePropertyName JournalFileIdentity -NotePropertyValue $journalIdentity -Force
        $journal | Add-Member `
            -NotePropertyName JournalSha256 `
            -NotePropertyValue (Get-SyncVisionServerInstallJournalSha256 -Bytes $bytes) `
            -Force
        return $journal
    }
    finally { $stream.Dispose() }
}

function Set-SyncVisionServerInstallJournalPhase {
    param(
        [Parameter(Mandatory = $true)][object]$Journal,
        [Parameter(Mandatory = $true)][string]$Phase,
        [AllowEmptyString()][string]$CandidateIdentity = ([string]$Journal.CandidateIdentity)
    )

    $current = Assert-SyncVisionServerInstallJournal -Journal $Journal
    if (@(Get-SyncVisionServerInstallJournalPhases) -cnotcontains $Phase) {
        throw "Unsupported server install transaction journal phase transition target: $Phase"
    }
    $allowedTransitions = @{
        Prepared = @("Prepared", "ServiceStopPending", "BackupMovePending", "PublishMovePending")
        ServiceStopPending = @("ServiceStopMutationStarted")
        ServiceStopMutationStarted = @("ServiceStopped")
        ServiceStopped = @("DirectoriesPending", "BackupMovePending", "PublishMovePending")
        DirectoriesPending = @("DirectoriesApplied")
        DirectoriesApplied = @("DirectoriesApplied", "BackupMovePending", "PublishMovePending")
        BackupMovePending = @("BackupMoved")
        BackupMoved = @("PublishMovePending")
        PublishMovePending = @("Published")
        Published = @("ConfigPending", "ForwardCommitted")
        ConfigPending = @("ConfigApplied")
        ConfigApplied = @("ServiceDefinitionPending")
        ServiceDefinitionPending = @("ServiceDefinitionMutationStarted")
        ServiceDefinitionMutationStarted = @("ServiceDefinitionApplied")
        ServiceDefinitionApplied = @("FirewallPending")
        FirewallPending = @("FirewallMutationStarted")
        FirewallMutationStarted = @("FirewallApplied")
        FirewallApplied = @("ServiceStartPending")
        ServiceStartPending = @("ServiceStarted")
        ServiceStarted = @("VerificationPending")
        VerificationPending = @("Verified")
        Verified = @("ForwardCommitted")
        ForwardCommitted = @("Committed")
        Committed = @("Committed")
    }
    if (@($allowedTransitions[$current.Phase]) -cnotcontains $Phase) {
        throw "Refusing invalid server install transaction phase transition $($current.Phase) -> $Phase."
    }
    $Journal.Phase = $Phase
    $Journal.CandidateIdentity = $CandidateIdentity
    $persisted = Write-SyncVisionServerInstallJournal -Journal $Journal
    $Journal.Phase = $persisted.Phase
    $Journal.CandidateIdentity = $persisted.CandidateIdentity
    $Journal | Add-Member `
        -NotePropertyName JournalFileIdentity `
        -NotePropertyValue $persisted.JournalFileIdentity `
        -Force
    $Journal | Add-Member `
        -NotePropertyName JournalSha256 `
        -NotePropertyValue $persisted.JournalSha256 `
        -Force
    return $Journal
}

function Get-SyncVisionServerInstallJournalTreeState {
    param(
        [Parameter(Mandatory = $true)][string]$Path,
        [AllowEmptyCollection()][object[]]$ExpectedInputs = @(),
        [AllowEmptyString()][string]$ExpectedIdentity = ""
    )

    if ($null -eq (Get-SyncVisionServerInstallSiblingItem -Path $Path)) {
        return [pscustomobject]@{
            Exists = $false
            Exact = $false
            Empty = $false
            Identity = ""
            IdentityMatches = $false
        }
    }
    $canonicalPath = Assert-SyncVisionServerInstallDestinationBoundary -InstallDir $Path
    $identity = Get-SyncVisionInstallFileSystemIdentity -Path $canonicalPath
    $observed = @(Get-ChildItem -LiteralPath $canonicalPath -Force)
    $expected = @(ConvertTo-SyncVisionServerInstallJournalInputs `
            -Inputs $ExpectedInputs `
            -Context "Server install recovery expected file set")
    $expectedByName = New-Object "System.Collections.Generic.Dictionary[string,object]" ([StringComparer]::OrdinalIgnoreCase)
    foreach ($record in $expected) { $expectedByName.Add($record.DestinationName, $record) }
    $exact = $observed.Count -eq $expected.Count
    if ($exact) {
        foreach ($file in $observed) {
            if ($file.PSIsContainer -or
                ($file.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0 -or
                -not $expectedByName.ContainsKey($file.Name)) {
                $exact = $false
                break
            }
            try {
                Assert-SyncVisionFileTrustMetadata `
                    -Path $file.FullName `
                    -Context "Server install recovery tree verification" | Out-Null
            }
            catch {
                $exact = $false
                break
            }
            $record = $expectedByName[$file.Name]
            if ($file.Length -ne [int64]$record.ExpectedLength -or
                (Get-FileHash -LiteralPath $file.FullName -Algorithm SHA256).Hash.ToLowerInvariant() -cne [string]$record.ExpectedHash) {
                $exact = $false
                break
            }
        }
    }
    return [pscustomobject]@{
        Exists = $true
        Exact = $exact
        Empty = ($observed.Count -eq 0)
        Identity = $identity
        IdentityMatches = (-not [string]::IsNullOrEmpty($ExpectedIdentity) -and $identity -ceq $ExpectedIdentity)
    }
}

function Enter-SyncVisionServerInstallJournalFinalUseLease {
    param([Parameter(Mandatory = $true)][object]$Journal)

    $expected = Assert-SyncVisionServerInstallJournal -Journal $Journal
    if ($null -eq $expected.PSObject.Properties["JournalFileIdentity"] -or
        [string]::IsNullOrEmpty([string]$expected.JournalFileIdentity)) {
        throw "Server install transaction final use requires the journal File ID returned by its protected read or write."
    }
    $path = Assert-SyncVisionServerInstallJournalFileSecurity -Path $expected.JournalPath
    $stream = [IO.File]::Open(
        $path,
        [IO.FileMode]::Open,
        [IO.FileAccess]::Read,
        [IO.FileShare]::Read)
    try {
        $identity = Get-SyncVisionInstallRegularFileIdentity -Path $path
        if ($identity -cne [string]$expected.JournalFileIdentity) {
            throw "Server install transaction journal File ID changed before destructive final use."
        }
        if ($stream.Length -le 0 -or $stream.Length -gt 1048576) {
            throw "Server install transaction journal size is invalid at destructive final use."
        }
        $bytes = New-Object byte[] ([int]$stream.Length)
        $offset = 0
        while ($offset -lt $bytes.Length) {
            $read = $stream.Read($bytes, $offset, $bytes.Length - $offset)
            if ($read -le 0) { throw "Server install transaction journal read ended early at destructive final use." }
            $offset += $read
        }
        try { $text = [Text.UTF8Encoding]::new($false, $true).GetString($bytes) }
        catch { throw "Server install transaction journal is not strict UTF-8 at destructive final use." }
        $current = ConvertFrom-SyncVisionServerInstallJournalText `
            -Text $text `
            -ExpectedInstallDir $expected.InstallPath
        $current | Add-Member -NotePropertyName JournalFileIdentity -NotePropertyValue $identity -Force
        if ((ConvertTo-SyncVisionServerInstallJournalText -Journal $current) -cne
            (ConvertTo-SyncVisionServerInstallJournalText -Journal $expected)) {
            throw "Server install transaction journal transaction, phase, or target identity changed before destructive final use."
        }
        return [pscustomobject]@{ Stream = $stream; Journal = $current }
    }
    catch {
        $stream.Dispose()
        throw
    }
}

function Exit-SyncVisionServerInstallJournalFinalUseLease {
    param([AllowNull()]$Lease)

    if ($null -ne $Lease -and $null -ne $Lease.Stream) { $Lease.Stream.Dispose() }
}

function Get-SyncVisionServerInstallJournalTreeRemovalPlan {
    param(
        [Parameter(Mandatory = $true)][object]$Journal,
        [Parameter(Mandatory = $true)]
        [ValidateSet("RollbackCandidateLive", "RollbackCandidatePublish", "CommittedPreviousBackup")]
        [string]$Operation
    )

    $journalState = Assert-SyncVisionServerInstallJournal -Journal $Journal
    $rollbackCandidatePhases = @(
        "PublishMovePending", "Published", "ConfigPending", "ConfigApplied",
        "ServiceDefinitionPending", "ServiceDefinitionMutationStarted", "ServiceDefinitionApplied",
        "FirewallPending", "FirewallMutationStarted", "FirewallApplied",
        "ServiceStartPending", "ServiceStarted", "VerificationPending", "Verified")
    switch ($Operation) {
        "RollbackCandidateLive" {
            $path = $journalState.InstallPath
            $expectedInputs = $journalState.NewInputs
            $expectedIdentity = $journalState.CandidateIdentity
            $allowedPhases = $rollbackCandidatePhases
        }
        "RollbackCandidatePublish" {
            $path = $journalState.PublishPath
            $expectedInputs = $journalState.NewInputs
            $expectedIdentity = $journalState.CandidateIdentity
            $allowedPhases = @(
                "Prepared", "ServiceStopPending", "ServiceStopMutationStarted", "ServiceStopped", "DirectoriesPending", "DirectoriesApplied",
                "BackupMovePending", "BackupMoved") + $rollbackCandidatePhases
        }
        "CommittedPreviousBackup" {
            if (-not $journalState.HadPrevious) {
                throw "A fresh install has no predecessor backup eligible for committed cleanup."
            }
            $path = $journalState.BackupPath
            $expectedInputs = $journalState.PreviousInputs
            $expectedIdentity = $journalState.PreviousIdentity
            $allowedPhases = @("ForwardCommitted", "Committed")
        }
    }
    if ($allowedPhases -cnotcontains $journalState.Phase) {
        throw "Server install tree removal operation $Operation is not allowed in journal phase $($journalState.Phase)."
    }
    if ([string]::IsNullOrEmpty([string]$expectedIdentity)) {
        throw "Server install tree removal operation $Operation has no directory identity recorded in the protected journal."
    }
    return [pscustomobject]@{
        Path = [string]$path
        ExpectedInputs = @($expectedInputs)
        ExpectedIdentity = [string]$expectedIdentity
    }
}

function Remove-SyncVisionServerInstallJournalTree {
    param(
        [Parameter(Mandatory = $true)][object]$Journal,
        [Parameter(Mandatory = $true)]
        [ValidateSet("RollbackCandidateLive", "RollbackCandidatePublish", "CommittedPreviousBackup")]
        [string]$Operation,
        [AllowNull()][scriptblock]$TestFinalUseHook,
        [AllowNull()][scriptblock]$TestHandleUseHook
    )

    $journalState = Assert-SyncVisionServerInstallJournal -Journal $Journal
    $plan = Get-SyncVisionServerInstallJournalTreeRemovalPlan -Journal $journalState -Operation $Operation
    $observedState = Get-SyncVisionServerInstallJournalTreeState `
        -Path $plan.Path `
        -ExpectedInputs $plan.ExpectedInputs `
        -ExpectedIdentity $plan.ExpectedIdentity
    if (-not $observedState.Exists) { return }
    if (-not $observedState.IdentityMatches) {
        throw "Refusing to remove a server install transaction tree whose directory identity changed: $($plan.Path)"
    }
    if ($null -ne $TestFinalUseHook) { & $TestFinalUseHook $journalState $observedState }

    $parentLease = $null
    $lease = $null
    $treeLease = $null
    try {
        $parentIdentity = Get-SyncVisionInstallFileSystemIdentity -Path $journalState.ParentPath
        $parentLease = Enter-SyncVisionInstallDirectoryLease `
            -Path $journalState.ParentPath `
            -ExpectedIdentity $parentIdentity
        $lease = Enter-SyncVisionServerInstallJournalFinalUseLease -Journal $journalState
        $finalPlan = Get-SyncVisionServerInstallJournalTreeRemovalPlan `
            -Journal $lease.Journal `
            -Operation $Operation
        $canonicalPath = Assert-SyncVisionServerInstallDestinationBoundary -InstallDir $finalPlan.Path
        if (-not [string]::Equals(
                (Split-Path -Parent $canonicalPath),
                $lease.Journal.ParentPath,
                [StringComparison]::OrdinalIgnoreCase)) {
            throw "Server install tree removal operation $Operation escaped its protected journal parent."
        }
        $item = Get-SyncVisionServerInstallSiblingItem -Path $canonicalPath
        if ($null -eq $item) {
            throw "Refusing to remove a server install transaction tree that disappeared before final use: $canonicalPath"
        }
        if (-not $item.PSIsContainer -or
            ($item.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
            throw "Refusing to remove a server install transaction path that changed type at final use: $canonicalPath"
        }
        if ((Get-SyncVisionInstallFileSystemIdentity -Path $item.FullName) -cne $finalPlan.ExpectedIdentity) {
            throw "Refusing to remove a server install transaction tree whose directory identity changed at final use: $canonicalPath"
        }
        $treeLease = Enter-SyncVisionInstallDirectoryLease `
            -Path $item.FullName `
            -ExpectedIdentity $finalPlan.ExpectedIdentity `
            -DeleteAccess
        Assert-SyncVisionExistingPathChainNoReparse `
            -Path (Split-Path -Parent $item.FullName) `
            -Context "Server install transaction tree final removal parent"
        if ($null -ne $TestHandleUseHook) { & $TestHandleUseHook $canonicalPath }
        $treeLease.DeleteTree()
        Exit-SyncVisionInstallDirectoryLease -Lease $treeLease
        $treeLease = $null
        if ($null -ne (Get-SyncVisionServerInstallSiblingItem -Path $canonicalPath)) {
            throw "The identity-bound server install tree was removed, but a replacement appeared at its protected path."
        }
    }
    finally {
        Exit-SyncVisionInstallDirectoryLease -Lease $treeLease
        Exit-SyncVisionServerInstallJournalFinalUseLease -Lease $lease
        Exit-SyncVisionInstallDirectoryLease -Lease $parentLease
    }
}

function Get-SyncVisionServerInstallJournalTreeMovePlan {
    param(
        [Parameter(Mandatory = $true)][object]$Journal,
        [Parameter(Mandatory = $true)]
        [ValidateSet("PreviousLiveToBackup", "PreviousBackupToLive", "CandidatePublishToLive")]
        [string]$Operation
    )

    $journalState = Assert-SyncVisionServerInstallJournal -Journal $Journal
    switch ($Operation) {
        "PreviousLiveToBackup" {
            if (-not $journalState.HadPrevious) {
                throw "A fresh install cannot move a previous live tree to backup."
            }
            $sourcePath = $journalState.InstallPath
            $destinationPath = $journalState.BackupPath
            $expectedInputs = $journalState.PreviousInputs
            $expectedIdentity = $journalState.PreviousIdentity
            $allowedPhases = @("BackupMovePending")
        }
        "PreviousBackupToLive" {
            if (-not $journalState.HadPrevious) {
                throw "A fresh install cannot restore a previous backup tree."
            }
            $sourcePath = $journalState.BackupPath
            $destinationPath = $journalState.InstallPath
            $expectedInputs = $journalState.PreviousInputs
            $expectedIdentity = $journalState.PreviousIdentity
            $allowedPhases = @(
                "BackupMovePending", "BackupMoved", "PublishMovePending", "Published", "ConfigPending", "ConfigApplied",
                "ServiceDefinitionPending", "ServiceDefinitionMutationStarted", "ServiceDefinitionApplied",
                "FirewallPending", "FirewallMutationStarted", "FirewallApplied",
                "ServiceStartPending", "ServiceStarted", "VerificationPending", "Verified")
        }
        "CandidatePublishToLive" {
            $sourcePath = $journalState.PublishPath
            $destinationPath = $journalState.InstallPath
            $expectedInputs = $journalState.NewInputs
            $expectedIdentity = $journalState.CandidateIdentity
            $allowedPhases = @("PublishMovePending")
        }
    }
    if ($allowedPhases -cnotcontains $journalState.Phase) {
        throw "Server install tree move operation $Operation is not allowed in journal phase $($journalState.Phase)."
    }
    if ([string]::IsNullOrEmpty([string]$expectedIdentity)) {
        throw "Server install transaction move $Operation is missing its recorded source directory identity."
    }
    return [pscustomobject]@{
        SourcePath = [string]$sourcePath
        DestinationPath = [string]$destinationPath
        ExpectedInputs = @($expectedInputs)
        ExpectedIdentity = [string]$expectedIdentity
    }
}

function Move-SyncVisionServerInstallJournalTree {
    param(
        [Parameter(Mandatory = $true)][object]$Journal,
        [Parameter(Mandatory = $true)]
        [ValidateSet("PreviousLiveToBackup", "PreviousBackupToLive", "CandidatePublishToLive")]
        [string]$Operation,
        [AllowNull()][scriptblock]$TestFinalUseHook,
        [AllowNull()][scriptblock]$TestHandleUseHook
    )

    $journalState = Assert-SyncVisionServerInstallJournal -Journal $Journal
    $plan = Get-SyncVisionServerInstallJournalTreeMovePlan -Journal $journalState -Operation $Operation
    $sourceState = Get-SyncVisionServerInstallJournalTreeState `
        -Path $plan.SourcePath `
        -ExpectedInputs $plan.ExpectedInputs `
        -ExpectedIdentity $plan.ExpectedIdentity
    if (-not $sourceState.Exists -or -not $sourceState.Exact -or -not $sourceState.IdentityMatches) {
        throw "Server install transaction move refuses a missing, changed, or incomplete source tree: $($plan.SourcePath)"
    }
    if ($null -ne (Get-SyncVisionServerInstallSiblingItem -Path $plan.DestinationPath)) {
        throw "Server install transaction move refuses an existing destination tree: $($plan.DestinationPath)"
    }

    if ($null -ne $TestFinalUseHook) { & $TestFinalUseHook $journalState $sourceState }
    $parentLease = $null
    $lease = $null
    $sourceLease = $null
    try {
        $parentIdentity = Get-SyncVisionInstallFileSystemIdentity -Path $journalState.ParentPath
        $parentLease = Enter-SyncVisionInstallDirectoryLease `
            -Path $journalState.ParentPath `
            -ExpectedIdentity $parentIdentity
        $lease = Enter-SyncVisionServerInstallJournalFinalUseLease -Journal $journalState
        $finalPlan = Get-SyncVisionServerInstallJournalTreeMovePlan `
            -Journal $lease.Journal `
            -Operation $Operation
        $source = Assert-SyncVisionServerInstallDestinationBoundary -InstallDir $finalPlan.SourcePath
        $destination = Assert-SyncVisionServerInstallDestinationBoundary -InstallDir $finalPlan.DestinationPath
        if (-not [string]::Equals((Split-Path -Parent $source), $lease.Journal.ParentPath, [StringComparison]::OrdinalIgnoreCase) -or
            -not [string]::Equals((Split-Path -Parent $destination), $lease.Journal.ParentPath, [StringComparison]::OrdinalIgnoreCase)) {
            throw "Server install transaction move escaped its transaction parent."
        }
        Assert-SyncVisionExistingPathChainNoReparse `
            -Path $lease.Journal.ParentPath `
            -Context "Server install transaction move parent"
        $sourceItem = Get-SyncVisionServerInstallSiblingItem -Path $source
        if ($null -eq $sourceItem -or -not $sourceItem.PSIsContainer -or
            ($sourceItem.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0 -or
            (Get-SyncVisionInstallFileSystemIdentity -Path $sourceItem.FullName) -cne $finalPlan.ExpectedIdentity) {
            throw "Server install transaction source identity or type changed at final move use: $source"
        }
        $sourceLease = Enter-SyncVisionInstallDirectoryLease `
            -Path $sourceItem.FullName `
            -ExpectedIdentity $finalPlan.ExpectedIdentity `
            -DeleteAccess
        $leasedSourceState = Get-SyncVisionServerInstallJournalTreeState `
            -Path $source `
            -ExpectedInputs $finalPlan.ExpectedInputs `
            -ExpectedIdentity $finalPlan.ExpectedIdentity
        if (-not $leasedSourceState.Exists -or
            -not $leasedSourceState.Exact -or
            -not $leasedSourceState.IdentityMatches) {
            throw "Server install transaction source changed after its no-follow directory lease was acquired: $source"
        }
        if ($null -ne (Get-SyncVisionServerInstallSiblingItem -Path $destination)) {
            throw "Server install transaction destination appeared before final move use: $destination"
        }

        if ($null -ne $TestHandleUseHook) { & $TestHandleUseHook $source $destination }
        $sourceLease.RenameNoReplace($destination)
        Exit-SyncVisionInstallDirectoryLease -Lease $sourceLease
        $sourceLease = $null
        $destinationState = Get-SyncVisionServerInstallJournalTreeState `
            -Path $destination `
            -ExpectedInputs $finalPlan.ExpectedInputs `
            -ExpectedIdentity $finalPlan.ExpectedIdentity
        if (-not $destinationState.Exists -or -not $destinationState.Exact -or -not $destinationState.IdentityMatches) {
            throw "Server install transaction move did not publish the exact recorded tree: $destination"
        }
    }
    finally {
        Exit-SyncVisionInstallDirectoryLease -Lease $sourceLease
        Exit-SyncVisionServerInstallJournalFinalUseLease -Lease $lease
        Exit-SyncVisionInstallDirectoryLease -Lease $parentLease
    }
}

function Remove-SyncVisionServerInstallJournalFile {
    param(
        [Parameter(Mandatory = $true)][object]$Journal,
        [Parameter(Mandatory = $true)][string]$InstallDir,
        [AllowNull()][scriptblock]$TestFinalUseHook
    )

    $expected = Assert-SyncVisionServerInstallJournal -Journal $Journal -ExpectedInstallDir $InstallDir
    if ($null -eq (Get-SyncVisionServerInstallSiblingItem -Path $expected.JournalPath)) { return }
    $validatedPath = Assert-SyncVisionServerInstallJournalFileSecurity -Path $expected.JournalPath
    $validatedIdentity = Get-SyncVisionInstallRegularFileIdentity -Path $validatedPath
    $current = Read-SyncVisionServerInstallJournal -InstallDir $InstallDir
    if ((Get-SyncVisionInstallRegularFileIdentity -Path $validatedPath) -cne $validatedIdentity -or
        $current.TransactionId -cne $expected.TransactionId) {
        throw "Refusing to remove a server install transaction journal that changed transactions."
    }
    if ($null -ne $TestFinalUseHook) {
        & $TestFinalUseHook $current $validatedIdentity
    }

    $finalPath = Assert-SyncVisionServerInstallJournalFileSecurity -Path $expected.JournalPath
    $finalIdentity = Get-SyncVisionInstallRegularFileIdentity -Path $finalPath
    if ($finalIdentity -cne $validatedIdentity) {
        throw "Refusing to remove a server install transaction journal whose file identity changed at final use."
    }
    $finalJournal = Read-SyncVisionServerInstallJournal -InstallDir $InstallDir
    if ($finalJournal.TransactionId -cne $expected.TransactionId -or
        (Get-SyncVisionInstallRegularFileIdentity -Path $finalPath) -cne $validatedIdentity) {
        throw "Refusing to remove a server install transaction journal whose transaction or file identity changed at final use."
    }

    Initialize-SyncVisionServerInstallJournalAtomicType
    [SyncVisionServerInstallJournalAtomic]::DeleteIfIdentity($finalPath, $validatedIdentity)
    $replacement = Get-SyncVisionServerInstallSiblingItem -Path $expected.JournalPath
    if ($null -ne $replacement) {
        throw "The validated journal was deleted, but a replacement journal appeared at the canonical path and was preserved."
    }
}

function Invoke-SyncVisionServerInstallPublicationRecovery {
    param(
        [Parameter(Mandatory = $true)][string]$InstallDir,
        [AllowEmptyString()][string]$ExpectedTransactionId = "",
        [switch]$RollbackForwardCommitted,
        [switch]$RetainJournal
    )

    $journal = Read-SyncVisionServerInstallJournal -InstallDir $InstallDir -AllowMissing
    if ($null -eq $journal) {
        return [pscustomobject]@{ Recovered = $false; Action = "None"; TransactionId = "" }
    }
    if (-not [string]::IsNullOrEmpty($ExpectedTransactionId) -and
        $journal.TransactionId -cne $ExpectedTransactionId) {
        throw "Server install transaction journal belongs to a different transaction."
    }

    $installAsPrevious = Get-SyncVisionServerInstallJournalTreeState `
        -Path $journal.InstallPath `
        -ExpectedInputs $journal.PreviousInputs `
        -ExpectedIdentity $journal.PreviousIdentity
    $installAsCandidate = Get-SyncVisionServerInstallJournalTreeState `
        -Path $journal.InstallPath `
        -ExpectedInputs $journal.NewInputs `
        -ExpectedIdentity $journal.CandidateIdentity
    $publishState = Get-SyncVisionServerInstallJournalTreeState `
        -Path $journal.PublishPath `
        -ExpectedInputs $journal.NewInputs `
        -ExpectedIdentity $journal.CandidateIdentity
    $backupState = Get-SyncVisionServerInstallJournalTreeState `
        -Path $journal.BackupPath `
        -ExpectedInputs $journal.PreviousInputs `
        -ExpectedIdentity $journal.PreviousIdentity

    if ($RollbackForwardCommitted -and $journal.Phase -ceq "ForwardCommitted") {
        throw "A forward-committed server install transaction cannot be rolled back."
    }
    if ($journal.Phase -ceq "Committed" -or $journal.Phase -ceq "ForwardCommitted") {
        if (-not $installAsCandidate.Exists -or
            -not $installAsCandidate.Exact -or
            -not $installAsCandidate.IdentityMatches) {
            throw "Forward-committed server install recovery refuses a missing, changed, or incomplete live tree."
        }
        if ($publishState.Exists) {
            throw "Forward-committed server install recovery found an unexpected candidate tree and preserved it for inspection."
        }
        if ($journal.HadPrevious -and $backupState.Exists) {
            if (-not $backupState.IdentityMatches) {
                throw "Forward-committed server install recovery refuses a predecessor tree whose directory identity changed."
            }
            Remove-SyncVisionServerInstallJournalTree `
                -Journal $journal `
                -Operation "CommittedPreviousBackup"
        }
        elseif (-not $journal.HadPrevious -and $backupState.Exists) {
            throw "Forward-committed fresh install recovery found an unexpected predecessor tree."
        }
        if (-not $RetainJournal) {
            Remove-SyncVisionServerInstallJournalFile -Journal $journal -InstallDir $InstallDir
        }
        $cleanupAction = if ($journal.Phase -ceq "Committed") { "CommittedCleanup" } else { "ForwardCommittedCleanup" }
        return [pscustomobject]@{ Recovered = $true; Action = $cleanupAction; TransactionId = $journal.TransactionId }
    }

    $prePublicationPhases = @(
        "Prepared", "ServiceStopPending", "ServiceStopMutationStarted", "ServiceStopped", "DirectoriesPending", "DirectoriesApplied")
    if ($prePublicationPhases -ccontains $journal.Phase) {
        if ($backupState.Exists) {
            throw "Prepared server install recovery found an unexpected predecessor backup."
        }
        if ($journal.HadPrevious) {
            if (-not $installAsPrevious.Exists -or
                -not $installAsPrevious.Exact -or
                -not $installAsPrevious.IdentityMatches) {
                throw "Prepared server install recovery refuses a changed or missing previous live tree."
            }
        }
        elseif ($installAsPrevious.Exists) {
            throw "Prepared fresh install recovery found an unexpected live tree."
        }
        if ($publishState.Exists) {
            if ([string]::IsNullOrEmpty($journal.CandidateIdentity)) {
                if (@("Prepared", "DirectoriesApplied") -cnotcontains $journal.Phase -or -not $publishState.Empty) {
                    throw "Prepared server install recovery found a non-empty or out-of-phase publication tree without a journal-bound directory identity and preserved it."
                }
                $publishPath = Assert-SyncVisionServerInstallDestinationBoundary -InstallDir $journal.PublishPath
                Assert-SyncVisionServerInstallPathAcl `
                    -Path $publishPath `
                    -RejectWrite $true `
                    -Context "Interrupted empty server install candidate" | Out-Null
                $journal = Set-SyncVisionServerInstallJournalPhase `
                    -Journal $journal `
                    -Phase $journal.Phase `
                    -CandidateIdentity (Get-SyncVisionInstallFileSystemIdentity -Path $publishPath)
                $publishState = Get-SyncVisionServerInstallJournalTreeState `
                    -Path $journal.PublishPath `
                    -ExpectedInputs $journal.NewInputs `
                    -ExpectedIdentity $journal.CandidateIdentity
            }
            Remove-SyncVisionServerInstallJournalTree `
                -Journal $journal `
                -Operation "RollbackCandidatePublish"
        }
        if (-not $RetainJournal) {
            Remove-SyncVisionServerInstallJournalFile -Journal $journal -InstallDir $InstallDir
        }
        return [pscustomobject]@{ Recovered = $true; Action = "RolledBack"; TransactionId = $journal.TransactionId }
    }

    if ($publishState.Exists -and -not $publishState.IdentityMatches) {
        throw "Server install recovery refuses a candidate tree whose directory identity changed."
    }

    if ($journal.Phase -ceq "BackupMovePending" -or $journal.Phase -ceq "BackupMoved") {
        if (-not $journal.HadPrevious) {
            throw "Server install recovery found a backup phase without a previous tree."
        }
        if ($backupState.Exists) {
            if (-not $backupState.Exact -or -not $backupState.IdentityMatches -or $installAsPrevious.Exists) {
                throw "Server install recovery refuses an ambiguous or changed predecessor backup."
            }
            if ($installAsCandidate.Exists) {
                throw "Server install recovery found a live candidate before the publish phase."
            }
            Move-SyncVisionServerInstallJournalTree `
                -Journal $journal `
                -Operation "PreviousBackupToLive"
            $installAsPrevious = Get-SyncVisionServerInstallJournalTreeState `
                -Path $journal.InstallPath `
                -ExpectedInputs $journal.PreviousInputs `
                -ExpectedIdentity $journal.PreviousIdentity
            if (-not $installAsPrevious.Exact -or -not $installAsPrevious.IdentityMatches) {
                throw "Server install recovery could not restore the exact previous live tree."
            }
        }
        elseif (-not $installAsPrevious.Exists -or
            -not $installAsPrevious.Exact -or
            -not $installAsPrevious.IdentityMatches) {
            throw "Server install recovery cannot find the exact previous tree in live or backup state."
        }
    }
    elseif (@(
            "PublishMovePending", "Published", "ConfigPending", "ConfigApplied",
            "ServiceDefinitionPending", "ServiceDefinitionMutationStarted", "ServiceDefinitionApplied",
            "FirewallPending", "FirewallMutationStarted", "FirewallApplied",
            "ServiceStartPending", "ServiceStarted", "VerificationPending", "Verified") -ccontains $journal.Phase) {
        if ($journal.HadPrevious) {
            if ($backupState.Exists) {
                if (-not $backupState.Exact -or -not $backupState.IdentityMatches -or
                    ($installAsPrevious.Exact -and $installAsPrevious.IdentityMatches)) {
                    throw "Server install recovery refuses an ambiguous or changed predecessor backup."
                }
                if ($installAsCandidate.Exists) {
                    if (-not $installAsCandidate.IdentityMatches) {
                        throw "Server install recovery refuses a live candidate whose directory identity changed."
                    }
                    Remove-SyncVisionServerInstallJournalTree `
                        -Journal $journal `
                        -Operation "RollbackCandidateLive"
                }
                Move-SyncVisionServerInstallJournalTree `
                    -Journal $journal `
                    -Operation "PreviousBackupToLive"
                $installAsPrevious = Get-SyncVisionServerInstallJournalTreeState `
                    -Path $journal.InstallPath `
                    -ExpectedInputs $journal.PreviousInputs `
                    -ExpectedIdentity $journal.PreviousIdentity
                if (-not $installAsPrevious.Exact -or -not $installAsPrevious.IdentityMatches) {
                    throw "Server install recovery could not restore the exact previous live tree."
                }
            }
            elseif (-not $installAsPrevious.Exists -or
                -not $installAsPrevious.Exact -or
                -not $installAsPrevious.IdentityMatches) {
                throw "Server install recovery cannot find the exact previous tree after an interrupted publish."
            }
        }
        else {
            if ($backupState.Exists) {
                throw "Fresh server install recovery found an unexpected predecessor backup."
            }
            if ($installAsCandidate.Exists) {
                if (-not $installAsCandidate.IdentityMatches) {
                    throw "Fresh server install recovery refuses a live candidate whose identity changed."
                }
                Remove-SyncVisionServerInstallJournalTree `
                    -Journal $journal `
                    -Operation "RollbackCandidateLive"
            }
        }
    }
    else {
        throw "Server install recovery does not recognize phase $($journal.Phase)."
    }

    if ($publishState.Exists) {
        Remove-SyncVisionServerInstallJournalTree `
            -Journal $journal `
            -Operation "RollbackCandidatePublish"
    }
    if (-not $RetainJournal) {
        Remove-SyncVisionServerInstallJournalFile -Journal $journal -InstallDir $InstallDir
    }
    return [pscustomobject]@{ Recovered = $true; Action = "RolledBack"; TransactionId = $journal.TransactionId }
}

function Publish-SyncVisionExactServerInstallTree {
    param(
        [Parameter(Mandatory = $true)][string]$InstallDir,
        [Parameter(Mandatory = $true)][object[]]$StagedInputs,
        [switch]$RetainBackup,
        [AllowNull()][object]$PreparedJournal,
        [AllowNull()][scriptblock]$TestPhaseHook
    )

    Assert-SyncVisionStagedPackageInstallInputs -StagedInputs $StagedInputs
    $installPath = Assert-SyncVisionServerInstallDestinationBoundary -InstallDir $InstallDir
    $parentPath = Split-Path -Parent $installPath
    $leafName = Split-Path -Leaf $installPath
    New-Item -ItemType Directory -Force -Path $parentPath | Out-Null
    $installPath = Assert-SyncVisionServerInstallDestinationBoundary -InstallDir $installPath
    $nonce = if ($null -eq $PreparedJournal) { [Guid]::NewGuid().ToString("N") } else { [string]$PreparedJournal.TransactionId }
    $hadPrevious = Test-Path -LiteralPath $installPath -PathType Container
    $previousInputs = @()
    $previousIdentity = ""
    if ($hadPrevious) {
        Assert-SyncVisionServerInstallDestinationBoundary -InstallDir $installPath | Out-Null
        $previousIdentity = Get-SyncVisionInstallFileSystemIdentity -Path $installPath
        $previousInputs = @(
            Get-ChildItem -LiteralPath $installPath -File -Force |
                ForEach-Object {
                    [pscustomobject]@{
                        DestinationName = $_.Name
                        ExpectedLength = [int64]$_.Length
                        ExpectedHash = (Get-FileHash -LiteralPath $_.FullName -Algorithm SHA256).Hash.ToLowerInvariant()
                    }
                })
    }
    $newInputs = @(ConvertTo-SyncVisionServerInstallJournalInputs `
            -Inputs $StagedInputs `
            -Context "Server install transaction candidate file set" `
            -RequireServerExecutable)
    $existingJournal = Read-SyncVisionServerInstallJournal -InstallDir $installPath -AllowMissing
    if ($null -eq $PreparedJournal) {
        if ($null -ne $existingJournal) {
            throw "An interrupted server install transaction must be recovered before a new publication starts: $($existingJournal.JournalPath)"
        }
        $journal = New-SyncVisionServerInstallJournal `
            -InstallDir $installPath `
            -TransactionId $nonce `
            -HadPrevious $hadPrevious `
            -PreviousInputs $previousInputs `
            -NewInputs $newInputs `
            -PreviousIdentity $previousIdentity
        $journal = Write-SyncVisionServerInstallJournal -Journal $journal
        $ownsJournal = $true
    }
    else {
        $journal = Assert-SyncVisionServerInstallJournal -Journal $PreparedJournal -ExpectedInstallDir $installPath
        if ($null -eq $existingJournal -or
            $existingJournal.TransactionId -cne $journal.TransactionId -or
            (ConvertTo-SyncVisionServerInstallJournalText -Journal $existingJournal) -cne
                (ConvertTo-SyncVisionServerInstallJournalText -Journal $journal) -or
            [bool]$journal.HadPrevious -ne $hadPrevious -or
            [string]$journal.PreviousIdentity -cne $previousIdentity -or
            (ConvertTo-Json @($journal.PreviousInputs) -Compress -Depth 10) -cne
                (ConvertTo-Json @($previousInputs) -Compress -Depth 10) -or
            (ConvertTo-Json @($journal.NewInputs) -Compress -Depth 10) -cne
                (ConvertTo-Json @($newInputs) -Compress -Depth 10)) {
            throw "Prepared full install journal no longer matches the exact binary publication boundary."
        }
        $ownsJournal = $false
    }
    $publication = [pscustomobject]@{
        InstallPath = $journal.InstallPath
        BackupPath = $journal.BackupPath
        PublishPath = $journal.PublishPath
        ParentPath = $journal.ParentPath
        BackupPrefix = "$leafName.previous-"
        HadPrevious = $journal.HadPrevious
        PreviousInputs = $journal.PreviousInputs
        NewInputs = $journal.NewInputs
        JournalPath = $journal.JournalPath
        TransactionId = $journal.TransactionId
        Journal = $journal
    }
    try {
        [IO.Directory]::CreateDirectory(
            $journal.PublishPath,
            (New-SyncVisionProtectedServerPublicationDirectorySecurity)) | Out-Null
        Assert-SyncVisionServerInstallDestinationBoundary -InstallDir $journal.PublishPath | Out-Null
        if ($null -ne $TestPhaseHook) {
            & $TestPhaseHook "AfterCandidateDirectoryCreatedBeforeIdentityJournal" $journal
        }
        $candidateIdentity = Get-SyncVisionInstallFileSystemIdentity -Path $journal.PublishPath
        $journal = Set-SyncVisionServerInstallJournalPhase `
            -Journal $journal `
            -Phase $journal.Phase `
            -CandidateIdentity $candidateIdentity
        if ($null -ne $TestPhaseHook) {
            & $TestPhaseHook "AfterPreparedJournal" $journal
        }
        foreach ($input in $StagedInputs) {
            $destinationName = if ($null -ne $input.PSObject.Properties["DestinationName"]) {
                [string]$input.DestinationName
            }
            else {
                Split-Path -Leaf $input.Path
            }
            Assert-SyncVisionServerInstallDestinationBoundary -InstallDir $installPath | Out-Null
            Assert-SyncVisionServerInstallDestinationBoundary -InstallDir $journal.PublishPath | Out-Null
            [IO.File]::Copy($input.Path, (Join-Path $journal.PublishPath $destinationName), $false)
        }
        Assert-SyncVisionExactServerInstallTree -InstallDir $journal.PublishPath -StagedInputs $journal.NewInputs | Out-Null

        if ($journal.HadPrevious) {
            Assert-SyncVisionServerInstallDestinationBoundary -InstallDir $installPath | Out-Null
            $previousState = Get-SyncVisionServerInstallJournalTreeState `
                -Path $installPath `
                -ExpectedInputs $journal.PreviousInputs `
                -ExpectedIdentity $journal.PreviousIdentity
            if (-not $previousState.Exact -or -not $previousState.IdentityMatches) {
                throw "Previous server install tree content or identity changed before backup publication."
            }
            $journal = Set-SyncVisionServerInstallJournalPhase -Journal $journal -Phase "BackupMovePending"
            if ($null -ne $TestPhaseHook) {
                & $TestPhaseHook "AfterBackupMovePendingJournal" $journal
            }
            Move-SyncVisionServerInstallJournalTree `
                -Journal $journal `
                -Operation "PreviousLiveToBackup"
            if ($null -ne $TestPhaseHook) {
                & $TestPhaseHook "AfterBackupMoveBeforeJournal" $journal
            }
            Assert-SyncVisionServerInstallDestinationBoundary -InstallDir $journal.BackupPath | Out-Null
            if ((Get-SyncVisionInstallFileSystemIdentity -Path $journal.BackupPath) -cne $journal.PreviousIdentity) {
                throw "Previous server install tree identity changed during backup publication."
            }
            $journal = Set-SyncVisionServerInstallJournalPhase -Journal $journal -Phase "BackupMoved"
            if ($null -ne $TestPhaseHook) {
                & $TestPhaseHook "AfterBackupMovedJournal" $journal
            }
        }
        $journal = Set-SyncVisionServerInstallJournalPhase -Journal $journal -Phase "PublishMovePending"
        if ($null -ne $TestPhaseHook) {
            & $TestPhaseHook "AfterPublishMovePendingJournal" $journal
        }
        Assert-SyncVisionServerInstallDestinationBoundary -InstallDir $installPath | Out-Null
        Assert-SyncVisionServerInstallDestinationBoundary -InstallDir $journal.PublishPath | Out-Null
        Move-SyncVisionServerInstallJournalTree `
            -Journal $journal `
            -Operation "CandidatePublishToLive"
        if ($null -ne $TestPhaseHook) {
            & $TestPhaseHook "AfterPublishMoveBeforeJournal" $journal
        }
        if ((Get-SyncVisionInstallFileSystemIdentity -Path $installPath) -cne $journal.CandidateIdentity) {
            throw "Candidate server install tree identity changed during live publication."
        }
        $journal = Set-SyncVisionServerInstallJournalPhase -Journal $journal -Phase "Published"
        Assert-SyncVisionExactServerInstallTree -InstallDir $installPath -StagedInputs $journal.NewInputs | Out-Null
        if ($null -ne $TestPhaseHook) {
            & $TestPhaseHook "AfterPublishedJournal" $journal
        }

        if ($RetainBackup) {
            return $publication
        }
        Set-SyncVisionServerInstallPublicationCrashForwardPoint -Publication $publication | Out-Null
        Complete-SyncVisionServerInstallPublication -Publication $publication
        $journal = Set-SyncVisionServerInstallJournalPhase -Journal $journal -Phase "Committed"
        $publication.Journal = $journal
        Remove-SyncVisionServerInstallPublicationBackupAfterCommit -Publication $publication | Out-Null
        return $installPath
    }
    catch {
        $publicationError = $_
        if (-not $ownsJournal) { throw $publicationError }
        $recoveryError = $null
        try {
            Invoke-SyncVisionServerInstallPublicationRecovery `
                -InstallDir $installPath `
                -ExpectedTransactionId $nonce | Out-Null
        }
        catch { $recoveryError = $_ }
        if ($null -ne $recoveryError) {
            throw "Exact server install publication failed and durable rollback was incomplete. Transaction artifacts were preserved. Publication failure: $($publicationError.Exception.Message) Recovery failure: $($recoveryError.Exception.Message)"
        }
        throw $publicationError
    }
}

function Set-SyncVisionServerInstallPublicationCrashForwardPoint {
    param(
        [Parameter(Mandatory = $true)][object]$Publication,
        [ValidateSet("Published", "Verified")]
        [string]$ExpectedJournalPhase = "Published",
        [AllowNull()][scriptblock]$TestPhaseHook
    )

    Complete-SyncVisionServerInstallPublication `
        -Publication $Publication `
        -ExpectedJournalPhase $ExpectedJournalPhase
    $Publication.Journal = Set-SyncVisionServerInstallJournalPhase `
        -Journal $Publication.Journal `
        -Phase "ForwardCommitted"
    if ($null -ne $TestPhaseHook) {
        & $TestPhaseHook "AfterForwardCommittedJournal" $Publication.Journal
    }
    return $Publication
}

function Restore-SyncVisionServerInstallPublication {
    param([Parameter(Mandatory = $true)][object]$Publication)

    if ($null -eq $Publication.PSObject.Properties["Journal"] -or
        $null -eq $Publication.Journal) {
        throw "Server install publication rollback requires its protected durable journal; refusing path-only destructive fallback."
    }
    $currentJournal = Read-SyncVisionServerInstallJournal -InstallDir $Publication.InstallPath
    if ($currentJournal.TransactionId -cne [string]$Publication.TransactionId) {
        throw "Retained server install publication journal changed transactions before rollback."
    }
    if ($currentJournal.Phase -ceq "Committed" -or $currentJournal.Phase -ceq "ForwardCommitted") {
        throw "A forward-committed server install publication cannot be rolled back."
    }
    $recovery = Invoke-SyncVisionServerInstallPublicationRecovery `
        -InstallDir $Publication.InstallPath `
        -ExpectedTransactionId $Publication.TransactionId
    if (-not $recovery.Recovered -or $recovery.Action -cne "RolledBack") {
        throw "Durable server install publication rollback did not restore the previous state."
    }
}

function Complete-SyncVisionServerInstallPublication {
    param(
        [Parameter(Mandatory = $true)][object]$Publication,
        [ValidateSet("Published", "Verified", "ForwardCommitted")]
        [string]$ExpectedJournalPhase = "ForwardCommitted"
    )

    Assert-SyncVisionExactServerInstallTree `
        -InstallDir $Publication.InstallPath `
        -StagedInputs $Publication.NewInputs | Out-Null
    if ($Publication.HadPrevious) {
        if (-not (Test-Path -LiteralPath $Publication.BackupPath -PathType Container)) {
            throw "Retained server install backup is missing before commit: $($Publication.BackupPath)"
        }
        Assert-SyncVisionExactServerInstallTree `
            -InstallDir $Publication.BackupPath `
            -StagedInputs $Publication.PreviousInputs | Out-Null
    }
    if ($null -ne $Publication.PSObject.Properties["Journal"] -and
        $null -ne $Publication.Journal) {
        $currentJournal = Read-SyncVisionServerInstallJournal -InstallDir $Publication.InstallPath
        if ($currentJournal.TransactionId -cne [string]$Publication.TransactionId -or
            $currentJournal.Phase -cne $ExpectedJournalPhase) {
            throw "Server install publication journal is not in the exact $ExpectedJournalPhase phase before commit."
        }
        if ((Get-SyncVisionInstallFileSystemIdentity -Path $Publication.InstallPath) -cne $currentJournal.CandidateIdentity) {
            throw "Server install publication live directory identity changed before commit."
        }
        if ($Publication.HadPrevious -and
            (Get-SyncVisionInstallFileSystemIdentity -Path $Publication.BackupPath) -cne $currentJournal.PreviousIdentity) {
            throw "Server install publication predecessor directory identity changed before commit."
        }
    }
}

function Remove-SyncVisionServerInstallPublicationBackupAfterCommit {
    param([Parameter(Mandatory = $true)][object]$Publication)

    try {
        if ($null -eq $Publication.PSObject.Properties["Journal"] -or
            $null -eq $Publication.Journal) {
            throw "Committed server install publication cleanup requires its protected durable journal; refusing path-only destructive fallback."
        }
        $currentJournal = Read-SyncVisionServerInstallJournal -InstallDir $Publication.InstallPath
        if ($currentJournal.TransactionId -cne [string]$Publication.TransactionId -or
            $currentJournal.Phase -cne "Committed") {
            throw "Server install publication journal is not durably committed before cleanup."
        }
        $recovery = Invoke-SyncVisionServerInstallPublicationRecovery `
            -InstallDir $Publication.InstallPath `
            -ExpectedTransactionId $Publication.TransactionId
        if (-not $recovery.Recovered -or $recovery.Action -cne "CommittedCleanup") {
            throw "Committed server install publication cleanup did not finish."
        }
        return $true
    }
    catch {
        Write-Warning "Install commit is complete; predecessor cleanup did not complete and will not trigger rollback: $($_.Exception.Message)"
        return $false
    }
}

function Invoke-SyncVisionServerInstallBackendAction {
    param(
        [Parameter(Mandatory = $true)][object]$Backend,
        [Parameter(Mandatory = $true)][string]$Name,
        [Parameter(Mandatory = $true)][object]$State
    )

    $property = $Backend.PSObject.Properties[$Name]
    if ($null -eq $property -or $property.Value -isnot [scriptblock]) {
        throw "Server install transaction backend '$($Backend.Kind)' is missing action $Name."
    }
    & $property.Value $State
}

function Assert-SyncVisionServerInstallPreviousBinaryState {
    param([Parameter(Mandatory = $true)][object]$Journal)

    $journalState = Assert-SyncVisionServerInstallJournal -Journal $Journal
    $previous = Get-SyncVisionServerInstallJournalTreeState `
        -Path $journalState.InstallPath `
        -ExpectedInputs $journalState.PreviousInputs `
        -ExpectedIdentity $journalState.PreviousIdentity
    if ($journalState.HadPrevious) {
        if (-not $previous.Exists -or -not $previous.Exact -or -not $previous.IdentityMatches) {
            throw "Server install rollback did not restore the exact previous binary tree and File ID."
        }
    }
    elseif ($previous.Exists) {
        throw "Fresh server install rollback left a live binary tree."
    }
}

function Assert-SyncVisionServerInstallCandidateBinaryState {
    param([Parameter(Mandatory = $true)][object]$Journal)

    $journalState = Assert-SyncVisionServerInstallJournal -Journal $Journal
    $candidate = Get-SyncVisionServerInstallJournalTreeState `
        -Path $journalState.InstallPath `
        -ExpectedInputs $journalState.NewInputs `
        -ExpectedIdentity $journalState.CandidateIdentity
    if (-not $candidate.Exists -or -not $candidate.Exact -or -not $candidate.IdentityMatches) {
        throw "Server install forward recovery did not preserve the exact candidate binary tree and File ID."
    }
}

function Invoke-SyncVisionServerInstallTransactionRecovery {
    param(
        [Parameter(Mandatory = $true)][string]$InstallDir,
        [AllowEmptyString()][string]$ExpectedTransactionId = "",
        [AllowNull()][object]$ResourceBackend,
        [AllowNull()][scriptblock]$TestPhaseHook
    )

    $intent = Read-SyncVisionServerInstallIntent -InstallDir $InstallDir -AllowMissing
    $journal = Read-SyncVisionServerInstallJournal -InstallDir $InstallDir -AllowMissing
    if ($null -eq $journal) {
        if ($null -ne $intent) {
            if (-not [string]::IsNullOrEmpty($ExpectedTransactionId) -and
                $intent.TransactionId -cne $ExpectedTransactionId) {
                throw "Server install transaction intent belongs to a different transaction."
            }
            return Invoke-SyncVisionServerInstallIntentOnlyRecovery -Intent $intent
        }
        $intentTemporaryPath = Get-SyncVisionServerInstallIntentTemporaryPath -InstallDir $InstallDir
        $hadIntentTemporary = $null -ne (Get-SyncVisionServerInstallSiblingItem -Path $intentTemporaryPath)
        Remove-SyncVisionServerInstallProtectedTemporaryFile `
            -Path $intentTemporaryPath `
            -Context "Server install intent temporary file"
        if ($hadIntentTemporary) {
            return [pscustomobject]@{ Recovered = $true; Action = "IntentTemporaryCleanup"; TransactionId = "" }
        }
        return [pscustomobject]@{ Recovered = $false; Action = "None"; TransactionId = "" }
    }
    if (-not [string]::IsNullOrEmpty($ExpectedTransactionId) -and
        $journal.TransactionId -cne $ExpectedTransactionId) {
        throw "Server install transaction journal belongs to a different transaction."
    }
    if ($null -ne $intent -and $intent.TransactionId -cne $journal.TransactionId) {
        throw "Server install transaction intent and journal belong to different transactions."
    }
    if ($null -ne $intent) {
        Remove-SyncVisionServerInstallProtectedTemporaryFile `
            -Path (Get-SyncVisionServerInstallIntentTemporaryPath -InstallDir $InstallDir) `
            -Context "Server install intent temporary file"
        Remove-SyncVisionServerInstallProtectedTemporaryFile `
            -Path (Get-SyncVisionServerInstallJournalTemporaryPath -InstallDir $InstallDir) `
            -Context "Server install journal temporary file"
        Remove-SyncVisionServerInstallProtectedTemporaryFile `
            -Path (Get-SyncVisionServerInstallResourceStateTemporaryPath `
                -InstallDir $InstallDir `
                -TransactionId $journal.TransactionId) `
            -Context "Server install resource-state temporary file"
    }
    elseif ($journal.ResourceBackendKind -ceq "Windows") {
        throw "Windows server install recovery found a durable journal without its required bootstrap intent."
    }
    if ([string]::IsNullOrEmpty($journal.ResourceStatePath)) {
        return Invoke-SyncVisionServerInstallPublicationRecovery `
            -InstallDir $InstallDir `
            -ExpectedTransactionId $ExpectedTransactionId
    }

    $state = Read-SyncVisionServerInstallResourceState -Journal $journal
    if ($null -ne $intent) {
        foreach ($propertyName in @("IntentPath", "IntentTransactionId")) {
            if ($null -eq $state.PSObject.Properties[$propertyName]) {
                throw "Server install durable resource state is missing its bootstrap intent binding."
            }
        }
        if ([string]$state.IntentPath -cne [string]$intent.IntentPath -or
            [string]$state.IntentTransactionId -cne [string]$intent.TransactionId) {
            throw "Server install durable resource state does not match its bootstrap intent."
        }
    }
    if ($null -eq $ResourceBackend) {
        if ($journal.ResourceBackendKind -cne "Windows") {
            throw "Server install recovery requires an injected '$($journal.ResourceBackendKind)' resource backend."
        }
        $ResourceBackend = New-SyncVisionWindowsServerInstallResourceBackend
    }
    if ([string]$ResourceBackend.Kind -cne $journal.ResourceBackendKind) {
        throw "Server install recovery backend kind does not match the durable journal."
    }

    $forward = $journal.Phase -ceq "ForwardCommitted" -or $journal.Phase -ceq "Committed"
    $cleanupOnly = $null -ne $intent -and [string]$intent.Mode -ceq "Cleanup"
    $state | Add-Member `
        -NotePropertyName TransactionRecoveryMode `
        -NotePropertyValue $(if ($forward) { "Forward" } else { "Rollback" }) `
        -Force
    $state | Add-Member -NotePropertyName TransactionRecoveryPhase -NotePropertyValue ([string]$journal.Phase) -Force
    $state | Add-Member -NotePropertyName TransactionId -NotePropertyValue ([string]$journal.TransactionId) -Force
    $serviceMayHaveMutated = $false
    $directoriesMayHaveMutated = $false
    $firewallMayHaveMutated = $false
    if (-not $forward) {
        $phaseOrder = [string[]]@(Get-SyncVisionServerInstallJournalPhases)
        $phaseIndex = [Array]::IndexOf($phaseOrder, [string]$journal.Phase)
        $serviceMutationIndex = [Array]::IndexOf($phaseOrder, "ServiceStopMutationStarted")
        $directoryMutationIndex = [Array]::IndexOf($phaseOrder, "DirectoriesPending")
        $firewallMutationIndex = [Array]::IndexOf($phaseOrder, "FirewallMutationStarted")
        if ($phaseIndex -lt 0 -or $serviceMutationIndex -lt 0 -or
            $directoryMutationIndex -lt 0 -or $firewallMutationIndex -lt 0) {
            throw "Server install rollback encountered an unsupported durable phase."
        }
        $serviceMayHaveMutated = $phaseIndex -ge $serviceMutationIndex
        $directoriesMayHaveMutated = $phaseIndex -ge $directoryMutationIndex
        $firewallMayHaveMutated = $phaseIndex -ge $firewallMutationIndex
        $state | Add-Member -NotePropertyName TransactionServiceMayHaveMutated -NotePropertyValue $serviceMayHaveMutated -Force
        $state | Add-Member -NotePropertyName TransactionDirectoriesMayHaveMutated -NotePropertyValue $directoriesMayHaveMutated -Force
        $state | Add-Member -NotePropertyName TransactionFirewallMayHaveMutated -NotePropertyValue $firewallMayHaveMutated -Force
    }
    if ($cleanupOnly) {
        if ($forward) {
            Assert-SyncVisionServerInstallCandidateBinaryState -Journal $journal
            Invoke-SyncVisionServerInstallBackendAction -Backend $ResourceBackend -Name VerifyNewState -State $state
            $action = "ForwardCommittedCleanup"
        }
        else {
            Assert-SyncVisionServerInstallPreviousBinaryState -Journal $journal
            Invoke-SyncVisionServerInstallBackendAction -Backend $ResourceBackend -Name VerifyOldState -State $state
            $action = "RolledBack"
        }
    }
    elseif ($forward) {
        Assert-SyncVisionServerInstallCandidateBinaryState -Journal $journal
        Invoke-SyncVisionServerInstallBackendAction -Backend $ResourceBackend -Name VerifyNewState -State $state
        if ($journal.Phase -ceq "ForwardCommitted") {
            $journal = Set-SyncVisionServerInstallJournalPhase -Journal $journal -Phase "Committed"
        }
        Invoke-SyncVisionServerInstallPublicationRecovery `
            -InstallDir $InstallDir `
            -ExpectedTransactionId $journal.TransactionId `
            -RetainJournal | Out-Null
        $journal = Read-SyncVisionServerInstallJournal -InstallDir $InstallDir
        Assert-SyncVisionServerInstallCandidateBinaryState -Journal $journal
        Invoke-SyncVisionServerInstallBackendAction -Backend $ResourceBackend -Name VerifyNewState -State $state
        $action = "ForwardCommittedCleanup"
    }
    else {
        if ($serviceMayHaveMutated) {
            Invoke-SyncVisionServerInstallBackendAction -Backend $ResourceBackend -Name StopCurrentService -State $state
        }
        if ($directoriesMayHaveMutated) {
            Invoke-SyncVisionServerInstallBackendAction -Backend $ResourceBackend -Name RestoreDirectories -State $state
        }
        Invoke-SyncVisionServerInstallPublicationRecovery `
            -InstallDir $InstallDir `
            -ExpectedTransactionId $journal.TransactionId `
            -RetainJournal | Out-Null
        $journal = Read-SyncVisionServerInstallJournal -InstallDir $InstallDir
        Assert-SyncVisionServerInstallPreviousBinaryState -Journal $journal
        if ($serviceMayHaveMutated) {
            Invoke-SyncVisionServerInstallBackendAction -Backend $ResourceBackend -Name RestoreServiceDefinition -State $state
        }
        if ($firewallMayHaveMutated) {
            Invoke-SyncVisionServerInstallBackendAction -Backend $ResourceBackend -Name RestoreFirewall -State $state
        }
        if ($serviceMayHaveMutated) {
            Invoke-SyncVisionServerInstallBackendAction -Backend $ResourceBackend -Name VerifyOldStoppedState -State $state
            Invoke-SyncVisionServerInstallBackendAction -Backend $ResourceBackend -Name RestoreRunningState -State $state
        }
        Assert-SyncVisionServerInstallPreviousBinaryState -Journal $journal
        if ($serviceMayHaveMutated -or $firewallMayHaveMutated) {
            Invoke-SyncVisionServerInstallBackendAction -Backend $ResourceBackend -Name VerifyOldState -State $state
        }
        $action = "RolledBack"
    }

    $transactionId = $journal.TransactionId
    if ($null -ne $intent -and -not $cleanupOnly) {
        $intent = Set-SyncVisionServerInstallIntentMode -Intent $intent -Mode "Cleanup"
        if ($null -ne $TestPhaseHook) { & $TestPhaseHook "AfterCleanupIntentPublished" $intent }
    }
    $cleanupFailures = New-Object "System.Collections.Generic.List[string]"
    try { Invoke-SyncVisionServerInstallBackendAction -Backend $ResourceBackend -Name Cleanup -State $state }
    catch { $cleanupFailures.Add("backend: $($_.Exception.Message)") }
    if ($cleanupFailures.Count -ne 0) {
        throw "Server install transaction reached a complete $action state, but protected recovery artifact cleanup was incomplete: $($cleanupFailures -join ' | ')"
    }
    if ($null -ne $TestPhaseHook) { & $TestPhaseHook "AfterCleanupBackendCompleted" $(if ($null -ne $intent) { $intent } else { $journal }) }
    Remove-SyncVisionServerInstallJournalFile -Journal $journal -InstallDir $InstallDir
    if ($null -ne $TestPhaseHook) { & $TestPhaseHook "AfterCleanupJournalRemoved" $journal }
    if ($null -ne $intent) {
        Remove-SyncVisionServerInstallIntentWorkPaths -Intent $intent
        if ($null -ne $TestPhaseHook) { & $TestPhaseHook "AfterCleanupWorkPathsRemoved" $intent }
        Remove-SyncVisionServerInstallIntentResourceState -Intent $intent
        Remove-SyncVisionServerInstallProtectedTemporaryFile `
            -Path (Get-SyncVisionServerInstallResourceStateTemporaryPath `
                -InstallDir $InstallDir `
                -TransactionId $transactionId) `
            -Context "Server install resource-state temporary file"
        if ($null -ne $TestPhaseHook) { & $TestPhaseHook "AfterCleanupResourceStateRemoved" $intent }
        Remove-SyncVisionServerInstallIntent -Intent $intent
        if ($null -ne $TestPhaseHook) { & $TestPhaseHook "AfterCleanupIntentRemoved" $intent }
    }
    else {
        Remove-SyncVisionServerInstallResourceState -Journal $journal
    }
    return [pscustomobject]@{ Recovered = $true; Action = $action; TransactionId = $transactionId }
}

function Invoke-SyncVisionServerInstallTransactionCoordinator {
    param(
        [Parameter(Mandatory = $true)][object]$Journal,
        [Parameter(Mandatory = $true)][object[]]$StagedInputs,
        [Parameter(Mandatory = $true)][object]$ResourceBackend,
        [Parameter(Mandatory = $true)][object]$ResourceState,
        [AllowNull()][scriptblock]$TestPhaseHook
    )

    $journalState = Assert-SyncVisionServerInstallJournal -Journal $Journal
    if ([string]$ResourceBackend.Kind -cne $journalState.ResourceBackendKind) {
        throw "Server install coordinator backend kind does not match the durable journal."
    }
    $invokeHook = {
        param($Name, $CurrentJournal)
        if ($null -ne $TestPhaseHook) { & $TestPhaseHook $Name $CurrentJournal }
    }
    $setPhase = {
        param($Phase, $HookName, $CurrentJournal)
        $next = Set-SyncVisionServerInstallJournalPhase -Journal $CurrentJournal -Phase $Phase
        & $invokeHook $HookName $next
        return $next
    }

    $publication = $null
    try {
        & $invokeHook "AfterPreparedJournal" $journalState
        $journalState = & $setPhase "ServiceStopPending" "AfterServiceStopPendingJournal" $journalState
        Invoke-SyncVisionServerInstallBackendAction -Backend $ResourceBackend -Name VerifyServiceSnapshotUnchanged -State $ResourceState
        $journalState = & $setPhase "ServiceStopMutationStarted" "AfterServiceStopMutationStartedJournal" $journalState
        Invoke-SyncVisionServerInstallBackendAction -Backend $ResourceBackend -Name StopCurrentService -State $ResourceState
        $journalState = & $setPhase "ServiceStopped" "AfterServiceStoppedJournal" $journalState

        Invoke-SyncVisionServerInstallBackendAction -Backend $ResourceBackend -Name VerifyDirectorySnapshotsQuiesced -State $ResourceState
        $journalState = & $setPhase "DirectoriesPending" "AfterDirectoriesPendingJournal" $journalState
        Invoke-SyncVisionServerInstallBackendAction -Backend $ResourceBackend -Name ApplyDirectories -State $ResourceState
        $journalState = & $setPhase "DirectoriesApplied" "AfterDirectoriesAppliedJournal" $journalState

        $publication = Publish-SyncVisionExactServerInstallTree `
            -InstallDir $journalState.InstallPath `
            -StagedInputs $StagedInputs `
            -RetainBackup `
            -PreparedJournal $journalState `
            -TestPhaseHook $TestPhaseHook
        $journalState = $publication.Journal

        $journalState = & $setPhase "ConfigPending" "AfterConfigPendingJournal" $journalState
        Invoke-SyncVisionServerInstallBackendAction -Backend $ResourceBackend -Name ApplyConfig -State $ResourceState
        $journalState = & $setPhase "ConfigApplied" "AfterConfigAppliedJournal" $journalState

        $journalState = & $setPhase "ServiceDefinitionPending" "AfterServiceDefinitionPendingJournal" $journalState
        Invoke-SyncVisionServerInstallBackendAction -Backend $ResourceBackend -Name VerifyServiceFenceState -State $ResourceState
        $journalState = & $setPhase "ServiceDefinitionMutationStarted" "AfterServiceDefinitionMutationStartedJournal" $journalState
        Invoke-SyncVisionServerInstallBackendAction -Backend $ResourceBackend -Name ApplyServiceDefinition -State $ResourceState
        $journalState = & $setPhase "ServiceDefinitionApplied" "AfterServiceDefinitionAppliedJournal" $journalState

        $journalState = & $setPhase "FirewallPending" "AfterFirewallPendingJournal" $journalState
        Invoke-SyncVisionServerInstallBackendAction -Backend $ResourceBackend -Name VerifyFirewallSnapshotUnchanged -State $ResourceState
        $journalState = & $setPhase "FirewallMutationStarted" "AfterFirewallMutationStartedJournal" $journalState
        Invoke-SyncVisionServerInstallBackendAction -Backend $ResourceBackend -Name ApplyFirewall -State $ResourceState
        $journalState = & $setPhase "FirewallApplied" "AfterFirewallAppliedJournal" $journalState

        $journalState = & $setPhase "ServiceStartPending" "AfterServiceStartPendingJournal" $journalState
        Invoke-SyncVisionServerInstallBackendAction -Backend $ResourceBackend -Name ApplyRunningState -State $ResourceState
        $journalState = & $setPhase "ServiceStarted" "AfterServiceStartedJournal" $journalState

        $journalState = & $setPhase "VerificationPending" "AfterVerificationPendingJournal" $journalState
        Assert-SyncVisionServerInstallCandidateBinaryState -Journal $journalState
        Invoke-SyncVisionServerInstallBackendAction -Backend $ResourceBackend -Name VerifyNewState -State $ResourceState
        $journalState = & $setPhase "Verified" "AfterVerifiedJournal" $journalState
        $publication.Journal = $journalState
        Set-SyncVisionServerInstallPublicationCrashForwardPoint `
            -Publication $publication `
            -ExpectedJournalPhase "Verified" `
            -TestPhaseHook $TestPhaseHook | Out-Null
        $journalState = $publication.Journal
        $journalState = & $setPhase "Committed" "AfterCommittedJournal" $journalState
        $publication.Journal = $journalState
        return Invoke-SyncVisionServerInstallTransactionRecovery `
            -InstallDir $journalState.InstallPath `
            -ExpectedTransactionId $journalState.TransactionId `
            -ResourceBackend $ResourceBackend `
            -TestPhaseHook $TestPhaseHook
    }
    catch {
        $transactionFailure = $_
        $recoveryFailure = $null
        try {
            $current = Read-SyncVisionServerInstallJournal -InstallDir $journalState.InstallPath -AllowMissing
            if ($null -ne $current) {
                Invoke-SyncVisionServerInstallTransactionRecovery `
                    -InstallDir $journalState.InstallPath `
                    -ExpectedTransactionId $journalState.TransactionId `
                    -ResourceBackend $ResourceBackend | Out-Null
            }
        }
        catch { $recoveryFailure = $_ }
        if ($null -ne $recoveryFailure) {
            throw "Server install transaction failed and durable recovery was incomplete. Failure: $($transactionFailure.Exception.Message) Recovery: $($recoveryFailure.Exception.Message)"
        }
        throw $transactionFailure
    }
}

function Get-SyncVisionInstallDirectoryTreeSha256 {
    param([Parameter(Mandatory = $true)][string]$Root)

    $resolved = (Resolve-Path -LiteralPath $Root).Path.TrimEnd('\', '/')
    $records = New-Object "System.Collections.Generic.List[string]"
    $pending = New-Object "System.Collections.Generic.Stack[string]"
    $pending.Push($resolved)
    while ($pending.Count -ne 0) {
        foreach ($item in (Get-ChildItem -LiteralPath $pending.Pop() -Force)) {
            if (($item.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
                throw "Install data tree contains a reparse point: $($item.FullName)"
            }
            $relative = $item.FullName.Substring($resolved.Length).TrimStart([char[]]@('\', '/')) -replace '\\', '/'
            if ($item.PSIsContainer) {
                $records.Add("D|$relative")
                $pending.Push($item.FullName)
            }
            else {
                $records.Add("F|$relative|$((Get-FileHash -LiteralPath $item.FullName -Algorithm SHA256).Hash.ToLowerInvariant())")
            }
        }
    }
    $ordered = $records.ToArray()
    [Array]::Sort($ordered, [StringComparer]::Ordinal)
    $sha256 = [Security.Cryptography.SHA256]::Create()
    try {
        return ([BitConverter]::ToString($sha256.ComputeHash([Text.UTF8Encoding]::new($false).GetBytes(($ordered -join "`n"))))).Replace("-", "").ToLowerInvariant()
    }
    finally { $sha256.Dispose() }
}

function Initialize-SyncVisionInstallFileIdentityType {
    if ("SyncVisionTask19FileIdentity" -as [type]) { return }
    Add-Type -TypeDefinition @'
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Text;
using Microsoft.Win32.SafeHandles;

public static class SyncVisionTask19FileIdentity
{
    [StructLayout(LayoutKind.Sequential)]
    private struct BY_HANDLE_FILE_INFORMATION
    {
        public uint FileAttributes;
        public System.Runtime.InteropServices.ComTypes.FILETIME CreationTime;
        public System.Runtime.InteropServices.ComTypes.FILETIME LastAccessTime;
        public System.Runtime.InteropServices.ComTypes.FILETIME LastWriteTime;
        public uint VolumeSerialNumber;
        public uint FileSizeHigh;
        public uint FileSizeLow;
        public uint NumberOfLinks;
        public uint FileIndexHigh;
        public uint FileIndexLow;
    }

    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern bool GetFileInformationByHandle(
        SafeFileHandle handle,
        out BY_HANDLE_FILE_INFORMATION information);

    [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    private static extern uint GetFinalPathNameByHandle(
        SafeFileHandle handle,
        StringBuilder path,
        uint pathLength,
        uint flags);

    [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    private static extern SafeFileHandle CreateFile(
        string fileName,
        uint desiredAccess,
        uint shareMode,
        IntPtr securityAttributes,
        uint creationDisposition,
        uint flagsAndAttributes,
        IntPtr templateFile);

    [StructLayout(LayoutKind.Sequential)]
    private struct IO_STATUS_BLOCK
    {
        public IntPtr Status;
        public IntPtr Information;
    }

    [DllImport("ntdll.dll")]
    private static extern int NtQueryEaFile(
        SafeFileHandle fileHandle,
        out IO_STATUS_BLOCK ioStatusBlock,
        IntPtr buffer,
        uint length,
        [MarshalAs(UnmanagedType.U1)] bool returnSingleEntry,
        IntPtr eaList,
        uint eaListLength,
        IntPtr eaIndex,
        [MarshalAs(UnmanagedType.U1)] bool restartScan);

    public static string Get(string path)
    {
        using (SafeFileHandle handle = CreateFile(
            path,
            0,
            0x00000001u | 0x00000002u | 0x00000004u,
            IntPtr.Zero,
            3u,
            0x02000000u,
            IntPtr.Zero))
        {
            if (handle.IsInvalid)
            {
                throw new Win32Exception(Marshal.GetLastWin32Error(), "CreateFile for directory identity failed.");
            }
            BY_HANDLE_FILE_INFORMATION information;
            if (!GetFileInformationByHandle(handle, out information))
            {
                throw new Win32Exception(Marshal.GetLastWin32Error(), "GetFileInformationByHandle failed.");
            }
            return information.VolumeSerialNumber.ToString("x8") + ":" +
                information.FileIndexHigh.ToString("x8") + information.FileIndexLow.ToString("x8");
        }
    }

    public static uint GetLinkCount(string path)
    {
        using (SafeFileHandle handle = CreateFile(
            path,
            0,
            0x00000001u | 0x00000002u | 0x00000004u,
            IntPtr.Zero,
            3u,
            0x00200000u,
            IntPtr.Zero))
        {
            if (handle.IsInvalid)
            {
                throw new Win32Exception(Marshal.GetLastWin32Error(), "CreateFile for hard-link count failed.");
            }
            BY_HANDLE_FILE_INFORMATION information;
            if (!GetFileInformationByHandle(handle, out information))
            {
                throw new Win32Exception(Marshal.GetLastWin32Error(), "GetFileInformationByHandle for hard-link count failed.");
            }
            return information.NumberOfLinks;
        }
    }

    public static bool HasExtendedAttributes(string path)
    {
        const uint FILE_READ_EA = 0x00000008u;
        const int STATUS_NO_EAS_ON_FILE = unchecked((int)0xC0000052u);
        const int STATUS_NO_MORE_EAS = unchecked((int)0x80000012u);
        const int STATUS_BUFFER_OVERFLOW = unchecked((int)0x80000005u);
        const int STATUS_BUFFER_TOO_SMALL = unchecked((int)0xC0000023u);
        using (SafeFileHandle handle = CreateFile(
            path,
            FILE_READ_EA,
            0x00000001u | 0x00000002u | 0x00000004u,
            IntPtr.Zero,
            3u,
            0x02000000u | 0x00200000u,
            IntPtr.Zero))
        {
            if (handle.IsInvalid)
            {
                throw new Win32Exception(Marshal.GetLastWin32Error(), "CreateFile for extended-attribute inspection failed.");
            }
            IntPtr buffer = Marshal.AllocHGlobal(65536);
            try
            {
                IO_STATUS_BLOCK statusBlock;
                int status = NtQueryEaFile(
                    handle,
                    out statusBlock,
                    buffer,
                    65536u,
                    false,
                    IntPtr.Zero,
                    0u,
                    IntPtr.Zero,
                    true);
                if (status == STATUS_NO_EAS_ON_FILE || status == STATUS_NO_MORE_EAS)
                {
                    return false;
                }
                if (status == STATUS_BUFFER_OVERFLOW || status == STATUS_BUFFER_TOO_SMALL)
                {
                    return true;
                }
                if (status < 0)
                {
                    throw new Win32Exception(status, "NtQueryEaFile failed while inspecting rollback metadata.");
                }
                return statusBlock.Information.ToInt64() != 0;
            }
            finally
            {
                Marshal.FreeHGlobal(buffer);
            }
        }
    }

    public static string GetCanonicalPath(string path)
    {
        using (SafeFileHandle handle = CreateFile(
            path,
            0,
            0x00000001u | 0x00000002u | 0x00000004u,
            IntPtr.Zero,
            3u,
            0x02000000u,
            IntPtr.Zero))
        {
            if (handle.IsInvalid)
            {
                throw new Win32Exception(Marshal.GetLastWin32Error(), "CreateFile for canonical directory path failed.");
            }
            StringBuilder buffer = new StringBuilder(32768);
            uint length = GetFinalPathNameByHandle(handle, buffer, (uint)buffer.Capacity, 0u);
            if (length == 0 || length >= buffer.Capacity)
            {
                throw new Win32Exception(Marshal.GetLastWin32Error(), "GetFinalPathNameByHandle failed.");
            }
            return buffer.ToString();
        }
    }
}
'@
}

function Get-SyncVisionInstallFileSystemIdentity {
    param([Parameter(Mandatory = $true)][string]$Path)

    $resolved = (Resolve-Path -LiteralPath $Path).ProviderPath
    $item = Get-Item -LiteralPath $resolved -Force
    if (-not $item.PSIsContainer -or ($item.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
        throw "Install filesystem identity requires a non-reparse directory: $resolved"
    }
    Initialize-SyncVisionInstallFileIdentityType
    return [SyncVisionTask19FileIdentity]::Get($resolved)
}

function Get-SyncVisionInstallCanonicalDirectoryPath {
    param([Parameter(Mandatory = $true)][string]$Path)

    $resolved = (Resolve-Path -LiteralPath $Path).ProviderPath
    $item = Get-Item -LiteralPath $resolved -Force
    if (-not $item.PSIsContainer -or ($item.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
        throw "Canonical install path requires a non-reparse directory: $resolved"
    }
    Initialize-SyncVisionInstallFileIdentityType
    return [SyncVisionTask19FileIdentity]::GetCanonicalPath($resolved).TrimEnd('\', '/')
}

function Get-SyncVisionInstallRegularFileIdentity {
    param([Parameter(Mandatory = $true)][string]$Path)

    $resolved = (Resolve-Path -LiteralPath $Path).ProviderPath
    $item = Get-Item -LiteralPath $resolved -Force
    if ($item.PSIsContainer -or ($item.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
        throw "Install file identity requires a regular non-reparse file: $resolved"
    }
    Initialize-SyncVisionInstallFileIdentityType
    return [SyncVisionTask19FileIdentity]::Get($resolved)
}

function Assert-SyncVisionFileTrustMetadata {
    param(
        [Parameter(Mandatory = $true)][string]$Path,
        [Parameter(Mandatory = $true)][string]$Context
    )

    $item = Get-Item -LiteralPath $Path -Force
    if (($item.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
        throw "$Context rejected a reparse point: $($item.FullName)"
    }
    $streams = @(Get-Item -LiteralPath $item.FullName -Stream * -ErrorAction Stop)
    if (@($streams | Where-Object { [string]$_.Stream -cne ':$DATA' }).Count -ne 0) {
        throw "$Context rejected an NTFS named data stream: $($item.FullName)"
    }
    Initialize-SyncVisionInstallFileIdentityType
    if ([SyncVisionTask19FileIdentity]::HasExtendedAttributes($item.FullName)) {
        throw "$Context rejected NTFS extended attributes that are outside the authenticated rollback format: $($item.FullName)"
    }
    return $item
}

function Assert-SyncVisionInstallSnapshotItemSupported {
    param([Parameter(Mandatory = $true)][IO.FileSystemInfo]$Item)

    $Item = Assert-SyncVisionFileTrustMetadata `
        -Path $Item.FullName `
        -Context "Install rollback snapshot"
    if (-not $Item.PSIsContainer) {
        Initialize-SyncVisionInstallFileIdentityType
        if ([SyncVisionTask19FileIdentity]::GetLinkCount($Item.FullName) -ne [uint32]1) {
            throw "Install rollback snapshot rejected a hard-linked file whose link topology cannot be restored exactly: $($Item.FullName)"
        }
    }
}

function Copy-SyncVisionInstallDirectoryTreeExact {
    param(
        [Parameter(Mandatory = $true)][string]$SourceRoot,
        [Parameter(Mandatory = $true)][string]$DestinationRoot,
        [object[]]$DirectoryMetadata = @()
    )

    $source = (Resolve-Path -LiteralPath $SourceRoot).Path.TrimEnd('\', '/')
    $destination = (Resolve-Path -LiteralPath $DestinationRoot).Path.TrimEnd('\', '/')
    if (@(Get-ChildItem -LiteralPath $destination -Force).Count -ne 0) {
        throw "Install data snapshot destination must be empty."
    }
    $pending = New-Object "System.Collections.Generic.Stack[object]"
    $directorySecurityByRelativePath = New-Object "System.Collections.Generic.Dictionary[string,object]" ([StringComparer]::OrdinalIgnoreCase)
    foreach ($metadataEntry in @($DirectoryMetadata | Where-Object { $_.IsDirectory -and -not [string]::IsNullOrEmpty([string]$_.RelativePath) })) {
        $directorySecurityByRelativePath[[string]$metadataEntry.RelativePath] = $metadataEntry
    }
    $pending.Push([pscustomobject]@{ Source = $source; Destination = $destination })
    while ($pending.Count -ne 0) {
        $pair = $pending.Pop()
        foreach ($item in (Get-ChildItem -LiteralPath $pair.Source -Force)) {
            if (($item.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
                throw "Install data snapshot rejected a reparse point: $($item.FullName)"
            }
            $relative = $item.FullName.Substring($source.Length).TrimStart([char[]]@('\', '/'))
            $target = Join-Path $destination $relative
            if ($item.PSIsContainer) {
                $metadataKey = $relative -replace '\\', '/'
                if ($directorySecurityByRelativePath.ContainsKey($metadataKey)) {
                    $security = [Security.AccessControl.DirectorySecurity]::new()
                    $security.SetSecurityDescriptorSddlForm([string]$directorySecurityByRelativePath[$metadataKey].SecurityDescriptor)
                    [IO.Directory]::CreateDirectory($target, $security) | Out-Null
                }
                else {
                    [IO.Directory]::CreateDirectory($target) | Out-Null
                }
                $pending.Push([pscustomobject]@{ Source = $item.FullName; Destination = $target })
            }
            else { [IO.File]::Copy($item.FullName, $target, $false) }
        }
    }
}

function Assert-SyncVisionInstallDirectorySnapshotTreeSupported {
    param(
        [Parameter(Mandatory = $true)][string]$Root,
        [Parameter(Mandatory = $true)][string]$Context
    )

    if (-not (Test-Path -LiteralPath $Root -PathType Container)) {
        throw "$Context snapshot tree was not found: $Root"
    }
    $pending = New-Object "System.Collections.Generic.Stack[string]"
    $pending.Push((Resolve-Path -LiteralPath $Root).ProviderPath)
    while ($pending.Count -ne 0) {
        $item = Get-Item -LiteralPath $pending.Pop() -Force
        Assert-SyncVisionInstallSnapshotItemSupported -Item $item
        if ($item.PSIsContainer) {
            foreach ($child in (Get-ChildItem -LiteralPath $item.FullName -Force)) {
                $pending.Push($child.FullName)
            }
        }
    }
}

function Get-SyncVisionInstallDirectoryMetadata {
    param([Parameter(Mandatory = $true)][string]$Root)

    $resolved = (Resolve-Path -LiteralPath $Root).Path.TrimEnd('\', '/')
    $sections = [Security.AccessControl.AccessControlSections]::Owner -bor
        [Security.AccessControl.AccessControlSections]::Group -bor
        [Security.AccessControl.AccessControlSections]::Access
    $items = New-Object "System.Collections.Generic.List[object]"
    $pending = New-Object "System.Collections.Generic.Stack[string]"
    $pending.Push($resolved)
    while ($pending.Count -ne 0) {
        $path = $pending.Pop()
        $item = Get-Item -LiteralPath $path -Force
        if (($item.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
            throw "Install metadata snapshot rejected a reparse point: $($item.FullName)"
        }
        Assert-SyncVisionInstallSnapshotItemSupported -Item $item
        $relative = if ([string]::Equals($item.FullName.TrimEnd('\', '/'), $resolved, [StringComparison]::OrdinalIgnoreCase)) {
            ""
        }
        else {
            $item.FullName.Substring($resolved.Length).TrimStart([char[]]@('\', '/')) -replace '\\', '/'
        }
        $items.Add([pscustomobject]@{
                RelativePath = $relative
                IsDirectory = [bool]$item.PSIsContainer
                Attributes = [Int32]$item.Attributes
                CreationTimeUtcTicks = $item.CreationTimeUtc.Ticks
                LastWriteTimeUtcTicks = $item.LastWriteTimeUtc.Ticks
                SecurityDescriptor = (Get-Acl -LiteralPath $item.FullName).GetSecurityDescriptorSddlForm($sections)
            })
        if ($item.PSIsContainer) {
            foreach ($child in (Get-ChildItem -LiteralPath $item.FullName -Force)) {
                $pending.Push($child.FullName)
            }
        }
    }
    return @($items.ToArray() | Sort-Object RelativePath)
}

function Get-SyncVisionInstallDirectoryMetadataSha256 {
    param(
        [Parameter(Mandatory = $true)][object[]]$Metadata,
        [switch]$NormalizeDaclAutoInherited
    )

    $utf8 = [Text.UTF8Encoding]::new($false)
    $records = foreach ($entry in @($Metadata | Sort-Object RelativePath)) {
        $path = [Convert]::ToBase64String($utf8.GetBytes([string]$entry.RelativePath))
        $securityDescriptor = [string]$entry.SecurityDescriptor
        if ($NormalizeDaclAutoInherited) {
            $rawSecurityDescriptor = [Security.AccessControl.RawSecurityDescriptor]::new($securityDescriptor)
            $controlFlags = $rawSecurityDescriptor.ControlFlags
            if (($controlFlags -band [Security.AccessControl.ControlFlags]::DiscretionaryAclAutoInherited) -ne 0) {
                $controlFlags = $controlFlags -band `
                    (-bnot [Security.AccessControl.ControlFlags]::DiscretionaryAclAutoInherited)
                $rawSecurityDescriptor.SetFlags($controlFlags)
                $sections = [Security.AccessControl.AccessControlSections]::Owner -bor
                    [Security.AccessControl.AccessControlSections]::Group -bor
                    [Security.AccessControl.AccessControlSections]::Access
                $securityDescriptor = $rawSecurityDescriptor.GetSddlForm($sections)
            }
        }
        $sddl = [Convert]::ToBase64String($utf8.GetBytes($securityDescriptor))
        "$path|$([int][bool]$entry.IsDirectory)|$([Int32]$entry.Attributes)|$([Int64]$entry.CreationTimeUtcTicks)|$([Int64]$entry.LastWriteTimeUtcTicks)|$sddl"
    }
    $sha256 = [Security.Cryptography.SHA256]::Create()
    try {
        return ([BitConverter]::ToString($sha256.ComputeHash($utf8.GetBytes(($records -join "`n"))))).Replace("-", "").ToLowerInvariant()
    }
    finally { $sha256.Dispose() }
}

function Get-SyncVisionInstallDirectoryNonSecurityMetadataSha256 {
    param([Parameter(Mandatory = $true)][object[]]$Metadata)

    $utf8 = [Text.UTF8Encoding]::new($false)
    $records = foreach ($entry in @($Metadata | Sort-Object RelativePath)) {
        $path = [Convert]::ToBase64String($utf8.GetBytes([string]$entry.RelativePath))
        "$path|$([int][bool]$entry.IsDirectory)|$([Int32]$entry.Attributes)|$([Int64]$entry.CreationTimeUtcTicks)|$([Int64]$entry.LastWriteTimeUtcTicks)"
    }
    $sha256 = [Security.Cryptography.SHA256]::Create()
    try {
        return ([BitConverter]::ToString($sha256.ComputeHash($utf8.GetBytes(($records -join "`n"))))).Replace("-", "").ToLowerInvariant()
    }
    finally { $sha256.Dispose() }
}

function Restore-SyncVisionInstallDirectoryMetadata {
    param(
        [Parameter(Mandatory = $true)][string]$Root,
        [Parameter(Mandatory = $true)][object[]]$Metadata,
        [AllowNull()]$RootLease
    )

    $resolved = (Resolve-Path -LiteralPath $Root).Path.TrimEnd('\', '/')
    $ordered = @($Metadata | Sort-Object @{ Expression = {
                    if ([string]::IsNullOrEmpty([string]$_.RelativePath)) { 0 } else { ([string]$_.RelativePath -split '/').Count }
                }; Descending = $true }, RelativePath)
    foreach ($entry in $ordered) {
        $path = if ([string]::IsNullOrEmpty([string]$entry.RelativePath)) {
            $resolved
        }
        else {
            Join-Path $resolved (([string]$entry.RelativePath) -replace '/', '\')
        }
        if (-not (Test-Path -LiteralPath $path)) {
            throw "Install rollback metadata target was not found: $path"
        }
        $item = Get-Item -LiteralPath $path -Force
        if ([bool]$item.PSIsContainer -ne [bool]$entry.IsDirectory -or
            ($item.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
            throw "Install rollback metadata target type changed: $path"
        }
        $sections = [Security.AccessControl.AccessControlSections]::Owner -bor
            [Security.AccessControl.AccessControlSections]::Group -bor
            [Security.AccessControl.AccessControlSections]::Access
        $currentSddl = (Get-Acl -LiteralPath $path).GetSecurityDescriptorSddlForm($sections)
        if ($currentSddl -cne [string]$entry.SecurityDescriptor) {
            $security = if ($item.PSIsContainer) {
                [Security.AccessControl.DirectorySecurity]::new()
            }
            else {
                [Security.AccessControl.FileSecurity]::new()
            }
            $security.SetSecurityDescriptorSddlForm([string]$entry.SecurityDescriptor)
            Set-Acl -LiteralPath $path -AclObject $security
        }
        if ([string]::IsNullOrEmpty([string]$entry.RelativePath) -and $null -ne $RootLease) {
            $RootLease.ApplyBasicMetadata(
                [Int64]$entry.CreationTimeUtcTicks,
                [Int64]$entry.LastWriteTimeUtcTicks,
                [Int32]$entry.Attributes)
        }
        else {
            $item = Get-Item -LiteralPath $path -Force
            $item.CreationTimeUtc = [DateTime]::new([Int64]$entry.CreationTimeUtcTicks, [DateTimeKind]::Utc)
            $item.LastWriteTimeUtc = [DateTime]::new([Int64]$entry.LastWriteTimeUtcTicks, [DateTimeKind]::Utc)
            $item.Attributes = [IO.FileAttributes][Int32]$entry.Attributes
        }
    }
}

function Assert-SyncVisionLegacyInstallAncestorBoundary {
    param(
        [Parameter(Mandatory = $true)][string]$Path,
        [Parameter(Mandatory = $true)][string]$Context
    )

    $programData = [IO.Path]::GetFullPath(
        [Environment]::GetFolderPath([Environment+SpecialFolder]::CommonApplicationData)).TrimEnd('\', '/')
    $resolved = (Resolve-Path -LiteralPath $Path).Path.TrimEnd('\', '/')
    if (-not [string]::Equals($resolved, $programData, [StringComparison]::OrdinalIgnoreCase) -and
        -not (Test-SyncVisionPathWithin -Path $resolved -Parent $programData)) {
        throw "$Context legacy ACL migration is allowed only below ProgramData: $resolved"
    }

    $trustedSids = New-Object "System.Collections.Generic.HashSet[string]" ([StringComparer]::OrdinalIgnoreCase)
    foreach ($sid in @(Get-SyncVisionTrustedDestinationSids)) { [void]$trustedSids.Add([string]$sid) }
    $identity = [Security.Principal.WindowsIdentity]::GetCurrent()
    $principal = [Security.Principal.WindowsPrincipal]::new($identity)
    if ($principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
        [void]$trustedSids.Add($identity.User.Value)
    }
    $destructiveRights = Get-SyncVisionDestructiveAncestorRights
    $current = Get-Item -LiteralPath $resolved -Force
    while ($null -ne $current) {
        if ($current -isnot [IO.DirectoryInfo] -or
            ($current.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
            throw "$Context contains a non-directory or reparse-point ancestor: $($current.FullName)"
        }
        $acl = Get-Acl -LiteralPath $current.FullName
        $ownerSid = $acl.GetOwner([Security.Principal.SecurityIdentifier]).Value
        if (-not $trustedSids.Contains($ownerSid)) {
            throw "$Context has an untrusted ancestor owner SID $ownerSid at $($current.FullName)."
        }
        foreach ($rule in $acl.GetAccessRules($true, $true, [Security.Principal.SecurityIdentifier])) {
            $applies = ($rule.PropagationFlags -band [Security.AccessControl.PropagationFlags]::InheritOnly) -eq 0
            if ($applies -and
                $rule.AccessControlType -eq [Security.AccessControl.AccessControlType]::Allow -and
                -not $trustedSids.Contains($rule.IdentityReference.Value) -and
                ($rule.FileSystemRights -band $destructiveRights) -ne 0) {
                throw "$Context grants an untrusted SID delete or ACL-control rights at $($current.FullName)."
            }
        }
        if ([string]::Equals($current.FullName.TrimEnd('\', '/'), $programData, [StringComparison]::OrdinalIgnoreCase)) {
            break
        }
        $current = $current.Parent
    }
}

function Test-SyncVisionLegacyProgramDataWriteRule {
    param(
        [Parameter(Mandatory = $true)][object]$Rule,
        [Parameter(Mandatory = $true)][string]$Path
    )

    $programData = [IO.Path]::GetFullPath(
        [Environment]::GetFolderPath([Environment+SpecialFolder]::CommonApplicationData)).TrimEnd('\', '/')
    $fullPath = [IO.Path]::GetFullPath($Path).TrimEnd('\', '/')
    $usersSid = [Security.Principal.SecurityIdentifier]::new(
        [Security.Principal.WellKnownSidType]::BuiltinUsersSid,
        $null).Value
    $mutationValue = [Int32]($Rule.FileSystemRights -band (Get-SyncVisionContentMutationRights))
    return ($fullPath.StartsWith($programData + [IO.Path]::DirectorySeparatorChar, [StringComparison]::OrdinalIgnoreCase) -and
        $Rule.IsInherited -and
        $Rule.AccessControlType -eq [Security.AccessControl.AccessControlType]::Allow -and
        $Rule.IdentityReference.Value -eq $usersSid -and
        $mutationValue -eq [Int32][Security.AccessControl.FileSystemRights]::Write)
}

function Assert-SyncVisionInstallDirectoryAclMigrationSource {
    param(
        [Parameter(Mandatory = $true)][string]$Path,
        [AllowEmptyString()][string]$ServiceAccount = "",
        [Parameter(Mandatory = $true)][string]$Context,
        [switch]$RequireNoLegacyWrite
    )

    if (-not (Test-Path -LiteralPath $Path -PathType Container)) {
        throw "$Context was not found: $Path"
    }
    $root = (Resolve-Path -LiteralPath $Path).Path.TrimEnd('\', '/')
    $programData = [IO.Path]::GetFullPath(
        [Environment]::GetFolderPath([Environment+SpecialFolder]::CommonApplicationData)).TrimEnd('\', '/')
    if ($root.StartsWith($programData + [IO.Path]::DirectorySeparatorChar, [StringComparison]::OrdinalIgnoreCase)) {
        Assert-SyncVisionLegacyInstallAncestorBoundary `
            -Path (Split-Path -Parent $root) `
            -Context "$Context ancestor"
    }
    else {
        Assert-SyncVisionInstallAncestorBoundary `
            -Path (Split-Path -Parent $root) `
            -Context "$Context ancestor" `
            -ServiceAccount $ServiceAccount `
            -AllowProgramDataAtomicCreate
    }
    $trustedSids = New-Object "System.Collections.Generic.HashSet[string]" ([StringComparer]::OrdinalIgnoreCase)
    foreach ($sid in @(Get-SyncVisionTrustedDestinationSids)) { [void]$trustedSids.Add([string]$sid) }
    [void]$trustedSids.Add((Resolve-SyncVisionServiceAccountSid -ServiceAccount $ServiceAccount).Value)
    $identity = [Security.Principal.WindowsIdentity]::GetCurrent()
    $principal = [Security.Principal.WindowsPrincipal]::new($identity)
    if ($principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
        [void]$trustedSids.Add($identity.User.Value)
    }

    $mutationRights = Get-SyncVisionContentMutationRights
    $pending = New-Object "System.Collections.Generic.Stack[string]"
    $pending.Push($root)
    while ($pending.Count -ne 0) {
        $currentPath = $pending.Pop()
        $item = Get-Item -LiteralPath $currentPath -Force
        if (($item.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
            throw "$Context contains a reparse point: $($item.FullName)"
        }
        $acl = Get-Acl -LiteralPath $item.FullName
        $ownerSid = $acl.GetOwner([Security.Principal.SecurityIdentifier]).Value
        if (-not $trustedSids.Contains($ownerSid)) {
            throw "$Context has an untrusted owner SID $ownerSid at $($item.FullName)."
        }
        foreach ($rule in $acl.GetAccessRules($true, $true, [Security.Principal.SecurityIdentifier])) {
            $applies = ($rule.PropagationFlags -band [Security.AccessControl.PropagationFlags]::InheritOnly) -eq 0
            if ($applies -and
                $rule.AccessControlType -eq [Security.AccessControl.AccessControlType]::Allow -and
                -not $trustedSids.Contains($rule.IdentityReference.Value) -and
                ($rule.FileSystemRights -band $mutationRights) -ne 0) {
                if (-not $RequireNoLegacyWrite -and
                    (Test-SyncVisionLegacyProgramDataWriteRule -Rule $rule -Path $item.FullName)) {
                    continue
                }
                throw "$Context grants an untrusted SID $($rule.IdentityReference.Value) mutation rights at $($item.FullName)."
            }
        }
        if ($item.PSIsContainer) {
            foreach ($child in (Get-ChildItem -LiteralPath $item.FullName -Force)) {
                $pending.Push($child.FullName)
            }
        }
    }
    return $root
}

function Test-SyncVisionInstallDirectoryContainsLegacyProgramDataWrite {
    param([Parameter(Mandatory = $true)][string]$Path)

    $pending = New-Object "System.Collections.Generic.Stack[string]"
    $pending.Push((Resolve-Path -LiteralPath $Path).Path)
    while ($pending.Count -ne 0) {
        $item = Get-Item -LiteralPath $pending.Pop() -Force
        foreach ($rule in (Get-Acl -LiteralPath $item.FullName).GetAccessRules(
                $true,
                $true,
                [Security.Principal.SecurityIdentifier])) {
            if (Test-SyncVisionLegacyProgramDataWriteRule -Rule $rule -Path $item.FullName) {
                return $true
            }
        }
        if ($item.PSIsContainer) {
            foreach ($child in (Get-ChildItem -LiteralPath $item.FullName -Force)) {
                $pending.Push($child.FullName)
            }
        }
    }
    return $false
}

function Assert-SyncVisionInstallDirectorySnapshotSource {
    param(
        [Parameter(Mandatory = $true)][string]$Path,
        [AllowEmptyString()][string]$ServiceAccount = "",
        [switch]$ServiceModify,
        [Parameter(Mandatory = $true)][string]$Context,
        [switch]$AllowLegacyAclMigration
    )

    $boundary = Resolve-SyncVisionInstallDirectoryCreationBoundary `
        -Path $Path `
        -ServiceAccount $ServiceAccount `
        -Context $Context
    $fullPath = $boundary.Path
    if (-not $boundary.Existed) {
        return [pscustomobject]@{
            Path = $fullPath
            Existed = $false
            ExistingPath = $boundary.ExistingPath
            MissingPaths = @($boundary.MissingPaths)
            RequiresAclMigration = $false
        }
    }

    $strictFailure = $null
    try {
        Assert-SyncVisionProtectedInstallDirectory `
            -Path $fullPath `
            -ServiceAccount $ServiceAccount `
            -ServiceModify:$ServiceModify `
            -Context $Context | Out-Null
    }
    catch { $strictFailure = $_ }
    if ($null -eq $strictFailure) {
        if ($AllowLegacyAclMigration) {
            Assert-SyncVisionInstallDirectoryAclMigrationSource `
                -Path $fullPath `
                -ServiceAccount $ServiceAccount `
                -Context $Context | Out-Null
        }
        $requiresTreeMigration = $AllowLegacyAclMigration -and
            (Test-SyncVisionInstallDirectoryContainsLegacyProgramDataWrite -Path $fullPath)
        return [pscustomobject]@{ Path = $fullPath; Existed = $true; ExistingPath = $boundary.ExistingPath; MissingPaths = @(); RequiresAclMigration = [bool]$requiresTreeMigration }
    }
    if (-not $AllowLegacyAclMigration) { throw $strictFailure }

    Assert-SyncVisionInstallDirectoryAclMigrationSource `
        -Path $fullPath `
        -ServiceAccount $ServiceAccount `
        -Context $Context | Out-Null
    return [pscustomobject]@{ Path = $fullPath; Existed = $true; ExistingPath = $boundary.ExistingPath; MissingPaths = @(); RequiresAclMigration = $true }
}

function Invoke-SyncVisionInstallDirectoryPreflight {
    param(
        [Parameter(Mandatory = $true)][string]$DataDir,
        [Parameter(Mandatory = $true)][string]$LogDir,
        [AllowEmptyString()][string]$ServiceAccount = ""
    )

    $logUsesDataSnapshot = [string]::Equals(
        $LogDir.TrimEnd('\', '/'),
        $DataDir.TrimEnd('\', '/'),
        [StringComparison]::OrdinalIgnoreCase) -or
        (Test-SyncVisionPathWithin -Path $LogDir -Parent $DataDir)
    Assert-SyncVisionInstallDirectorySnapshotSource `
        -Path $DataDir `
        -ServiceAccount $ServiceAccount `
        -Context "SyncVision data directory preflight" `
        -AllowLegacyAclMigration | Out-Null
    Assert-SyncVisionInstallDirectorySnapshotSource `
        -Path $LogDir `
        -ServiceAccount $ServiceAccount `
        -ServiceModify `
        -Context "SyncVision log directory preflight" `
        -AllowLegacyAclMigration | Out-Null

    return [pscustomobject]@{ LogUsesDataSnapshot = [bool]$logUsesDataSnapshot }
}

function New-SyncVisionInstallDirectorySnapshot {
    param(
        [Parameter(Mandatory = $true)][string]$Path,
        [Parameter(Mandatory = $true)][string]$SnapshotRoot,
        [Parameter(Mandatory = $true)][string]$Name,
        [AllowEmptyString()][string]$ServiceAccount = "",
        [switch]$ServiceModify,
        [switch]$AllowLegacyAclMigration,
        [switch]$DeferAclMigration,
        [AllowNull()][scriptblock]$TestPhaseHook
    )

    $sourceState = Assert-SyncVisionInstallDirectorySnapshotSource `
        -Path $Path `
        -ServiceAccount $ServiceAccount `
        -ServiceModify:$ServiceModify `
        -Context "$Name snapshot source" `
        -AllowLegacyAclMigration:$AllowLegacyAclMigration
    $fullPath = $sourceState.Path
    if (-not $sourceState.Existed) {
        return [pscustomobject]@{ Path = $fullPath; Existed = $false; OriginalIdentity = $null; SnapshotPath = $null; TreeSha256 = $null; Metadata = @(); MetadataSha256 = $null; ServiceAccount = $ServiceAccount; ServiceModify = [bool]$ServiceModify; AllowsAclMigration = [bool]$AllowLegacyAclMigration; RequiresAclMigration = $false; AclMigrationApplied = $false; MissingPaths = @($sourceState.MissingPaths); TransactionOwnedPath = $null; TransactionOwnedIdentity = $null }
    }
    $originalIdentity = Get-SyncVisionInstallFileSystemIdentity -Path $fullPath
    $snapshotPath = Join-Path $SnapshotRoot ("$Name-" + [Guid]::NewGuid().ToString("N"))
    [IO.Directory]::CreateDirectory($snapshotPath) | Out-Null
    $metadata = @(Get-SyncVisionInstallDirectoryMetadata -Root $fullPath)
    $metadataHash = Get-SyncVisionInstallDirectoryMetadataSha256 -Metadata $metadata
    $nonSecurityMetadataHash = Get-SyncVisionInstallDirectoryNonSecurityMetadataSha256 -Metadata $metadata
    $sourceTreeHash = Get-SyncVisionInstallDirectoryTreeSha256 -Root $fullPath
    $aclMutationAttempted = $false
    $aclMigrationApplied = $false
    try {
        if ($sourceState.RequiresAclMigration -and -not $DeferAclMigration) {
            $aclMutationAttempted = $true
            Set-Acl `
                -LiteralPath $fullPath `
                -AclObject (New-SyncVisionProtectedInstallDirectorySecurity `
                    -ServiceAccount $ServiceAccount `
                    -ServiceModify:$ServiceModify)
            Assert-SyncVisionProtectedInstallDirectory `
                -Path $fullPath `
                -ServiceAccount $ServiceAccount `
                -ServiceModify:$ServiceModify `
                -Context "$Name snapshot ACL migration" | Out-Null
            Assert-SyncVisionInstallDirectoryAclMigrationSource `
                -Path $fullPath `
                -ServiceAccount $ServiceAccount `
                -Context "$Name snapshot ACL migration" `
                -RequireNoLegacyWrite | Out-Null
            $hardenedMetadata = @(Get-SyncVisionInstallDirectoryMetadata -Root $fullPath)
            if ((Get-SyncVisionInstallFileSystemIdentity -Path $fullPath) -cne $originalIdentity -or
                (Get-SyncVisionInstallDirectoryTreeSha256 -Root $fullPath) -cne $sourceTreeHash -or
                (Get-SyncVisionInstallDirectoryNonSecurityMetadataSha256 -Metadata $hardenedMetadata) -cne $nonSecurityMetadataHash) {
                throw "Install data or non-security metadata changed while the legacy ACL was being hardened: $fullPath"
            }
            $aclMigrationApplied = $true
        }

        Copy-SyncVisionInstallDirectoryTreeExact -SourceRoot $fullPath -DestinationRoot $snapshotPath
        if ($null -ne $TestPhaseHook) {
            & $TestPhaseHook "AfterInstallDirectorySnapshotCopied" ([pscustomobject]@{
                    Path = $fullPath
                    SnapshotPath = $snapshotPath
                })
        }
        Assert-SyncVisionInstallDirectorySnapshotTreeSupported `
            -Root $snapshotPath `
            -Context "$Name copied rollback snapshot"
        $hash = Get-SyncVisionInstallDirectoryTreeSha256 -Root $snapshotPath
        $sourceAfterHash = Get-SyncVisionInstallDirectoryTreeSha256 -Root $fullPath
        $sourceMetadataAfter = @(Get-SyncVisionInstallDirectoryMetadata -Root $fullPath)
        $metadataStable = if ($aclMigrationApplied) {
            (Get-SyncVisionInstallDirectoryNonSecurityMetadataSha256 -Metadata $sourceMetadataAfter) -ceq $nonSecurityMetadataHash
        }
        else {
            (Get-SyncVisionInstallDirectoryMetadataSha256 -Metadata $sourceMetadataAfter) -ceq $metadataHash
        }
        if ($hash -cne $sourceTreeHash -or
            $sourceAfterHash -cne $sourceTreeHash -or
            (Get-SyncVisionInstallFileSystemIdentity -Path $fullPath) -cne $originalIdentity -or
            -not $metadataStable) {
            throw "Install data or metadata changed while the rollback snapshot was being captured: $fullPath"
        }
    }
    catch {
        $snapshotFailure = $_
        if ($aclMutationAttempted) {
            try {
                if ((Get-SyncVisionInstallFileSystemIdentity -Path $fullPath) -cne $originalIdentity) {
                    throw "Legacy ACL compensation refused a replaced directory identity."
                }
                Restore-SyncVisionInstallDirectoryMetadata -Root $fullPath -Metadata $metadata
                if ((Get-SyncVisionInstallFileSystemIdentity -Path $fullPath) -cne $originalIdentity -or
                    (Get-SyncVisionInstallDirectoryTreeSha256 -Root $fullPath) -cne $sourceTreeHash -or
                    (Get-SyncVisionInstallDirectoryMetadataSha256 -Metadata @(Get-SyncVisionInstallDirectoryMetadata -Root $fullPath)) -cne $metadataHash) {
                    throw "Legacy ACL compensation did not restore the exact pre-migration tree and metadata."
                }
            }
            catch {
                throw "Install rollback snapshot failed and legacy ACL compensation was incomplete. Failure: $($snapshotFailure.Exception.Message) Compensation: $($_.Exception.Message)"
            }
        }
        throw $snapshotFailure
    }
    return [pscustomobject]@{ Path = $fullPath; Existed = $true; OriginalIdentity = $originalIdentity; SnapshotPath = $snapshotPath; TreeSha256 = $hash; Metadata = $metadata; MetadataSha256 = $metadataHash; NonSecurityMetadataSha256 = $nonSecurityMetadataHash; ServiceAccount = $ServiceAccount; ServiceModify = [bool]$ServiceModify; AllowsAclMigration = [bool]$AllowLegacyAclMigration; RequiresAclMigration = [bool]$sourceState.RequiresAclMigration; AclMigrationApplied = $aclMigrationApplied; MissingPaths = @(); TransactionOwnedPath = $null; TransactionOwnedIdentity = $null }
}

function Assert-SyncVisionInstallDirectorySnapshotQuiesced {
    param([Parameter(Mandatory = $true)][object]$Snapshot)

    $path = [IO.Path]::GetFullPath([string]$Snapshot.Path).TrimEnd('\', '/')
    if (-not [bool]$Snapshot.Existed) {
        $ownedIdentity = [string]$Snapshot.TransactionOwnedIdentity
        if ([string]::IsNullOrWhiteSpace($ownedIdentity)) {
            if (Test-Path -LiteralPath $path) {
                throw "Install directory appeared without durable transaction ownership after its rollback boundary was captured: $path"
            }
            return
        }
        if (-not (Test-Path -LiteralPath $path -PathType Container) -or
            (Get-SyncVisionInstallFileSystemIdentity -Path $path) -cne $ownedIdentity) {
            throw "Transaction-owned fresh install directory identity changed before the quiescence boundary: $path"
        }
        if ($null -eq $Snapshot.PSObject.Properties["TransactionOwnedInitialTreeSha256"] -or
            $null -eq $Snapshot.PSObject.Properties["TransactionOwnedInitialMetadataSha256"] -or
            (Get-SyncVisionInstallDirectoryTreeSha256 -Root $path) -cne [string]$Snapshot.TransactionOwnedInitialTreeSha256 -or
            (Get-SyncVisionInstallDirectoryMetadataSha256 -Metadata @(Get-SyncVisionInstallDirectoryMetadata -Root $path)) -cne [string]$Snapshot.TransactionOwnedInitialMetadataSha256) {
            throw "Transaction-owned fresh install directory changed before the quiescence boundary: $path"
        }
        return
    }

    if (-not (Test-Path -LiteralPath $path -PathType Container)) {
        throw "Install directory disappeared after its rollback snapshot was captured: $path"
    }
    if ([string]::IsNullOrWhiteSpace([string]$Snapshot.SnapshotPath) -or
        -not (Test-Path -LiteralPath ([string]$Snapshot.SnapshotPath) -PathType Container)) {
        throw "Install directory rollback snapshot is unavailable at the quiescence boundary: $path"
    }
    Assert-SyncVisionInstallDirectorySnapshotTreeSupported `
        -Root ([string]$Snapshot.SnapshotPath) `
        -Context "Install directory quiescence"
    if ((Get-SyncVisionInstallDirectoryTreeSha256 -Root ([string]$Snapshot.SnapshotPath)) -cne [string]$Snapshot.TreeSha256 -or
        (Get-SyncVisionInstallDirectoryMetadataSha256 -Metadata @($Snapshot.Metadata)) -cne [string]$Snapshot.MetadataSha256) {
        throw "Install directory rollback snapshot changed before the quiescence boundary: $path"
    }

    $currentMetadata = @(Get-SyncVisionInstallDirectoryMetadata -Root $path)
    $metadataStable = if ([bool]$Snapshot.AclMigrationApplied) {
        $null -ne $Snapshot.PSObject.Properties["NonSecurityMetadataSha256"] -and
            (Get-SyncVisionInstallDirectoryNonSecurityMetadataSha256 -Metadata $currentMetadata) -ceq [string]$Snapshot.NonSecurityMetadataSha256
    }
    else {
        (Get-SyncVisionInstallDirectoryMetadataSha256 -Metadata $currentMetadata) -ceq [string]$Snapshot.MetadataSha256
    }
    if ((Get-SyncVisionInstallFileSystemIdentity -Path $path) -cne [string]$Snapshot.OriginalIdentity -or
        (Get-SyncVisionInstallDirectoryTreeSha256 -Root $path) -cne [string]$Snapshot.TreeSha256 -or
        -not $metadataStable) {
        throw "Install data or metadata changed before the service reached its quiesced rollback boundary: $path"
    }
}

function Assert-SyncVisionWindowsServerInstallDirectorySnapshotsQuiesced {
    param([Parameter(Mandatory = $true)][object]$State)

    $serviceName = [string]$State.Desired.ServiceName
    $service = Get-Service -Name $serviceName -ErrorAction SilentlyContinue
    if ($null -ne $service -and $service.Status -ne [System.ServiceProcess.ServiceControllerStatus]::Stopped) {
        throw "SyncVision service must remain stopped while its data and log rollback snapshots are validated: $serviceName"
    }
    if ($null -ne $service) {
        $cim = Get-CimInstance Win32_Service `
            -Filter "Name='$($serviceName.Replace("'", "''"))'" `
            -ErrorAction Stop
        if ([string]$cim.StartMode -cne "Disabled") {
            throw "SyncVision service restart fence is not durable while rollback snapshots are validated: $serviceName"
        }
    }
    foreach ($snapshot in @($State.DirectorySnapshots)) {
        Assert-SyncVisionInstallDirectorySnapshotQuiesced -Snapshot $snapshot
    }
}

function Stop-SyncVisionWindowsServiceWithInstallFence {
    param([Parameter(Mandatory = $true)][string]$ServiceName)

    $service = Get-Service -Name $ServiceName -ErrorAction SilentlyContinue
    if ($null -eq $service) { return }
    Invoke-SyncVisionScCommand `
        -Arguments @("config", $ServiceName, "start=", "disabled") `
        -Context "Fence SyncVision service restart during install"
    $service = Get-Service -Name $ServiceName -ErrorAction Stop
    if ($service.Status -ne [System.ServiceProcess.ServiceControllerStatus]::Stopped) {
        Stop-Service -Name $ServiceName -Force -ErrorAction Stop
        (Get-Service -Name $ServiceName -ErrorAction Stop).WaitForStatus(
            [System.ServiceProcess.ServiceControllerStatus]::Stopped,
            [TimeSpan]::FromSeconds(30))
    }
    $state = [pscustomobject]@{ Desired = [pscustomobject]@{ ServiceName = $ServiceName }; DirectorySnapshots = @() }
    Assert-SyncVisionWindowsServerInstallDirectorySnapshotsQuiesced -State $state
}

function Convert-SyncVisionLegacyInstallDirectoryAcl {
    param(
        [Parameter(Mandatory = $true)][object]$Snapshot,
        [Parameter(Mandatory = $true)][object[]]$Targets
    )

    if (-not $Snapshot.Existed) { return }
    if ($null -eq $Snapshot.PSObject.Properties["AllowsAclMigration"] -or -not [bool]$Snapshot.AllowsAclMigration) {
        throw "Install ACL migration requires a rollback snapshot that explicitly authorized legacy ACL migration."
    }
    if ((Get-SyncVisionInstallDirectoryTreeSha256 -Root $Snapshot.SnapshotPath) -cne $Snapshot.TreeSha256 -or
        (Get-SyncVisionInstallDirectoryMetadataSha256 -Metadata @($Snapshot.Metadata)) -cne $Snapshot.MetadataSha256) {
        throw "Install ACL migration rollback snapshot changed before migration."
    }
    $currentMetadata = if (Test-Path -LiteralPath $Snapshot.Path -PathType Container) {
        @(Get-SyncVisionInstallDirectoryMetadata -Root $Snapshot.Path)
    }
    else { @() }
    $metadataMatchesSnapshotBoundary = if ([bool]$Snapshot.AclMigrationApplied) {
        $null -ne $Snapshot.PSObject.Properties["NonSecurityMetadataSha256"] -and
            (Get-SyncVisionInstallDirectoryNonSecurityMetadataSha256 -Metadata $currentMetadata) -ceq [string]$Snapshot.NonSecurityMetadataSha256
    }
    else {
        (Get-SyncVisionInstallDirectoryMetadataSha256 -Metadata $currentMetadata) -ceq $Snapshot.MetadataSha256
    }
    if (-not (Test-Path -LiteralPath $Snapshot.Path -PathType Container) -or
        (Get-SyncVisionInstallFileSystemIdentity -Path $Snapshot.Path) -cne [string]$Snapshot.OriginalIdentity -or
        (Get-SyncVisionInstallDirectoryTreeSha256 -Root $Snapshot.Path) -cne $Snapshot.TreeSha256 -or
        -not $metadataMatchesSnapshotBoundary) {
        throw "Install ACL migration source changed after its rollback snapshot was captured."
    }

    $migrationTargets = New-Object "System.Collections.Generic.List[object]"
    foreach ($target in $Targets) {
        $targetPath = [IO.Path]::GetFullPath([string]$target.Path).TrimEnd('\', '/')
        $snapshotPath = [IO.Path]::GetFullPath([string]$Snapshot.Path).TrimEnd('\', '/')
        $insideSnapshot = [string]::Equals($targetPath, $snapshotPath, [StringComparison]::OrdinalIgnoreCase) -or
            (Test-SyncVisionPathWithin -Path $targetPath -Parent $snapshotPath)
        if (-not $insideSnapshot) {
            throw "Install ACL migration target is outside its rollback snapshot: $targetPath"
        }
        if (-not (Test-Path -LiteralPath $targetPath -PathType Container)) { continue }
        $serviceModify = $null -ne $target.PSObject.Properties["ServiceModify"] -and [bool]$target.ServiceModify
        $context = if ($null -ne $target.PSObject.Properties["Context"] -and
            -not [string]::IsNullOrWhiteSpace([string]$target.Context)) { [string]$target.Context } else { "Install ACL migration" }
        $isStrict = $true
        try {
            Assert-SyncVisionProtectedInstallDirectory `
                -Path $targetPath `
                -ServiceAccount $Snapshot.ServiceAccount `
                -ServiceModify:$serviceModify `
                -Context $context | Out-Null
        }
        catch { $isStrict = $false }
        if (-not $isStrict) {
            Assert-SyncVisionInstallDirectoryAclMigrationSource `
                -Path $targetPath `
                -ServiceAccount $Snapshot.ServiceAccount `
                -Context $context | Out-Null
            $migrationTargets.Add([pscustomobject]@{
                    Path = $targetPath
                    ServiceModify = $serviceModify
                    Context = $context
                })
        }
    }

    foreach ($target in @($migrationTargets.ToArray() | Sort-Object @{ Expression = { $_.Path.Length } }, Path)) {
        Set-Acl `
            -LiteralPath $target.Path `
            -AclObject (New-SyncVisionProtectedInstallDirectorySecurity `
                -ServiceAccount $Snapshot.ServiceAccount `
                -ServiceModify:$target.ServiceModify)
        Assert-SyncVisionProtectedInstallDirectory `
            -Path $target.Path `
            -ServiceAccount $Snapshot.ServiceAccount `
            -ServiceModify:$target.ServiceModify `
            -Context $target.Context | Out-Null
    }
    if ((Get-SyncVisionInstallFileSystemIdentity -Path $Snapshot.Path) -cne [string]$Snapshot.OriginalIdentity -or
        (Get-SyncVisionInstallDirectoryTreeSha256 -Root $Snapshot.Path) -cne $Snapshot.TreeSha256) {
        throw "Install ACL migration changed data or replaced the snapshotted directory identity."
    }
    $Snapshot.AclMigrationApplied = [bool]$Snapshot.AclMigrationApplied -or $migrationTargets.Count -ne 0
}

function Register-SyncVisionInstallFreshDirectory {
    param(
        [Parameter(Mandatory = $true)][object]$Snapshot,
        [Parameter(Mandatory = $true)][string]$Path
    )

    if ($Snapshot.Existed) {
        throw "Cannot register an existing install tree as transaction-owned fresh data."
    }
    $resolved = Assert-SyncVisionProtectedInstallDirectory `
        -Path $Path `
        -ServiceAccount $Snapshot.ServiceAccount `
        -ServiceModify:$Snapshot.ServiceModify `
        -Context "Fresh install transaction-owned directory"
    if (-not [string]::Equals($resolved, [IO.Path]::GetFullPath($Snapshot.Path).TrimEnd('\', '/'), [StringComparison]::OrdinalIgnoreCase)) {
        throw "Fresh install transaction-owned path differs from the snapshotted target."
    }
    $Snapshot.TransactionOwnedPath = $resolved
    $Snapshot.TransactionOwnedIdentity = Get-SyncVisionInstallFileSystemIdentity -Path $resolved
    $initialMetadata = @(Get-SyncVisionInstallDirectoryMetadata -Root $resolved)
    $Snapshot | Add-Member `
        -NotePropertyName TransactionOwnedInitialTreeSha256 `
        -NotePropertyValue (Get-SyncVisionInstallDirectoryTreeSha256 -Root $resolved) `
        -Force
    $Snapshot | Add-Member `
        -NotePropertyName TransactionOwnedInitialMetadataSha256 `
        -NotePropertyValue (Get-SyncVisionInstallDirectoryMetadataSha256 -Metadata $initialMetadata) `
        -Force
}

function New-SyncVisionInstallDirectoryConflictArchive {
    param(
        [Parameter(Mandatory = $true)][string]$SourcePath,
        [Parameter(Mandatory = $true)][string]$ArchiveRoot,
        [Parameter(Mandatory = $true)][string]$Context
    )

    $source = (Resolve-Path -LiteralPath $SourcePath).ProviderPath.TrimEnd('\', '/')
    $sourceIdentity = Get-SyncVisionInstallFileSystemIdentity -Path $source
    $sourceTreeSha256 = Get-SyncVisionInstallDirectoryTreeSha256 -Root $source
    $sourceMetadata = @(Get-SyncVisionInstallDirectoryMetadata -Root $source)
    $sourceMetadataSha256 = Get-SyncVisionInstallDirectoryMetadataSha256 -Metadata $sourceMetadata
    $sourceArchiveMetadataSha256 = Get-SyncVisionInstallDirectoryMetadataSha256 `
        -Metadata $sourceMetadata `
        -NormalizeDaclAutoInherited

    if (-not (Test-Path -LiteralPath $ArchiveRoot -PathType Container)) {
        [IO.Directory]::CreateDirectory(
            $ArchiveRoot,
            (New-SyncVisionProtectedInstallStagingDirectorySecurity)) | Out-Null
    }
    $archiveBase = Assert-SyncVisionTrustedStagingDirectory `
        -Path $ArchiveRoot `
        -Context "$Context conflict archive root"
    $archivePath = Join-Path $archiveBase ("directory-" + [Guid]::NewGuid().ToString("N"))
    [IO.Directory]::CreateDirectory(
        $archivePath,
        (New-SyncVisionProtectedInstallStagingDirectorySecurity)) | Out-Null
    try {
        Copy-SyncVisionInstallDirectoryTreeExact `
            -SourceRoot $source `
            -DestinationRoot $archivePath `
            -DirectoryMetadata $sourceMetadata
        Restore-SyncVisionInstallDirectoryMetadata -Root $archivePath -Metadata $sourceMetadata
        $archiveTreeSha256 = Get-SyncVisionInstallDirectoryTreeSha256 -Root $archivePath
        $archiveMetadata = @(Get-SyncVisionInstallDirectoryMetadata -Root $archivePath)
        # Windows may set SE_DACL_AUTO_INHERITED while materializing an
        # otherwise identical DACL. The bit records provenance; ACEs, P and AR
        # remain part of the exact conflict-archive comparison.
        $archiveMetadataSha256 = Get-SyncVisionInstallDirectoryMetadataSha256 `
            -Metadata $archiveMetadata `
            -NormalizeDaclAutoInherited
        if ($archiveTreeSha256 -cne $sourceTreeSha256 -or
            $archiveMetadataSha256 -cne $sourceArchiveMetadataSha256) {
            $metadataDifference = for ($index = 0; $index -lt [Math]::Max($sourceMetadata.Count, $archiveMetadata.Count); ++$index) {
                $expected = if ($index -lt $sourceMetadata.Count) { $sourceMetadata[$index] } else { $null }
                $actual = if ($index -lt $archiveMetadata.Count) { $archiveMetadata[$index] } else { $null }
                if (($expected | ConvertTo-Json -Compress) -cne ($actual | ConvertTo-Json -Compress)) {
                    "index=$index expected=$(($expected | ConvertTo-Json -Compress)) actual=$(($actual | ConvertTo-Json -Compress))"
                    break
                }
            }
            throw "$Context conflict archive validation failed: $archivePath (tree expected=$sourceTreeSha256 actual=$archiveTreeSha256 metadata expected=$sourceArchiveMetadataSha256 actual=$archiveMetadataSha256 first_difference=$metadataDifference)"
        }
        if ((Get-SyncVisionInstallFileSystemIdentity -Path $source) -cne $sourceIdentity -or
            (Get-SyncVisionInstallDirectoryTreeSha256 -Root $source) -cne $sourceTreeSha256 -or
            (Get-SyncVisionInstallDirectoryMetadataSha256 -Metadata @(Get-SyncVisionInstallDirectoryMetadata -Root $source)) -cne $sourceMetadataSha256) {
            throw "$Context live tree changed while its conflict archive was captured: $source"
        }
        Write-Warning "$Context preserved post-snapshot data at $archivePath before rollback."
        return $archivePath
    }
    catch {
        if (Test-Path -LiteralPath $archivePath -PathType Container) {
            Remove-Item -LiteralPath $archivePath -Recurse -Force -ErrorAction SilentlyContinue
        }
        throw
    }
}

function Restore-SyncVisionInstallDirectorySnapshot {
    param(
        [Parameter(Mandatory = $true)][object]$Snapshot,
        [AllowEmptyString()][string]$TransactionPhase = "ConfigPending",
        [AllowEmptyString()][string]$ConflictArchiveRoot = "",
        [AllowNull()][scriptblock]$TestRootLeaseHook,
        [AllowNull()][scriptblock]$TestChildPublicationHook,
        [AllowNull()][scriptblock]$TestPostDeleteHook
    )

    if ($Snapshot.Existed) {
        Assert-SyncVisionInstallDirectorySnapshotTreeSupported `
            -Root ([string]$Snapshot.SnapshotPath) `
            -Context "Install directory rollback final use"
    }
    if ($Snapshot.Existed -and
        (Get-SyncVisionInstallDirectoryTreeSha256 -Root $Snapshot.SnapshotPath) -cne $Snapshot.TreeSha256) {
        throw "Install data backup changed before rollback: $($Snapshot.SnapshotPath)"
    }
    if ($Snapshot.Existed -and
        (Get-SyncVisionInstallDirectoryMetadataSha256 -Metadata @($Snapshot.Metadata)) -cne $Snapshot.MetadataSha256) {
        throw "Install data metadata backup changed before rollback: $($Snapshot.SnapshotPath)"
    }
    $phaseOrder = [string[]]@(Get-SyncVisionServerInstallJournalPhases)
    $currentPhaseIndex = [Array]::IndexOf($phaseOrder, $TransactionPhase)
    $configMutationIndex = [Array]::IndexOf($phaseOrder, "ConfigPending")
    if ($currentPhaseIndex -lt 0 -or $configMutationIndex -lt 0) {
        throw "Install directory rollback requires a recognized transaction phase: $TransactionPhase"
    }
    if ([string]::IsNullOrWhiteSpace($ConflictArchiveRoot)) {
        $archiveParent = if (-not [string]::IsNullOrWhiteSpace([string]$Snapshot.SnapshotPath)) {
            Split-Path -Parent ([string]$Snapshot.SnapshotPath)
        }
        else {
            Split-Path -Parent ([string]$Snapshot.Path)
        }
        $ConflictArchiveRoot = Join-Path $archiveParent "syncvision-install-conflicts"
    }
    if ($Snapshot.Existed) {
        if ($null -eq $Snapshot.PSObject.Properties["OriginalIdentity"] -or
            [string]::IsNullOrWhiteSpace([string]$Snapshot.OriginalIdentity)) {
            throw "Install rollback snapshot is missing the original directory File ID: $($Snapshot.Path)"
        }
        if (-not (Test-Path -LiteralPath $Snapshot.Path -PathType Container)) {
            throw "Install rollback refuses to recreate a missing protected data pathname: $($Snapshot.Path)"
        }
        $currentRoot = ""
        try {
            $currentRoot = Assert-SyncVisionProtectedInstallDirectory -Path $Snapshot.Path -ServiceAccount $Snapshot.ServiceAccount -ServiceModify:$Snapshot.ServiceModify -Context "Install rollback current data"
        }
        catch {
            if ($null -eq $Snapshot.PSObject.Properties["AllowsAclMigration"] -or -not [bool]$Snapshot.AllowsAclMigration) {
                throw
            }
            $currentRoot = Assert-SyncVisionInstallDirectoryAclMigrationSource `
                -Path $Snapshot.Path `
                -ServiceAccount $Snapshot.ServiceAccount `
                -Context "Install rollback current legacy data"
        }
        $originalIdentity = [string]$Snapshot.OriginalIdentity
        if ((Get-SyncVisionInstallFileSystemIdentity -Path $currentRoot) -cne $originalIdentity) {
            throw "Install rollback destination identity differs from the snapshotted File ID: $currentRoot"
        }
        $currentRootLease = $null
        $restoreRootLease = $null
        try {
            $currentRootLease = Enter-SyncVisionInstallDirectoryLease `
                -Path $currentRoot `
                -ExpectedIdentity $originalIdentity
            if ($null -ne $TestRootLeaseHook) { & $TestRootLeaseHook $currentRoot }
            $currentTreeSha256 = Get-SyncVisionInstallDirectoryTreeSha256 -Root $currentRoot
            $currentMetadataSha256 = Get-SyncVisionInstallDirectoryMetadataSha256 `
                -Metadata @(Get-SyncVisionInstallDirectoryMetadata -Root $currentRoot)
            if ($currentTreeSha256 -ceq [string]$Snapshot.TreeSha256 -and
                $currentMetadataSha256 -ceq [string]$Snapshot.MetadataSha256) {
                return
            }
            if ($currentTreeSha256 -cne [string]$Snapshot.TreeSha256 -or
                $currentMetadataSha256 -cne [string]$Snapshot.MetadataSha256) {
                if ($currentPhaseIndex -lt $configMutationIndex) {
                    throw "Install rollback found unowned data or metadata changes before the configuration mutation boundary; preserving the live tree: $currentRoot"
                }
                New-SyncVisionInstallDirectoryConflictArchive `
                    -SourcePath $currentRoot `
                    -ArchiveRoot $ConflictArchiveRoot `
                    -Context "SyncVision existing-directory rollback" | Out-Null
            }
            $rootMetadata = @($Snapshot.Metadata | Where-Object { [string]::IsNullOrEmpty([string]$_.RelativePath) })[0]
            $legacyAclSnapshot = $null -ne $Snapshot.PSObject.Properties["RequiresAclMigration"] -and [bool]$Snapshot.RequiresAclMigration
            $rootSecurity = if ($legacyAclSnapshot) {
                New-SyncVisionProtectedInstallStagingDirectorySecurity
            }
            else {
                $security = [Security.AccessControl.DirectorySecurity]::new()
                $security.SetSecurityDescriptorSddlForm([string]$rootMetadata.SecurityDescriptor)
                $security
            }
            $restoreRoot = Join-Path (Split-Path -Parent $Snapshot.SnapshotPath) ("restore-" + [Guid]::NewGuid().ToString("N"))
            [IO.Directory]::CreateDirectory($restoreRoot, $rootSecurity) | Out-Null
            if ($legacyAclSnapshot) {
                Copy-SyncVisionInstallDirectoryTreeExact `
                    -SourceRoot $Snapshot.SnapshotPath `
                    -DestinationRoot $restoreRoot
            }
            else {
                Copy-SyncVisionInstallDirectoryTreeExact `
                    -SourceRoot $Snapshot.SnapshotPath `
                    -DestinationRoot $restoreRoot `
                    -DirectoryMetadata @($Snapshot.Metadata)
                Restore-SyncVisionInstallDirectoryMetadata -Root $restoreRoot -Metadata @($Snapshot.Metadata)
            }
            $stagingMetadataValid = $legacyAclSnapshot -or
                (Get-SyncVisionInstallDirectoryMetadataSha256 -Metadata @(Get-SyncVisionInstallDirectoryMetadata -Root $restoreRoot)) -ceq $Snapshot.MetadataSha256
            if ((Get-SyncVisionInstallDirectoryTreeSha256 -Root $restoreRoot) -cne $Snapshot.TreeSha256 -or
                -not $stagingMetadataValid) {
                throw "Install data rollback staging validation failed: $restoreRoot"
            }
            if ((Get-SyncVisionInstallFileSystemIdentity -Path $currentRoot) -cne $originalIdentity) {
                throw "Install rollback destination identity changed before publication: $currentRoot"
            }
            Assert-SyncVisionInstallDirectorySnapshotTreeSupported `
                -Root ([string]$Snapshot.SnapshotPath) `
                -Context "Install directory rollback pre-clear final use"
            Assert-SyncVisionInstallDirectorySnapshotTreeSupported `
                -Root $restoreRoot `
                -Context "Install directory rollback staging final use"
            $restoreRootLease = Enter-SyncVisionInstallDirectoryLease `
                -Path $restoreRoot `
                -ExpectedIdentity (Get-SyncVisionInstallFileSystemIdentity -Path $restoreRoot) `
                -DeleteAccess
            $currentRootLease.ClearContents()
            if ($null -ne $TestChildPublicationHook) {
                & $TestChildPublicationHook $currentRoot $restoreRoot
            }
            $restoreRootLease.MoveChildrenNoReplaceTo($currentRootLease)
            Restore-SyncVisionInstallDirectoryMetadata `
                -Root $currentRoot `
                -Metadata @($Snapshot.Metadata) `
                -RootLease $currentRootLease
            if ((Get-SyncVisionInstallFileSystemIdentity -Path $currentRoot) -cne $originalIdentity) {
                throw "Install rollback replaced the protected data pathname: $currentRoot"
            }
            if ((Get-SyncVisionInstallDirectoryTreeSha256 -Root $currentRoot) -cne $Snapshot.TreeSha256) {
                throw "Install data rollback final validation failed: $($Snapshot.Path)"
            }
            $restoredMetadata = @(Get-SyncVisionInstallDirectoryMetadata -Root $currentRoot)
            if ((Get-SyncVisionInstallDirectoryMetadataSha256 -Metadata $restoredMetadata) -cne $Snapshot.MetadataSha256) {
                throw "Install data rollback metadata validation failed: $($Snapshot.Path)"
            }
            $restoreRootLease.DeleteTree()
            Exit-SyncVisionInstallDirectoryLease -Lease $restoreRootLease
            $restoreRootLease = $null
        }
        finally {
            Exit-SyncVisionInstallDirectoryLease -Lease $restoreRootLease
            Exit-SyncVisionInstallDirectoryLease -Lease $currentRootLease
        }
    }
    else {
        $ownedPath = [string]$Snapshot.TransactionOwnedPath
        $ownedIdentity = [string]$Snapshot.TransactionOwnedIdentity
        if ([string]::IsNullOrWhiteSpace($ownedPath) -or [string]::IsNullOrWhiteSpace($ownedIdentity)) {
            if (Test-Path -LiteralPath ([string]$Snapshot.Path)) {
                throw "Install rollback refuses to infer ownership of an unregistered fresh directory: $($Snapshot.Path)"
            }
            return
        }
        if (-not (Test-Path -LiteralPath $ownedPath)) { return }
        $ownedPath = Assert-SyncVisionProtectedInstallDirectory `
            -Path $ownedPath `
            -ServiceAccount $Snapshot.ServiceAccount `
            -ServiceModify:$Snapshot.ServiceModify `
            -Context "Install rollback transaction-owned fresh directory"
        if ((Get-SyncVisionInstallFileSystemIdentity -Path $ownedPath) -cne $ownedIdentity) {
            throw "Install rollback refuses to remove a fresh path whose identity is no longer transaction-owned: $ownedPath"
        }
        $ownedParentLease = $null
        $ownedLease = $null
        try {
            $ownedParentPath = Split-Path -Parent $ownedPath
            $ownedParentLease = Enter-SyncVisionInstallDirectoryLease `
                -Path $ownedParentPath `
                -ExpectedIdentity (Get-SyncVisionInstallFileSystemIdentity -Path $ownedParentPath)
            $ownedLease = Enter-SyncVisionInstallDirectoryLease `
                -Path $ownedPath `
                -ExpectedIdentity $ownedIdentity `
                -DeleteAccess
            if ($null -ne $TestRootLeaseHook) { & $TestRootLeaseHook $ownedPath }
            $currentTreeSha256 = Get-SyncVisionInstallDirectoryTreeSha256 -Root $ownedPath
            $initialTreeSha256 = [string]$Snapshot.TransactionOwnedInitialTreeSha256
            $initialMetadataSha256 = [string]$Snapshot.TransactionOwnedInitialMetadataSha256
            if ([string]::IsNullOrWhiteSpace($initialTreeSha256) -or
                [string]::IsNullOrWhiteSpace($initialMetadataSha256)) {
                throw "Install rollback fresh-directory ownership is missing its durable initial tree or metadata digest: $ownedPath"
            }
            $currentMetadataSha256 = Get-SyncVisionInstallDirectoryMetadataSha256 `
                -Metadata @(Get-SyncVisionInstallDirectoryMetadata -Root $ownedPath)
            if ($currentTreeSha256 -cne $initialTreeSha256 -or
                $currentMetadataSha256 -cne $initialMetadataSha256) {
                if ($currentPhaseIndex -lt $configMutationIndex) {
                    throw "Install rollback found unowned content or metadata in a fresh directory before the configuration mutation boundary; preserving the live tree: $ownedPath"
                }
                New-SyncVisionInstallDirectoryConflictArchive `
                    -SourcePath $ownedPath `
                    -ArchiveRoot $ConflictArchiveRoot `
                    -Context "SyncVision fresh-directory rollback" | Out-Null
            }
            $ownedLease.DeleteTree()
            Exit-SyncVisionInstallDirectoryLease -Lease $ownedLease
            $ownedLease = $null
            if ($null -ne $TestPostDeleteHook) { & $TestPostDeleteHook $ownedPath }
            if (Test-Path -LiteralPath $ownedPath) {
                throw "Install rollback removed its transaction-owned fresh directory, but a replacement appeared at the protected path: $ownedPath"
            }
        }
        finally {
            Exit-SyncVisionInstallDirectoryLease -Lease $ownedLease
            Exit-SyncVisionInstallDirectoryLease -Lease $ownedParentLease
        }
    }
}

function Restore-SyncVisionDurableInstallDirectorySnapshot {
    param(
        [Parameter(Mandatory = $true)][object]$Snapshot,
        [Parameter(Mandatory = $true)][string]$TransactionPhase,
        [Parameter(Mandatory = $true)][string]$ConflictArchiveRoot
    )

    Restore-SyncVisionInstallDirectorySnapshot `
        -Snapshot $Snapshot `
        -TransactionPhase $TransactionPhase `
        -ConflictArchiveRoot $ConflictArchiveRoot
}

function Assert-SyncVisionTextFileContent {
    param(
        [Parameter(Mandatory = $true)][string]$Path,
        [Parameter(Mandatory = $true)][string]$ExpectedText,
        [Parameter(Mandatory = $true)][string]$Context
    )

    if (-not (Test-Path -LiteralPath $Path -PathType Leaf)) {
        throw "$Context was not found: $Path"
    }
    $item = Get-Item -LiteralPath $Path -Force
    if (($item.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
        throw "$Context is a reparse point: $Path"
    }
    $expected = [Text.UTF8Encoding]::new($false).GetBytes($ExpectedText)
    $actual = [IO.File]::ReadAllBytes($item.FullName)
    if ($actual.Length -ne $expected.Length -or
        (Get-SyncVisionServerInstallJournalSha256 -Bytes $actual) -cne
            (Get-SyncVisionServerInstallJournalSha256 -Bytes $expected)) {
        throw "$Context does not match the durable transaction target."
    }
}

function Assert-SyncVisionServiceTransactionSnapshotState {
    param(
        [Parameter(Mandatory = $true)][object]$Snapshot,
        [Parameter(Mandatory = $true)][bool]$ExpectedRunning,
        [Parameter(Mandatory = $true)][string]$Context
    )

    $currentService = Get-Service -Name ([string]$Snapshot.ServiceName) -ErrorAction SilentlyContinue
    if (-not [bool]$Snapshot.Exists) {
        if ($null -ne $currentService) { throw "$Context expected the service to be absent." }
        return
    }
    if ($null -eq $currentService) { throw "$Context expected the service to exist." }
    $current = Get-SyncVisionServiceTransactionSnapshot -ServiceName ([string]$Snapshot.ServiceName)
    foreach ($name in @("PathName", "StartName", "StartMode", "DisplayName", "Description")) {
        if ([string]$current.Cim.$name -cne [string]$Snapshot.Cim.$name) {
            throw "$Context service $name differs from the durable snapshot."
        }
    }
    if ([string]$current.Sddl -cne [string]$Snapshot.Sddl) {
        throw "$Context service security differs from the durable snapshot."
    }
    $registryPath = "SYSTEM\CurrentControlSet\Services\$([string]$Snapshot.ServiceName)"
    $registryKey = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey($registryPath, $false)
    if ($null -eq $registryKey) { throw "$Context service registry subtree is absent." }
    try {
        Assert-SyncVisionRegistryTreeSnapshot `
            -Key $registryKey `
            -Snapshot $Snapshot.RegistryTree `
            -Context "$Context service registry subtree" | Out-Null
    }
    finally { $registryKey.Dispose() }
    if ([bool]$current.Running -ne $ExpectedRunning) {
        throw "$Context service running state differs from the durable snapshot."
    }
}

function ConvertTo-SyncVisionCanonicalServiceFenceRegistryModel {
    param([Parameter(Mandatory = $true)][object]$RegistryTree)

    $model = ConvertTo-SyncVisionCanonicalRegistryTreeModel -Snapshot $RegistryTree
    $startValues = @($model.values | Where-Object { [string]$_.name -ceq "Start" })
    if ($startValues.Count -ne 1 -or [string]$startValues[0].kind -cne "DWord") {
        throw "Service install fence requires exactly one DWORD Start registry value."
    }
    $startValues[0].value = "<service-start-mode>"
    return $model
}

function Assert-SyncVisionServiceTransactionFenceState {
    param(
        [Parameter(Mandatory = $true)][object]$Snapshot,
        [Parameter(Mandatory = $true)][string]$Context
    )

    $currentService = Get-Service -Name ([string]$Snapshot.ServiceName) -ErrorAction SilentlyContinue
    if (-not [bool]$Snapshot.Exists) {
        if ($null -ne $currentService) { throw "$Context expected the service to remain absent." }
        return
    }
    if ($null -eq $currentService -or
        $currentService.Status -ne [System.ServiceProcess.ServiceControllerStatus]::Stopped) {
        throw "$Context expected the snapshotted service to be stopped."
    }
    $current = Get-SyncVisionServiceTransactionSnapshot -ServiceName ([string]$Snapshot.ServiceName)
    foreach ($name in @("PathName", "StartName", "DisplayName", "Description")) {
        if ([string]$current.Cim.$name -cne [string]$Snapshot.Cim.$name) {
            throw "$Context service $name changed outside the durable install fence."
        }
    }
    if ([string]$current.Cim.StartMode -cne "Disabled" -or
        [string]$current.Sddl -cne [string]$Snapshot.Sddl) {
        throw "$Context service restart fence or security descriptor changed."
    }
    $expectedRegistry = ConvertTo-SyncVisionCanonicalServiceFenceRegistryModel `
        -RegistryTree $Snapshot.RegistryTree | ConvertTo-Json -Compress -Depth 100
    $currentRegistry = ConvertTo-SyncVisionCanonicalServiceFenceRegistryModel `
        -RegistryTree $current.RegistryTree | ConvertTo-Json -Compress -Depth 100
    if ($currentRegistry -cne $expectedRegistry) {
        throw "$Context service registry differs from the durable snapshot beyond the owned Start-mode fence."
    }
}

function Assert-SyncVisionWindowsServerInstallNewState {
    param([Parameter(Mandatory = $true)][object]$State)

    $desired = $State.Desired
    Assert-SyncVisionProtectedInstallDirectory `
        -Path ([string]$desired.DataDir) `
        -ServiceAccount ([string]$desired.ServiceAccountIdentity) `
        -Context "Committed SyncVision data directory" | Out-Null
    Assert-SyncVisionProtectedInstallDirectory `
        -Path ([string]$desired.LogDir) `
        -ServiceAccount ([string]$desired.ServiceAccountIdentity) `
        -ServiceModify `
        -Context "Committed SyncVision log directory" | Out-Null
    Assert-SyncVisionTextFileContent `
        -Path ([string]$desired.TokenPath) `
        -ExpectedText (([string]$desired.Token) + [Environment]::NewLine) `
        -Context "Committed SyncVision token file"
    Assert-SyncVisionTextFileContent `
        -Path ([string]$desired.ConfigPath) `
        -ExpectedText ([string]$desired.ConfigText) `
        -Context "Committed SyncVision config file"
    if (-not [string]::IsNullOrEmpty([string]$desired.TransportSecretPath)) {
        Assert-SyncVisionTextFileContent `
            -Path ([string]$desired.TransportSecretPath) `
            -ExpectedText (([string]$desired.TransportSecret) + [Environment]::NewLine) `
            -Context "Committed SyncVision transport secret file"
    }

    $service = Get-Service -Name ([string]$desired.ServiceName) -ErrorAction SilentlyContinue
    if ($null -eq $service) { throw "Committed SyncVision service definition is absent." }
    $cim = Get-CimInstance Win32_Service `
        -Filter "Name='$(([string]$desired.ServiceName).Replace("'", "''"))'" `
        -ErrorAction Stop
    if ([string]$cim.PathName -cne [string]$desired.BinPath -or
        [string]$cim.StartName -cne [string]$desired.ServiceAccountIdentity -or
        [string]$cim.Description -cne [string]$desired.ServiceDescription) {
        throw "Committed SyncVision service definition differs from the durable target."
    }
    $running = $service.Status -ne [System.ServiceProcess.ServiceControllerStatus]::Stopped
    if ($running -ne [bool]$desired.ShouldStartService) {
        throw "Committed SyncVision service running state differs from the durable target."
    }
    if ([bool]$desired.ConfigureFirewall) {
        $managedRules = @(Get-SyncVisionManagedFirewallRules `
                -ServiceName ([string]$desired.ServiceName) `
                -Rules @($desired.FirewallRules))
        $expectedNames = @($desired.FirewallRules | ForEach-Object { [string]$_.Name } | Sort-Object)
        $actualNames = @($managedRules | ForEach-Object { [string]$_.Name } | Sort-Object)
        if (($actualNames -join "`n") -cne ($expectedNames -join "`n")) {
            throw "Committed SyncVision firewall rule set contains stale or missing managed rules."
        }
        foreach ($plan in @($desired.FirewallRules)) {
            $rules = @(Get-NetFirewallRule -Name ([string]$plan.Name) -ErrorAction SilentlyContinue)
            if ($rules.Count -ne 1 -or -not (Test-SyncVisionFirewallRuleMatchesPlan -ExpectedRule $plan -FirewallRule $rules[0])) {
                throw "Committed SyncVision firewall rule differs from the durable target: $($plan.DisplayName)"
            }
        }
    }
}

function New-SyncVisionWindowsServerInstallResourceBackend {
    param([AllowNull()][scriptblock]$AdditionalVerification)

    return [pscustomobject]@{
        Kind = "Windows"
        VerifyServiceSnapshotUnchanged = {
            param($state)
            Assert-SyncVisionServiceTransactionSnapshotState `
                -Snapshot $state.ServiceSnapshot `
                -ExpectedRunning ([bool]$state.ServiceSnapshot.Running) `
                -Context "Pre-fence server install service"
        }
        StopCurrentService = {
            param($state)
            Stop-SyncVisionWindowsServiceWithInstallFence -ServiceName ([string]$state.Desired.ServiceName)
        }
        VerifyDirectorySnapshotsQuiesced = {
            param($state)
            Assert-SyncVisionWindowsServerInstallDirectorySnapshotsQuiesced -State $state
        }
        ApplyDirectories = {
            param($state)
            $forwardRecovery = $null -ne $state.PSObject.Properties["TransactionRecoveryMode"] -and
                [string]$state.TransactionRecoveryMode -ceq "Forward"
            if (-not $forwardRecovery) {
                Assert-SyncVisionWindowsServerInstallDirectorySnapshotsQuiesced -State $state
                foreach ($migration in @($state.AclMigrations)) {
                    $snapshot = @($state.DirectorySnapshots)[[int]$migration.SnapshotIndex]
                    Convert-SyncVisionLegacyInstallDirectoryAcl `
                        -Snapshot $snapshot `
                        -Targets @($migration.Targets)
                }
            }
            $state.Desired.DataDir = Initialize-SyncVisionProtectedInstallDirectory `
                -Path ([string]$state.Desired.DataDir) `
                -ServiceAccount ([string]$state.Desired.ServiceAccountIdentity) `
                -Context "SyncVision data directory"
            $state.Desired.LogDir = Initialize-SyncVisionProtectedInstallDirectory `
                -Path ([string]$state.Desired.LogDir) `
                -ServiceAccount ([string]$state.Desired.ServiceAccountIdentity) `
                -ServiceModify `
                -Context "SyncVision log directory"
            if (-not $forwardRecovery) {
                foreach ($snapshot in @($state.DirectorySnapshots | Where-Object { -not [bool]$_.Existed })) {
                    if ([string]::IsNullOrWhiteSpace([string]$snapshot.TransactionOwnedIdentity)) {
                        throw "Fresh install directory ownership was not durably registered before mutation: $($snapshot.Path)"
                    }
                    if ((Get-SyncVisionInstallFileSystemIdentity -Path ([string]$snapshot.Path)) -cne [string]$snapshot.TransactionOwnedIdentity) {
                        throw "Fresh install directory identity changed before mutation: $($snapshot.Path)"
                    }
                }
            }
        }
        ApplyConfig = {
            param($state)
            $desired = $state.Desired
            Write-SyncVisionTokenFile `
                -Path ([string]$desired.TokenPath) `
                -Token ([string]$desired.Token) `
                -ServiceAccount ([string]$desired.ServiceAccountIdentity)
            if (-not [string]::IsNullOrEmpty([string]$desired.TransportSecretPath)) {
                Write-SyncVisionTransportSecretFile `
                    -Path ([string]$desired.TransportSecretPath) `
                    -Secret ([string]$desired.TransportSecret) `
                    -ServiceAccount ([string]$desired.ServiceAccountIdentity)
            }
            Write-SyncVisionProtectedTextFile `
                -Path ([string]$desired.ConfigPath) `
                -Text ([string]$desired.ConfigText) `
                -Security (New-SyncVisionTokenFileAcl -ServiceAccount ([string]$desired.ServiceAccountIdentity)) `
                -Context "SyncVision server config"
        }
        VerifyServiceFenceState = {
            param($state)
            Assert-SyncVisionServiceTransactionFenceState `
                -Snapshot $state.ServiceSnapshot `
                -Context "Pre-definition server install service"
        }
        ApplyServiceDefinition = {
            param($state)
            $desired = $state.Desired
            $current = Get-Service -Name ([string]$desired.ServiceName) -ErrorAction SilentlyContinue
            $arguments = if ($null -eq $current) { @($desired.ServiceCreateArguments) } else { @($desired.ServiceConfigArguments) }
            Invoke-SyncVisionScCommand -Arguments $arguments -Context "Create or configure SyncVision service"
            Invoke-SyncVisionScCommand `
                -Arguments @("description", [string]$desired.ServiceName, [string]$desired.ServiceDescription) `
                -Context "Configure SyncVision service description"
            if (-not [bool]$desired.NoServiceRecovery) {
                Invoke-SyncVisionServiceRecovery `
                    -ServiceName ([string]$desired.ServiceName) `
                    -RestartDelayMs ([uint32]$desired.ServiceRecoveryRestartDelayMs)
            }
        }
        VerifyFirewallSnapshotUnchanged = {
            param($state)
            if ($null -ne $state.FirewallSnapshot) {
                Assert-SyncVisionFirewallTransactionSnapshotRestored `
                    -Snapshot $state.FirewallSnapshot `
                    -Context "Pre-mutation server install firewall"
            }
        }
        ApplyFirewall = {
            param($state)
            if ([bool]$state.Desired.ConfigureFirewall) {
                Set-SyncVisionFirewallRulePlansTransactional `
                    -Rules @($state.Desired.FirewallRules) `
                    -Snapshot $state.FirewallSnapshot
            }
        }
        ApplyRunningState = {
            param($state)
            $service = Get-Service -Name ([string]$state.Desired.ServiceName) -ErrorAction Stop
            if ([bool]$state.Desired.ShouldStartService) {
                if ($service.Status -eq [System.ServiceProcess.ServiceControllerStatus]::Stopped) {
                    Start-Service -Name ([string]$state.Desired.ServiceName) -ErrorAction Stop
                }
            }
            elseif ($service.Status -ne [System.ServiceProcess.ServiceControllerStatus]::Stopped) {
                Stop-Service -Name ([string]$state.Desired.ServiceName) -Force -ErrorAction Stop
                (Get-Service -Name ([string]$state.Desired.ServiceName) -ErrorAction Stop).WaitForStatus(
                    [System.ServiceProcess.ServiceControllerStatus]::Stopped,
                    [TimeSpan]::FromSeconds(30))
            }
        }
        VerifyNewState = {
            param($state)
            Assert-SyncVisionWindowsServerInstallNewState -State $state
            if ($null -ne $AdditionalVerification) { & $AdditionalVerification $state }
        }.GetNewClosure()
        RestoreDirectories = {
            param($state)
            $snapshots = @($state.DirectorySnapshots)
            [Array]::Reverse($snapshots)
            foreach ($snapshot in $snapshots) {
                Restore-SyncVisionDurableInstallDirectorySnapshot `
                    -Snapshot $snapshot `
                    -TransactionPhase ([string]$state.TransactionRecoveryPhase) `
                    -ConflictArchiveRoot ([string]$state.ConflictArchiveRoot)
            }
        }
        RestoreServiceDefinition = {
            param($state)
            Restore-SyncVisionServiceTransactionSnapshot -Snapshot $state.ServiceSnapshot -DeferStart
        }
        RestoreFirewall = {
            param($state)
            if ($null -ne $state.FirewallSnapshot -and
                ($null -eq $state.PSObject.Properties["TransactionFirewallMayHaveMutated"] -or
                    [bool]$state.TransactionFirewallMayHaveMutated)) {
                Restore-SyncVisionFirewallTransactionSnapshot -Snapshot $state.FirewallSnapshot
            }
        }
        VerifyOldStoppedState = {
            param($state)
            Assert-SyncVisionServiceTransactionSnapshotState `
                -Snapshot $state.ServiceSnapshot `
                -ExpectedRunning $false `
                -Context "Stopped server install rollback"
        }
        RestoreRunningState = {
            param($state)
            Restore-SyncVisionServiceRunningState -Snapshot $state.ServiceSnapshot
        }
        VerifyOldState = {
            param($state)
            Assert-SyncVisionServiceTransactionSnapshotState `
                -Snapshot $state.ServiceSnapshot `
                -ExpectedRunning ([bool]$state.ServiceSnapshot.Running) `
                -Context "Completed server install rollback"
            if ($null -ne $state.FirewallSnapshot) {
                Assert-SyncVisionFirewallTransactionSnapshotRestored `
                    -Snapshot $state.FirewallSnapshot `
                    -Context "Completed server install rollback firewall"
            }
        }
        Cleanup = {
            param($state)
            if ([string]::IsNullOrEmpty([string]$state.SnapshotContextPath)) { return }
            if (-not (Test-Path -LiteralPath ([string]$state.SnapshotContextPath))) { return }
            $path = Assert-SyncVisionTrustedStagingPath `
                -BasePath ([string]$state.SnapshotContextBasePath) `
                -StagingPath ([string]$state.SnapshotContextPath)
            if ((Get-SyncVisionInstallFileSystemIdentity -Path $path) -cne [string]$state.SnapshotContextIdentity) {
                throw "Protected install recovery snapshot directory identity changed before cleanup."
            }
            $parentLease = $null
            $snapshotLease = $null
            try {
                $parentLease = Enter-SyncVisionInstallDirectoryLease `
                    -Path ([string]$state.SnapshotContextBasePath) `
                    -ExpectedIdentity (Get-SyncVisionInstallFileSystemIdentity -Path ([string]$state.SnapshotContextBasePath))
                $snapshotLease = Enter-SyncVisionInstallDirectoryLease `
                    -Path $path `
                    -ExpectedIdentity ([string]$state.SnapshotContextIdentity) `
                    -DeleteAccess
                $snapshotLease.DeleteTree()
                Exit-SyncVisionInstallDirectoryLease -Lease $snapshotLease
                $snapshotLease = $null
                if (Test-Path -LiteralPath $path) {
                    throw "Protected install recovery snapshot was replaced during cleanup."
                }
            }
            finally {
                Exit-SyncVisionInstallDirectoryLease -Lease $snapshotLease
                Exit-SyncVisionInstallDirectoryLease -Lease $parentLease
            }
        }
    }
}

function Test-SyncVisionPathWithin {
    param([Parameter(Mandatory = $true)][string]$Path, [Parameter(Mandatory = $true)][string]$Parent)

    $basePath = Get-SyncVisionCurrentFileSystemProviderPath
    $fullPath = (Resolve-SyncVisionUserFileSystemPath `
            -Path $Path `
            -BasePath $basePath `
            -Context "Child path comparison").TrimEnd('\', '/')
    $fullParent = (Resolve-SyncVisionUserFileSystemPath `
            -Path $Parent `
            -BasePath $basePath `
            -Context "Parent path comparison").TrimEnd('\', '/')
    return $fullPath.StartsWith($fullParent + [IO.Path]::DirectorySeparatorChar, [StringComparison]::OrdinalIgnoreCase)
}

function Assert-SyncVisionInstallDataDirectorySeparation {
    param(
        [Parameter(Mandatory = $true)][string]$InstallDir,
        [Parameter(Mandatory = $true)][string]$DataDir,
        [Parameter(Mandatory = $true)][string]$LogDir
    )

    $basePath = Get-SyncVisionCurrentFileSystemProviderPath
    $paths = @(
        [pscustomobject]@{ Name = "InstallDir"; Value = $InstallDir },
        [pscustomobject]@{ Name = "DataDir"; Value = $DataDir },
        [pscustomobject]@{ Name = "LogDir"; Value = $LogDir })
    foreach ($entry in $paths) {
        $entry.Value = (Resolve-SyncVisionUserFileSystemPath `
                -Path ([string]$entry.Value) `
                -BasePath $basePath `
                -Context "$($entry.Name) overlap preflight").TrimEnd('\', '/')
        Assert-SyncVisionExistingPathChainNoReparse `
            -Path ([string]$entry.Value) `
            -Context "$($entry.Name) overlap preflight"
    }

    $pathSummary = ($paths | ForEach-Object { "$($_.Name)='$($_.Value)'" }) -join " "
    for ($leftIndex = 0; $leftIndex -lt $paths.Count; ++$leftIndex) {
        for ($rightIndex = $leftIndex + 1; $rightIndex -lt $paths.Count; ++$rightIndex) {
            $left = $paths[$leftIndex]
            $right = $paths[$rightIndex]
            if ([string]::Equals(
                    [string]$left.Value,
                    [string]$right.Value,
                    [StringComparison]::OrdinalIgnoreCase) -or
                (Test-SyncVisionPathWithin -Path ([string]$left.Value) -Parent ([string]$right.Value)) -or
                (Test-SyncVisionPathWithin -Path ([string]$right.Value) -Parent ([string]$left.Value))) {
                throw "InstallDir, DataDir, and LogDir must be separate, non-overlapping directory trees; no path may equal or contain another. $pathSummary."
            }

            if ((Test-Path -LiteralPath ([string]$left.Value) -PathType Container) -and
                (Test-Path -LiteralPath ([string]$right.Value) -PathType Container)) {
                $leftIdentity = Get-SyncVisionInstallFileSystemIdentity -Path ([string]$left.Value)
                $rightIdentity = Get-SyncVisionInstallFileSystemIdentity -Path ([string]$right.Value)
                foreach ($identityCheck in @(
                        [pscustomobject]@{ Path = [string]$left.Value; OtherIdentity = $rightIdentity },
                        [pscustomobject]@{ Path = [string]$right.Value; OtherIdentity = $leftIdentity })) {
                    $current = Get-Item -LiteralPath $identityCheck.Path -Force
                    while ($null -ne $current) {
                        if ((Get-SyncVisionInstallFileSystemIdentity -Path $current.FullName) -ceq $identityCheck.OtherIdentity) {
                            throw "InstallDir, DataDir, and LogDir resolve to overlapping directory identities through an alias or ancestor. $pathSummary."
                        }
                        $current = $current.Parent
                    }
                }
            }
        }
    }
}

function New-SyncVisionProtectedInstallStagingDirectorySecurity {
    $acl = New-Object System.Security.AccessControl.DirectorySecurity
    $acl.SetAccessRuleProtection($true, $false)

    $inheritance = [Security.AccessControl.InheritanceFlags]"ContainerInherit, ObjectInherit"
    $allow = [Security.AccessControl.AccessControlType]::Allow
    $noPropagation = [Security.AccessControl.PropagationFlags]::None
    $administratorsSid = [Security.Principal.SecurityIdentifier]::new(
        [Security.Principal.WellKnownSidType]::BuiltinAdministratorsSid,
        $null)
    $systemSid = [Security.Principal.SecurityIdentifier]::new(
        [Security.Principal.WellKnownSidType]::LocalSystemSid,
        $null)
    $acl.SetOwner($administratorsSid)
    foreach ($sid in @($administratorsSid, $systemSid)) {
        $acl.AddAccessRule([Security.AccessControl.FileSystemAccessRule]::new(
                $sid,
                [Security.AccessControl.FileSystemRights]::FullControl,
                $inheritance,
                $noPropagation,
                $allow)) | Out-Null
    }

    return $acl
}

function Get-SyncVisionTrustedPackageStagingBasePath {
    $commonApplicationData = [Environment]::GetFolderPath([Environment+SpecialFolder]::CommonApplicationData)
    if ([string]::IsNullOrWhiteSpace($commonApplicationData)) {
        throw "Trusted package staging failed: CommonApplicationData is unavailable."
    }
    return Join-Path $commonApplicationData "SyncVisionPackageStaging"
}

function Assert-SyncVisionStagingAncestorChain {
    param(
        [Parameter(Mandatory = $true)]
        [string]$Path
    )

    $trustedOwnerSids = @(
        "S-1-5-18",
        "S-1-5-32-544",
        "S-1-5-80-956008885-3418522649-1831038044-1853292631-2271478464"
    )
    $dangerousRights = [Security.AccessControl.FileSystemRights]::DeleteSubdirectoriesAndFiles -bor
        [Security.AccessControl.FileSystemRights]::Delete -bor
        [Security.AccessControl.FileSystemRights]::ChangePermissions -bor
        [Security.AccessControl.FileSystemRights]::TakeOwnership

    $current = Get-Item -LiteralPath (Resolve-Path -LiteralPath $Path).Path -Force
    while ($null -ne $current) {
        if (($current.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
            throw "Trusted package staging failed: reparse-point ancestor: $($current.FullName)"
        }

        $acl = Get-Acl -LiteralPath $current.FullName
        $ownerSid = $acl.GetOwner([Security.Principal.SecurityIdentifier]).ToString()
        if ($trustedOwnerSids -notcontains $ownerSid) {
            throw "Trusted package staging failed: untrusted ancestor owner $ownerSid at $($current.FullName)."
        }
        foreach ($rule in $acl.GetAccessRules($true, $true, [Security.Principal.SecurityIdentifier])) {
            $appliesToDirectory = ($rule.PropagationFlags -band [Security.AccessControl.PropagationFlags]::InheritOnly) -eq 0
            if ($appliesToDirectory -and
                $rule.AccessControlType -eq [Security.AccessControl.AccessControlType]::Allow -and
                $trustedOwnerSids -notcontains $rule.IdentityReference.Value -and
                ($rule.FileSystemRights -band $dangerousRights) -ne 0) {
                throw "Trusted package staging failed: standard-user delete or ACL control on ancestor $($current.FullName)."
            }
        }

        $current = $current.Parent
    }
}

function Assert-SyncVisionTrustedStagingDirectory {
    param(
        [Parameter(Mandatory = $true)]
        [string]$Path,

        [Parameter(Mandatory = $true)]
        [string]$Context
    )

    $item = Get-Item -LiteralPath $Path -Force
    if (-not $item.PSIsContainer -or ($item.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
        throw "Trusted package staging failed: $Context must be a non-reparse directory: $Path"
    }

    $acl = Get-Acl -LiteralPath $item.FullName
    if (-not $acl.AreAccessRulesProtected) {
        throw "Trusted package staging failed: $Context ACL inheritance is enabled: $($item.FullName)"
    }
    $ownerSid = $acl.GetOwner([Security.Principal.SecurityIdentifier]).ToString()
    if (@("S-1-5-18", "S-1-5-32-544") -notcontains $ownerSid) {
        throw "Trusted package staging failed: $Context owner must be SYSTEM or BUILTIN\\Administrators, got $ownerSid."
    }

    $rules = @($acl.GetAccessRules($true, $true, [Security.Principal.SecurityIdentifier]))
    $expectedSids = @("S-1-5-18", "S-1-5-32-544")
    $expectedSidSet = New-Object "System.Collections.Generic.HashSet[string]" ([StringComparer]::OrdinalIgnoreCase)
    $actualSidSet = New-Object "System.Collections.Generic.HashSet[string]" ([StringComparer]::OrdinalIgnoreCase)
    foreach ($expectedSid in $expectedSids) {
        [void]$expectedSidSet.Add($expectedSid)
    }
    $expectedInheritance = [Security.AccessControl.InheritanceFlags]"ContainerInherit, ObjectInherit"
    if ($rules.Count -ne 2) {
        throw "Trusted package staging failed: $Context must contain exactly two access rules."
    }
    foreach ($rule in $rules) {
        [void]$actualSidSet.Add($rule.IdentityReference.Value)
        if ($expectedSids -notcontains $rule.IdentityReference.Value -or
            $rule.AccessControlType -ne [Security.AccessControl.AccessControlType]::Allow -or
            $rule.FileSystemRights -ne [Security.AccessControl.FileSystemRights]::FullControl -or
            $rule.InheritanceFlags -ne $expectedInheritance -or
            $rule.PropagationFlags -ne [Security.AccessControl.PropagationFlags]::None -or
            $rule.IsInherited) {
            throw "Trusted package staging failed: $Context contains a non-exact ACL rule."
        }
    }
    if (-not $actualSidSet.SetEquals($expectedSidSet)) {
        throw "Trusted package staging failed: $Context must contain exactly one SYSTEM and one BUILTIN\\Administrators access rule."
    }

    return $item.FullName
}

function Initialize-SyncVisionTrustedPackageStagingBase {
    $basePath = Get-SyncVisionTrustedPackageStagingBasePath
    $parentPath = Split-Path -Parent $basePath
    Assert-SyncVisionStagingAncestorChain -Path $parentPath

    if (Test-Path -LiteralPath $basePath) {
        if (-not (Test-Path -LiteralPath $basePath -PathType Container)) {
            throw "Trusted package staging failed: the fixed staging base is not a directory: $basePath"
        }
        Assert-SyncVisionTrustedStagingDirectory -Path $basePath -Context "staging base" | Out-Null
        Assert-SyncVisionStagingAncestorChain -Path $basePath
        return (Resolve-Path -LiteralPath $basePath).Path
    }

    $stagingSecurity = New-SyncVisionProtectedInstallStagingDirectorySecurity
    [IO.Directory]::CreateDirectory($basePath, $stagingSecurity) | Out-Null
    Assert-SyncVisionTrustedStagingDirectory -Path $basePath -Context "new staging base" | Out-Null
    Assert-SyncVisionStagingAncestorChain -Path $basePath
    return (Resolve-Path -LiteralPath $basePath).Path
}

function Assert-SyncVisionTrustedStagingPath {
    param(
        [Parameter(Mandatory = $true)]
        [string]$BasePath,

        [Parameter(Mandatory = $true)]
        [string]$StagingPath
    )

    $resolvedBase = Assert-SyncVisionTrustedStagingDirectory -Path $BasePath -Context "staging base"
    Assert-SyncVisionStagingAncestorChain -Path $resolvedBase
    $resolvedStaging = Assert-SyncVisionTrustedStagingDirectory -Path $StagingPath -Context "staging leaf"
    if (-not [string]::Equals((Split-Path -Parent $resolvedStaging), $resolvedBase, [StringComparison]::OrdinalIgnoreCase)) {
        throw "Trusted package staging failed: staging leaf is not a direct child of the trusted base."
    }
    return $resolvedStaging
}

function New-SyncVisionProtectedInstallStagingDirectory {
    param(
        [AllowEmptyString()][string]$DirectoryName = "",
        [AllowNull()][scriptblock]$TestPhaseHook
    )

    $basePath = Initialize-SyncVisionTrustedPackageStagingBase
    if (-not [string]::IsNullOrWhiteSpace($DirectoryName) -and
        $DirectoryName -cnotmatch '^txn-[0-9a-f]{32}-(package|status|snapshot)$') {
        throw "Protected install staging has an invalid deterministic transaction directory name: $DirectoryName"
    }
    $leafName = if ([string]::IsNullOrWhiteSpace($DirectoryName)) {
        "stage-" + [Guid]::NewGuid().ToString("N")
    }
    else { $DirectoryName }
    $stagingDirectory = Join-Path $basePath $leafName
    if (Test-Path -LiteralPath $stagingDirectory) {
        throw "Protected install staging directory already exists and must be recovered before reuse: $stagingDirectory"
    }
    $stagingSecurity = New-SyncVisionProtectedInstallStagingDirectorySecurity
    [IO.Directory]::CreateDirectory($stagingDirectory, $stagingSecurity) | Out-Null
    $resolvedStaging = Assert-SyncVisionTrustedStagingPath -BasePath $basePath -StagingPath $stagingDirectory
    $context = [pscustomobject]@{
        BasePath = $basePath
        Path = $resolvedStaging
    }
    if ($null -ne $TestPhaseHook) { & $TestPhaseHook "AfterProtectedInstallStagingDirectoryCreated" $context }
    return $context
}

function Copy-SyncVisionStatusScriptToProtectedStaging {
    param(
        [Parameter(Mandatory = $true)][string]$SourcePath,
        [Parameter(Mandatory = $true)][string]$ExpectedHash,
        [Parameter(Mandatory = $true)][string]$StagingDirectory
    )

    if ($ExpectedHash -cnotmatch '^[0-9a-f]{64}$') {
        throw "Protected status verifier expected hash must be a lowercase SHA-256 string."
    }
    if (-not (Test-Path -LiteralPath $SourcePath -PathType Leaf) -or
        -not (Test-Path -LiteralPath $StagingDirectory -PathType Container)) {
        throw "Protected status verifier source or staging directory was not found."
    }
    $source = Get-Item -LiteralPath $SourcePath -Force
    $staging = Get-Item -LiteralPath $StagingDirectory -Force
    if (($source.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0 -or
        ($staging.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
        throw "Protected status verifier source and staging directory must not be reparse points."
    }
    Assert-SyncVisionStagingAncestorChain -Path $staging.FullName
    $sourceHash = (Get-FileHash -LiteralPath $source.FullName -Algorithm SHA256).Hash.ToLowerInvariant()
    if ($sourceHash -cne $ExpectedHash) {
        throw "Status verifier source hash mismatch before protected staging. Expected $ExpectedHash, got $sourceHash."
    }
    $destination = Join-Path $staging.FullName "status-server.ps1"
    if (Test-Path -LiteralPath $destination) {
        throw "Protected status verifier staging destination already exists: $destination"
    }
    [IO.File]::Copy($source.FullName, $destination, $false)
    $sourceAfterHash = (Get-FileHash -LiteralPath $source.FullName -Algorithm SHA256).Hash.ToLowerInvariant()
    $stagedHash = (Get-FileHash -LiteralPath $destination -Algorithm SHA256).Hash.ToLowerInvariant()
    if ($sourceAfterHash -cne $ExpectedHash -or $stagedHash -cne $ExpectedHash) {
        throw "Status verifier changed while copying it into protected staging. Source=$sourceAfterHash Staged=$stagedHash Expected=$ExpectedHash"
    }
    $stagedItem = Get-Item -LiteralPath $destination -Force
    if (($stagedItem.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0 -or
        -not [string]::Equals((Split-Path -Parent $stagedItem.FullName), $staging.FullName, [StringComparison]::OrdinalIgnoreCase)) {
        throw "Protected status verifier escaped its validated staging directory."
    }
    return [pscustomobject]@{ Path = $stagedItem.FullName; ExpectedHash = $ExpectedHash }
}

function Assert-SyncVisionStagedStatusScriptIdentity {
    param([Parameter(Mandatory = $true)][object]$StagedStatusScript)

    if ($null -eq $StagedStatusScript -or
        [string]$StagedStatusScript.ExpectedHash -cnotmatch '^[0-9a-f]{64}$' -or
        -not (Test-Path -LiteralPath $StagedStatusScript.Path -PathType Leaf)) {
        throw "Staged status verifier identity is incomplete or missing."
    }
    $item = Get-Item -LiteralPath $StagedStatusScript.Path -Force
    if (($item.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
        throw "Staged status verifier identity is a reparse point: $($item.FullName)"
    }
    Assert-SyncVisionStagingAncestorChain -Path (Split-Path -Parent $item.FullName)
    $actualHash = (Get-FileHash -LiteralPath $item.FullName -Algorithm SHA256).Hash.ToLowerInvariant()
    if ($actualHash -cne [string]$StagedStatusScript.ExpectedHash) {
        throw "Staged status verifier hash changed at the final use point. Expected $($StagedStatusScript.ExpectedHash), got $actualHash."
    }
    return $item.FullName
}

function Assert-SyncVisionPackageInstallManifest {
    param(
        [Parameter(Mandatory = $true)]
        [string]$RepoRoot,

        [Parameter(Mandatory = $true)]
        [string]$ReleaseDir,

        [switch]$SkipBuild,

        [string]$ExpectedManifestSha256 = "",

        [switch]$AllowUntrustedPackageManifestForLocalDevelopment,

        [switch]$AllowSourceCheckoutSkipBuildForLocalDevelopment
    )

    if (-not $SkipBuild) {
        return
    }

    $rootPath = (Resolve-Path -LiteralPath $RepoRoot).Path.TrimEnd('\', '/')
    $rootItem = Get-Item -LiteralPath $rootPath -Force
    if (($rootItem.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
        throw "Package manifest verification failed: reparse-point package root: $rootPath"
    }
    $packageMarkerPath = Join-Path $rootPath "SyncVisionPackage.json"
    $sourceSolutionPath = Join-Path $rootPath "SyncVision.sln"
    $sourceBuildScriptPath = Join-Path $rootPath "scripts\build.ps1"
    $hasPackageMarker = Test-Path -LiteralPath $packageMarkerPath -PathType Leaf
    $hasSourceSolution = Test-Path -LiteralPath $sourceSolutionPath -PathType Leaf
    $hasSourceBuildScript = Test-Path -LiteralPath $sourceBuildScriptPath -PathType Leaf

    if ($hasPackageMarker -and ($hasSourceSolution -or $hasSourceBuildScript)) {
        throw "Package manifest verification failed: release package marker conflicts with source checkout files."
    }
    if (-not $hasPackageMarker) {
        if ($hasSourceSolution -and $hasSourceBuildScript -and $AllowSourceCheckoutSkipBuildForLocalDevelopment) {
            return
        }
        if ($hasSourceSolution -and $hasSourceBuildScript) {
            throw "Package manifest verification failed: markerless -SkipBuild source checkouts require -AllowSourceCheckoutSkipBuildForLocalDevelopment."
        }
        throw "Package manifest verification failed: SyncVisionPackage.json is required for package installs, or run from a complete source checkout containing SyncVision.sln and scripts\build.ps1."
    }

    $manifestPath = Join-Path $rootPath "SHA256SUMS.txt"
    if (-not (Test-Path -LiteralPath $manifestPath -PathType Leaf)) {
        throw "Package manifest verification failed: SHA256SUMS.txt is required for -SkipBuild package installs: $manifestPath"
    }

    $manifestBytes = [IO.File]::ReadAllBytes($manifestPath)
    if (-not $AllowUntrustedPackageManifestForLocalDevelopment) {
        if ([string]::IsNullOrWhiteSpace($ExpectedManifestSha256)) {
            throw "Package manifest verification failed: -ExpectedManifestSha256 is required for -SkipBuild package installs. Obtain it from the publisher-provided external manifest digest."
        }
        if ($ExpectedManifestSha256 -notmatch '^[0-9a-fA-F]{64}$') {
            throw "Package manifest verification failed: ExpectedManifestSha256 must be a 64-character hexadecimal SHA-256 value."
        }

        $manifestHasher = [Security.Cryptography.SHA256]::Create()
        try {
            $actualManifestSha256 = [BitConverter]::ToString($manifestHasher.ComputeHash($manifestBytes)).Replace("-", "").ToLowerInvariant()
        }
        finally {
            $manifestHasher.Dispose()
        }
        if (-not [string]::Equals($actualManifestSha256, $ExpectedManifestSha256, [StringComparison]::OrdinalIgnoreCase)) {
            throw "Package manifest verification failed: trusted manifest SHA-256 mismatch. Expected $ExpectedManifestSha256, got $actualManifestSha256."
        }
    }
    try {
        $packageMarker = Get-Content -LiteralPath $packageMarkerPath -Raw | ConvertFrom-Json
    }
    catch {
        throw "Package manifest verification failed: SyncVisionPackage.json is not valid JSON. $($_.Exception.Message)"
    }
    $expectedConfiguration = Split-Path -Leaf $ReleaseDir
    $expectedMarkerProperties = @(
        "schema_version",
        "product",
        "artifact_kind",
        "platform",
        "configuration",
        "checksum_manifest",
        "publisher_authentication",
        "installation_mode",
        "unsigned_development_bootstrap"
    )
    $actualMarkerProperties = if ($null -eq $packageMarker) {
        @()
    }
    else {
        @($packageMarker.PSObject.Properties | ForEach-Object { $_.Name })
    }
    $markerShapeMatches = $actualMarkerProperties.Count -eq $expectedMarkerProperties.Count
    if ($markerShapeMatches) {
        foreach ($name in $expectedMarkerProperties) {
            if ($actualMarkerProperties -cnotcontains $name) {
                $markerShapeMatches = $false
                break
            }
        }
    }
    if ($null -eq $packageMarker -or
        -not $markerShapeMatches -or
        $packageMarker.schema_version -isnot [int] -or
        $packageMarker.schema_version -ne 2 -or
        $packageMarker.product -cne "SyncVision" -or
        $packageMarker.artifact_kind -cne "development-package" -or
        $packageMarker.platform -cne "win-x64" -or
        $packageMarker.configuration -cne $expectedConfiguration -or
        $packageMarker.checksum_manifest -cne "SHA256SUMS.txt" -or
        $packageMarker.publisher_authentication -cne "none" -or
        $packageMarker.installation_mode -cne "manual-verification" -or
        $packageMarker.unsigned_development_bootstrap -isnot [bool]) {
        throw "Package manifest verification failed: SyncVisionPackage.json does not describe this unsigned manual-verification SyncVision $expectedConfiguration win-x64 development package."
    }
    if (-not (Test-Path -LiteralPath $ReleaseDir -PathType Container)) {
        throw "Package manifest verification failed: release directory was not found at $ReleaseDir."
    }

    $manifestEntries = New-Object "System.Collections.Generic.Dictionary[string,string]" ([StringComparer]::OrdinalIgnoreCase)
    $manifestText = [Text.UTF8Encoding]::new($false).GetString($manifestBytes)
    foreach ($line in ($manifestText -split "`r?`n")) {
        $trimmed = $line.Trim()
        if ([string]::IsNullOrWhiteSpace($trimmed)) {
            continue
        }
        if ($trimmed -notmatch '^([0-9a-fA-F]{64})\s+(.+)$') {
            throw "Package manifest verification failed: invalid SHA256SUMS.txt entry: $line"
        }

        $normalizedRelativePath = ConvertTo-SyncVisionPackageManifestRelativePath -RelativePath $Matches[2] -Context "SHA256SUMS.txt entry"
        if ($normalizedRelativePath -ieq "SHA256SUMS.txt") {
            throw "Package manifest verification failed: SHA256SUMS.txt must not list itself."
        }
        if ($manifestEntries.ContainsKey($normalizedRelativePath)) {
            throw "Package manifest verification failed: SHA256SUMS.txt contains a duplicate entry: $normalizedRelativePath"
        }
        $manifestEntries.Add($normalizedRelativePath, $Matches[1].ToLowerInvariant())
    }

    Assert-SyncVisionPackageTreeSnapshot `
        -RootPath $rootPath `
        -ManifestPath $manifestPath `
        -ManifestEntries $manifestEntries

    return [pscustomobject]@{
        IsPackage = $true
        RootPath = $rootPath
        ManifestPath = $manifestPath
        ManifestEntries = $manifestEntries
        InstallInputs = @(Get-SyncVisionPackageInstallInputs -RootPath $rootPath -ReleaseDir $ReleaseDir -ManifestEntries $manifestEntries)
    }
}

function Invoke-SyncVisionInstallVerification {
    param(
        [Parameter(Mandatory = $true)]
        [string]$ServiceName,

        [Parameter(Mandatory = $true)]
        [string]$ServerExe,

        [Parameter(Mandatory = $true)]
        [string]$ConfigPath,

        [Parameter(Mandatory = $true)]
        [string]$TokenPath,

        [Parameter(Mandatory = $true)]
        [object]$StagedStatusScript,

        [Parameter(Mandatory = $true)]
        [string]$ProbeEndpoint,

        [Parameter(Mandatory = $true)]
        [bool]$StartRequested,

        [Parameter(Mandatory = $true)]
        [bool]$ConfigureFirewall,

        [object[]]$FirewallRules = @(),

        [UInt32]$TimeoutMs = 10000
    )

    $service = Get-Service -Name $ServiceName -ErrorAction SilentlyContinue
    if (-not $service) {
        throw "Install verification failed: service '$ServiceName' was not found."
    }
    if (-not (Test-Path -LiteralPath $ServerExe -PathType Leaf)) {
        throw "Install verification failed: server binary was not found at $ServerExe."
    }
    if (-not (Test-Path -LiteralPath $ConfigPath -PathType Leaf)) {
        throw "Install verification failed: server config was not found at $ConfigPath."
    }
    if (-not (Test-Path -LiteralPath $TokenPath -PathType Leaf)) {
        throw "Install verification failed: server token file was not found at $TokenPath."
    }

    if ($StartRequested) {
        try {
            $service.WaitForStatus(
                [System.ServiceProcess.ServiceControllerStatus]::Running,
                [TimeSpan]::FromMilliseconds($TimeoutMs))
        }
        catch {
            throw "Install verification failed: service '$ServiceName' did not reach Running within $TimeoutMs ms."
        }

        $statusScript = Assert-SyncVisionStagedStatusScriptIdentity -StagedStatusScript $StagedStatusScript

        $powerShell = Resolve-SyncVisionTrustedWindowsTool `
            -RelativePath "System32\WindowsPowerShell\v1.0\powershell.exe" `
            -Context "Windows PowerShell install verifier"
        $powerShell = Assert-SyncVisionTrustedWindowsToolIdentity `
            -Identity $powerShell `
            -Context "Windows PowerShell install verifier"
        $statusScript = Assert-SyncVisionStagedStatusScriptIdentity -StagedStatusScript $StagedStatusScript
        & $powerShell.Path -NoProfile -ExecutionPolicy Bypass -File $statusScript -ServiceName $ServiceName -Probe -Server $ProbeEndpoint -TimeoutMs $TimeoutMs
        $statusExitCode = $LASTEXITCODE
        if ($statusExitCode -ne 0) {
            $exception = [InvalidOperationException]::new(
                "Install verification failed: live status probe exited with code $statusExitCode.")
            $exception.Data["SyncVisionInstallExitCode"] = [int]$statusExitCode
            throw $exception
        }
    }
    else {
        Write-Host "Install verification: live probe skipped because -Start was not passed."
    }

    if ($ConfigureFirewall) {
        if (-not (Get-Command Get-NetFirewallRule -ErrorAction SilentlyContinue)) {
            throw "Install verification failed: Get-NetFirewallRule is unavailable; firewall rules cannot be checked."
        }
        if (-not (Get-Command Get-NetFirewallPortFilter -ErrorAction SilentlyContinue)) {
            throw "Install verification failed: Get-NetFirewallPortFilter is unavailable; firewall port filters cannot be checked."
        }
        if (-not (Get-Command Get-NetFirewallAddressFilter -ErrorAction SilentlyContinue)) {
            throw "Install verification failed: Get-NetFirewallAddressFilter is unavailable; firewall address filters cannot be checked."
        }
        if (-not (Get-Command Get-NetFirewallApplicationFilter -ErrorAction SilentlyContinue)) {
            throw "Install verification failed: Get-NetFirewallApplicationFilter is unavailable; firewall application filters cannot be checked."
        }

        foreach ($rule in $FirewallRules) {
            $matchingRules = @(Get-NetFirewallRule -DisplayName $rule.DisplayName -ErrorAction SilentlyContinue)
            if ($matchingRules.Count -eq 0) {
                throw "Install verification failed: Windows Firewall rule was not found: $($rule.DisplayName)"
            }
            $usableRules = @($matchingRules | Where-Object {
                    Test-SyncVisionFirewallRuleMatchesPlan -ExpectedRule $rule -FirewallRule $_
            })
            if ($usableRules.Count -eq 0) {
                throw "Install verification failed: Windows Firewall rule does not match expected inbound allow protocol=$($rule.Protocol) local_port=$($rule.LocalPort) program=$($rule.Program) remote_address=$($rule.RemoteAddress): $($rule.DisplayName)"
            }
        }
    }

    Write-Host "Install verification passed."
}

function Get-SyncVisionInstallFailureExitCode {
    param([Parameter(Mandatory = $true)]$Failure)

    $exception = if ($Failure -is [Management.Automation.ErrorRecord]) {
        $Failure.Exception
    }
    elseif ($Failure -is [Exception]) {
        $Failure
    }
    else {
        $null
    }
    while ($null -ne $exception) {
        if ($exception.Data.Contains("SyncVisionInstallExitCode")) {
            $exitCode = $exception.Data["SyncVisionInstallExitCode"]
            if ($exitCode -is [int] -and $exitCode -ne 0) {
                return [int]$exitCode
            }
            throw "Install verification failure carried an invalid process exit code."
        }
        $exception = $exception.InnerException
    }
    return $null
}

function Invoke-SyncVisionCompensatingInstallTransaction {
    param(
        [Parameter(Mandatory = $true)][Collections.IDictionary]$Steps,
        [Parameter(Mandatory = $true)][scriptblock]$Rollback,
        [scriptblock]$Commit = {},
        [AllowEmptyString()][string]$FaultInjectionPoint = ""
    )

    try {
        foreach ($entry in $Steps.GetEnumerator()) {
            & $entry.Value
            if (-not [string]::IsNullOrWhiteSpace($FaultInjectionPoint) -and
                [string]::Equals([string]$entry.Key, $FaultInjectionPoint, [StringComparison]::Ordinal)) {
                throw "Task 19 controlled install failure after $FaultInjectionPoint."
            }
        }
        & $Commit
    }
    catch {
        $transactionError = $_
        try {
            & $Rollback
        }
        catch {
            throw "Install transaction failed and compensation was incomplete. Failure: $($transactionError.Exception.Message) Compensation: $($_.Exception.Message)"
        }
        throw $transactionError
    }
}

function Assert-SyncVisionPreviousServiceRollbackStartReady {
    param([Parameter(Mandatory = $true)][Collections.IDictionary]$State)

    $incomplete = New-Object "System.Collections.Generic.List[string]"
    foreach ($name in @(
            "CurrentServiceStopped",
            "DirectoriesRestored",
            "BinaryRestored",
            "ServiceDefinitionRestored",
            "FirewallRestored")) {
        if (-not $State.Contains($name) -or -not [bool]$State[$name]) {
            $incomplete.Add($name)
        }
    }
    if ($incomplete.Count -ne 0) {
        throw "Previous service start was withheld because rollback prerequisites were incomplete: $($incomplete -join ', ')."
    }
}

function Invoke-SyncVisionInstallRollbackPlan {
    param(
        [switch]$MutationStarted,
        [Parameter(Mandatory = $true)][scriptblock]$StopCurrentService,
        [Parameter(Mandatory = $true)][scriptblock]$RestoreDirectories,
        [Parameter(Mandatory = $true)][scriptblock]$RestoreBinary,
        [Parameter(Mandatory = $true)][scriptblock]$RestoreServiceDefinition,
        [Parameter(Mandatory = $true)][scriptblock]$RestoreFirewall,
        [Parameter(Mandatory = $true)][scriptblock]$StartPreviousService
    )

    if (-not $MutationStarted) { return }
    $failures = New-Object "System.Collections.Generic.List[string]"
    $steps = @(
        [pscustomobject]@{ Name = "StopCurrentService"; Action = $StopCurrentService },
        [pscustomobject]@{ Name = "RestoreDirectories"; Action = $RestoreDirectories },
        [pscustomobject]@{ Name = "RestoreBinary"; Action = $RestoreBinary },
        [pscustomobject]@{ Name = "RestoreServiceDefinition"; Action = $RestoreServiceDefinition },
        [pscustomobject]@{ Name = "RestoreFirewall"; Action = $RestoreFirewall },
        [pscustomobject]@{ Name = "StartPreviousService"; Action = $StartPreviousService })
    foreach ($step in $steps) {
        try { & $step.Action | Out-Null }
        catch { $failures.Add("$($step.Name): $($_.Exception.Message)") }
    }
    if ($failures.Count -ne 0) {
        throw "Install rollback steps failed: $($failures -join ' | ')"
    }
}

function Get-SyncVisionInstallPathLockResources {
    param([Parameter(Mandatory = $true)][string]$Path)

    $basePath = Get-SyncVisionCurrentFileSystemProviderPath
    $fullPath = (Resolve-SyncVisionUserFileSystemPath `
            -Path $Path `
            -BasePath $basePath `
            -Context "Install transaction lock path").TrimEnd('\', '/')
    $volumeRoot = [IO.Path]::GetPathRoot($fullPath)
    if ([string]::IsNullOrWhiteSpace($volumeRoot) -and
        $fullPath -match '^\\\\\?\\[A-Za-z]:\\') {
        $volumeRoot = $fullPath.Substring(0, 7)
    }
    if ([string]::IsNullOrWhiteSpace($volumeRoot)) {
        throw "Install resource lock path has an unsupported filesystem root: $fullPath"
    }
    $relative = $fullPath.Substring($volumeRoot.Length).Trim([char[]]@('\', '/'))
    $segments = if ([string]::IsNullOrWhiteSpace($relative)) { @() } else { @($relative -split '[\\/]') }
    $resources = New-Object "System.Collections.Generic.List[string]"
    $rootItem = Get-Item -LiteralPath $volumeRoot -Force
    if (($rootItem.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
        throw "Install resource volume root is a reparse point: $volumeRoot"
    }
    $current = $volumeRoot.TrimEnd('\', '/')
    $deepestIdentity = Get-SyncVisionInstallFileSystemIdentity -Path $volumeRoot
    $missing = New-Object "System.Collections.Generic.List[string]"
    if ($segments.Count -eq 0) {
        $resources.Add("PathIdentity|$deepestIdentity")
    }
    foreach ($segment in $segments) {
        $candidate = $current.TrimEnd('\', '/') + [IO.Path]::DirectorySeparatorChar + $segment
        $entrySuffix = if ($missing.Count -eq 0) {
            $segment
        }
        else {
            ((@($missing) + @($segment)) -join '\')
        }
        # This parent-identity/name slot is stable across a missing-to-existing transition.
        $resources.Add("PathEntry|$deepestIdentity|$($entrySuffix.ToUpperInvariant())")
        if ($missing.Count -eq 0 -and (Test-Path -LiteralPath $candidate -PathType Container)) {
            $item = Get-Item -LiteralPath $candidate -Force
            if (($item.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
                throw "Install resource lock path contains a reparse point: $($item.FullName)"
            }
            $deepestIdentity = Get-SyncVisionInstallFileSystemIdentity -Path $item.FullName
            $resources.Add("PathIdentity|$deepestIdentity")
            $current = $item.FullName
        }
        else {
            $missing.Add($segment)
            $resources.Add("PathMissing|$deepestIdentity|$((@($missing) -join '\').ToUpperInvariant())")
        }
    }
    return @($resources | Sort-Object -Unique)
}

function New-SyncVisionInstallMutexSecurity {
    $security = [Security.AccessControl.MutexSecurity]::new()
    $security.SetAccessRuleProtection($true, $false)
    $administratorsSid = [Security.Principal.SecurityIdentifier]::new(
        [Security.Principal.WellKnownSidType]::BuiltinAdministratorsSid,
        $null)
    $security.SetOwner($administratorsSid)
    foreach ($sidValue in @("S-1-5-18", "S-1-5-32-544")) {
        $security.AddAccessRule([Security.AccessControl.MutexAccessRule]::new(
                [Security.Principal.SecurityIdentifier]::new($sidValue),
                [Security.AccessControl.MutexRights]::FullControl,
                [Security.AccessControl.AccessControlType]::Allow)) | Out-Null
    }
    return $security
}

function Assert-SyncVisionInstallMutexSecurity {
    param(
        [Parameter(Mandatory = $true)][Threading.Mutex]$Mutex,
        [Parameter(Mandatory = $true)][string]$Name
    )

    $expectedSids = @("S-1-5-18", "S-1-5-32-544")
    $security = $Mutex.GetAccessControl()
    $owner = $security.GetOwner([Security.Principal.SecurityIdentifier]).Value
    $rules = @($security.GetAccessRules($true, $true, [Security.Principal.SecurityIdentifier]))
    $actualSids = @($rules | ForEach-Object { $_.IdentityReference.Value } | Sort-Object -Unique)
    if (-not $security.AreAccessRulesProtected -or
        $owner -cne "S-1-5-32-544" -or
        $rules.Count -ne $expectedSids.Count -or
        @(Compare-Object -CaseSensitive -ReferenceObject $expectedSids -DifferenceObject $actualSids).Count -ne 0) {
        throw "Install transaction mutex must have a trusted owner, protected DACL, and exact nonempty principal set: $Name"
    }
    foreach ($rule in $rules) {
        if ($rule.IsInherited -or
            $rule.AccessControlType -ne [Security.AccessControl.AccessControlType]::Allow -or
            $rule.MutexRights -ne [Security.AccessControl.MutexRights]::FullControl) {
            throw "Install transaction mutex contains a non-exact access rule: $Name"
        }
    }
}

function Get-SyncVisionInstallTransactionLockResources {
    param(
        [Parameter(Mandatory = $true)][string]$InstallDir,
        [Parameter(Mandatory = $true)][string]$DataDir,
        [Parameter(Mandatory = $true)][string]$ServiceName,
        [AllowEmptyString()][string]$LogDir = "",
        [string[]]$FirewallResourceNames = @(),
        [string[]]$AdditionalPaths = @(),
        [string[]]$AdditionalServiceNames = @(),
        [string[]]$AdditionalFirewallResourceNames = @(),
        [string[]]$AdditionalResources = @(),
        [switch]$InstallPathOnly
    )

    $resourceSet = New-Object "System.Collections.Generic.HashSet[string]" ([StringComparer]::Ordinal)
    $paths = if ($InstallPathOnly) { @($InstallDir) } else { @($InstallDir, $DataDir, $LogDir) + @($AdditionalPaths) }
    foreach ($path in $paths) {
        if (-not [string]::IsNullOrWhiteSpace($path)) {
            foreach ($resource in (Get-SyncVisionInstallPathLockResources -Path $path)) {
                [void]$resourceSet.Add($resource)
            }
        }
    }
    if (-not $InstallPathOnly) {
        foreach ($service in @($ServiceName) + @($AdditionalServiceNames)) {
            if (-not [string]::IsNullOrWhiteSpace($service)) {
                [void]$resourceSet.Add("Service|" + $service.Trim().ToUpperInvariant())
            }
        }
        foreach ($firewallName in @($FirewallResourceNames) + @($AdditionalFirewallResourceNames)) {
            if (-not [string]::IsNullOrWhiteSpace($firewallName)) {
                [void]$resourceSet.Add("Firewall|" + $firewallName.Trim().ToUpperInvariant())
            }
        }
    }
    foreach ($resource in $AdditionalResources) {
        if ([string]::IsNullOrWhiteSpace($resource)) {
            throw "Install transaction mutex additional resource set contains an empty value."
        }
        Get-SyncVisionInstallMutexName -Resource $resource | Out-Null
        [void]$resourceSet.Add($resource)
    }
    return @($resourceSet | Sort-Object)
}

function Get-SyncVisionInstallMutexName {
    param([Parameter(Mandatory = $true)][string]$Resource)

    $separator = $Resource.IndexOf('|')
    if ($separator -le 0 -or $separator -eq $Resource.Length - 1) {
        throw "Install transaction mutex resource has an invalid canonical form: $Resource"
    }
    $sha256 = [Security.Cryptography.SHA256]::Create()
    try {
        $hash = ([BitConverter]::ToString(
                $sha256.ComputeHash([Text.UTF8Encoding]::new($false).GetBytes($Resource)))).Replace("-", "").ToLowerInvariant()
    }
    finally { $sha256.Dispose() }
    $kind = $Resource.Substring(0, $separator).ToLowerInvariant()
    if ($kind -cnotmatch '^[a-z][a-z0-9]{0,31}$') {
        throw "Install transaction mutex resource has an invalid kind: $Resource"
    }
    return "Global\SyncVision.Task19.Install.$kind.$hash"
}

function Enter-SyncVisionInstallResourceMutexes {
    param(
        [Parameter(Mandatory = $true)][string[]]$Resources,
        [ValidateRange(1, 3600000)][int]$TimeoutMs = 30000
    )

    $timer = [Diagnostics.Stopwatch]::StartNew()
    $names = New-Object "System.Collections.Generic.List[string]"
    $resourceSet = New-Object "System.Collections.Generic.HashSet[string]" ([StringComparer]::Ordinal)
    foreach ($resource in $Resources) {
        if ([string]::IsNullOrWhiteSpace($resource)) {
            throw "Install transaction mutex resource set contains an empty value."
        }
        if ($resourceSet.Add($resource)) {
            $names.Add((Get-SyncVisionInstallMutexName -Resource $resource))
        }
    }
    $orderedNames = $names.ToArray()
    [Array]::Sort($orderedNames, [StringComparer]::Ordinal)
    $locks = New-Object "System.Collections.Generic.List[object]"
    $abandonedNames = New-Object "System.Collections.Generic.List[string]"
    try {
        foreach ($name in $orderedNames) {
            $createdNew = $false
            $mutex = [Threading.Mutex]::new($false, $name, [ref]$createdNew, (New-SyncVisionInstallMutexSecurity))
            try {
                Assert-SyncVisionInstallMutexSecurity -Mutex $mutex -Name $name
                $remaining = [int64]$TimeoutMs - $timer.ElapsedMilliseconds
                if ($remaining -le 0) {
                    throw "Install transaction mutex timed out after $TimeoutMs ms total while waiting for $name"
                }
                try { $acquired = $mutex.WaitOne([int]$remaining) }
                catch [Threading.AbandonedMutexException] {
                    $acquired = $true
                    $abandonedNames.Add($name)
                }
                if (-not $acquired) {
                    throw "Install transaction mutex timed out after $TimeoutMs ms total while waiting for $name"
                }
                $locks.Add([pscustomobject]@{ Mutex = $mutex; Acquired = $true; Name = $name })
            }
            catch {
                $mutex.Dispose()
                throw
            }
        }
        return [pscustomobject]@{
            Locks = $locks.ToArray()
            HadAbandonedMutex = ($abandonedNames.Count -ne 0)
            AbandonedMutexNames = $abandonedNames.ToArray()
            Resources = @($resourceSet | Sort-Object)
        }
    }
    catch {
        $acquiredLocks = $locks.ToArray()
        [Array]::Reverse($acquiredLocks)
        foreach ($lock in $acquiredLocks) {
            try { if ($lock.Acquired) { $lock.Mutex.ReleaseMutex() } }
            finally { $lock.Mutex.Dispose() }
        }
        throw
    }
}

function Enter-SyncVisionInstallTransactionMutex {
    param(
        [Parameter(Mandatory = $true)][string]$InstallDir,
        [Parameter(Mandatory = $true)][string]$DataDir,
        [Parameter(Mandatory = $true)][string]$ServiceName,
        [AllowEmptyString()][string]$LogDir = "",
        [string[]]$FirewallResourceNames = @(),
        [string[]]$AdditionalPaths = @(),
        [string[]]$AdditionalServiceNames = @(),
        [string[]]$AdditionalFirewallResourceNames = @(),
        [string[]]$AdditionalResources = @(),
        [switch]$InstallPathOnly,
        [AllowNull()][scriptblock]$TestPhaseHook,
        [ValidateRange(1, 3600000)][int]$TimeoutMs = 30000
    )

    $resources = @(Get-SyncVisionInstallTransactionLockResources `
            -InstallDir $InstallDir `
            -DataDir $DataDir `
            -ServiceName $ServiceName `
            -LogDir $LogDir `
            -FirewallResourceNames $FirewallResourceNames `
            -AdditionalPaths $AdditionalPaths `
            -AdditionalServiceNames $AdditionalServiceNames `
            -AdditionalFirewallResourceNames $AdditionalFirewallResourceNames `
            -AdditionalResources $AdditionalResources `
            -InstallPathOnly:$InstallPathOnly)
    $resourceSet = New-Object "System.Collections.Generic.HashSet[string]" ([StringComparer]::Ordinal)
    foreach ($resource in $resources) { [void]$resourceSet.Add($resource) }
    $abandonedNames = New-Object "System.Collections.Generic.HashSet[string]" ([StringComparer]::Ordinal)
    $timer = [Diagnostics.Stopwatch]::StartNew()
    for ($attempt = 0; $attempt -lt 16; ++$attempt) {
        $remaining = [int64]$TimeoutMs - $timer.ElapsedMilliseconds
        if ($remaining -le 0) {
            throw "Install transaction mutex resource stabilization timed out after $TimeoutMs ms."
        }
        $context = $null
        try {
            $context = Enter-SyncVisionInstallResourceMutexes `
                -Resources @($resourceSet | Sort-Object) `
                -TimeoutMs ([int]$remaining)
            foreach ($name in @($context.AbandonedMutexNames)) { [void]$abandonedNames.Add([string]$name) }
            if ($null -ne $TestPhaseHook) {
                & $TestPhaseHook "AfterInstallResourceLocksAcquired" ([pscustomobject]@{
                        Attempt = $attempt
                        Resources = @($context.Resources)
                    })
            }
            $currentResources = @(Get-SyncVisionInstallTransactionLockResources `
                    -InstallDir $InstallDir `
                    -DataDir $DataDir `
                    -ServiceName $ServiceName `
                    -LogDir $LogDir `
                    -FirewallResourceNames $FirewallResourceNames `
                    -AdditionalPaths $AdditionalPaths `
                    -AdditionalServiceNames $AdditionalServiceNames `
                    -AdditionalFirewallResourceNames $AdditionalFirewallResourceNames `
                    -AdditionalResources $AdditionalResources `
                    -InstallPathOnly:$InstallPathOnly)
            $expanded = $false
            foreach ($resource in $currentResources) {
                if ($resourceSet.Add($resource)) { $expanded = $true }
            }
            if ($timer.ElapsedMilliseconds -ge [int64]$TimeoutMs) {
                throw "Install transaction mutex resource stabilization timed out after $TimeoutMs ms."
            }
            if (-not $expanded) {
                $result = [pscustomobject]@{
                    Locks = @($context.Locks)
                    HadAbandonedMutex = ($abandonedNames.Count -ne 0)
                    AbandonedMutexNames = @($abandonedNames | Sort-Object)
                    Resources = @($resourceSet | Sort-Object)
                }
                $context = $null
                return $result
            }
        }
        finally {
            if ($null -ne $context) {
                Exit-SyncVisionInstallTransactionMutex -Context $context
            }
        }
    }
    throw "Install transaction mutex resources did not stabilize after 16 attempts."
}

function Enter-SyncVisionServerInstallJournalDiscoveryMutex {
    param(
        [Parameter(Mandatory = $true)][string]$InstallDir,
        [ValidateRange(1, 3600000)][int]$TimeoutMs = 30000
    )

    $resource = Get-SyncVisionServerInstallJournalResourceIdentity -InstallDir $InstallDir
    return Enter-SyncVisionInstallResourceMutexes -Resources @($resource) -TimeoutMs $TimeoutMs
}

function Get-SyncVisionFirewallLockResourceNames {
    param([AllowEmptyCollection()][object[]]$Rules = @())

    $names = New-Object "System.Collections.Generic.HashSet[string]" ([StringComparer]::OrdinalIgnoreCase)
    foreach ($rule in $Rules) {
        if ($null -eq $rule) { continue }
        $value = if ($null -ne $rule.PSObject.Properties["Name"] -and
            -not [string]::IsNullOrWhiteSpace([string]$rule.Name)) {
            [string]$rule.Name
        }
        elseif ($null -ne $rule.PSObject.Properties["DisplayName"] -and
            -not [string]::IsNullOrWhiteSpace([string]$rule.DisplayName)) {
            [string]$rule.DisplayName
        }
        else { "" }
        if (-not [string]::IsNullOrWhiteSpace($value)) { [void]$names.Add($value) }
    }
    return @($names | Sort-Object)
}

function Get-SyncVisionServerInstallRecoveryLockSpec {
    param(
        [Parameter(Mandatory = $true)][string]$InstallDir,
        [switch]$AllowInjectedResourceBackendForTest
    )

    $intent = Read-SyncVisionServerInstallIntent -InstallDir $InstallDir -AllowMissing
    $journal = Read-SyncVisionServerInstallJournal -InstallDir $InstallDir -AllowMissing
    if ($null -eq $journal -and $null -eq $intent) {
        return [pscustomobject]@{
            HasIntent = $false
            Intent = $null
            IntentIdentity = ""
            IntentSha256 = ""
            HasJournal = $false
            Journal = $null
            JournalIdentity = ""
            JournalSha256 = ""
            ResourceState = $null
            Resources = @()
            Paths = @()
            ServiceNames = @()
            FirewallResourceNames = @()
            RecoveredServiceName = ""
        }
    }
    $intentIdentity = if ($null -eq $intent) { "" } else { [string]$intent.IntentFileIdentity }
    $intentSha256 = if ($null -eq $intent) { "" } else { [string]$intent.IntentSha256 }
    $intentResources = if ($null -eq $intent) { @() } else { @($intent.LockResources) }
    if ($null -eq $journal) {
        return [pscustomobject]@{
            HasIntent = $true
            Intent = $intent
            IntentIdentity = $intentIdentity
            IntentSha256 = $intentSha256
            HasJournal = $false
            Journal = $null
            JournalIdentity = ""
            JournalSha256 = ""
            ResourceState = $null
            Resources = $intentResources
            Paths = @()
            ServiceNames = @()
            FirewallResourceNames = @()
            RecoveredServiceName = ""
        }
    }
    if ($null -ne $intent -and $intent.TransactionId -cne $journal.TransactionId) {
        throw "Discovered server install intent and journal belong to different transactions."
    }
    $journalIdentity = [string]$journal.JournalFileIdentity
    $journalSha256 = [string]$journal.JournalSha256
    $paths = New-Object "System.Collections.Generic.HashSet[string]" ([StringComparer]::OrdinalIgnoreCase)
    $services = New-Object "System.Collections.Generic.HashSet[string]" ([StringComparer]::OrdinalIgnoreCase)
    $firewall = New-Object "System.Collections.Generic.HashSet[string]" ([StringComparer]::OrdinalIgnoreCase)
    $resourceState = $null
    $recoveredServiceName = ""
    if (-not [string]::IsNullOrEmpty([string]$journal.ResourceStatePath)) {
        if ([string]$journal.ResourceBackendKind -cne "Windows" -and
            -not $AllowInjectedResourceBackendForTest) {
            throw "Server install runtime recovery cannot acquire resources for backend '$($journal.ResourceBackendKind)'."
        }
        $resourceState = Read-SyncVisionServerInstallResourceState -Journal $journal
        if ($null -eq $resourceState.PSObject.Properties["Desired"] -or
            $null -eq $resourceState.Desired -or
            $null -eq $resourceState.Desired.PSObject.Properties["ServiceName"] -or
            [string]::IsNullOrWhiteSpace([string]$resourceState.Desired.ServiceName)) {
            throw "Server install durable resource state is missing its recovery service identity."
        }
        $recoveredServiceName = [string]$resourceState.Desired.ServiceName
        [void]$services.Add($recoveredServiceName)
        foreach ($name in @("DataDir", "LogDir")) {
            if ($null -ne $resourceState.Desired.PSObject.Properties[$name] -and
                -not [string]::IsNullOrWhiteSpace([string]$resourceState.Desired.$name)) {
                [void]$paths.Add([string]$resourceState.Desired.$name)
            }
        }
        if ($null -ne $resourceState.PSObject.Properties["DirectorySnapshots"]) {
            foreach ($snapshot in @($resourceState.DirectorySnapshots)) {
                foreach ($name in @("Path", "SnapshotPath")) {
                    if ($null -ne $snapshot -and $null -ne $snapshot.PSObject.Properties[$name] -and
                        -not [string]::IsNullOrWhiteSpace([string]$snapshot.$name)) {
                        [void]$paths.Add([string]$snapshot.$name)
                    }
                }
            }
        }
        if ($null -ne $resourceState.PSObject.Properties["ServiceSnapshot"] -and
            $null -ne $resourceState.ServiceSnapshot -and
            $null -ne $resourceState.ServiceSnapshot.PSObject.Properties["ServiceName"] -and
            -not [string]::IsNullOrWhiteSpace([string]$resourceState.ServiceSnapshot.ServiceName)) {
            [void]$services.Add([string]$resourceState.ServiceSnapshot.ServiceName)
        }
        if ($null -ne $resourceState.Desired.PSObject.Properties["FirewallRules"]) {
            foreach ($name in (Get-SyncVisionFirewallLockResourceNames -Rules @($resourceState.Desired.FirewallRules))) {
                [void]$firewall.Add($name)
            }
        }
        if ($null -ne $resourceState.PSObject.Properties["FirewallSnapshot"] -and
            $null -ne $resourceState.FirewallSnapshot) {
            foreach ($propertyName in @("Rules", "Plans")) {
                if ($null -ne $resourceState.FirewallSnapshot.PSObject.Properties[$propertyName]) {
                    foreach ($name in (Get-SyncVisionFirewallLockResourceNames -Rules @($resourceState.FirewallSnapshot.$propertyName))) {
                        [void]$firewall.Add($name)
                    }
                }
            }
        }
    }
    return [pscustomobject]@{
        HasIntent = $null -ne $intent
        Intent = $intent
        IntentIdentity = $intentIdentity
        IntentSha256 = $intentSha256
        HasJournal = $true
        Journal = $journal
        JournalIdentity = $journalIdentity
        JournalSha256 = $journalSha256
        ResourceState = $resourceState
        Resources = $intentResources
        Paths = @($paths | Sort-Object)
        ServiceNames = @($services | Sort-Object)
        FirewallResourceNames = @($firewall | Sort-Object)
        RecoveredServiceName = $recoveredServiceName
    }
}

function Assert-SyncVisionServerInstallRecoveryLockSpecCurrent {
    param(
        [Parameter(Mandatory = $true)][string]$InstallDir,
        [Parameter(Mandatory = $true)][object]$Spec
    )

    $currentIntent = Read-SyncVisionServerInstallIntent -InstallDir $InstallDir -AllowMissing
    $current = Read-SyncVisionServerInstallJournal -InstallDir $InstallDir -AllowMissing
    if (-not [bool]$Spec.HasIntent) {
        if ($null -ne $currentIntent) {
            throw "A server install transaction intent appeared after discovery and before resource lock acquisition."
        }
    }
    else {
        if ($null -eq $currentIntent -or
            [string]$currentIntent.TransactionId -cne [string]$Spec.Intent.TransactionId -or
            [string]$currentIntent.IntentFileIdentity -cne [string]$Spec.IntentIdentity -or
            [string]$currentIntent.IntentSha256 -cne [string]$Spec.IntentSha256) {
            throw "The discovered server install intent changed before complete resource lock acquisition."
        }
    }
    if (-not [bool]$Spec.HasJournal) {
        if ($null -ne $current) {
            throw "A server install transaction appeared after journal discovery and before resource lock acquisition."
        }
        return $currentIntent
    }
    if ($null -eq $current -or
        [string]$current.TransactionId -cne [string]$Spec.Journal.TransactionId) {
        throw "The discovered server install transaction changed before complete resource lock acquisition."
    }
    if ([string]$current.JournalFileIdentity -cne [string]$Spec.JournalIdentity -or
        [string]$current.JournalSha256 -cne [string]$Spec.JournalSha256) {
        throw "The discovered server install journal File ID or SHA-256 changed before complete resource lock acquisition."
    }
    if (-not [string]::IsNullOrEmpty([string]$current.ResourceStatePath)) {
        Read-SyncVisionServerInstallResourceState -Journal $current | Out-Null
    }
    return $current
}

function Exit-SyncVisionInstallTransactionMutex {
    param([AllowNull()]$Context)

    if ($null -eq $Context) { return }
    $locks = @($Context.Locks)
    [Array]::Reverse($locks)
    foreach ($lock in $locks) {
        try { if ($lock.Acquired) { $lock.Mutex.ReleaseMutex() } }
        finally { $lock.Mutex.Dispose() }
    }
}

function Write-SyncVisionPlan {
    param(
        [Parameter(Mandatory = $true)]
        [string]$Message
    )

    Write-Output "[WhatIf] $Message"
}

if ($TestMode) {
    return
}

$scriptDir = Split-Path -Parent $PSCommandPath
$userPathBase = Get-SyncVisionCurrentFileSystemProviderPath
$InstallDir = Resolve-SyncVisionUserFileSystemPath `
    -Path $InstallDir `
    -BasePath $userPathBase `
    -Context "InstallDir"
$DataDir = Resolve-SyncVisionUserFileSystemPath `
    -Path $DataDir `
    -BasePath $userPathBase `
    -Context "DataDir"
if (-not [string]::IsNullOrWhiteSpace($LogFile)) {
    $LogFile = Resolve-SyncVisionUserFileSystemPath `
        -Path $LogFile `
        -BasePath $userPathBase `
        -Context "LogFile"
}
if (-not [string]::IsNullOrWhiteSpace($DeviceTokensFile)) {
    $DeviceTokensFile = Resolve-SyncVisionUserFileSystemPath `
        -Path $DeviceTokensFile `
        -BasePath $userPathBase `
        -Context "DeviceTokensFile"
}
if (-not [string]::IsNullOrWhiteSpace($TransportSecretFile)) {
    $TransportSecretFile = Resolve-SyncVisionUserFileSystemPath `
        -Path $TransportSecretFile `
        -BasePath $userPathBase `
        -Context "TransportSecretFile"
}

$repoRoot = (Resolve-Path -LiteralPath (Join-Path $scriptDir "..")).Path
$buildScript = Join-Path $scriptDir "build.ps1"
$releaseDir = Join-Path $repoRoot "build\x64\$Configuration"
$sourceServerExe = Join-Path $releaseDir "SyncVisionServer.exe"
$targetServerExe = Join-Path $InstallDir "SyncVisionServer.exe"
$configPath = Join-Path $DataDir "server.conf"
$tokenPath = Join-Path $DataDir "server.token"
$transportSecretPath = Join-Path $DataDir "transport.secret"
$resolvedLogFile = if ([string]::IsNullOrWhiteSpace($LogFile)) {
    $trimmedDataDir = $DataDir.TrimEnd('\', '/')
    $trimmedDataRoot = ([IO.Path]::GetPathRoot($DataDir)).TrimEnd('\', '/')
    $defaultLogDir = if ([string]::Equals(
            $trimmedDataDir,
            $trimmedDataRoot,
            [StringComparison]::OrdinalIgnoreCase)) {
        Join-Path $DataDir "SyncVision.logs"
    }
    else { $trimmedDataDir + ".logs" }
    Join-Path $defaultLogDir "server.log"
}
else { $LogFile }
$logDir = Split-Path -Parent $resolvedLogFile
Assert-SyncVisionInstallDataDirectorySeparation `
    -InstallDir $InstallDir `
    -DataDir $DataDir `
    -LogDir $logDir
$binPath = New-SyncVisionServiceBinPath -ServerExe $targetServerExe -ConfigPath $configPath -ServiceName $ServiceName
$serviceAccountIdentity = Resolve-SyncVisionServiceAccountIdentity -ServiceAccount $ServiceAccount
$serviceCreateArguments = New-SyncVisionServiceCreateArguments -ServiceName $ServiceName -BinPath $binPath -ServiceAccount $ServiceAccount
$serviceConfigArguments = New-SyncVisionServiceConfigArguments -ServiceName $ServiceName -BinPath $binPath -ServiceAccount $ServiceAccount
$tokenWasGenerated = [string]::IsNullOrWhiteSpace($Token)
$transportSecretWasGenerated = $TransportEncryption -ne "disabled" -and
    [string]::IsNullOrWhiteSpace($TransportSecret) -and
    [string]::IsNullOrWhiteSpace($TransportSecretFile)
$resolvedToken = Resolve-SyncVisionInstallToken -Token $Token -Listen $Listen
$resolvedTransportSecret = Resolve-SyncVisionInstallTransportSecret `
    -TransportEncryption $TransportEncryption `
    -TransportSecret $TransportSecret `
    -TransportSecretFile $TransportSecretFile
$resolvedTransportSecretFile = if ($TransportEncryption -eq "disabled") { "" } else { $transportSecretPath }
$resolvedDeviceTokensFile = $DeviceTokensFile
if (-not [string]::IsNullOrWhiteSpace($DeviceTokensFile) -and (Test-Path -LiteralPath $DeviceTokensFile -PathType Leaf)) {
    $resolvedDeviceTokensFile = (Resolve-Path -LiteralPath $DeviceTokensFile).ProviderPath
}
Assert-SyncVisionUnsafePublicRelayAcknowledged `
    -Listen $Listen `
    -AllowUnsafePublicRelay ([bool]$AllowUnsafePublicRelay)
Assert-SyncVisionPublicFirewallRemoteAddressRestricted `
    -Listen $Listen `
    -ConfigureFirewall ([bool]$ConfigureFirewall) `
    -FirewallRemoteAddress $FirewallRemoteAddress
$resolvedDiscoveryEnabled = Resolve-SyncVisionInstallDiscoveryEnabled `
    -Listen $Listen `
    -Advertise $Advertise `
    -NoDiscovery ([bool]$NoDiscovery) `
    -Lan:$Lan
$resolvedAdvertise = Resolve-SyncVisionInstallAdvertise `
    -Listen $Listen `
    -Advertise $Advertise `
    -DiscoveryEnabled $resolvedDiscoveryEnabled `
    -Lan:$Lan
$configText = New-SyncVisionServerConfigText `
    -Listen $Listen `
    -TokenFile $tokenPath `
    -DeviceTokensFile $resolvedDeviceTokensFile `
    -LogFile $resolvedLogFile `
    -LogMaxBytes $LogMaxBytes `
    -LogRetainedFiles $LogRetainedFiles `
    -DiscoveryListen $DiscoveryListen `
    -Advertise $resolvedAdvertise `
    -DiscoveryEnabled $resolvedDiscoveryEnabled `
    -FirstFrameTimeoutMs $FirstFrameTimeoutMs `
    -IdleTimeoutMs $IdleTimeoutMs `
    -HeartbeatTtlMs $HeartbeatTtlMs `
    -MaxSessions $MaxSessions `
    -MaxPendingFirstFrames $MaxPendingFirstFrames `
    -TransportEncryption $TransportEncryption `
    -TransportSecretFile $resolvedTransportSecretFile `
    -AllowUnsafePublicRelay ([bool]$AllowUnsafePublicRelay)
$firewallRules = New-SyncVisionFirewallRulePlans `
    -ServiceName $ServiceName `
    -Listen $Listen `
    -DiscoveryListen $DiscoveryListen `
    -DiscoveryEnabled $resolvedDiscoveryEnabled `
    -Program $targetServerExe `
    -RemoteAddress $FirewallRemoteAddress
$probeEndpoint = Resolve-SyncVisionInstallProbeEndpoint -Listen $Listen

if (-not $WhatIf -and -not (Test-SyncVisionAdministrator)) {
    throw "Installing the SyncVision Windows service requires an elevated PowerShell session. Re-run as Administrator, or use -WhatIf for a dry run."
}

if (-not $WhatIf -and -not [string]::IsNullOrWhiteSpace($DeviceTokensFile) -and -not (Test-Path -LiteralPath $DeviceTokensFile -PathType Leaf)) {
    throw "Device tokens file was not found: $DeviceTokensFile"
}

if ($WhatIf) {
    $packageManifestPreflight = Get-Command -CommandType Function -Name ("Assert-SyncVisionPackage" + "InstallManifest")
    & $packageManifestPreflight `
        -RepoRoot $repoRoot `
        -ReleaseDir $releaseDir `
        -SkipBuild:$SkipBuild `
        -ExpectedManifestSha256 $ExpectedManifestSha256 `
        -AllowUntrustedPackageManifestForLocalDevelopment:$AllowUntrustedPackageManifestForLocalDevelopment `
        -AllowSourceCheckoutSkipBuildForLocalDevelopment:$AllowSourceCheckoutSkipBuildForLocalDevelopment | Out-Null

    Write-SyncVisionPlan "Repository root: $repoRoot"
    if (-not $SkipBuild) {
        Write-SyncVisionPlan "Would run build script: $buildScript -Configuration $Configuration"
    }
    else {
        Write-SyncVisionPlan "Would skip build and require binaries under: $releaseDir"
    }
    Write-SyncVisionPlan "Would validate and exactly replace install directory: $InstallDir"
    Write-SyncVisionPlan "Would create data directory: $DataDir"
    Write-SyncVisionPlan "Would create log directory: $logDir"
    Write-SyncVisionPlan "Would stage and publish the exact SyncVisionServer file set from: $releaseDir"
    Write-SyncVisionPlan "Would write token file: $tokenPath"
    if ($resolvedTransportSecretFile) {
        if ($transportSecretWasGenerated) {
            Write-SyncVisionPlan "Would generate and write transport secret file: $resolvedTransportSecretFile"
        }
        else {
            Write-SyncVisionPlan "Would write transport secret file: $resolvedTransportSecretFile"
        }
    }
    if ($resolvedDeviceTokensFile) {
        Write-SyncVisionPlan "Would reference device tokens file: $resolvedDeviceTokensFile"
    }
    Write-SyncVisionPlan "Would write UTF-8 config: $configPath"
    Write-Output (Redact-SyncVisionServerConfigText -Text $configText)
    Write-SyncVisionPlan "Would create or reconfigure service '$ServiceName' with binPath: $binPath"
    Write-SyncVisionPlan "Would create service account: $serviceAccountIdentity"
    Write-SyncVisionPlan (Format-SyncVisionCommandLine -Command "sc.exe" -Arguments $serviceCreateArguments)
    Write-SyncVisionPlan "Would set service description."
    if ($NoServiceRecovery) {
        Write-SyncVisionPlan "Would not configure service recovery."
    }
    else {
        Write-SyncVisionPlan "Would configure service recovery:"
        foreach ($command in (New-SyncVisionServiceRecoveryCommands -ServiceName $ServiceName -RestartDelayMs $ServiceRecoveryRestartDelayMs)) {
            Write-SyncVisionPlan $command
        }
    }
    if ($ConfigureFirewall) {
        Write-SyncVisionPlan "Would configure Windows Firewall rules:"
        foreach ($rule in $firewallRules) {
            Write-SyncVisionPlan (Format-SyncVisionFirewallRuleCommand -Rule $rule)
        }
    }
    else {
        Write-SyncVisionPlan "Would not configure Windows Firewall. Pass -ConfigureFirewall after choosing trusted listen/discovery ports."
    }
    if ($Start) {
        Write-SyncVisionPlan "Would start service '$ServiceName'."
    }
    if ($VerifyInstall) {
        Write-SyncVisionPlan "Would verify install:"
        foreach ($item in (New-SyncVisionInstallVerificationPlan `
            -ServiceName $ServiceName `
            -ServerExe $targetServerExe `
            -ConfigPath $configPath `
            -TokenPath $tokenPath `
            -ProbeEndpoint $probeEndpoint `
            -StartRequested ([bool]$Start) `
            -ConfigureFirewall ([bool]$ConfigureFirewall) `
            -FirewallRules $firewallRules)) {
            Write-SyncVisionPlan $item
        }
    }
    return
}

$installTransactionBootstrapMutex = $null
$installJournalDiscoveryMutex = $null
$installTransactionMutex = $null
$recoveryLockSpec = $null
$installSnapshotContext = $null
$installDirectorySnapshots = @()
$dataDirectorySnapshot = $null
$logDirectorySnapshot = $null
$statusStagingContext = $null
$stagedStatusScript = $null
$serviceTransactionSnapshot = $null
$firewallTransactionSnapshot = $null
$installIntent = $null
$preparedInstallJournal = $null
$durableResourceStateContext = $null
$resourceBackend = $null
$resourceState = $null
$installTransactionCommitted = $false
$installRollbackComplete = $false
$durableTransactionStarted = $false
$packageStagingBase = ""
$packageStagingDirectory = ""
$transactionId = ""
$transactionWorkPaths = @()
try {
$installTransactionBootstrapMutex = Enter-SyncVisionInstallTransactionMutex `
    -InstallDir $InstallDir `
    -DataDir $DataDir `
    -ServiceName $ServiceName `
    -LogDir $logDir `
    -InstallPathOnly
Initialize-SyncVisionServerInstallParentBoundary -InstallDir $InstallDir | Out-Null
$installJournalDiscoveryMutex = Enter-SyncVisionServerInstallJournalDiscoveryMutex -InstallDir $InstallDir
$recoveryLockSpec = Get-SyncVisionServerInstallRecoveryLockSpec -InstallDir $InstallDir
$installTransactionMutex = Enter-SyncVisionInstallTransactionMutex `
    -InstallDir $InstallDir `
    -DataDir $DataDir `
    -ServiceName $ServiceName `
    -LogDir $logDir `
    -FirewallResourceNames $(if ($ConfigureFirewall) { @(Get-SyncVisionFirewallLockResourceNames -Rules $firewallRules) } else { @() }) `
    -AdditionalPaths @($recoveryLockSpec.Paths) `
    -AdditionalServiceNames @($recoveryLockSpec.ServiceNames) `
    -AdditionalFirewallResourceNames @($recoveryLockSpec.FirewallResourceNames) `
    -AdditionalResources @($recoveryLockSpec.Resources)
Assert-SyncVisionServerInstallRecoveryLockSpecCurrent `
    -InstallDir $InstallDir `
    -Spec $recoveryLockSpec | Out-Null
$publicationRecovery = Invoke-SyncVisionServerInstallTransactionRecovery -InstallDir $InstallDir
if ($installTransactionBootstrapMutex.HadAbandonedMutex -or
    $installJournalDiscoveryMutex.HadAbandonedMutex -or
    $installTransactionMutex.HadAbandonedMutex) {
    Write-Warning "Recovered ownership of an abandoned install transaction mutex; canonical journal recovery was checked before continuing."
}
if ($publicationRecovery.Recovered) {
    Write-Warning "Recovered interrupted server install transaction $($publicationRecovery.TransactionId) with action $($publicationRecovery.Action)."
    if (-not [string]::IsNullOrWhiteSpace([string]$recoveryLockSpec.RecoveredServiceName) -and
        -not [string]::Equals(
            [string]$recoveryLockSpec.RecoveredServiceName,
            $ServiceName,
            [StringComparison]::OrdinalIgnoreCase)) {
        throw "Recovered an interrupted transaction for service '$($recoveryLockSpec.RecoveredServiceName)'. Refusing to continue the same invocation as '$ServiceName' while the recovered service may be running from this install tree. Run the installer again after reviewing the recovered service."
    }
}
$InstallDir = Assert-SyncVisionServerInstallDestinationBoundary -InstallDir $InstallDir

$packageInstallManifest = Assert-SyncVisionPackageInstallManifest `
    -RepoRoot $repoRoot `
    -ReleaseDir $releaseDir `
    -SkipBuild:$SkipBuild `
    -ExpectedManifestSha256 $ExpectedManifestSha256 `
    -AllowUntrustedPackageManifestForLocalDevelopment:$AllowUntrustedPackageManifestForLocalDevelopment `
    -AllowSourceCheckoutSkipBuildForLocalDevelopment:$AllowSourceCheckoutSkipBuildForLocalDevelopment
Assert-SyncVisionVcRuntimeAvailable `
    -WindowsDirectory $env:WINDIR `
    -RuntimeDirectory $releaseDir

if (-not $SkipBuild) {
    if (-not (Test-Path -LiteralPath $buildScript)) {
        throw "Build script was not found at $buildScript."
    }

    $powerShell = Resolve-SyncVisionTrustedWindowsTool `
        -RelativePath "System32\WindowsPowerShell\v1.0\powershell.exe" `
        -Context "Windows PowerShell build host"
    $powerShell = Assert-SyncVisionTrustedWindowsToolIdentity `
        -Identity $powerShell `
        -Context "Windows PowerShell build host"
    & $powerShell.Path -NoProfile -ExecutionPolicy Bypass -File $buildScript -Configuration $Configuration
    if ($LASTEXITCODE -ne 0) {
        exit $LASTEXITCODE
    }
}

if (-not (Test-Path -LiteralPath $sourceServerExe)) {
    throw "SyncVisionServer.exe was not found at $sourceServerExe. Run scripts\build.ps1 -Configuration $Configuration first, or verify the build output path."
}

$directoryPreflight = Invoke-SyncVisionInstallDirectoryPreflight `
    -DataDir $DataDir `
    -LogDir $logDir `
    -ServiceAccount $serviceAccountIdentity
$logUsesDataSnapshot = [bool]$directoryPreflight.LogUsesDataSnapshot

$transactionId = [Guid]::NewGuid().ToString("N")
$workBasePath = Get-SyncVisionTrustedPackageStagingBasePath
$transactionWorkPaths = @(
    (Join-Path $workBasePath "txn-$transactionId-package"),
    (Join-Path $workBasePath "txn-$transactionId-status"),
    (Join-Path $workBasePath "txn-$transactionId-snapshot"))
$dataIntentBoundary = Resolve-SyncVisionInstallDirectoryCreationBoundary `
    -Path $DataDir `
    -ServiceAccount $serviceAccountIdentity `
    -Context "SyncVision data durable-intent boundary"
$logIntentBoundary = Resolve-SyncVisionInstallDirectoryCreationBoundary `
    -Path $logDir `
    -ServiceAccount $serviceAccountIdentity `
    -Context "SyncVision log durable-intent boundary"
$installIntent = New-SyncVisionServerInstallIntent `
    -InstallDir $InstallDir `
    -TransactionId $transactionId `
    -ServiceAccount $serviceAccountIdentity `
    -WorkPaths $transactionWorkPaths `
    -LockResources @($installTransactionMutex.Resources) `
    -FreshBoundaries @(
        [pscustomobject]@{ Role = "data"; Boundary = $dataIntentBoundary; ServiceModify = $false },
        [pscustomobject]@{ Role = "log"; Boundary = $logIntentBoundary; ServiceModify = $true })
$installIntent = Write-SyncVisionServerInstallIntent -Intent $installIntent
$durableTransactionStarted = $true

$statusSourcePath = Join-Path $scriptDir "status-server.ps1"
$stagedInputs = @()
try {
    $stagingContext = New-SyncVisionProtectedInstallStagingDirectory `
        -DirectoryName (Split-Path -Leaf $transactionWorkPaths[0])
    $packageStagingBase = $stagingContext.BasePath
    $packageStagingDirectory = $stagingContext.Path
    if ($null -ne $packageInstallManifest -and $packageInstallManifest.IsPackage) {
        $stagedInputs = @(Copy-SyncVisionPackageInstallInputsToStaging -PackageManifest $packageInstallManifest -StagingDirectory $packageStagingDirectory)
    }
    else {
        $sourceInstallInputs = @(Get-SyncVisionSourceInstallInputs -ReleaseDir $releaseDir)
        $stagedInputs = @(Copy-SyncVisionInstallInputsToStaging `
            -InstallInputs $sourceInstallInputs `
            -StagingDirectory $packageStagingDirectory)
    }
    if ($null -ne $packageInstallManifest -and $packageInstallManifest.IsPackage) {
        Assert-SyncVisionPackageTreeSnapshot `
            -RootPath $packageInstallManifest.RootPath `
            -ManifestPath $packageInstallManifest.ManifestPath `
            -ManifestEntries $packageInstallManifest.ManifestEntries
    }

    if ($VerifyInstall) {
        $statusExpectedHash = if ($null -ne $packageInstallManifest -and $packageInstallManifest.IsPackage) {
            $statusRelativePath = "scripts\status-server.ps1"
            if (-not $packageInstallManifest.ManifestEntries.ContainsKey($statusRelativePath)) {
                throw "Package manifest verification failed: SHA256SUMS.txt does not contain $statusRelativePath."
            }
            [string]$packageInstallManifest.ManifestEntries[$statusRelativePath]
        }
        else {
            (Get-FileHash -LiteralPath $statusSourcePath -Algorithm SHA256).Hash.ToLowerInvariant()
        }
        $statusStagingContext = New-SyncVisionProtectedInstallStagingDirectory `
            -DirectoryName (Split-Path -Leaf $transactionWorkPaths[1])
        $stagedStatusScript = Copy-SyncVisionStatusScriptToProtectedStaging `
            -SourcePath $statusSourcePath `
            -ExpectedHash $statusExpectedHash `
            -StagingDirectory $statusStagingContext.Path
    }

    Assert-SyncVisionTrustedStagingPath `
        -BasePath $packageStagingBase `
        -StagingPath $packageStagingDirectory | Out-Null
    Assert-SyncVisionStagedPackageInstallInputs -StagedInputs $stagedInputs

    $serviceTransactionSnapshot = Get-SyncVisionServiceTransactionSnapshot -ServiceName $ServiceName
    Assert-SyncVisionServiceRollbackCredentialSafe -Snapshot $serviceTransactionSnapshot
    Assert-SyncVisionServiceRegistryTransactionCapabilities `
        -Snapshot $serviceTransactionSnapshot `
        -RequireSnapshotMatch
    if ($ConfigureFirewall) {
        $firewallTransactionSnapshot = Get-SyncVisionFirewallTransactionSnapshot `
            -Rules $firewallRules `
            -ServiceName $ServiceName
    }
    $existingWasRunning = $serviceTransactionSnapshot.Exists -and $serviceTransactionSnapshot.Running
    $shouldStartService = [bool]$Start -or $existingWasRunning

    $installSnapshotContext = New-SyncVisionProtectedInstallStagingDirectory `
        -DirectoryName (Split-Path -Leaf $transactionWorkPaths[2])
    $dataDirectorySnapshot = New-SyncVisionInstallDirectorySnapshot `
        -Path $DataDir `
        -SnapshotRoot $installSnapshotContext.Path `
        -Name "data" `
        -ServiceAccount $serviceAccountIdentity `
        -AllowLegacyAclMigration `
        -DeferAclMigration
    $installDirectorySnapshots = @($dataDirectorySnapshot)
    if (-not $logUsesDataSnapshot) {
        $logDirectorySnapshot = New-SyncVisionInstallDirectorySnapshot `
            -Path $logDir `
            -SnapshotRoot $installSnapshotContext.Path `
            -Name "log" `
            -ServiceAccount $serviceAccountIdentity `
            -ServiceModify `
            -AllowLegacyAclMigration `
            -DeferAclMigration
        $installDirectorySnapshots += $logDirectorySnapshot
    }

    if (-not [bool]$dataDirectorySnapshot.Existed) {
        $DataDir = Initialize-SyncVisionProtectedInstallDirectory `
            -Path $DataDir `
            -ServiceAccount $serviceAccountIdentity `
            -Context "SyncVision transaction-owned fresh data directory"
        if ($logUsesDataSnapshot) {
            $logDir = Initialize-SyncVisionProtectedInstallDirectory `
                -Path $logDir `
                -ServiceAccount $serviceAccountIdentity `
                -ServiceModify `
                -Context "SyncVision transaction-owned fresh log directory"
        }
        Register-SyncVisionInstallFreshDirectory -Snapshot $dataDirectorySnapshot -Path $DataDir
    }
    if ($null -ne $logDirectorySnapshot -and -not [bool]$logDirectorySnapshot.Existed) {
        $logDir = Initialize-SyncVisionProtectedInstallDirectory `
            -Path $logDir `
            -ServiceAccount $serviceAccountIdentity `
            -ServiceModify `
            -Context "SyncVision transaction-owned fresh log directory"
        Register-SyncVisionInstallFreshDirectory -Snapshot $logDirectorySnapshot -Path $logDir
    }

    $dataAclTargets = New-Object "System.Collections.Generic.List[object]"
    $dataAclTargets.Add([pscustomobject]@{
            Path = $DataDir
            ServiceModify = $false
            Context = "SyncVision data directory migration"
        })
    if ($logUsesDataSnapshot) {
        $dataAclTargets.Add([pscustomobject]@{
                Path = $logDir
                ServiceModify = $true
                Context = "SyncVision log directory migration"
            })
    }
    $aclMigrations = New-Object "System.Collections.Generic.List[object]"
    $aclMigrations.Add([pscustomobject]@{
            SnapshotIndex = 0
            Targets = $dataAclTargets.ToArray()
        })
    if ($null -ne $logDirectorySnapshot) {
        $aclMigrations.Add([pscustomobject]@{
                SnapshotIndex = 1
                Targets = @([pscustomobject]@{
                    Path = $logDir
                    ServiceModify = $true
                    Context = "SyncVision log directory migration"
                })
            })
    }

    $hadPreviousBinary = Test-Path -LiteralPath $InstallDir -PathType Container
    $previousBinaryInputs = @()
    $previousBinaryIdentity = ""
    if ($hadPreviousBinary) {
        $previousBinaryIdentity = Get-SyncVisionInstallFileSystemIdentity -Path $InstallDir
        $previousBinaryInputs = @(
            Get-ChildItem -LiteralPath $InstallDir -File -Force |
                ForEach-Object {
                    [pscustomobject]@{
                        DestinationName = $_.Name
                        ExpectedLength = [int64]$_.Length
                        ExpectedHash = (Get-FileHash -LiteralPath $_.FullName -Algorithm SHA256).Hash.ToLowerInvariant()
                    }
                })
    }
    $newBinaryInputs = @(ConvertTo-SyncVisionServerInstallJournalInputs `
            -Inputs $stagedInputs `
            -Context "Full server install transaction candidate file set" `
            -RequireServerExecutable)
    $resourceState = [pscustomobject]@{
        TransactionId = $transactionId
        IntentPath = $installIntent.IntentPath
        IntentTransactionId = $installIntent.TransactionId
        SnapshotContextPath = $installSnapshotContext.Path
        SnapshotContextBasePath = $installSnapshotContext.BasePath
        SnapshotContextIdentity = Get-SyncVisionInstallFileSystemIdentity -Path $installSnapshotContext.Path
        ConflictArchiveRoot = Join-Path $installSnapshotContext.BasePath ("install-conflict-" + $transactionId)
        DirectorySnapshots = @($installDirectorySnapshots)
        AclMigrations = @($aclMigrations.ToArray())
        ServiceSnapshot = $serviceTransactionSnapshot
        FirewallSnapshot = $firewallTransactionSnapshot
        Desired = [pscustomobject]@{
            DataDir = $DataDir
            LogDir = $logDir
            ServiceAccountIdentity = $serviceAccountIdentity
            TokenPath = $tokenPath
            Token = $resolvedToken
            TransportSecretPath = $resolvedTransportSecretFile
            TransportSecret = $resolvedTransportSecret
            ConfigPath = $configPath
            ConfigText = $configText
            ServiceName = $ServiceName
            BinPath = $binPath
            ServiceCreateArguments = @($serviceCreateArguments)
            ServiceConfigArguments = @($serviceConfigArguments)
            ServiceDescription = "SyncVision local/public relay server"
            NoServiceRecovery = [bool]$NoServiceRecovery
            ServiceRecoveryRestartDelayMs = [uint32]$ServiceRecoveryRestartDelayMs
            ConfigureFirewall = [bool]$ConfigureFirewall
            FirewallRules = @($firewallRules)
            ShouldStartService = [bool]$shouldStartService
        }
    }
    $durableResourceStateContext = Write-SyncVisionServerInstallResourceState `
        -InstallDir $InstallDir `
        -TransactionId $transactionId `
        -BackendKind "Windows" `
        -State $resourceState
    $preparedInstallJournal = New-SyncVisionServerInstallJournal `
        -InstallDir $InstallDir `
        -TransactionId $transactionId `
        -HadPrevious $hadPreviousBinary `
        -PreviousInputs $previousBinaryInputs `
        -NewInputs $newBinaryInputs `
        -PreviousIdentity $previousBinaryIdentity `
        -ResourceStatePath $durableResourceStateContext.Path `
        -ResourceStateIdentity $durableResourceStateContext.Identity `
        -ResourceStateSha256 $durableResourceStateContext.Sha256 `
        -ResourceBackendKind $durableResourceStateContext.BackendKind
    $preparedInstallJournal = Write-SyncVisionServerInstallJournal -Journal $preparedInstallJournal
    $durableTransactionStarted = $true
    Read-SyncVisionServerInstallResourceState -Journal $preparedInstallJournal | Out-Null

    $additionalVerification = if ($VerifyInstall) {
        {
            param($state)
            Invoke-SyncVisionInstallVerification `
                -ServiceName $ServiceName `
                -ServerExe $targetServerExe `
                -ConfigPath $configPath `
                -TokenPath $tokenPath `
                -StagedStatusScript $stagedStatusScript `
                -ProbeEndpoint $probeEndpoint `
                -StartRequested $shouldStartService `
                -ConfigureFirewall ([bool]$ConfigureFirewall) `
                -FirewallRules $firewallRules `
                -TimeoutMs $VerifyTimeoutMs
        }.GetNewClosure()
    }
    else { $null }
    $resourceBackend = New-SyncVisionWindowsServerInstallResourceBackend `
        -AdditionalVerification $additionalVerification
    $transactionOutcome = Invoke-SyncVisionServerInstallTransactionCoordinator `
        -Journal $preparedInstallJournal `
        -StagedInputs $stagedInputs `
        -ResourceBackend $resourceBackend `
        -ResourceState $resourceState
    if (-not $transactionOutcome.Recovered -or $transactionOutcome.Action -ne "ForwardCommittedCleanup") {
        throw "Full server install transaction did not reach its durable forward cleanup state."
    }
    $installTransactionCommitted = $true
    $durableTransactionStarted = $false
}
finally {
    if (-not [string]::IsNullOrWhiteSpace($packageStagingDirectory) -and
        (Test-Path -LiteralPath $packageStagingDirectory)) {
        try {
            Assert-SyncVisionTrustedStagingPath `
                -BasePath $packageStagingBase `
                -StagingPath $packageStagingDirectory | Out-Null
            Remove-Item -LiteralPath $packageStagingDirectory -Recurse -Force -ErrorAction Stop
        }
        catch {
            Write-Warning "Trusted staging cleanup was refused: $($_.Exception.Message)"
        }
    }
}

Write-Host "Installed service '$ServiceName'."
Write-Host "Binary: $targetServerExe"
Write-Host "Config: $configPath"
Write-Host "TokenFile: $tokenPath"
Write-Host "LogFile: $resolvedLogFile"
Write-Host "ServiceAccount: $serviceAccountIdentity"
if ($tokenWasGenerated -and $RevealGeneratedToken) {
    Write-Host "Access token: $resolvedToken"
}
elseif ($tokenWasGenerated) {
    Write-Host "Access token: <generated; see token file>"
}
else {
    Write-Host "Access token: <provided; see token file>"
}
if ($resolvedTransportSecretFile) {
    if ($transportSecretWasGenerated) {
        Write-Host "Transport secret: <generated; see transport secret file>"
    }
    else {
        Write-Host "Transport secret: <provided; see transport secret file>"
    }
    Write-Host "TransportSecretFile: $resolvedTransportSecretFile"
}
if ($ConfigureFirewall) {
    Write-Host "Windows Firewall rules: configured"
}
if (-not $NoServiceRecovery) {
    Write-Host "Service recovery: configured"
}
}
catch {
    $installFailure = $_
    $installFailureExitCode = Get-SyncVisionInstallFailureExitCode -Failure $installFailure
    $outerRecoveryFailure = $null
    if ($durableTransactionStarted) {
        try {
            Invoke-SyncVisionServerInstallTransactionRecovery `
                -InstallDir $InstallDir `
                -ExpectedTransactionId $transactionId | Out-Null
            $remainingIntent = Read-SyncVisionServerInstallIntent -InstallDir $InstallDir -AllowMissing
            $remainingJournal = Read-SyncVisionServerInstallJournal -InstallDir $InstallDir -AllowMissing
            if ($null -eq $remainingIntent -and $null -eq $remainingJournal) {
                $installRollbackComplete = $true
                $durableTransactionStarted = $false
            }
        }
        catch { $outerRecoveryFailure = $_ }
    }
    if ($null -ne $outerRecoveryFailure) {
        throw "Server install failed and bootstrap-intent recovery was incomplete. Failure: $($installFailure.Exception.Message) Recovery: $($outerRecoveryFailure.Exception.Message)"
    }
    if ($null -ne $installFailureExitCode) {
        Write-Error -ErrorRecord $installFailure -ErrorAction Continue
        exit $installFailureExitCode
    }
    throw $installFailure
}
finally {
    if ($null -ne $statusStagingContext -and (Test-Path -LiteralPath $statusStagingContext.Path)) {
        try {
            Assert-SyncVisionTrustedStagingPath -BasePath $statusStagingContext.BasePath -StagingPath $statusStagingContext.Path | Out-Null
            Remove-Item -LiteralPath $statusStagingContext.Path -Recurse -Force -ErrorAction Stop
        }
        catch { Write-Warning "Protected status verifier staging cleanup was refused: $($_.Exception.Message)" }
    }
    if (-not $durableTransactionStarted -and
        $null -ne $installSnapshotContext -and
        (Test-Path -LiteralPath $installSnapshotContext.Path)) {
        try {
            Assert-SyncVisionTrustedStagingPath -BasePath $installSnapshotContext.BasePath -StagingPath $installSnapshotContext.Path | Out-Null
            Remove-Item -LiteralPath $installSnapshotContext.Path -Recurse -Force -ErrorAction Stop
        }
        catch { Write-Warning "Install transaction snapshot cleanup was refused: $($_.Exception.Message)" }
    }
    elseif ($null -ne $installSnapshotContext -and (Test-Path -LiteralPath $installSnapshotContext.Path)) {
        Write-Warning "Install rollback was incomplete; preserving the protected recovery snapshot at $($installSnapshotContext.Path)."
    }
    if (-not $durableTransactionStarted -and
        $null -ne $durableResourceStateContext -and
        (Test-Path -LiteralPath $durableResourceStateContext.Path -PathType Leaf)) {
        try {
            $statePath = Assert-SyncVisionServerInstallJournalFileSecurity -Path $durableResourceStateContext.Path
            if ((Get-SyncVisionInstallRegularFileIdentity -Path $statePath) -cne $durableResourceStateContext.Identity) {
                throw "Durable resource-state identity changed before orphan cleanup."
            }
            Initialize-SyncVisionServerInstallJournalAtomicType
            [SyncVisionServerInstallJournalAtomic]::DeleteIfIdentity($statePath, $durableResourceStateContext.Identity)
        }
        catch { Write-Warning "Protected resource-state orphan cleanup was refused: $($_.Exception.Message)" }
    }
    Exit-SyncVisionInstallTransactionMutex -Context $installTransactionMutex
    Exit-SyncVisionInstallTransactionMutex -Context $installJournalDiscoveryMutex
    Exit-SyncVisionInstallTransactionMutex -Context $installTransactionBootstrapMutex
}
