Tengo un archivo de registro de seguimiento de inicio de sesión que es una fusión de múltiples fuentes. Las fuentes (y hay muchas) usan una variedad de formatos de fecha. Estoy usando el objeto resultante $ objList para entregarlos a una base de datos SQL. Cuando intento usar consultas SQL, me faltan datos.

Aquí hay una pequeña porción de la entrada sin procesar, de septiembre de 2007:

  1. Inicio de sesión; Nombre de usuario; Servidor01; 10/09/2007 09:56:40
  2. Inicio de sesión; Nombre de usuario; Servidor02; 09/10/2007 11:26:20
  3. Inicio de sesión; Nombre de usuario; Servidor03; 11/09/2007 10:16:27 AM
  4. Inicio de sesión; Nombre de usuario; Servidor04; 09/11/2007 12:28:45

Observe que el tercero es formato americano, los otros son europeos. Necesito una forma de hacer que estas cosas se ingieran en un script en un formato de fecha consistente. Hay literalmente cientos de miles de líneas en este archivo, por lo que no es realista pasar a mano y modificar nada.

Esto es lo que tengo hasta ahora.

  IF ($SplitUsr.Count -eq '4')
    {
        $varAction = $SplitUsr[0]
        IF ($varAction -eq 'Logon')
        {
            $varActionx = $SplitUsr[0].Trim()
            $varUser = $SplitUsr[1].Trim()
            $varHostname = $SplitUsr[2].Trim()
            $varTime = $SplitUsr[3].Trim()

            try {$datetime = [dateTime]::Parse("$varTime",([Globalization.CultureInfo]::CreateSpecificCulture('en-GB')))}
            catch [System.Management.Automation.MethodInvocationException]
            {
                $datetime = [dateTime]::Parse("$varTime",([Globalization.CultureInfo]::CreateSpecificCulture('en-US')))
            }

                $objLogon = New-Object PSObject
                $objLogon | Add-Member -Membertype NoteProperty -Name "Entry" -Value $intCount
                $objLogon | Add-Member -Membertype NoteProperty -Name "Logon" -Value '1'
                $objLogon | Add-Member -Membertype NoteProperty -Name "User" -Value $varUser
                $objLogon | Add-Member -Membertype NoteProperty -Name "Hostname" -Value $varHostname
                $objLogon | Add-Member -Membertype NoteProperty -Name "Date" -Value $datetime
                $objList += $objLogon

Desafortunadamente, esto los analiza

  1. 10 de septiembre de 2007 09:56:40
  2. 10 de septiembre de 2007 11:26:20
  3. 09 de noviembre de 2007 10:16:27
  4. 11 de septiembre de 2007 12:28:45

Puede ver que el tercer ejemplo, el que tiene el formato estadounidense en los datos sin procesar, salió como noviembre en lugar del 11 de septiembre (invirtiendo el 9 y el 11).

Lo mismo está sucediendo en todo el lugar. Cuando miro las entradas SQL de diciembre, esto es lo que obtengo:

  1. 07 de diciembre de 2007 09:53:33
  2. 07 de diciembre de 2007 11:37:48
  3. 12 de julio de 2007 13:25:02
  4. 07 de diciembre de 2007 13:26:38
  5. 07 de diciembre de 2007 15:04:56

Puedes ver que el tercero de alguna manera invirtió el 12 y el 7. Este es el problema que estoy tratando de resolver.

¿Alguna sugerencia?

Editar: algunas muestras más:

  1. Inicio de sesión; Nombre de usuario; Servidor01; 18/11/2008 11:19:08
  2. Inicio de sesión; Nombre de usuario; Servidor02; 18/11/2008 11:21:46 AM
  3. Inicio de sesión; Nombre de usuario; Servidor03; 18/11/2008 14:28:30
  4. Inicio de sesión; Nombre de usuario; Servidor04; 19/11/2008 09:55:50
  5. Inicio de sesión; Nombre de usuario; Nombre del servidor; 19/11/2008 14:14:09
  6. Inicio de sesión; Nombre de usuario; Nombre del servidor; 19/11/2008 14:19:56
  7. Inicio de sesión; Nombre de usuario; Nombre del servidor; 20/11/2008 12:19:57 PM

No todas las AM / PM indican formato americano, desafortunadamente.

1
RickRDR 20 feb. 2020 a las 19:01

2 respuestas

La mejor respuesta

Este es el "KI" del que estabas hablando:

$dates = @( '10/09/2007 09:56:40',
            '09/10/2007 11:26:20',
            '10/09/2007 10:16:27 AM',
            '10/09/2007 12:28:45' )

    $cultureUS = [CultureInfo]::CreateSpecificCulture("en-US")
    $cultureEU = [CultureInfo]::CreateSpecificCulture("en-GB")

    $maxDays   = 2  # Max. allowed difference between current date and former date in days

    for( $i = 0; $i -lt $dates.Count; $i++ ) {

        $currentDate = [DateTime]::Parse( $dates[ $i ],$cultureEU )

        if( $i -gt 0 ) {
            $diffPast = New-TimeSpan -Start $lastDate -End $currentDate
        }
        else {
            $diffPast = New-TimeSpan -Start $currentDate -End $currentDate
        }

        if( $diffPast.Days -gt $maxDays ) {

            # check if month of current date is day of last date => culture issue
            if( $currentDate.Day -eq $lastDate.Month -or $currentDate.Month -eq $lastDate.Day ) {
                $currentDate = [DateTime]::Parse( $dates[ $i ],$cultureUS )
            }
        }

        $currentDate

        $lastDate = $currentDate

    }
1
f6a4 21 feb. 2020 a las 14:46

Desafortunadamente, no todos los AM / PM indican formatos de fecha estadounidenses.

Sin información adicional, no puede resolver su problema debido a ambigüedades inherentes:

9/11/2007 10:16:27 AM

Es imposible saber si esta es una marca de tiempo en-US (EE. UU.) Que se refiere al día 11 de septiembre (primer mes), o una marca de tiempo en-GB (Reino Unido) que se refiere al día 9 de noviembre ( día primero).

Solo si el primer o el segundo componente resulta ser 13 o superior es en-US o en-GB implícito , y solo las marcas de tiempo serían manejadas correctamente por la lógica try / catch en su pregunta.


Si proporciona una restricción adicional que deben cumplir todas las fechas, es posible una solución.

Por ejemplo, si sabe que todas las fechas caen en un mes dado :

# The month that all log entries are expected to fall into:
$refMonth = 9  # September, for example.

# Create an array of the cultures to use for parsing:
[cultureinfo[]] $cultures = 'en-GB', 'en-US'

'11/9/2007 17:02:15',
'9/11/2007 05:02:44 PM',
'11/9/2007 05:03:01 PM' | ForEach-Object {

   $ok = $false; [datetime] $dt = 0
   foreach ($culture in $cultures) {
     $ok = [datetime]::TryParse($_, $culture, 'None', [ref] $dt) -and $dt.Month -eq $refMonth
     if ($ok) { break }
   }
   if (-not $ok) { Write-Error "Not recognized as a date in the expected month: $_" }
   else { $date } # Output the resulting date.

}

Lo anterior produce lo siguiente, que muestra que todas las fechas se analizaron como fechas del mes 9 (septiembre):

Tuesday, September 11, 2007 5:02:15 PM
Tuesday, September 11, 2007 5:02:44 PM
Tuesday, September 11, 2007 5:03:01 PM
0
mklement0 21 feb. 2020 a las 16:41