SCCM Script: Fix Kerberos Authentication Errors

Overview

At times, SCCM client machines may lose the ability to communicate properly with the SCCM site server due to Kerberos authentication errors. You will see these errors in Deployment Statuses or other times invoking PowerShell scripts on remote clients.

This script attempts to invoke a generic script remotely on an imported set of SCCM clients and determine if there is a Kerberos authentication error:

 Invoke-Command -ComputerName $h -ScriptBlock { Test-Connection SCCMSERVER -Quiet -Count 1 } -ErrorAction Stop 

If the invocation returns the exception error System.Management.Automation.Remoting.PSRemotingTransportException you can assume there is an error and we can remotely instruct a CLI through WinRM:

 $command = "C:\ADMIN`\PSTools\PsExec.exe \\$h /s /accepteula /nobanner cmd /c `"Winrm quickconfig /q`"" 

Therefor it is a prerequisite that you have PsExec.exe in the C:\ADMIN\PSTools\ directory of the PC before running the script, as shown above.

The script will also try to resolve DNS issues that may be related to the error.

Fixing Kerberos Errors on an Imported List of Computers

You can import a generic list of computers via a CSV that is in the following format:

 Fix-DGMKerberosError –CSV \\Pathto\the.csv 

Logging Output

The function outputs its progress to a log file and is fully compatible with CMTrace.exe.

PowerShell Function

 
<#
.Synopsis
   Fix SCCM Kerberos Errors
.DESCRIPTION
   The tool, Fix-DMGKerberosError.ps1 was written by David Maiolo which will attempt to fix Kerberos Authentican Issues on remote computers.
.EXAMPLE
   Fix-DMGKerberosError -CSVFile kerberos_error_import.csv
.EXAMPLE
   Fix-DMGKerberosError -Hostname LT061222
#>


function LogIt
{
  param (
  [Parameter(Mandatory=$true)]
  $message,
  [Parameter(Mandatory=$true)]
  $component,
  [Parameter(Mandatory=$true)]
  $type )

  switch ($type)
  {
    1 { $type = "Info" }
    2 { $type = "Warning" }
    3 { $type = "Error" }
    4 { $type = "Verbose" }
  }

  if (($type -eq "Verbose") -and ($Global:Verbose))
  {
    $toLog = "{0} `$$<{1}><{2} {3}><thread={4}>" -f ($type + ":" + $message), ($Global:ScriptName + ":" + $component), (Get-Date -Format "MM-dd-yyyy"), (Get-Date -Format "HH:mm:ss.ffffff"), $pid
    $toLog | Out-File -Append -Encoding UTF8 -FilePath ("filesystem::{0}" -f $Global:LogFile)
    Write-Host $message
  }
  elseif ($type -ne "Verbose")
  {
    $toLog = "{0} `$$<{1}><{2} {3}><thread={4}>" -f ($type + ":" + $message), ($Global:ScriptName + ":" + $component), (Get-Date -Format "MM-dd-yyyy"), (Get-Date -Format "HH:mm:ss.ffffff"), $pid
    $toLog | Out-File -Append -Encoding UTF8 -FilePath ("filesystem::{0}" -f $Global:LogFile)
    if ($type -eq 'Info') { Write-Host $message }
    if ($type -eq 'Warning') { Write-Host $message -ForegroundColor Yellow}
    if ($type -eq 'Error') { Write-Host $message -ForegroundColor Red}
    

  }
  if (($type -eq 'Warning') -and ($Global:ScriptStatus -ne 'Error')) { $Global:ScriptStatus = $type }
  if ($type -eq 'Error') { $Global:ScriptStatus = $type }

  if ((Get-Item $Global:LogFile).Length/1KB -gt $Global:MaxLogSizeInKB)
  {
    $log = $Global:LogFile
    Remove-Item ($log.Replace(".log", ".lo_"))
    Rename-Item $Global:LogFile ($log.Replace(".log", ".lo_")) -Force
  }
} 

function GetScriptDirectory
{
  $invocation = (Get-Variable MyInvocation -Scope 1).Value
  Split-Path $invocation.MyCommand.Path
} 

function Fix-DMGKerberosError
{
    [CmdletBinding()]
    [Alias()]
    [OutputType([int])]
    Param
    (
        # Param1 help description
        [Parameter(Mandatory=$true,
                   ValueFromPipeline=$true,
                   Position=0,
                   ParameterSetName='Parameter Set 1')]
                   [ValidateScript({(Test-Path $_)})]
                   $CSVFile,
        # Param2 help description
        [Parameter(Mandatory=$true,
                   ValueFromPipeline=$true,
                   Position=0,
                   ParameterSetName='Parameter Set 2')]
                   [ValidateScript({(Get-ADComputer -Identity $_).objectclass -eq 'computer' })]
                   [String]$Hostname
    )

    Begin
    {
        $path = (get-item -Path .).FullName 
        
        if ($CSVFile -ne $null){
            Write-Host Importing $CSVFile...
            $csv = import-csv "$CSVFile"
        }else{
            $csv = [PSCustomObject]@{
                Hostname = $Hostname}
        }
        Write-Host ==========================================
        Write-Host SCCM Kerberos Remote Execution Fix Tool
        Write-Host ==========================================
        Write-Host "v0.1 (2017-12-20) by dmaiolo"
        LogIt -message ("Starting Logging for Fix-DMGKerberosError") -component "Main()" -type 1 
    }
    Process
    {
    

    $computers = @();
        
    $csv | foreach-object {
        $h = $_.Hostname
    

        if(Test-Connection -ComputerName $h -Count 1 -Quiet){

            Write-Host "$h`: Invoking Generic Command (Test-Connection SCCMSERVER -Quiet -Count 1)..."
            Try{
                Invoke-Command -ComputerName $h -ScriptBlock { Test-Connection SCCMSERVER -Quiet -Count 1 } -ErrorAction Stop
                LogIt -message ("$h`: Generic Command (Test-Connection SCCMSERVER -Quiet -Count 1) Ran Succesfully. No Fix Required.") -component "Main()" -type 1
            }
            Catch [System.Management.Automation.Remoting.PSRemotingTransportException]{
                LogIt -message ("$h`: Kerberos Issue Detected. Fix Required") -component "Main()" -type 2
                Write-Host "$h`: Attempting to Repair WinRM for Kerberos Authentication..."
                $command = "C:\ADMIN`\PSTools\PsExec.exe \\$h /s /accepteula /nobanner cmd /c `"Winrm quickconfig /q`""
                if($expression = Invoke-Expression -Command:"$command" -ErrorAction Stop) {
                    LogIt -message ("$h`: WinRM Repair Ran Succesfully for Kerberos Authentication") -component "Main()" -type 1
                    }
                else{
                    LogIt -message ("$h`: WinRM Repair NOT Succesfull for Kerberos Authentication") -component "Main()" -type 3
                    LogIt -message ("$h`: Attempting DNS Repair by running PsExec for ipconfig /registerdns against the IP Address... ") -component "Main()" -type 1
                    try{
                        $IPv4AddressPinged = (Test-Connection -ComputerName $h -Count 1 -ErrorAction SilentlyContinue).IPV4Address.IPAddressToString
                        LogIt -message ("$h`: Found a valid IP Address To Invoke-Expression against ($IPv4AddressPinged).") -component "Main()" -type 1
                        $RealHostName = (Resolve-DnsName $IPv4AddressPinged).NameHost
                        LogIt -message ("$h`: Your DNS has accociated $h to $IPv4AddressPinged, but it acually belongs to $RealHostName. This is part of your problem.") -component "Main()" -type 1
                        
                    }
                    catch{
                        LogIt -message ("$h`: No Valid IP Address for this host could be determined.") -component "Main()" -type 3
                        $RealHostName = $false
                        $IPv4AddressPinged = $false
                    }
                    if ($IPv4AddressPinged){
                        $command2 = "C:\ADMIN\PSTools\PsExec.exe \\$IPv4AddressPinged /s /accepteula /nobanner cmd /c `"ipconfig /registerdns`""
                        if(Invoke-Expression -Command:"$command2"){
                            LogIt -message ("$h`: ($RealHostName) Succesfully Ran $command2.") -component "Main()" -type 1
                            Write-Host "$h`: ($RealHostName) Attempting to Repair WinRM for Kerberos Authentication against IP Address ($IPv4AddressPinged)..."
                            $command3 = "C:\ADMIN`\PSTools\PsExec.exe \\$IPv4AddressPinged /s /accepteula /nobanner cmd /c `"Winrm quickconfig /q`""
                            if($expression2 = Invoke-Expression -Command:"$command3" -ErrorAction Stop) {
                                LogIt -message ("$h`: ($RealHostName) WinRM Repair Ran Succesfully for Kerberos Authentication against IP Address ($IPv4AddressPinged)") -component "Main()" -type 1
                            }
                            else{
                                LogIt -message ("$h`: ($RealHostName) WinRM Repair NOT Succesfull for Kerberos Authentication against IP Address ($IPv4AddressPinged)") -component "Main()" -type 3
                               }
                        }
                        else{
                            LogIt -message ("$h`: ($RealHostName) Unable to Run $command2.") -component "Main()" -type 3
                        }
                    }
                 }
            }
            Catch{
                LogIt -message ("$h`: Generic Command (Test-Connection SCCMSERVER -Quiet -Count 1) Ran Into a Non-Kerberos Issue. Fix Unknown.") -component "Main()" -type 3
            }

        }
        else{
            LogIt -message ("$h`: is offline.") -component "Main()" -type 2
        }
       }
    }
    End
    {
       Write-Host ===============================================================
       Write-Host Log File of Results Generated at $Global:LogFile VIEW WITH CMTRACE.EXE
       LogIt -message ("Ending Logging for Fix-DMGKerberosError") -component "Main()" -type 1
    }
}

$VerboseLogging = "true"
[bool]$Global:Verbose = [System.Convert]::ToBoolean($VerboseLogging)
#$Global:LogFile = Join-Path (GetScriptDirectory) "Fix-DMGKerberosError_$(Get-Date -Format dd-MM-yyyy).log"
$Global:LogFile = Join-Path (GetScriptDirectory) "Fix-DMGKerberosError.log"
$Global:MaxLogSizeInKB = 10240
$Global:ScriptName = 'Fix-DMGKerberosError.ps1' 
$Global:ScriptStatus = 'Success'

Leave a Comment

Your email address will not be published.