Data/redaction-profile.json

{
  "version": 1,
  "description": "What -Anonymise changes, and what is always scrubbed. Read by Invoke-DoctorDOCollector -WhatIfRedaction and by the redaction code. Get-Help about_DoctorDO.Collector sums it up under PRIVACY.",
  "alwaysApplied": [
    { "field": "Log lines, error samples, notCollected details, firewall rule names and programs", "treatment": "Account forms replaced, by pattern: the folder after \\Users\\ or \\Documents and Settings\\ with any drive or prefix and either slash (C:\\Users\\<user>, also a name with spaces when a path separator follows it); everything after the server of a UNC path (\\\\server\\<path>); the account in AzureAD\\, MicrosoftAccount\\ and upper-case DOMAIN\\account forms (DOMAIN\\<user>; built-in principals such as NT AUTHORITY\\SYSTEM are kept); user SIDs (<sid>); e-mail addresses and UPNs (<upn>). URL paths are cut to two segments and query strings removed. Forms the patterns do not cover can get through: a lower-case domain, the part of a DOMAIN\\account name after a space, a name with spaces at the end of a path, or a name written in free text." },
    { "field": "Peer and connection addresses", "treatment": "In peerInfo and topPeers: a tenant-salted hash (sameSubnet computed before hashing; telemetry carries the first 16 hex characters). In endpoint rows (who served the bytes): an internet peer is always reduced to its /24 (IPv4) or /48 (IPv6) network; LAN and group peers are addresses, or that network under -Anonymise; never a hash beside a network. The device's own public address in DO's cloud responses (the geo service's ExternalIpAddress) is read only with -CollectPublicEgress, hashed at once, and never stored or cached. In log text and error samples addresses stay as written unless -Anonymise, which replaces IPv4 and IPv6 addresses alike." },
    { "field": "Connected Cache server and CDN nodes", "treatment": "Infrastructure, sent in clear: DOCacheHost, DHCP option 235, the cache server the DO service assigns (geo CacheHost), the per-file CacheHost and cache/CDN endpoint rows, reduced to a bare host or address (no scheme, path, port or credentials)." },
    { "field": "Endpoint health (ep:<id> connectivity results)", "treatment": "The host tested in clear (Microsoft endpoints, the cache server). No URL, path or query string: the URL of a file the device downloaded is used in memory for one Range: bytes=0-0 request and never stored or sent. Resolved addresses only for CDN and Connected Cache hosts. Under -Anonymise a non-Microsoft certificate issuer's name is dropped." },
    { "field": "Firewall rules (collectors from October 2026)", "treatment": "The remote address condition is reduced to a category (any, local-subnet, ranges, keywords, mixed) and a count of entries; the addresses themselves are never collected. Each rule's display name and program pass through the log-line scrub (a per-user rule's program is a profile path), and under -Anonymise the machine name and addresses go too." },
    { "field": "Provisioning (inventory provisioning section, collectors from 0.5.0)", "treatment": "Read on a device that showed the Enrollment Status Page, from HKLM\\SOFTWARE\\Microsoft\\Windows\\Autopilot\\EnrollmentStatusTracking: for up to 30 Win32 apps the Intune app ID, phase (device or account setup), installation state, reboot flag and the first and last time the ESP logged a status for it; the ESP's first and last status and its app counts by state. Once, within 7 days of the ESP's last status: Delivery Optimization's jobs of the ESP's time summed by priority and by source, the jobs below DOMinFileSizeToCache, and the 10 largest jobs (size, bytes by source, download time, calling application up to 64 characters). Never a user name, SID, URL, file name or file ID: the user's SID that names an account-setup key is read in memory only." },
    { "field": "Offline device report (New-DoctorDODeviceReport)", "treatment": "A local HTML file, never sent. Identifies the device like the local bundle unless -Anonymise is given; then also no Entra, tenant or Intune device ID, ConfigMgr site code or AD site, and hashes use a salt made for that report. The embedded JSON escapes every less-than sign; the page makes no network request." },
    { "field": "network.proxy.pac (collectors from October 2026)", "treatment": "The PACs in force are read and downloaded on the device only. Sent: whether one is in force, the number of versions, a tenant-salted fingerprint per PAC (pac:<16 hex>), its scopes, a count of signed-in user profiles, the DO endpoint services it names and whether it answers direct or proxy for DO. Never its URL, host, text or proxy names; never a user name, SID or profile path." },
    { "field": "Content sources (TelemetryV1.sources, collectors from October 2026)", "treatment": "Per Connected Cache server and per HTTP host: bytes, jobs and DownloadDuration, summed on the device over the jobs that finished since the last report. The cache server is infrastructure and in clear; an HTTP host follows the status sourceUrlHost rule (under -Anonymise only a Microsoft content host or its pseudonym, host:<16 hex>). Never a URL, path or file ID; the file IDs already summarised stay in the state file." },
    { "field": "Month totals (TelemetryV1.month, collectors from 0.7.0)", "treatment": "Delivery Optimization's own byte counters for the calendar month from Get-DeliveryOptimizationPerfSnapThisMonth: bytes over HTTP, from Connected Cache, from LAN, internet and (where Windows reports it) group peers, bytes uploaded to LAN and internet peers, and the date the month began. Byte counts only: no address, host, URL, file ID or user. Not sent in a first (baseline) report." },
    { "field": "Local bundle extras", "treatment": "Admin-run local bundles only: dosvc-registry.json (HKLM\\SYSTEM\\CurrentControlSet\\Services\\DoSvc), nlm-cost.txt (netsh nlm show cost) and dsregcmd-status.txt (dsregcmd /status), passed through the log-line scrub; under -Anonymise dsregcmd-status.txt also loses every GUID, thumbprint and long hex string, the tenant and domain names and the executing account. netsh nlm query all, which lists network names, is never run." },
    { "field": "Entra device ID, tenant ID, Intune device ID", "treatment": "Sent in the inventory ONLY (management section), and never as a payload field used for identity. Identity for authorisation is the signed request: the device certificate travels in the X-DoctorDO-Device-Cert header, and with the entra-device anchor its subject CN is the Entra device ID, so ingest learns that ID from every request whatever -Anonymise says." }
  ],
  "anonymise": [
    { "field": "device.hostname", "treatment": "Removed (null)." },
    { "field": "device.deviceId", "treatment": "sha256 of hostname + machine GUID + a random per-device salt kept in the protected state file (stable across runs so the inventory hash is stable)." },
    { "field": "hardware.serialHash", "treatment": "Salted sha256 of the baseboard serial number; the serial itself is never sent." },
    { "field": "network.localSubnet", "treatment": "IPv4 reduced to its subnet, for example 10.20.4.0/22." },
    { "field": "network.defaultGateway", "treatment": "Hashed with the device's own salt (ip:<16 hex>), so it cannot be compared across devices." },
    { "field": "network.publicEgressHash", "treatment": "Tenant-salted sha256 so devices behind one egress compare equal; address discarded. Collected only with -CollectPublicEgress (from the DO geo service's answer) or when -PublicIpProbeUri is supplied." },
    { "field": "network.doAdapter.name", "treatment": "Removed (null); the adapter's type, kind, subnet and default-route flag are kept. Never a hardware address." },
    { "field": "network.dhcpOption234 / DOGroupId", "treatment": "Hashed with the tenant salt (redacted:<16 hex>), so devices given the same group compare equal within the tenant and differ between tenants; like peer hashes, a guessed value can be tested by anyone who knows the tenant ID." },
    { "field": "network.proxy.pacUrlHost", "treatment": "Host only, no path; hashed." },
    { "field": "doConfig registry values", "treatment": "DOGroupId values replaced by their tenant-salted hash; all other values verbatim (the cache host is infrastructure and stays in clear)." },
    { "field": "status sourceUrlHost", "treatment": "A host that is not a Microsoft content host (a WSUS or internal web server) is hashed with the tenant salt (host:<16 hex>), so one server compares equal across the tenant's devices; Microsoft CDN hosts verbatim." },
    { "field": "endpoint rows: LAN and group peers", "treatment": "Reduced to their /24 (IPv4) or /48 (IPv6) network; rows in one network merged with a count." },
    { "field": "connectivity targets and evidence", "treatment": "Microsoft endpoints and the Connected Cache server verbatim; peer targets are hashed; evidence passes through the log-line scrub." },
    { "field": "log lines and error samples", "treatment": "The machine name (three characters or more) becomes <host>; IPv4 and IPv6 addresses become <ip:8 hex>, a truncated hash with the device's own salt, which stays in the protected state file." },
    { "field": "log excerpt (local bundle only)", "treatment": "Only lines matching retainedEventPatterns; the machine name and IPv4 and IPv6 addresses replaced as in log lines (URLs are always reduced); capped at maxExcerptBytes." }
  ],
  "retainedEventPatterns": [ "0x8[0-9A-Fa-f]{7}", "(?i)\\b(?:hr|hresult|error ?code)\\s*[:=]\\s*(?:0x)?8[0-9a-f]{7}\\b", "DoSvc", "DownloadManager", "PeerConnection", "GroupIdResolver", "CacheManager", "Connected Cache", "Teredo" ],
  "limits": { "maxSampleLength": 200, "maxExcerptBytes": 204800, "maxEvidenceLength": 512 },
  "neverCollected": [ "Entra group membership", "Intune compliance state", "assigned apps and policies other than Delivery Optimization", "primary user", "user names", "credentials or tokens", "response bodies from the ingest service" ]
}