ZnilTools:JP ProfileAnalyzer
Aus znilwiki
Changelog:
- 19.11.2018: erste Version 1.0.0.17
- 19.11.2018: Version 1.0.0.25: In den Statistiken wird nun auch die Anzahl der Schlüssel angezeigt, Neuer Parameter --noprogress und bessere Parameter-Verarbeitung
Download
Der Quellcode ist im Download mit enthalten!
- Version 1.0.0.17: JP_ProfileAnalyzer_V1.0.0.17.zip
- Version 1.0.0.25: JP_ProfileAnalyzer_V1.0.0.25.zip
Vorwort
Ich wollte ein paar JPUser.dat
auf deren Inhalt hin analysieren. In der Regel interessiert mich welchen Anteil welche Software an der Registry hat.
Dazu habe ich das hier beschriebene Tool geschrieben.
Anleitung
Einfach das Programm zusammen mit einer JPUser.dat
starten:
JP_ProfileAnalyzer.exe JPUser.dat
Folgende Parameter sind noch möglich:
--depth= : Bis zu welcher Tiefe sollen die Schlüssel zusammengefasst werden, Default Wert ist --depth=3 --show= : Ab welchen Prozentwert sollen die Werte angezeigt werden, Default Wert ist --show=10, Minimalwert ist 1
Beispiele
Wenn man mit der --depth=
ein wenig spielt bekommt man dann auch den Verursacher eines Riesen-Profiles heraus:
In diesem Fall hat sicher der "PhotoPrintingWizard" sämtliche Drucker in allen jemals vorhandenen Sitzung für jeden Server gemerkt,
Tipps und Merkwürdiges Verhalten
Hier Analysiere ich ein Profil mit der Standardtiefe --depth=3
:
Wenn ich die Tiefe jedoch um einen erhöhe verschwindet der Eintrag wieder (--depth=4
):
Das ist erst einmal merkwürdig - aber trotzdem logisch:
Die verwendeten Begriff sind wie folgt:
Schlüssel: HKEY_CURRENT_USER\Software\Quadram\Ergo8\ Wert: Test REG_SZ Ich bin ein Wert
- Er addiert alle Werte unterhalb eines Registry-Schlüssels sofern diese der entsprechenden Tiefe entsprechen. Bei der Tiefe von 3 ist die Ebene Ergo8' halt die 3. Ebene (HKCU zählt nicht mit)
- Bei der Anzahl werden nur die Werte addiert. Bei dem Volumen zählt er aber auch die Schlüssel / den Textstring dieser selbst mit, in diesem Fall die ganzen Unterschlüssel. Bei einem Programm mit vielen Schlüsseln kommt da einiges zusammen.
- Erhöhe ich nun die Tiefe auf 4 wird der Schlüssel nicht mehr angezeigt - weil jede der Nachfolgenden Ebenen unter dem Schwellwert von
--show=10
bleibt. Das ist nämlich z.B. ein Programm mit über 8.700 Unterschlüsseln die jeweils nur 8 Werte enthalten.
Quellcode
Wie so oft mit AutoIt geschrieben:
#NoTrayIcon
#Region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_Icon=Icon256-32.ico
#AutoIt3Wrapper_UseUpx=n
#AutoIt3Wrapper_Change2CUI=y
#AutoIt3Wrapper_Res_Description=Analyze JPUser.dat
#AutoIt3Wrapper_Res_Fileversion=1.0.0.26
#AutoIt3Wrapper_Res_Fileversion_AutoIncrement=y
#AutoIt3Wrapper_Res_Language=1031
#EndRegion ;**** Directives created by AutoIt3Wrapper_GUI ****
#include <array.au3>
#Include <string.au3>
Dim $sFilename ; Dateiname inklusive Pfad zur JPUser.dat
Dim $sTempLine ; die eingelesenen Zeilen werden hier temporär gespeichert
Dim $hSourceFile ; Zeiger auf die JPUser.dat
Dim $iTimerstart ; Startzeit der Filterung
Dim $iTimerend ; Endzeit der Filterung
Dim $iLineCounter = 0 ; Zeilenzählen - als Status geben wir alle 100 Zeilen einen Punkt aus
Dim $i_MaxDepth = 3 ; Maximale Schlüsseltiefe / Suchtiefe beim Addieren der Werte, aller darunter wird im Übergeordneten Schlüssel mit gespeichert
Dim $i_CurrentDepth = 0
Dim $s_temp = ""
Dim $s_LastKey = ""
Dim $i_TotalValues = 0 ; Anzahl aller Werte
Dim $i_TotalSize = 0 ; Größe alle Werte in Summe
Dim $i_TotalKeys = 0 ; Anzahl aller Schlüssel
Dim $a_JPUserDAT[1][7] ; [0][0] = Anzahl Schlüssel
; [x][1] = Name des Schlüssels
; [x][2] = Anzahl der Werte unter diesem Schlüssel
; [x][3] = Größe der Werte unter diesem Schlüssel
; [x][4] = Anteil Anzahl an Gesamt (Prozent)
; [x][5] = Anteil Größe an Gesamt (Prozent)
; [x][6] = Anzahl an Schlüsseln in diesem Schlüsselzweig
$a_JPUserDAT[0][0] = 0
$a_JPUserDAT[0][1] = "Name"
$a_JPUserDAT[0][2] = "Anzahl Werte"
$a_JPUserDAT[0][3] = "Volumen Werte"
$a_JPUserDAT[0][4] = "Anteil Anzahl"
$a_JPUserDAT[0][5] = "Anteil Größe"
$a_JPUserDAT[0][6] = "Anteil Prozent"
Dim $sBackupTempline = ""
Dim $i_ShowValuesOver = 10 ; Nur Werte über 10% anzeigen
Dim $b_NoProgress = False
; 10 20 30 40 50 60 70 80
; 12345678901234567890123456789012345678901234567890123456789012345678901234567890
Dim $sHelp = '+------------------------------------------------------------------------------' & @CRLF & _
'| JP_ProfileAnalyzer.exe - Version ' & FileGetVersion(@ScriptName) & @CRLF & _
'+------------------------------------------------------------------------------' & @CRLF & _
'| 2011-2015 von Bernhard Linz für http://znil.net - Kontakt: Bernhard@znil.net' & @CRLF & _
'+------------------------------------------------------------------------------' & @CRLF & _
@CRLF & _
'Analysiert den Inhalt einer JPUser.dat und listet die Schlüssel ' & @CRLF & _
'in Prozent für Anzahl und Volumen im Verhältnis zur Gesamtdatei auf' & @CRLF & _
'Damit kann man sich einen Überblick über die Belegung verschaffen.' & @CRLF & _
'-------------------------------------------------------------------------------' & @CRLF & _
@CRLF & _
'Aufruf:' & @CRLF & _
@ScriptName & ' [Pfad][Dateinname] <Parameter>' & @CRLF & _
@CRLF & _
'Beispiel:' & @CRLF & _
@ScriptName & ' D:\Profiles\Benutzer\JumpingProfile\JPUser.dat' & @CRLF & _
@CRLF & _
'Parameter:' & @CRLF & _
' --depth= : Bis zu welcher Tiefe sollen die Schlüssel zusammengefasst werden' & @CRLF & _
' Default Wert ist --depth=3' & @CRLF & _
@CRLF & _
' --show= : Ab welchen Prozentwert sollen die Werte angezeigt werden,' & @CRLF & _
' Default Wert ist --show=10, Minimalwert ist 1' & @CRLF & _
@CRLF & _
' --noprogress : Keine Fortschrittsanzeige mit Punkten anzeigen' & @CRLF & _
@CRLF & _
' Die Reihenfolger der Parameter und Optionen ist beliebig. Wird bei einem' & @CRLF & _
' Parameter/Option kein - am Anfang gefunden so wird dieser ' & @CRLF & _
' als Dateiname gesetzt.' & @CRLF & _
'+------------------------------------------------------------------------------' & @CRLF & _
'| JP_ProfileAnalyzer ist FREEWARE! Kopieren, weitergeben ausdrücklich erlaubt!' & @CRLF & _
'| Die jeweils aktuelleste Version und Anleitungen findet Ihr unter:' & @CRLF & _
'| https://znil.net/index.php?title=ZnilTools:JP_ProfileAnalyzer' & @CRLF & _
'+------------------------------------------------------------------------------' & @CRLF
; ###################################################################################
; _ANSI2OEM löst das Problem mit dem Umlauten und anderen Sonderzeichen. Es wandelt Text so um das er korrekt in der DOS-Box dargestellt wird
; So können hier im Quellcode auch Umlaute verwendet werden (in den Textausgaben) und diese werden dann korrekt dargestellt
; Dank an Xenobiologist von AutoIt.de für diese Lösung: http://www.autoit.de/index.php?page=Thread&threadID=9461&highlight=ANSI2OEM
Func _ANSI2OEM($text)
$text = DllCall('user32.dll', 'Int', 'CharToOem', 'str', $text, 'str', '')
Return $text[2]
EndFunc ;==>_ANSI2OEM
Func _ByteSuffix($iBytes, $iRound = 2) ; By Spiff59
Local $A, $aArray[9] = [" B", " KB", " MB", " GB", " TB", " PB", "EB", "ZB", "YB"]
While $iBytes > 1023
$A += 1
$iBytes /= 1024
WEnd
Return Round($iBytes, $iRound) & $aArray[$A]
EndFunc ;==>_ByteSuffix
Func _AddThousandDotNEU($iZahl)
Return StringRegExpReplace(StringReverse(StringRegExpReplace(StringReverse($iZahl),"\d{3}","\0.")),"(?<![0-9])\.","",1)
EndFunc
; ###################################################################################
; Hauptprogramm
$iTimerstart = TimerInit()
; Prüfen ob ein Parameter angegeben wurde - sonst beenden
If $CmdLine[0] = 0 Then
ConsoleWrite(_ANSI2OEM("FEHLER - Keine Datei angegeben, /? für Hilfe" & @CRLF))
Exit 0
EndIf
;Prüfen ob wir die Hilfe ausgeben sollen
If $CmdLine[1] = "/?" Then
ConsoleWrite(_ANSI2OEM($sHelp))
Exit 0
EndIf
For $i = 1 To (UBound($CmdLine) - 1) Step 1
If StringLeft($CmdLine[$i], 8) = "--depth=" Then
$i_MaxDepth = Int(StringMid($CmdLine[$i], 9))
If $i_MaxDepth = 0 Then
$i_MaxDepth = 3
EndIf
ElseIf StringLeft($CmdLine[$i], 7) = "--show=" Then
$i_ShowValuesOver = Int(StringMid($CmdLine[$i], 8))
If $i_ShowValuesOver = 0 Then
$i_ShowValuesOver = 10
EndIf
ElseIf $CmdLine[$i] = "--noprogress" Then
$b_NoProgress = True
ElseIf StringLeft($CmdLine[$i],1) = "-" Then
ConsoleWrite(_ANSI2OEM("Unbekannter Parameter: " & $CmdLine[$i] & @CRLF))
Exit 1
Else
$sFilename = $CmdLine[$i]
EndIf
Next
; Holen wir uns den Dateinamen - oder was auch immer da steht
;~ $sFilename = $CmdLine[1]
ConsoleWrite("STATUS - Verarbeite Datei " & $sFilename)
ConsoleWrite(@CRLF & "=> JP_ProfileAnalyzer = 2018 znil.net <=" & @CRLF)
; Analyze!
ConsoleWrite("STATUS - Analysiere Datei ")
$hSourceFile = FileOpen($sFilename,0)
If $hSourceFile = -1 Then
ConsoleWrite(_ANSI2OEM(@CRLF & "FEHLER - Konnte " & $sFilename & "nicht öffnen" & @CRLF))
Exit 1
EndIf
;~ $hTargetFile = FileOpen($sFilename & ".temp.txt",34)
While 1
$sTempLine = FileReadLine($hSourceFile)
If @error <> -1 Then ;123456789012345678
$sBackupTempline = $sTempLine ; Wert einmal sichern, inklusive der Umgebung hinten dran
If StringLeft($sTempLine,18) = "HKEY_CURRENT_USER\" Then
$i_TotalKeys = $i_TotalKeys + 1
; Schritt 0: Umgebung hinten abschneiden
$sTempLine = StringReverse($sTempLine)
$sTempLine = StringMid($sTempLine, StringInStr($sTempLine, "[") + 2)
$sTempLine = StringReverse($sTempLine)
; Schritt 1: Die Tiefe des Schlüssel ermitteln. Das machen wir indem wir die Anzahl der \ Zählen. Nicht 100% Perfekt aber ausreichend.
$s_temp = StringReplace($sTempLine, "\", "|")
$i_CurrentDepth = @extended
$i_CurrentDepth = $i_CurrentDepth - 1
; Schritt 2: Wenn die Tiefe die maximale Tiefe überschreitet schneiden wir den Rest ab.
If $i_CurrentDepth > $i_MaxDepth Then
$sTempLine = StringLeft($sTempLine, StringInStr($sTempLine, "\", 0, ($i_MaxDepth + 1)))
EndIf
; Schritt 3: Nun prüfen wir ob wir mit dem vorherigen Schlüssel übereinstimmen. Falls Nein legen wir im Array einen neuen Zähler an.
If $sTempLine <> $s_LastKey Then
$s_LastKey = $sTempLine
; Stimmt nicht überein, wir legen einen neuen Zähler im Array an
$a_JPUserDAT[0][0] = $a_JPUserDAT[0][0] + 1
Redim $a_JPUserDAT[ $a_JPUserDAT[0][0] + 1 ][7]
; Neuen Zähler mit Werten füllen
$a_JPUserDAT[ $a_JPUserDAT[0][0] ][1] = $sTempLine
$a_JPUserDAT[ $a_JPUserDAT[0][0] ][2] = 0
$a_JPUserDAT[ $a_JPUserDAT[0][0] ][3] = (StringLen($sBackupTempline) * 2 ) ; Unicode! 2 Byte pro Zeichen!
$i_TotalSize = $i_TotalSize + (StringLen($sBackupTempline) * 2 )
$a_JPUserDAT[ $a_JPUserDAT[0][0] ][4] = 0
$a_JPUserDAT[ $a_JPUserDAT[0][0] ][5] = 0
$a_JPUserDAT[ $a_JPUserDAT[0][0] ][6] = 1
Else
; Der (ggf. gekürzte) Keyname stimmt mit dem vorherigen Keynamen überein
; Wir müssen nichts tun! Die nachfolgenden Werte sollen einfach in der verherigen mit einfließen.
; Den Schlüssel selbst rechnen wir aber zu der Menge hinzu, Kleinvieh macht auch Mist!
$a_JPUserDAT[ $a_JPUserDAT[0][0] ][3] = $a_JPUserDAT[ $a_JPUserDAT[0][0] ][3] + (StringLen($sBackupTempline) * 2 ) ; Unicode! 2 Byte pro Zeichen!
$i_TotalSize = $i_TotalSize + (StringLen($sBackupTempline) * 2 )
$a_JPUserDAT[ $a_JPUserDAT[0][0] ][6] = $a_JPUserDAT[ $a_JPUserDAT[0][0] ][6] + 1
EndIf
Else
; Kein neuer Schlüssel, ergo muss es ein Wert sein.
; Aber bitte nur wenn wir schon mindestens einen Zähler haben!
If $a_JPUserDAT[0][0] > 0 Then
$a_JPUserDAT[ $a_JPUserDAT[0][0] ][2] = $a_JPUserDAT[ $a_JPUserDAT[0][0] ][2] + 1
$i_TotalValues = $i_TotalValues + 1
$a_JPUserDAT[ $a_JPUserDAT[0][0] ][3] = $a_JPUserDAT[ $a_JPUserDAT[0][0] ][3] + (StringLen($sTempLine) * 2)
$i_TotalSize = $i_TotalSize + (StringLen($sBackupTempline) * 2 )
EndIf
EndIf
; Nachster Abschnitt ist nur Fortschrittsanzeige
If $b_NoProgress = False Then
$iLineCounter = $iLineCounter + 1
If $iLineCounter > 99 Then
ConsoleWrite(".")
$iLineCounter = 0
EndIf
EndIf
Else
; Dateiende erreicht, raus aus der Schleife!
ExitLoop
EndIf
WEnd
FileClose($hSourceFile)
; Zusammenfassung!
ConsoleWrite(" fertig! Berechne Statistiken." & @CRLF & @CRLF)
; [x][1] = Name des Schlüssels
; [x][2] = Anzahl der Werte unter diesem Schlüssel
; [x][3] = Größe der Werte unter diesem Schlüssel
; [x][4] = Anteil Anzahl an Gesamt (Prozent)
; [x][5] = Anteil Größe an Gesamt (Prozent)
; [x][6] = Anzahl an Schlüsseln in diesem Schlüsselzweig
For $i = 1 To $a_JPUserDAT[0][0]
$a_JPUserDAT[$i][4] = Round($a_JPUserDAT[$i][2] / $i_TotalValues * 100, 2)
$a_JPUserDAT[$i][5] = Round($a_JPUserDAT[$i][3] / $i_TotalSize * 100, 2)
If $a_JPUserDAT[$i][4] > $i_ShowValuesOver Or $a_JPUserDAT[$i][5] > $i_ShowValuesOver Then
ConsoleWrite(_ANSI2OEM($a_JPUserDAT[$i][1] & @CRLF))
ConsoleWrite(_ANSI2OEM("Anzahl Schlüssel .......: " & _AddThousandDotNEU($a_JPUserDAT[$i][6]) & @CRLF))
ConsoleWrite("Anzahl Werte ...........: " & _AddThousandDotNEU($a_JPUserDAT[$i][2]) & @CRLF)
ConsoleWrite("Volumen ................: " & _ByteSuffix($a_JPUserDAT[$i][3]) & @CRLF)
ConsoleWrite("Anteil Anzahl an Gesamt : " & $a_JPUserDAT[$i][4] & "%" & @CRLF)
ConsoleWrite("Anteil Volumen an Gesamt: " & $a_JPUserDAT[$i][5] & "%" & @CRLF & @CRLF)
EndIf
Next
ConsoleWrite(_ANSI2OEM("Schlüssel Gesamt : " & _AddThousandDotNEU($i_TotalKeys) & @CRLF))
ConsoleWrite("Werte Gesamt ....: " & _AddThousandDotNEU($i_TotalValues) & @CRLF)
ConsoleWrite("Volumen Gesamt ..: " & _ByteSuffix($i_TotalSize) & @CRLF)
ConsoleWrite(@CRLF)
ConsoleWrite(_ANSI2OEM("Es wurden nur Werte über " & $i_ShowValuesOver & "% angezeigt" & @CRLF))
ConsoleWrite(@CRLF)
$iTimerend = TimerDiff($iTimerstart) / 1000
ConsoleWrite("Fertig, Laufzeit " & StringRegExpReplace($iTimerend,"(\d*)\.(\d{2})(\d*)","$1,$2") & " sec" & @CRLF & @CRLF)
Exit 0