💡 Volledig werkend voorbeeld beschikbaar op GitHub:
scrub-office-document-pii-dotnet
De oude manier was pijnlijk
Het routineproces ziet er als volgt uit. Open het document, Ga naar Bestand → Info → Controleer op problemen → Document inspecteren, vink de vakjes aan, Alles verwijderen, sla op onder een nieuwe naam, sluit, open het volgende. Veertig bestanden later merkt iemand dat Document inspecteren ook de Titel heeft verwijderd waar de indexsleutels van de archieven op gebaseerd zijn, en dat de kopie die een uur eerder werd verzonden nog steeds een SharePoint‑goedkeurder‑ID bevatte, omdat het bestand was opgeslagen vanuit een andere applicatie die het veld terugschreef.
Metadata‑PII‑verwijdering is een GroupDocs.Metadata‑functionaliteit voor .NET die identiteitsdragende eigenschappen uit Office‑documenten programmatically verwijdert en rapporteert wat er daarna overblijft. De handmatige routine faalt op drie punten: hij schaalt niet voorbij een handvol bestanden, hij is alles‑of‑niets wat betreft welke velden worden verwijderd, en hij levert geen verslag op van wat er verwijderd is. Dit artikel toont de .NET‑versie van hetzelfde werk, één eigenschapsgroep per keer.
Het helpt om te weten wat er eigenlijk in zit. Een Word‑bestand dat een review‑ronde heeft doorlopen bevat doorgaans Author en LastSavedBy van het Windows‑account van de persoon die het heeft opgeslagen, Manager en Company uit de corporate‑template, een revisieteller, TotalEditingTime, een LastPrinted‑tijdstempel, en tellers voor commentaar‑threads. Voeg SharePoint toe aan de keten en je krijgt ook goedkeurder‑identifiers, workflow‑paden, content‑type‑URI’s en de template waaruit het document is gemaakt. Niets hiervan is zichtbaar op de pagina, en alles reist mee in hetzelfde bestand.
Er is een betere manier
Alles in GroupDocs.Metadata voor .NET loopt via één eigenschap‑zoekmachine. RemoveProperties neemt een lambda over MetadataProperty, verwijdert elke eigenschap die de lambda accepteert, en retourneert het aantal. FindProperties voert dezelfde lambda uit zonder te schrijven. Eigenschappen dragen ook tags, dus Tags.Person.Creator identificeert auteur‑achtige velden over formaten en pakketten heen in plaats van letterlijke namen te matchen die per producer‑applicatie verschillen.
Dat levert drie vormen van opruimen op in plaats van één knop: een tag‑pass voor identiteitsvelden, naam‑passes voor families zoals commentaren en revisies, en Sanitize() wanneer niets mag overblijven. Alle drie geven cijfers terug, en die cijfers maken de pass controleerbaar.
De nieuwe manier: een predikaat per eigenschapsgroep
Stap 1 - Verwijder de namen
Vier tag‑controles dekken de identiteitsgroep. Beschrijvende velden blijven onaangeroerd, wat het verschil is met “Alles verwijderen” van de Document‑Inspector:
using (var metadata = new Metadata(inputPath))
{
if (metadata.FileFormat == FileFormat.Unknown) return 0;
var affected = metadata.RemoveProperties(p =>
p.Tags.Contains(Tags.Person.Creator) ||
p.Tags.Contains(Tags.Person.Editor) ||
p.Tags.Contains(Tags.Person.Manager) ||
p.Tags.Contains(Tags.Corporate.Company));
metadata.Save(outputPath);
return affected;
}
De controle FileFormat.Unknown is de bewaker die een nul eerlijk houdt: zonder deze zou een onleesbaar bestand en een schoon bestand er voor de aanroeper hetzelfde uitzien.
Stap 2 - Verwijder de families eromheen
Commentaren, revisies en server‑velden hebben geen tag, dus het predikaat matcht namen in plaats daarvan. De bewerkings‑tijdlijn is de groep die het vaakst wordt vergeten, en het is de groep die aangeeft hoe een document is geproduceerd:
using (var metadata = new Metadata(inputPath))
{
if (metadata.FileFormat == FileFormat.Unknown) return 0;
var affected = metadata.RemoveProperties(p =>
p.Name != null && (
p.Name.Contains("Revision") ||
p.Name.Contains("TrackedChange") ||
p.Name.Contains("LastPrinted") ||
p.Name.Contains("TotalEditingTime") ||
p.Name.Contains("EditTime")));
metadata.Save(outputPath);
return affected;
}
Substring‑matching is opzettelijk: het vangt CommentsCount naast Comment, en TotalEditingTime naast EditTime, zonder een exacte‑naam‑lijst per formaat te onderhouden. De SharePoint‑pass is dezelfde oproep met Server, Workflow, Approver, ContentType en Template.
Stap 3 - Wis alles, controleer vervolgens het resultaat
Op de trust‑boundary vervangt één oproep de vier passes:
using (var metadata = new Metadata(inputPath))
{
if (metadata.FileFormat == FileFormat.Unknown) return 0;
var affected = metadata.Sanitize();
metadata.Save(outputPath);
return affected;
}
Daarna volgt het deel waar de handmatige routine geen equivalent voor heeft. De verificatiescan hergebruikt de verwijder‑predicaten via FindProperties en sorteert de overlevenden in twee lijsten:
foreach (var p in props)
{
var value = p.InterpretedValue?.ToString() ?? p.Value?.ToString() ?? string.Empty;
if (string.IsNullOrWhiteSpace(value)) continue;
if (value == "0" || value == "0.0") continue;
var entry = $"{p.Name}={value}";
var name = p.Name ?? string.Empty;
if (name.StartsWith("Comment") || name.StartsWith("Revision"))
report.ContentLevelLeaks.Add(entry);
else
report.MetadataLeaks.Add(entry);
}
MetadataLeaks moet leeg zijn voordat een bestand als gesanitiseerd wordt beschouwd. ContentLevelLeaks is informatief: Word‑commentaren en auteurs van tracked‑changes zitten in word/document.xml, wat body‑content is, en het wissen daarvan vraagt om een content‑editing‑bibliotheek zoals Aspose.Words in plaats van een metadata‑API.
Waarom niet gewoon Sanitize aanroepen voor alles?
Omdat de meeste documenten nog in gebruik zijn. Sanitize() wist elk gedetecteerd pakket, en dat omvat Titel, Onderwerp en Trefwoorden, de velden waar een archiefsysteem en een zoekindex van afhankelijk zijn. Gebruik de gerichte passes terwijl een bestand intern circuleert, houd de beschrijvende metadata werkend, en reserveer de volledige wis‑actie voor de kopie die de organisatie daadwerkelijk verlaat.
Zij-aan-zij: Voor vs. Na
| Handmatige inspectie | GroupDocs.Metadata voor .NET | |
|---|---|---|
| Selectiviteit | Alles verwijderen, beschrijvende velden inbegrepen | één predikaat per eigenschapsgroep |
| Dekking | velden die de dialoog toont | elk pakket dat de bibliotheek detecteert, inclusief aangepaste OOXML‑onderdelen |
| Verslag | geen | aantal getroffen items geretourneerd per operatie |
| Verificatie | opnieuw openen en kijken | FindProperties‑scan met metadata‑ en content‑level‑lijsten |
| Batch van 200 bestanden | 200 klik‑doorlopen | één lus, vijf operaties, één logregel per bestand |
De rij die het gedrag verandert is de verslag‑rij. Zodra elke pass een aantal teruggeeft, stopt sanitization met een stap die iemand moet onthouden en wordt het data waarop de pipeline kan controleren: een drempel in een test, een veld in een audit‑tabel, een voorwaarde die een nachtelijke taak laat falen. Dat is ook de rij die een handmatige routine op geen enkel niveau van discipline kan produceren.
Praktijkvoorbeeld: De pre‑verzend hook
Een support‑portaal laat medewerkers documenten aan klant‑tickets toevoegen. De attachment‑handler voert nu de identiteits‑pass en de server‑pass uit voordat het bestand wordt opgeslagen, registreert beide aantallen bij het ticket, en voert de lek‑check uit op de opgeslagen kopie. Een niet‑lege metadata‑leklijst wijst de upload af met een bericht dat de overtredende eigenschap benoemt, zodat de persoon die het bestand bijvoegt direct weet wat er mis is in plaats van pas nadat het bij de klant is aangekomen.
Twee details maken die hook praktisch. De passes schrijven naar een nieuw pad, zodat het origineel in de opslag van de medewerker blijft en er niets wordt vernietigd door een geautomatiseerde stap. En de aantallen worden in het ticket‑record naast de attachment opgeslagen, wat betekent dat het antwoord op “wat is er uit dit document verwijderd” een opgeslagen getal is in plaats van een aanname over wat de pipeline gewoonlijk doet.
De eerste keer dat ik die controle op een echt sjabloon toepaste, kwam er een Manager‑waarde terug die de identiteits‑pass seconden eerder had verwijderd en die het corporate‑sjabloon direct bij het opslaan weer had teruggeschreven. De verwijder‑aanroep werkte precies zoals gedocumenteerd; de pipeline eromheen was het probleem, en alleen de read‑back toonde dat.
Wat kun je nog meer doen met GroupDocs.Metadata?
Dezelfde predikaat‑engine leest. Het vergelijken van eigenschappen tussen twee versies van een document brengt eigendom‑wijzigingen en her‑authoring buiten het review‑proces aan het licht, en de metadata scrubbing overview behandelt waar een interactieve tool nog steeds naast een API‑gedreven pass past. Omdat het tag‑systeem formaten overspant, draait het hier geschreven identiteits‑predikaat ook tegen PDF‑s, afbeeldingen en audiobestanden zonder aanpassing.
Die draagbaarheid is het waard om voor te plannen. Een opruim‑regel geschreven als een lambda over MetadataProperty is gewoon C#, dus hij kan in een gedeelde bibliotheek leven, unit‑tested worden tegen fixture‑documenten, en toegepast worden door elke service die het nodig heeft: een export‑endpoint, een geplande archief‑taak, of een build‑stap die documentatie‑attachments sanitiseert vóór release. De regels blijven op één plek; alleen de aanroep‑sites veranderen.
Conclusie
Vier gerichte passes, één volledige sanitize, één verificatiescan. Die set dekt het praktische bereik voor Office‑documenten: houd de beschrijvende metadata terwijl een bestand in omloop is, wis alles wanneer het de organisatie verlaat, en bewijs het resultaat in beide gevallen. Clone het voorbeeld, voer het uit tegen een document dat een echte review‑ronde heeft doorstaan, en lees de aantallen getroffen items. Ze zijn meestal hoger dan verwacht, en dat is precies het punt.