Adam Conkle from Microsoft has created a PowerShell script that helps you change the service account in use by ADFS v2.x (ADFS v2.0 on W2K8 and W2K8R2 and ADFS v2.1 on W2K12). The original script can be found here. The original script, and my updated script, do not support ADFS v3.0.
–
My opinion was that the script could be enhanced with better logic. My version of the script also supports the conversion from ADFS in StandAlone mode to ADFS in Farm mode. My version of the script can be found here.
–
Below you can find the changes that I made and of course "why?" Taking the original script into account replace the sections mentioned below, or get the final script using the link above
–
!!! DISCLAIMER/REMARKS !!!:
- The script is freeware, you are free to distribute it, but always refer to this website as the location where you got it
- This script is really really really dangerous!
- This script is furnished "as is". No warranty is expressed or implied!
- Always test first in lab environment to see if it meets your needs!
- Use this script at your own risk!
- I do not warrant this script to be fit for any purpose, use or environment
- I have tried to check everything that needed to be checked, but I do not guarantee the script does not have bugs.
- I do not guarantee the script will not damage or destroy your system(s), environment or whatever.
- I do not accept liability in any way if you screw up, use the script wrong or in any other way where damage is caused to your environment/systems!
- If you do not accept these terms do not use the script and delete it immediately!
!!! DISCLAIMER/REMARKS !!!:
–
REMOVING THE DEPENDENCY OF NTRIGHTS TO CONFIGURE THE REQUIRED USER RIGHTS
REPLACE THE FOLLOWING
Function AddUserRights
{
$RightsFailed = $false
NTRights.Exe -u $NewName +r SeServiceLogonRight | Out-File $LogPath -Append
If (!$?)
{
$RightsFailed = $true
Write-Host "`tFailed to add user rights for $NewName`n`tSee: POST-SAMPLE ITEMS THAT MUST BE EXECUTED MANUALLY" -ForegroundColor "yellow" -NoNewline
($ElapsedTime.Elapsed.ToString())+ "[WARN] Failed to add user rights for ${NewName}: 'Log on as a service', 'Generate security audits'" | Out-File $LogPath -Append
Return $RightsFailed
}
NTRights.Exe -u $NewName +r SeAuditPrivilege | Out-File $LogPath -Append
If (!$?)
{
$RightsFailed = $true
Write-Host "`tFailed to add user rights for $NewName`n`tSee: POST-SAMPLE ITEMS THAT MUST BE EXECUTED MANUALLY" -ForegroundColor "yellow" -NoNewline
($ElapsedTime.Elapsed.ToString())+ "[WARN] Failed to add user rights for ${NewName}: 'Log on as a service', 'Generate security audits'" | Out-File $LogPath -Append
Return $RightsFailed
}
Else
{
GPUpdate /Force | Out-File $LogPath -Append
$RightsFailed = $false
Write-Host "`tSuccess" -ForegroundColor "green" -NoNewline
($ElapsedTime.Elapsed.ToString())+" [INFO] User rights 'Log on as a service', 'Generate security audits' added for $NewName" | Out-File $LogPath -Append
}
Return $RightsFailed
}
WITH THE FOLLOWING
Function AddUserRights
{
$RightsFailed = $null
$tempPath = [System.IO.Path]::GetTempPath()
$import = Join-Path -Path $tempPath -ChildPath "import.inf"
if(Test-Path $import) {Remove-Item -Path $import -Force}
$export = Join-Path -Path $tempPath -ChildPath "export.inf"
if(Test-Path $export) {Remove-Item -Path $export -Force}
$secedt = Join-Path -Path $tempPath -ChildPath "secedt.sdb"
if(Test-Path $secedt) {Remove-Item -Path $secedt -Force}
Write-Host (" Granting 'Allow Logon As Service' to $NewName")
Write-Host (" Granting 'Generate Security Audits' to $NewName")
($ElapsedTime.Elapsed.ToString())+" [WORK ITEM] Grant SeServiceLogonRight to $NewName" | Out-File $LogPath -Append
($ElapsedTime.Elapsed.ToString())+" [WORK ITEM] Grant SeAuditPrivilege to $NewName" | Out-File $LogPath -Append
secedit /export /cfg $export /quiet
$currentSeServiceLogonRightSIDs = (Select-String $export -Pattern "SeServiceLogonRight").Line
$newSeServiceLogonRightSIDs = $currentSeServiceLogonRightSIDs
$currentSeAuditPrivilegeSIDs = (Select-String $export -Pattern "SeAuditPrivilege").Line
$newSeAuditPrivilegeSIDs = $currentSeAuditPrivilegeSIDs
$oldSidString = $OldSID.Value
$newSidString = $NewSID.Value
# Processing Allow Logon As Service
If ($newSeServiceLogonRightSIDs -match $oldSidString -And $oldSidString -ne "S-1-5-19" -And $oldSidString -ne "S-1-5-20") {
$newSeServiceLogonRightSIDs = $newSeServiceLogonRightSIDs.replace(",*$oldSidString","")
$newSeServiceLogonRightSIDs = $newSeServiceLogonRightSIDs.replace("*$oldSidString,","")
}
If ($newSeServiceLogonRightSIDs -notmatch $newSidString) {
$newSeServiceLogonRightSIDs = $newSeServiceLogonRightSIDs + ",*" + $newSidString
}
$newSeServiceLogonRightSIDs = $newSeServiceLogonRightSIDs.replace("Classic .NET AppPool","IIS AppPool\Classic .NET AppPool")
# Processing Allow Generate Security Audits
If ($newSeAuditPrivilegeSIDs -match $oldSidString -And $oldSidString -ne "S-1-5-19" -And $oldSidString -ne "S-1-5-20") {
$newSeAuditPrivilegeSIDs = $newSeAuditPrivilegeSIDs.replace(",*$oldSidString","")
$newSeAuditPrivilegeSIDs = $newSeAuditPrivilegeSIDs.replace("*$oldSidString,","")
}
If ($newSeAuditPrivilegeSIDs -notmatch $newSidString) {
$newSeAuditPrivilegeSIDs = $newSeAuditPrivilegeSIDs + ",*" + $newSidString
}
$newSeAuditPrivilegeSIDs = $newSeAuditPrivilegeSIDs.replace("Classic .NET AppPool","IIS AppPool\Classic .NET AppPool")
# Populate the import file
ForEach ($line in @("[Unicode]", "Unicode=yes", "[System Access]", "[Event Audit]", "[Registry Values]", "[Version]", "signature=`"`$CHICAGO$`"", "Revision=1", "[Profile Description]", "Description=Security Template To Configure Server For ADFS", "[Privilege Rights]", $newSeServiceLogonRightSIDs, $newSeAuditPrivilegeSIDs)){
Add-Content $import $line
}
secedit /import /db $secedt /cfg $import /quiet
If (!$?)
{
$secEditResult1 = "fail"
}
Else
{
$secEditResult1 = "success"
}
secedit /configure /db $secedt /quiet
If (!$?)
{
$secEditResult2 = "fail"
}
Else
{
$secEditResult2 = "success"
}
If ($secEditResult1 -eq "fail" -or $secEditResult2 -eq "fail")
{
$RightsFailed = $true
Write-Host "`tFailed to add user rights for $NewName`n`tSee: POST-SAMPLE ITEMS THAT MUST BE EXECUTED MANUALLY" -ForegroundColor "yellow" -NoNewline
($ElapsedTime.Elapsed.ToString())+ " [WARN] Failed to add user rights for ${NewName}: 'Log on as a service', 'Generate security audits'" | Out-File $LogPath -Append
}
If ($secEditResult1 -eq "success" -and $secEditResult2 -eq "success")
{
GPUpdate /Force | Out-File $LogPath -Append
$RightsFailed = $false
Write-Host "`tSuccess" -ForegroundColor "green" -NoNewline
($ElapsedTime.Elapsed.ToString())+" [INFO] User rights 'Log on as a service', 'Generate security audits' added for $NewName" | Out-File $LogPath -Append
}
Remove-Item -Path $import -Force
Remove-Item -Path $export -Force
Remove-Item -Path $secedt -Force
Return $RightsFailed
}
–
WHEN USING ADFS MANAGED SELF-SIGNED CERTIFICATES ALSO REMOVING THE PERMISSIONS FROM THE OLD SERVICE ACCOUNT
REPLACE THE FOLLOWING
Function Set-CertificateSharingContainerSecurity
{
param([String]$NewSID)
$FailedLdap = $false
# Get the new SID as a SID object and create AD Access Rules
$objNewSID = [System.Security.Principal.SecurityIdentifier]$NewSID
$RuleCreateChild = New-Object System.DirectoryServices.ActiveDirectoryAccessRule($objNewSID,'CreateChild','Allow','All')
$RuleSelf = New-Object System.DirectoryServices.ActiveDirectoryAccessRule($objNewSID,'Self','Allow','All')
$RuleWriteProperty = New-Object System.DirectoryServices.ActiveDirectoryAccessRule($objNewSID,'WriteProperty','Allow','All')
$RuleGenericRead = New-Object System.DirectoryServices.ActiveDirectoryAccessRule($objNewSID,'GenericRead','Allow','All')
# Get the LDAP object based on the certificate sharing container and add the AD Access Rules to the object
$DN = ($ADFSProperties.CertificateSharingContainer).ToString()
$objLDAP = [ADSI] "LDAP://$DN"
$objLDAP.get_ObjectSecurity().AddAccessRule($RuleCreateChild)
$objLDAP.get_ObjectSecurity().AddAccessRule($RuleSelf)
$objLDAP.get_ObjectSecurity().AddAccessRule($RuleWriteProperty)
$objLDAP.get_ObjectSecurity().AddAccessRule($RuleGenericRead)
# Commit the AD Access rule changes to the LDAP object
$objLDAP.CommitChanges()
If (!$?)
{
Write-Host "`tFailed to set permissions on the Certificate Sharing Container.`n`tSee: POST-SAMPLE ITEMS THAT MUST BE EXECUTED MANUALLY" -ForegroundColor "yellow" -NoNewline
($ElapsedTime.Elapsed.ToString())+" [ERROR] Failed setting permissions on AD cert sharing container: $DN. $NewName needs 'Create Child', 'Write', 'Read'." | Out-File $LogPath -Append
$FailedLdap = $true
}
Else
{
Write-Host "`tSuccess" -ForegroundColor "green" -NoNewline
($ElapsedTime.Elapsed.ToString())+" [INFO] Set permissions on cert sharing container: $DN" | Out-File $LogPath -Append
}
}
WITH THE FOLLOWING
Function Set-CertificateSharingContainerSecurity
{
param(
$OldSID,
$NewSID
)
$FailedLdap = $null
# Create AD Access Rules
$objOldSID = [System.Security.Principal.SecurityIdentifier]$OldSID
$objNewSID = [System.Security.Principal.SecurityIdentifier]$NewSID
$accessRuleCreateChild = New-Object System.DirectoryServices.ActiveDirectoryAccessRule($objNewSID,'CreateChild','Allow','All')
$accessRuleSelf = New-Object System.DirectoryServices.ActiveDirectoryAccessRule($objNewSID,'Self','Allow','All')
$accessRuleWriteProperty = New-Object System.DirectoryServices.ActiveDirectoryAccessRule($objNewSID,'WriteProperty','Allow','All')
$accessRuleGenericRead = New-Object System.DirectoryServices.ActiveDirectoryAccessRule($objNewSID,'GenericRead','Allow','All')
# Get the LDAP object based on the certificate sharing container
# REMOVE the AD Access Rules for the OLD service account
# ADD the AD access Rules for the NEW service account
$certSharingContainer = $ADFSProperties.CertificateSharingContainer
$DN = $certSharingContainer.ToString()
$objLDAPpath = [ADSI] "LDAP://$DN"
$objACL = $objLDAPpath.objectSecurity
$objACL.PurgeAccessRules($objOldSID)
If (!$?)
{
$objACLresult1 = "fail"
Write-Host "objACLresult1"
}
Else
{
$objACLresult1 = "success"
}
$objACL.AddAccessRule($accessRuleCreateChild)
If (!$?)
{
$objACLresult2 = "fail"
Write-Host "objACLresult2"
}
Else
{
$objACLresult2 = "success"
}
$objACL.AddAccessRule($accessRuleSelf)
If (!$?)
{
$objACLresult3 = "fail"
Write-Host "objACLresult3"
}
Else
{
$objACLresult3 = "success"
}
$objACL.AddAccessRule($accessRuleWriteProperty)
If (!$?)
{
$objACLresult4 = "fail"
Write-Host "objACLresult4"
}
Else
{
$objACLresult4 = "success"
}
$objACL.AddAccessRule($accessRuleGenericRead)
If (!$?)
{
$objACLresult5 = "fail"
Write-Host "objACLresult5"
}
Else
{
$objACLresult5 = "success"
}
$objLDAPpath.objectSecurity = $objACL
$objLDAPpath.CommitChanges()
If (!$?)
{
$objACLresult6 = "fail"
Write-Host "objACLresult6"
}
Else
{
$objACLresult6 = "success"
}
If ($objACLresult1 -eq "fail" -or $objACLresult2 -eq "fail" -or $objACLresult3 -eq "fail" -or $objACLresult4 -eq "fail" -or $objACLresult5 -eq "fail" -or $objACLresult6 -eq "fail")
{
Write-Host "`tFailed to set permissions on the Certificate Sharing Container.`n`tSee: POST-SAMPLE ITEMS THAT MUST BE EXECUTED MANUALLY" -ForegroundColor "yellow" -NoNewline
($ElapsedTime.Elapsed.ToString())+" [ERROR] Failed setting permissions on AD cert sharing container: $DN. $NewName needs 'Create Child', 'Write', 'Read'." | Out-File $LogPath -Append
$FailedLdap = $true
}
If ($objACLresult1 -eq "success" -and $objACLresult2 -eq "success" -and $objACLresult3 -eq "success" -and $objACLresult4 -eq "success" -and $objACLresult5 -eq "success" -and $objACLresult6 -eq "success")
{
Write-Host "`tSuccess" -ForegroundColor "green" -NoNewline
($ElapsedTime.Elapsed.ToString())+" [INFO] Set permissions on cert sharing container: $DN" | Out-File $LogPath -Append
$FailedLdap = $false
}
}
–
WHEN USING ADFS MANAGED SELF-SIGNED CERTIFICATES ALSO REMOVING THE PERMISSIONS FROM THE OLD SERVICE ACCOUNT
REPLACE THE FOLLOWING (2x)
Start sqlcmd.exe -ArgumentList
WITH THE FOLLOWING (2x)
&'Start' $sqlCmdFullPath -ArgumentList
–
WHEN CONVERTING FROM STANDALONE MODE TO FARM MODE THE CERTIFICATE SHARING CONTAINER NEEDS TO BE CREATED FIRST
REPLACE THE FOLLOWING
####STOP THE AD FS WINDOWS SERVICE####
WITH THE FOLLOWING
####CREATE/CONFIGURE CERT SHARING CONTAINER IF STANDALONE####
If ((($OldName).ToString() -eq "NT AUTHORITY\NETWORK SERVICE") -or (($OldName).ToString() -eq "NT AUTHORITY\LOCAL SYSTEM"))
{
Write-Host "`n Configuring the Certificate Sharing Container in AD"
($ElapsedTime.Elapsed.ToString())+" [WORK ITEM] Configuring the Certificate Sharing Container" | Out-File $LogPath -Append
Set-ADFSCertSharingContainer -ServiceAccount $(($OldName).ToString())
$ADFSProperties = Get-ADFSProperties
If (!$?)
{
Write-Host "`tThe Cert Sharing Container could not be created/configured.`n`tExiting`n" -ForegroundColor "red"
($ElapsedTime.Elapsed.ToString())+" [ERROR] The Cert Sharing Container could not be created/configured" | Out-File $LogPath -Append
exit
}
Else
{
Write-Host "`tSuccess" -ForegroundColor "green" -NoNewline
($ElapsedTime.Elapsed.ToString())+" [INFO] Cert Sharing Container has been created/configured" | Out-File $LogPath -Append
}
}
####STOP THE AD FS WINDOWS SERVICE####
–
DETECTING THE AVAILABILITY OF SQLCMD.EXE THROUGH THE PATH VARIABLE AND THROUGH A PRE-DEFINED FOLDER
REPLACE THE FOLLOWING
Write-Host "`n Detecting SQLCmd.exe"
($ElapsedTime.Elapsed.ToString())+" [WORK ITEM] Detecting SQLCMD.exe" | Out-File $LogPath -Append
$SQLCmdPresent = $false
sqlcmd.exe /? | Out-Null
If (!$?)
{
Write-Host "`tSQLCmd.exe was not found`n`tSee: POST-SAMPLE ITEMS THAT MUST BE EXECUTED MANUALLY." -ForegroundColor "yellow" -NoNewline
($ElapsedTime.Elapsed.ToString())+" [WARN] SQLCMD.exe not found. SQL scripts must be manually executed." | Out-File $LogPath -Append
}
Else
{
Write-Host "`tSuccess" -ForegroundColor "green" -NoNewline
($ElapsedTime.Elapsed.ToString())+" [INFO] SQLCMD.exe found" | Out-File $LogPath -Append
$SQLCmdPresent = $true
}
WITH THE FOLLOWING
Write-Host "`n Detecting SQLCmd.exe"
($ElapsedTime.Elapsed.ToString())+" [WORK ITEM] Detecting SQLCMD.exe" | Out-File $LogPath -Append
$SQLCmdPresent = $false
# Let's try to find SQLCMD.EXE the easy way. If that fails, because SQLCMD.EXE is installed, but its path has not been registered in the PATH variable, try to search for it
$sqlCmdFullPath = $null
$sqlCmdFullPath = WHERE.EXE SQLCMD.EXE
If ($sqlCmdFullPath -eq $null) {
$enumSQLCMDinstances = Get-ChildItem -path 'C:\Program Files\Microsoft SQL Server' -Recurse -Filter 'SQLCMD.EXE'
$sqlCmdCount = ($enumSQLCMDinstances | Measure-Object).Count
If ($sqlCmdCount -eq 0) {
Write-Host "`tSQLCmd.exe was not found`n`tSee: POST-SAMPLE ITEMS THAT MUST BE EXECUTED MANUALLY." -ForegroundColor "yellow" -NoNewline
($ElapsedTime.Elapsed.ToString())+" [WARN] SQLCMD.exe not found. SQL scripts must be manually executed." | Out-File $LogPath -Append
} Else {
If ($sqlCmdCount -eq 1) {
$sqlCmdFullPath = $enumSQLCMDinstances.FullName
}
If ($sqlCmdCount -gt 1) {
$sqlCmdFullPath = $enumSQLCMDinstances[0].FullName
}
Write-Host "`tSuccess" -ForegroundColor "green" -NoNewline
($ElapsedTime.Elapsed.ToString())+" [INFO] SQLCMD.exe found" | Out-File $LogPath -Append
$SQLCmdPresent = $true
}
}
–
DETERMINE WHETHER THE CERTIFICATE SHARING CONTAINER IS USED OR NOT BY CHECKING IF AUTOCERTROLLOVER IS ENABLED
REPLACE THE FOLLOWING
####ACL THE CERTIFICATE SHARING CONTAINER FOR THE NEW SERVICE ACCOUNT####
# Only execute if this is the first federation server
if ($Mode -eq 2)
{
# Check if CertificateSharingContainer has a value. If it does, ACL the container for the new service account.
If ($ADFSProperties.CertificateSharingContainer -ne $null)
{
Write-Host "`n Providing $NewName access to the Certificate Sharing Container"
($ElapsedTime.Elapsed.ToString())+" [WORK ITEM] Providing $NewName access to ($ADFSProperties.CertificateSharingContainer).ToString()" | Out-File $LogPath -Append
Set-CertificateSharingContainerSecurity -NewSID $NewSID
}
}
WITH THE FOLLOWING
####ACL THE CERTIFICATE SHARING CONTAINER FOR THE NEW SERVICE ACCOUNT####
# Only execute if this is the first federation server
if ($Mode -eq 2)
{
# Check if certificate rollover is enabled. If it is, ACL the container for the new service account.
# The presence of the cert sharing container only proves you are using ADFS managed self-signed certs OR have used them!
If ($ADFSProperties.AutoCertificateRollover -eq $true)
{
Write-Host "`n Providing $NewName access to the Certificate Sharing Container"
($ElapsedTime.Elapsed.ToString())+" [WORK ITEM] Providing $NewName access to ($ADFSProperties.CertificateSharingContainer).ToString()" | Out-File $LogPath -Append
Set-CertificateSharingContainerSecurity -OldSID $OldSID -NewSID $NewSID
}
}
–
Cheers,
Jorge
———————————————————————————————
* This posting is provided "AS IS" with no warranties and confers no rights!
* Always evaluate/test yourself before using/implementing this!
* DISCLAIMER:
https://jorgequestforknowledge.wordpress.com/disclaimer/
———————————————————————————————
############### Jorge’s Quest For Knowledge #############
#########
http://JorgeQuestForKnowledge.wordpress.com/ ########
———————————————————————————————
Like this:
Like Loading...