Nach dem CU startet kein 2010-Workflow mehr

Ein Anwender meldet, dass sein Genehmigungsworkflow nicht mehr startet. Auf der Statusseite steht „Fehler beim Start“. Kein Schritt läuft, keine Aufgabe entsteht, im Verlauf zwei dürre Zeilen vom Systemkonto. Das war alles, womit ich anfangen konnte.
SharePoint Server 2019, kurz zuvor gepatcht. Und auf dieser Farm war die bekannte Korrektur für genau dieses Problem längst eingespielt. Wochen vorher, dokumentiert, mit iisreset. Trotzdem lief nichts.
Was die Updates seit Juni geändert haben
Seit den Sicherheitsupdates ab Juni 2026 schaut SharePoint vor dem Übersetzen eines 2010-Workflows nach, ob jeder darin verwendete Baustein in der web.config freigegeben ist, im Abschnitt authorizedTypes. Fehlt einer, bricht die Übersetzung ab. Und ohne übersetzte Definition läuft eben keine Instanz.
Die Prüfung schließt eine reale Lücke. Sie legt nur eben auch völlig harmlose Workflows lahm, wenn die Liste unvollständig ist.
Im ULS steht es wörtlich
Die Oberfläche gibt nichts her, das Protokoll schon. Man braucht allerdings die ungefähre Uhrzeit des Startversuchs, sonst sucht man im Heuhaufen. Ich habe den Workflow also nochmal gestartet, auf die Uhr geschaut und dann ein enges Fenster abgegriffen:
$von = Get-Date "2026-09-09 11:26"
$bis = $von.AddMinutes(4)
Get-SPLogEvent -StartTime $von -EndTime $bis |
Where-Object { $_.Message -like "*malicious xoml node*" -or
$_.Message -like "*Block the namespace*" -or
$_.Message -like "*temporarily disabled*" } |
Select-Object Timestamp, Category, Message |
Format-ListZwei Hinweise dazu, die mich Zeit gekostet haben. Get-SPLogEvent läuft nur lokal auf dem Server, per Remoting kommt man an die Logs nicht ran. Und das Zeitfenster sollte wirklich eng sein, sonst wartet man ewig und bekommt zehntausende Zeilen.
Was dann herauskam:
Block the namespace: clr-namespace:Microsoft.Office.Workflow.Actions;
Assembly=Microsoft.Office.Workflow.Actions, Version=16.0.0.0,
Culture=neutral, PublicKeyToken=null, type: ApprovalTaskProcess
Potentially malicious xoml node: <ns1:ApprovalTaskProcess …>
CompileBytes: … Error parsing xoml …
System.InvalidOperationException: This feature has been temporarily disabled.
at SPNoCodeXomlCompiler.CompileBytes → LoadXomlAssembly
→ LoadDeclarativeAssembly → CreateInstance → RunWorkflowAn „This feature has been temporarily disabled“ habe ich mich erstmal festgebissen. Klingt nach einem Schalter, den jemand umgelegt hat, und prompt sucht man in der Farmkonfiguration. Ist aber bloß die Exception, die der Compiler wirft, wenn ihm ein Baustein verweigert wird. Die brauchbare Zeile steht zwei drüber.
Zwei Einträge, die nicht passten
Also in die web.config geschaut. Erstmal nachsehen, wo die überhaupt liegen — eine Webanwendung kann mehrere Zonen haben, und jede bringt ihre eigene Datei mit:
Get-SPWebApplication | ForEach-Object {
$_.Name
$_.IisSettings.Values.Path.FullName
}Und dann gezählt. Der Befehl, der die Sache aufgeklärt hat, gruppiert die Einträge des verdächtigen Namespace danach, ob sie einen echten Token tragen oder null:
$pfad = "C:\inetpub\wwwroot\wss\VirtualDirectories\443\web.config"
$xml = [xml](Get-Content $pfad)
$xml.SelectNodes("//authorizedType") |
Where-Object { $_.Namespace -eq "Microsoft.Office.Workflow.Actions" } |
ForEach-Object {
if ($_.Assembly -match "PublicKeyToken=null") { "null" } else { "signiert" }
} |
Group-Object |
Select-Object Name, CountErgebnis: zwei signierte, null mit null. Zum Vergleich derselbe Befehl für Microsoft.SharePoint.WorkflowActions — da standen zwei und zwei. Der eine Namespace war versorgt, der andere nicht.
| Namespace | signiert | mit null | |
|---|---|---|---|
Microsoft.SharePoint.WorkflowActions | 2 | 2 | läuft |
Microsoft.Office.Workflow.Actions | 2 | 0 | blockiert |
Warum das überhaupt einen Unterschied macht: Der Abgleich ist rein textuell. SharePoint vergleicht die Zeichenkette aus der Workflow-Definition mit den Zeichenketten in der Freigabeliste, nicht die tatsächliche Signatur der geladenen Assembly. Und SharePoint Designer schreibt die Bausteine so in die XOML-Datei:
xmlns:ns1="clr-namespace:Microsoft.Office.Workflow.Actions;
Assembly=Microsoft.Office.Workflow.Actions, Version=16.0.0.0,
Culture=neutral, PublicKeyToken=null"PublicKeyToken=null, obwohl die Assembly in Wirklichkeit signiert ist. Auf so eine Deklaration passt nur ein Freigabeeintrag, der ebenfalls null stehen hat. Die beiden vorhandenen trugen den echten Token und wurden deshalb schlicht nicht gefunden.
Warum die Korrektur vorher nichts genützt hatte
Die null-Variante war Wochen zuvor eingetragen worden. Für Microsoft.SharePoint.WorkflowActions. Für Microsoft.Office.Workflow.Actions nicht.
Dort liegt ApprovalTaskProcess, die Genehmigungsaufgabe. Also ausgerechnet der Baustein, ohne den in der Praxis kaum ein Workflow auskommt. Wer nach dem Einspielen mit irgendeinem Testworkflow prüft und dabei zufällig einen ohne Genehmigungsschritt erwischt, sieht grün und hakt ab. Genau so war es gelaufen.
Die Prüfung meldet immer nur den ersten Baustein, über den sie stolpert. „Die Korrektur ist drin“ sagt also nichts darüber, ob sie vollständig ist.
Die Behebung
Gefehlt hat eine Zeile:
<authorizedType Assembly="Microsoft.Office.Workflow.Actions, Version=16.0.0.0,
Culture=neutral, PublicKeyToken=null"
Namespace="Microsoft.Office.Workflow.Actions"
TypeName="*" Authorized="True" />Sie gehört in den Abschnitt <authorizedTypes> unter targetFx für .NET 4.0, direkt zu den anderen. Von Hand geht das natürlich, aber bei mehreren Zonen und erst recht bei mehreren Servern will man das skripten — inklusive Sicherung vorher und einer XML-Prüfung hinterher, damit man sich die Datei nicht zerschießt:
Copy-Item $pfad "$pfad.$(Get-Date -f yyyyMMdd-HHmmss).bak"
$xml = [xml](Get-Content $pfad)
$liste = $xml.SelectSingleNode("//authorizedTypes/targetFx[@version='v4.0']")
$neu = $xml.CreateElement("authorizedType")
$neu.SetAttribute("Assembly", "Microsoft.Office.Workflow.Actions, Version=16.0.0.0, Culture=neutral, PublicKeyToken=null")
$neu.SetAttribute("Namespace", "Microsoft.Office.Workflow.Actions")
$neu.SetAttribute("TypeName", "*")
$neu.SetAttribute("Authorized", "True")
$liste.AppendChild($neu) | Out-Null
$xml.Save($pfad)
[xml](Get-Content $pfad) | Out-Null # kracht, wenn das XML kaputt istDie Sicherung besser nicht als web.config.bak neben die Originaldatei legen — das Verzeichnis ist übers Web erreichbar. Lieber in einen Ordner außerhalb.
Dann iisreset, sonst passiert gar nichts. Danach liefen die Workflows wieder.
Noch zwei Sachen, über die man stolpern kann: In einer Mehrserverfarm liegen diese Dateien lokal und nicht in der Konfigurationsdatenbank, man muss also auf jeden Server. Und die vorhandenen Einträge mit echtem Token bleiben stehen — die werden weiter gebraucht, für Definitionen, die den Baustein mit Signatur deklarieren. Beide Schreibweisen nebeneinander sehen nach Dublette aus, sind aber der Normalfall.
Hinterher nachsehen, ob es wirklich sitzt
Derselbe Zählbefehl wie oben, nur diesmal über alle Zonen auf einmal. Am Ende soll für jeden der beiden Namespaces beides dastehen, signiert und null:
Get-SPWebApplication | ForEach-Object {
foreach ($iis in $_.IisSettings.Values) {
$datei = Join-Path $iis.Path.FullName "web.config"
if (-not (Test-Path $datei)) { continue }
$xml = [xml](Get-Content $datei)
foreach ($ns in "Microsoft.Office.Workflow.Actions",
"Microsoft.SharePoint.WorkflowActions") {
$treffer = $xml.SelectNodes("//authorizedType") |
Where-Object { $_.Namespace -eq $ns }
$mitNull = @($treffer | Where-Object { $_.Assembly -match "PublicKeyToken=null" }).Count
[PSCustomObject]@{
Zone = $iis.ServerComment
Namespace = $ns.Split('.')[-1]
Gesamt = @($treffer).Count
MitNull = $mitNull
Status = if ($mitNull -gt 0) { "OK" } else { "FEHLT" }
}
}
}
} | Format-Table -AutoSizeWenn da überall OK steht, kann man den Workflow anwerfen.
Der Notbehelf, den man überall liest
In etlichen Foren steht diese Zeile:
$farm = Get-SPFarm
$farm.EnablePreParseSecurityCheckForWorkflow = $false
$farm.Update()Wirkt sofort und löst das Symptom zuverlässig. Schaltet dummerweise genau die Sicherheitsprüfung ab, wegen der das Update überhaupt kam — farmweit und dauerhaft. Einen einzelnen Baustein gezielt freizugeben dauert ein paar Minuten länger. Die würde ich investieren.
Falls danach immer noch was klemmt
Weil die Meldung nur den ersten blockierten Baustein nennt, können weitere nachkommen. Das Vorgehen bleibt gleich: Workflow starten, Uhrzeit merken, den ULS-Auszug von oben nochmal ziehen und nach Block the namespace suchen. Die Zeile nennt Assembly, Version und Token des nächsten fehlenden Eintrags.
Diese Werte dann wörtlich übernehmen, inklusive eines etwaigen PublicKeyToken=null. Daran scheitert es ja gerade.
Quellen
- Trending Issue zum Juni-2026-CU, zu „This feature has been temporarily disabled“
- Trending Issue zum Juli-2026-CU, zu „Potentially malicious xoml node“
Dieser Beitrag wurde teilweise mit Hilfe von KI erstellt und automatisiert veröffentlicht.