vendredi 29 janvier 2016

Parseur de logs pour NPS (Network Policy Server)

Me revoilà avec quelques améliorations sur mon script pour interpréter les logs de IAS/NPS.
Je vous conseille de configurer votre serveur NPS pour effectuer une rotation quotidienne.

Le script est téléchargeable ici



Il n'est pas toujours simple d’interpréter ses logs de serveurs NPS ou IAS:


Et encore moins les causes de l’échec... qui sont représentées par un entier!

Ce script est là pour interpréter en PowerShell vos logs NPS et vous renvoyer les codes d'erreur (exemple de simulation):


Le chargement des logs s'effectue via mgmGet-NPSLogsFromFile
Sans option, la fenêtre suivante s'ouvre afin de sélectionner votre fichier de logs:


Vous pouvez aussi utiliser le paramètre -LogFile afin de spécifier le fichier de log à utiliser:
mgmGet-NPSLogsFromFile -LogFile "C:\Windows\System32\LogFiles\IN160129.log"

Lors des prochains appels de la fonction mgmGet-NPSLogsFromFile, le fichier de log précédent est utiliser. Pour changer de fichier, utilisez mgmGet-NPSLogsFromFile -LogFile "CheminDuNouveauLog" ou mgmGet-NPSLogsFromFile -LogFile "" pour afficher la fenêtre de sélection.

Pour voir les logs, tapez mgmView-NPSLogs :


Vous pouvez organiser l'affichage via les options -Wrap ou -AutoSize




-NoSuccess ou -Success permet de voir uniquement les requêtes en échec ou en réussite


Pour filter sur date et/ou heure: -Year -Month -Day -Hour -Minute -Second:


Afficher les n derniers enregistrements -Last :


Dont le nom du PC ou de l'utilisateur (ClientName) contient: -ClientName


L'option NasSource vous permet de filtrer par rapport au contrôleur qui à effectué l'authentification, et DisplayProperties vous permet de choisir les propriétés à afficher.

L'ensemble des informations se trouvent dans la variable $LogsNPS. Vous pouver faire vous-même vos filtres, comme par exemple: $LogsNPS | Where-Object { $_.ProxyPolicyName -eq "ConnectingUsersPolicy" } | Format-Table Proxy*,NPS*,ClientName -AutoSize  :


Le script en question:

#* FileName: NPSLogParser.ps1
#*=============================================================================
#* Script Name: [NPS Log Parser]
#* Created: [28/01/2016]
#* Modified: [01/03/2018]
#* Author: Grégory MERGOUX
#* Company: M.G.M Solutions
#* Email: gmergoux@mgmsolutions.fr
#* Web:
#* Reqrmnts: NPS with logging (ODBC)
#* Keywords:
#*=============================================================================
#* Purpose: This script get a specific log file from NPS server
#*
#*
#*=============================================================================

#*=============================================================================
#* REVISION HISTORY
#*=============================================================================
#* Date: [01/03/2018]
#* Time: [17:30]
#* Issue: Add ID for each rows
#* Solution:
#*
#*=============================================================================

Function mgmGet-NPSLogsFromFile{
param([string]$LogFile=$PreviousLogFile)
$Global:LogsNPS=@()
if($LogFile -eq "" -or $LogFile -eq $null){
    [System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") | Out-Null
    $OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog
    $OpenFileDialog.initialDirectory = "$((Get-Item Env:\SystemRoot).value)\System32\LOGFILES"
    $OpenFileDialog.filter = "All files (*.log)| *.log"
    $OpenFileDialog.ShowDialog() | Out-Null
    $LogFile=$OpenFileDialog.filename
}
$Global:PreviousLogFile=$LogFile
$MyFilePath=$LogFile
if($MyFilePath -ne "" -And $MyFilePath -ne $null){
    $Global:MyLogTempNPS=Import-Csv -Path $MyFilePath -Delimiter "," -Header "NPSServer","NPSService","Date","Hour","PacketType","ClientName","FQDNUserName","CallerIDStationTo","CallerIDStationFrom","CallBackNumber","FramedIP","NASSource","NASIPSource","NASPortSource","NASVendor","RadiusClientIP","RadiusClientName","TimestampEvent","NASPortLimit","NASPortType","ConnectInfo","Protocol","TypeUserOfService","AuthenticationType","NPSPolicyName","ReasonCode","Class","SessionTimeout","IdleTimeout","TerminationAction","EAPName","AcctStatusType","AcctDelayTime","AcctInputOctets","AcctOutputOctets","AcctSessionID","AcctAuth","AcctSessionTime","AcctInputPackets","AcctOutputPackets","AcctTerminateCause","AcctMultiSsnID","AcctLinkCount","AcctInterimInterval","TunnelType","TunnelMediumType","TunnelClientIP","TunnelServerIP","TunnelIdentifier","TunnelGroupID","TunnelAssignementID","TunnelPreference","MSAcctAuthType","MSAcctEAPType","MSRASVersion","MSRASVendor","MSCHAPError","MSCHAPDomain","MSMPPEEncryptionTypes","MSMPPEEncryptionPolicy","ProxyPolicyName","ProviderType","ProviderName","RemoteRadiusAuthenticationIP","MSRASClientName","MSRASClientVersion" | Select "NPSServer","NPSService",@{Expression={
        $Temp=($_.Date).Split("/")
        $TempDate=$Temp[1]+"/"+$Temp[0]+"/"+$Temp[2]
        $TempDate
    };Label="Date"},"Hour",@{Expression={
        Switch($_.PacketType){
            1 { "Access-Request" }
            2 { "Access-Accept" }
            3 { "Access-Reject" }
            4 { "Accounting-Request" }
            default { "N/A" }
        }
    };Label="PacketType"},"ClientName","FQDNUserName","CallerIDStationTo","CallerIDStationFrom","CallBackNumber","FramedIP","NASSource","NASIPSource","NASPortSource","NASVendor","RadiusClientIP","RadiusClientName","TimestampEvent","NASPortLimit","NASPortType","ConnectInfo","Protocol","TypeUserOfService",@{Expression={
        Switch($_.AuthenticationType){
            1 { "PAP" }
            2 { "CHAP" }
            3 { "MS-CHAP" }
            4 { "MS-CHAP V2" }
            5 { "EAP" }
            7 { "NONE" }
            8 { "Custom" }
            default { "N/A" }
        }
    };Label="AuthenticationType"},"NPSPolicyName",@{Expression={
        Switch($_.ReasonCode){
            0 { "IAS_SUCCESS" }
            1 { "IAS_INTERNAL_ERROR" }
            2 { "IAS_ACCESS_DENIED" }
            3 { "IAS_MALFORMED_REQUEST" }
            4 { "IAS_GLOBAL_CATALOG_UNAVAILABLE" }
            5 { "IAS_DOMAIN_UNAVAILABLE" }
            6 { "IAS_SERVER_UNAVAILABLE" }
            7 { "IAS_NO_SUCH_DOMAIN" }
            8 { "IAS_NO_SUCH_USER" }
            16 { "IAS_AUTH_FAILURE" }
            17 { "IAS_CHANGE_PASSWORD_FAILURE" }
            18 { "IAS_UNSUPPORTED_AUTH_TYPE" }
            32 { "IAS_LOCAL_USERS_ONLY" }
            33 { "IAS_PASSWORD_MUST_CHANGE" }
            34 { "IAS_ACCOUNT_DISABLED" }
            35 { "IAS_ACCOUNT_EXPIRED" }
            36 { "IAS_ACCOUNT_LOCKED_OUT" }
            37 { "IAS_INVALID_LOGON_HOURS" }
            38 { "IAS_ACCOUNT_RESTRICTION" }
            48 { "IAS_NO_POLICY_MATCH" }
            64 { "IAS_DIALIN_LOCKED_OUT" }
            65 { "IAS_DIALIN_DISABLED" }
            66 { "IAS_INVALID_AUTH_TYPE" }
            67 { "IAS_INVALID_CALLING_STATION" }
            68 { "IAS_INVALID_DIALIN_HOURS" }
            69 { "IAS_INVALID_CALLED_STATION" }
            70 { "IAS_INVALID_PORT_TYPE" }
            71 { "IAS_INVALID_RESTRICTION" }
            80 { "IAS_NO_RECORD" }
            96 { "IAS_SESSION_TIMEOUT" }
            97 { "IAS_UNEXPECTED_REQUEST" }
            default { "N/A" }
        }
    };Label="ReasonCode"},"Class","SessionTimeout","IdleTimeout","TerminationAction","EAPName","AcctStatusType","AcctDelayTime","AcctInputOctets","AcctOutputOctets","AcctSessionID","AcctAuth","AcctSessionTime","AcctInputPackets","AcctOutputPackets","AcctTerminateCause","AcctMultiSsnID","AcctLinkCount","AcctInterimInterval","TunnelType","TunnelMediumType","TunnelClientIP","TunnelServerIP","TunnelIdentifier","TunnelGroupID","TunnelAssignementID","TunnelPreference","MSAcctAuthType","MSAcctEAPType","MSRASVersion","MSRASVendor","MSCHAPError","MSCHAPDomain","MSMPPEEncryptionTypes","MSMPPEEncryptionPolicy","ProxyPolicyName",@{Expression={
        Switch($_.ProviderType){
            0 { "No authentication" }
            1 { "Authentication on local NPS" }
            2 { "Authentication to remote Radius" }
            default { "N/A" }
        }
    };Label="ProviderType"},@{Expression={
        Switch($_.ProviderName){
            0 { "None" }
            1 { "Windows" }
            2 { "Radius Proxy" }
            default { "N/A" }
        }
    };Label="ProviderName"},"RemoteRadiusAuthenticationIP","MSRASClientName","MSRASClientVersion"
    $Global:LogsNPS+=$MyLogTempNPS
    $Global:LogsNPS |% {$counter = -1} {$counter++; $_ | Add-Member -Name ID -Value $counter -MemberType NoteProperty}
    }else{
        Write-Host -ForegroundColor Red "Aucun fichier n'a été spécifié"
    }
}

function Format-Color([hashtable] $Colors = @{}, [switch] $SimpleMatch) {
 $lines = ($input | Out-String) -replace "`r", "" -split "`n"
 foreach($line in $lines) {
  $color = ''
  foreach($pattern in $Colors.Keys){
   if(!$SimpleMatch -and $line -match $pattern) { $color = $Colors[$pattern] }
   elseif ($SimpleMatch -and $line -like $pattern) { $color = $Colors[$pattern] }
  }
  if($color) {
   Write-Host -ForegroundColor $color $line
  } else {
   Write-Host $line
  }
 }
}

Function GetColoredLogs{
 $input | Format-Color @{'Access-Reject' = 'Red'; 'Access-Accept ' = 'Green'; 'Access-Request'='Yellow'; 'Accounting-Request'='Yellow'}
}

Function mgmView-NPSLogs{
    param([int]$Last=0, [switch]$NoColors=$false, [switch]$AutoSize=$false, [switch]$Wrap=$false, [switch]$SuccessOnly=$false, [switch]$NoSuccess=$false, [int]$Year, [int]$Month, [int]$Day, [int]$Hour, [int]$Minute, [int]$Second, [string]$ClientName="", [string]$NasSource="", [string[]]$DisplayProperties=@("ID","Date","Hour","NASSource","PacketType","ClientName","ReasonCode","NPSPolicyName","ProxyPolicyName"))
    $OriginalColor=$Host.UI.RawUI.ForegroundColor
    if($Last -ne 0){
        $MyLogs=$LogsNPS | Select-Object -Last $Last
    }else{
        $MyLogs=$LogsNPS
    }
    if($ClientName -ne ""){
        $MyLogs=$MyLogs | Where-Object { $_.ClientName -like "*$ClientName*" }
    }
    if($NasSource -ne ""){
        $MyLogs=$MyLogs | Where-Object { $_.NASSource -like "*$NasSource*" }
    }
    if($SuccessOnly){
        $MyLogs=$MyLogs | Where-Object { $_.ReasonCode -eq "IAS_SUCCESS" }
    }else{
        if($NoSuccess){
            $MyLogs=$MyLogs | Where-Object { $_.ReasonCode -ne "IAS_SUCCESS" }
        }
    }
    if($Year -ne ""){
        $MyLogs=$MyLogs | Where-Object { $_.Date.Split("/")[2] -like "*$Year" }
    }
    if($Month -ne ""){
        $MyLogs=$MyLogs | Where-Object { $_.Date.Split("/")[1] -like "*$Month" }
    }
    if($Day -ne ""){
        $MyLogs=$MyLogs | Where-Object { $_.Date.Split("/")[0] -like "*$Day" }
    }
    if($Hour -ne ""){
        $MyLogs=$MyLogs | Where-Object { $_.Hour.Split(":")[0] -like "*$Hour" }
    }
    if($Minute -ne ""){
        $MyLogs=$MyLogs | Where-Object { $_.Hour.Split(":")[1] -like "*$Minute" }
    }
    if($Second -ne ""){
        $MyLogs=$MyLogs | Where-Object { $_.Hour.Split(":")[2] -like "*$Second" }
    }
    $MyParams=""
    if($AutoSize){
         $MyParams+=" -AutoSize"
    }
    if($Wrap){
         $MyParams+=" -Wrap"
    }
    if($NoColors -eq $false){
        $MyParams+=" | GetColoredLogs"
    }
    $MyCmd="`$MyLogs | ft `$DisplayProperties $MyParams"
    iex $MyCMD
}

Function mgmGet-Help{
    Write-Host "Utilisez mgmGet-NPSLogsFromFile pour charger les logs"
    Write-Host "         mgmView-NPSLogs pour voir les connexions."
    Write-Host ""
    Write-Host " Les informations sont disponibles dans la variable `$LogsNPS"
    Write-Host ""
    Write-Host "Option disponible pour mgmGet-NPSLogsFromFile:"
    Write-Host "        Chemin du fichier de logs:                           -LogFile CheminDuFichierDeLogs"
    Write-Host ""
    Write-Host "Options disponibles pour mgmView-NPSLogs:"
    Write-Host "        Afficher les n dernières lignes:                     -Last n"
    Write-Host "        Afficher uniqument les authentifications réussies:   -SuccessOnly"
    Write-Host "        Afficher uniqument les authentifications en echecs:  -NoSuccess"
    Write-Host "        Uniquement l'année XXXX:                             -Year XXXX"
    Write-Host "        Uniquement le mois XX:                               -Month XX"
    Write-Host "        Uniquement le jour XX:                               -Day XX"
    Write-Host "        Uniquement l'heure XX:                               -Hour XX"
    Write-Host "        Uniquement les minutes XX:                           -Minute XX"
    Write-Host "        Uniquement les secondes XX:                          -Second XX"
    Write-Host "        Uniquement le client dont le nom contient XXXXXX     -ClientName XXXXXX"
    Write-Host "        Uniquement le NAS dont le nom contient XXXXXX        -NasSource XXXXXX"
    Write-Host "        Affiche les colonnes définies dans le tableau        -DisplayProperties @(""Date"",""Hour"")"
    Write-Host "        Ne pas afficher la coloration                        -NoColors"
    Write-Host ""
    Write-Host "        Si le texte est trop long, retour à la ligne         -Wrap"
    Write-Host "        Ajuste la taille des colonnes automatiquement        -AutoSize"
    Write-Host ""
    Write-Host "Pour actualiser le contenu en 1 ligne:"
    Write-Host "        mgmGet-NPSLogsFromFile; mgmView-NPSLogs -AutoSize -Last 40"
}

mgmGet-NPSLogsFromFile
mgmGet-Help

2 commentaires:

  1. Pour les utilisateurs de Windows 2008 R2, remplacez la premiere fonction de mgmGet-NPSLogsFromFile par:
    if($LogFile -eq "" -or $LogFile -eq $null){
    [System.Reflection.Assembly]::LoadWithPartialName("PresentationFramework") | Out-Null
    [System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") | Out-Null
    $OpenFileDialog = New-Object Microsoft.Win32.SaveFileDialog
    $OpenFileDialog.initialDirectory = "$((Get-Item Env:\SystemRoot).value)\System32\LOGFILES"
    $OpenFileDialog.filter = "All files (*.log)| *.log"
    $OpenFileDialog.ShowDialog()
    $LogFile=$OpenFileDialog.filename
    }

    RépondreSupprimer
  2. Le script à été modifié ce jour pour ajouter le numero de la ligne.
    Ceci permet donc de retrouver l'enregistrement via $LogNPS[ID]

    RépondreSupprimer