After the September 2020 Security update was released, we have seen many people (including myself) writing the Safe Controls incorrectly. I still reference and read KB4572409 for advice on how to find the Type, Namespace, and Assembly strong name.
I decided to simplify the process. This PowerShell script creates a function Build-SafeControlFromEntry. This builds the Safe Control from the error in the ULS log. Look for EventID 9tmwc
Copy this over to $ULS and pipe it into the function as seen below:
If we’re unable to build the safe controls this message will appear:
PowerShell below:
##Build-SafeControlFromEntry
##Author:adamsor; adamsorenson.com
##Version: 1.0
###Example###
##$ULS = "The type Contoso.Customizations.WebPartControl, Contoso.WebParts, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b03f5f8f11d50a3a could not be found or it is not registered as safe."
##$ULS | Build-SafeControlFromEntry
Function Build-SafeControlFromEntry
{
param([Parameter(ValueFromPipeline=$true)]$string)
#This code calls to a Microsoft web endpoint to track how often it is used.
#No data is sent on this call other than the application identifier
Add-Type -AssemblyName System.Net.Http
$client = New-Object -TypeName System.Net.Http.Httpclient
$cont = New-Object -TypeName System.Net.Http.StringContent($null,[system.text.encoding]::UTF8,"application/json")
$tsk = $client.PostAsync("https://msapptracker.azurewebsites.net/api/Hits/4b89c98c-473b-4fe3-8f8e-5552f13b0e30",$cont)
#if you want to make sure the call completes, add this to the end of your code
#$tsk.Wait()
$wcSafeControl = $null
$typeSafeControl = $null
[int]$indexc = $string.IndexOf('The type')
$indexTc = $indexc + 9
$string2 = $string.Substring($indexTc)
[int]$indexend = $string2.IndexOf("could not be found or it is not registered as safe.")
$string3 = $string2.Substring(0, $indexend)
$fcoma = $string3.IndexOf(",")
$nt = $string3.Substring(0,$fcoma)
$ASN = ($string3.Substring($fcoma+2)).Trim()
$type = $nt.Substring($nt.LastIndexOf(".")+1)
$namespace = $nt.Substring(0, $nt.LastIndexOf("."))
If($ASN -ne $null -and $namespace -ne $null -and $type -ne $null)
{
$wcSafeControl = '<SafeControl Assembly="'+$ASN+'" Namespace="'+$namespace+'" TypeName="*" Safe="True" />'
$typeSafeControl = '<SafeControl Assembly="'+$ASN+'" Namespace="'+$namespace+'" TypeName="'+$type+'" Safe="True" />'
Write-host "SafeControls build successfully. Use either Wildcard or Explicit in all of the web.configs from this web application" -ForegroundColor Green
Write-host "Wildcard SafeControl" -ForegroundColor Yellow
$wcSafeControl
Write-Host "Explicit type SafeControl" -ForegroundColor Yellow
$typeSafeControl
}
Else
{
Write-Host "Unable to find safe control from ULS entry. Please look for 9tmwc for event ID. Check KB" -ForegroundColor Red
Write-Host "Example:" -ForegroundColor Red
write-host "The type Contoso.Customizations.WebPartControl, Contoso.WebParts, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b03f5f8f11d50a3a could not be found or it is not registered as safe."
}
}


