mayho33
Goto Top

RegistryValues auslesen Count-Unterschiede zwischen C-Sharp und PS

Hi @ All

Ich habe eine Frage zu Powershell bzw. warum ich in Powershell andere Werte bekomme als in C#

Im Detail:

Ich habe eine Methode in C# mithilfe derer ich alle Registry-SubKeys von diesen Pfaden auslese:

  • Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall
  • Software\Microsoft\Windows\CurrentVersion\Uninstall


Dabei berücksichtige ich RegistryHive und RegistryView. Lasse ich die Methode in C# durchlaufen, habe ich am Ende 518 Einträge in meiner Liste. Mit der gleichen Methode in Powershell aber nur 368.
Mir ist aufgefallen, dass einige SubKeys nicht ausgewertet werden in PS und ich frage mich nun warum?

Methode in C#:
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace RegRead
{
    partial class Program
    {
        public static List<RegistryKey_Model> GetRegistryKeyPathes()
        {
            RegistryKey currentRegKey = null;
            List<RegistryKey_Model> toReturn = new List<RegistryKey_Model>();

            List<RegistryView> regViews = new List<RegistryView> { { RegistryView.Registry64 }, { RegistryView.Registry32 } };
            List<RegistryHive> regHives = new List<RegistryHive> { { RegistryHive.CurrentUser }, { RegistryHive.LocalMachine } };

            Dictionary<string,string> regTargetPathes = new Dictionary<string, string>
            {
                { "Registry64", "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall" },  
                { "Registry32", "Software\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall" }  
            };
            foreach (RegistryHive hive in regHives)
            {
                foreach (RegistryView view in regViews)
                {
                    try
                    {
                        if (hive == RegistryHive.LocalMachine && (view == RegistryView.Registry32 || view == RegistryView.Default))
                            currentRegKey = Registry.LocalMachine.OpenSubKey(regTargetPathes[RegistryView.Registry32.ToString()]);

                        else if (hive == RegistryHive.LocalMachine && view == RegistryView.Registry64)
                            currentRegKey = Registry.LocalMachine.OpenSubKey(regTargetPathes[RegistryView.Registry64.ToString()]);

                        else if (hive == RegistryHive.CurrentUser && (view == RegistryView.Registry32 || view == RegistryView.Default))
                            currentRegKey = Registry.CurrentUser.OpenSubKey(regTargetPathes[RegistryView.Registry32.ToString()]);

                        else if (hive == RegistryHive.CurrentUser && view == RegistryView.Registry64)
                            currentRegKey = Registry.CurrentUser.OpenSubKey(regTargetPathes[RegistryView.Registry64.ToString()]);
                    }
                    catch (Exception) { }


                    if (currentRegKey != null)
                    {
                        foreach (var subKey in currentRegKey.GetSubKeyNames())
                        {
                            toReturn.Add(new RegistryKey_Model
                            {
                                RegHive = GetRegistryHive(currentRegKey.Name),
                                RegView = GetRegistryView(currentRegKey.Name),
                                RegKey = Path.Combine(currentRegKey.Name.ToString(), subKey.ToString())
                            });
                        }
                    }
                }
            }
            return toReturn;
        }

        private static RegistryView GetRegistryView(string fullKeyOrValuePath)
        {
            RegistryView regView = RegistryView.Registry32;
            if (!Regex.Match(fullKeyOrValuePath, @"(Wow6432Node)", RegexOptions.IgnoreCase).Success && Environment.Is64BitOperatingSystem)  
                regView = RegistryView.Registry64;
            return regView;
        }
        private static RegistryHive GetRegistryHive(string fullKeyOrValuePath)
        {
            RegistryHive regHive = RegistryHive.LocalMachine;

            if (Regex.Match(fullKeyOrValuePath, @"(HKCU|HKEY_CURRENT_USER)", RegexOptions.IgnoreCase).Success)  
                regHive = RegistryHive.CurrentUser;

            if (Regex.Match(fullKeyOrValuePath, @"(HKCR|HKEY_CLASSES_ROOT)", RegexOptions.IgnoreCase).Success)  
                regHive = RegistryHive.ClassesRoot;

            if (Regex.Match(fullKeyOrValuePath, @"(HKU|HKEY_USERS)", RegexOptions.IgnoreCase).Success)  
                regHive = RegistryHive.Users;

            if (Regex.Match(fullKeyOrValuePath, @"(HKCC|HKEY_CURRENT_CONFIG)", RegexOptions.IgnoreCase).Success)  
                regHive = RegistryHive.CurrentConfig;

            if (Regex.Match(fullKeyOrValuePath, @"(HKLM|HKEY_LOCAL_MACHINE)", RegexOptions.IgnoreCase).Success)  
                regHive = RegistryHive.LocalMachine;
            return regHive;
        }
    }

    public class RegistryKey_Model
    {
        private RegistryHive _RegHive;
        public RegistryHive RegHive
        {
            get { return _RegHive; }
            set { _RegHive = value; }
        }

        private RegistryView _RegView;
        public RegistryView RegView
        {
            get { return _RegView; }
            set { _RegView = value; }
        }

        private string _RegKey;
        public string RegKey
        {
            get { return _RegKey; }
            set { _RegKey = value; }
        }
    }
}



Methode in Powershell:
$Source= @"  
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

public class RegistryKeyPathes
{
    public static List<RegistryKey_Model> Get()
    {
        RegistryKey currentRegKey = null;
        List<RegistryKey_Model> toReturn = new List<RegistryKey_Model>();

        List<RegistryView> regViews = new List<RegistryView> { { RegistryView.Registry64 }, { RegistryView.Registry32 } };
        List<RegistryHive> regHives = new List<RegistryHive> { { RegistryHive.CurrentUser }, { RegistryHive.LocalMachine } };

        Dictionary<string,string> regTargetPathes = new Dictionary<string, string>
        {
            { "Registry64", "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall" },  
            { "Registry32", "Software\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall" }  
        };
        foreach (RegistryHive hive in regHives)
        {
            foreach (RegistryView view in regViews)
            {
                try
                {
                    if (hive == RegistryHive.LocalMachine && (view == RegistryView.Registry32 || view == RegistryView.Default))
                        currentRegKey = Registry.LocalMachine.OpenSubKey(regTargetPathes[RegistryView.Registry32.ToString()]);

                    else if (hive == RegistryHive.LocalMachine && view == RegistryView.Registry64)
                        currentRegKey = Registry.LocalMachine.OpenSubKey(regTargetPathes[RegistryView.Registry64.ToString()]);

                    else if (hive == RegistryHive.CurrentUser && (view == RegistryView.Registry32 || view == RegistryView.Default))
                        currentRegKey = Registry.CurrentUser.OpenSubKey(regTargetPathes[RegistryView.Registry32.ToString()]);

                    else if (hive == RegistryHive.CurrentUser && view == RegistryView.Registry64)
                        currentRegKey = Registry.CurrentUser.OpenSubKey(regTargetPathes[RegistryView.Registry64.ToString()]);
                }
                catch (Exception) { }


                if (currentRegKey != null)
                {
                    foreach (var subKey in currentRegKey.GetSubKeyNames())
                    {
                        toReturn.Add(new RegistryKey_Model
                        {
                            RegHive = GetRegistryHive(currentRegKey.Name),
                            RegView = GetRegistryView(currentRegKey.Name),
                            RegKey = Path.Combine(currentRegKey.Name.ToString(), subKey.ToString())
                        });
                    }
                }
            }
        }
        return toReturn;
    }

    private static RegistryView GetRegistryView(string fullKeyOrValuePath)
    {
        RegistryView regView = RegistryView.Registry32;
        if (!Regex.Match(fullKeyOrValuePath, @"(Wow6432Node)", RegexOptions.IgnoreCase).Success && Environment.Is64BitOperatingSystem)  
            regView = RegistryView.Registry64;
        return regView;
    }
    private static RegistryHive GetRegistryHive(string fullKeyOrValuePath)
    {
        RegistryHive regHive = RegistryHive.LocalMachine;

        if (Regex.Match(fullKeyOrValuePath, @"(HKCU|HKEY_CURRENT_USER)", RegexOptions.IgnoreCase).Success)  
            regHive = RegistryHive.CurrentUser;

        if (Regex.Match(fullKeyOrValuePath, @"(HKCR|HKEY_CLASSES_ROOT)", RegexOptions.IgnoreCase).Success)  
            regHive = RegistryHive.ClassesRoot;

        if (Regex.Match(fullKeyOrValuePath, @"(HKU|HKEY_USERS)", RegexOptions.IgnoreCase).Success)  
            regHive = RegistryHive.Users;

        if (Regex.Match(fullKeyOrValuePath, @"(HKCC|HKEY_CURRENT_CONFIG)", RegexOptions.IgnoreCase).Success)  
            regHive = RegistryHive.CurrentConfig;

        if (Regex.Match(fullKeyOrValuePath, @"(HKLM|HKEY_LOCAL_MACHINE)", RegexOptions.IgnoreCase).Success)  
            regHive = RegistryHive.LocalMachine;
        return regHive;
    }
}

public class RegistryKey_Model
{
    private RegistryHive _RegHive;
    public RegistryHive RegHive
    {
        get { return _RegHive; }
        set { _RegHive = value; }
    }

    private RegistryView _RegView;
    public RegistryView RegView
    {
        get { return _RegView; }
        set { _RegView = value; }
    }

    private string _RegKey;
    public string RegKey
    {
        get { return _RegKey; }
        set { _RegKey = value; }
    }
}
"@  

Add-Type -TypeDefinition $Source
$values = [RegistryKeyPathes]::Get()


Lese ich die SubKeys Powershell-Like aus bekomme ich 346 Einträge in meiner Liste (HÄÄÄ ???).

$values = @()
try{
$values += Get-ItemProperty HKLM:Software\Microsoft\Windows\CurrentVersion\Uninstall\* -ErrorAction SilentlyContinue
$values += Get-ItemProperty HKLM:Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* -ErrorAction SilentlyContinue
$values += Get-ItemProperty HKCU:Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* -ErrorAction SilentlyContinue
$values += Get-ItemProperty HKCU:Software\Microsoft\Windows\CurrentVersion\Uninstall\* -ErrorAction SilentlyContinue
}
catch {}

$values.Count

Hat jemand Ahnung warum das so ist und wie ich das bereinigen kann?

Vielen Dank für eure Unterstützung und beste Grüße!

Mayho

Content-Key: 463894

Url: https://administrator.de/contentid/463894

Printed on: April 26, 2024 at 07:04 o'clock

Member: colinardo
colinardo Jun 19, 2019 updated at 16:37:40 (UTC)
Goto Top
Servus Mayho.
mithilfe derer ich alle Registry-SubKeys von diesen Pfaden auslese:
(HÄÄÄ ???).
Tass Kaffee rüber reich face-smile

Tipp :

Get-Itemproperty ≠ Get-ChildItem

Schönen Feierabend wenn's dann soweit ist.
Grüße Uwe
Member: mayho33
mayho33 Jun 19, 2019 at 20:13:16 (UTC)
Goto Top
Hi Colinardo,

Hmmmm... Kaffee nehme ich! Danke! face-smile

Aber auch mit Get-ChildItem bekomme ich nicht die Menge an Werten die ich mit der C#-Methode bekomme. Hab nachgezählt. C# machts richtig. Die gleiche Methode in Powershell (als eingebetteter C#-Code), siehe Beispiel, liefert weniger weniger und mit Get-ChildItem dito.

Warum ist die Frage. Kann PS doch nicht so gut mit .Net oder kann PS nicht mit C#?

Ebenfalls noch einen schönen Abend!

Mayho
Member: colinardo
colinardo Jun 19, 2019 updated at 22:04:29 (UTC)
Goto Top
Get-ChildItem liefert aber ganz andere Dinge als Get-Itemproperty, das ist dir hoffentlich schon bewusst?! Das eine Schlüssel, das andere Properties.

Als erstes würde ich mal die Catch-Blocks ausgeben lassen und nicht ins Nirvana laufen lassen, genauso bei der PS Variante.
Welches OS welche PS Version und Bitness der PS-Session als auch die Bitness der c# exe?
Member: mayho33
mayho33 Jul 05, 2019 updated at 21:08:01 (UTC)
Goto Top
Hi colinardo,

sorry wegen der verspäteten Rückmeldung. Urlaub war wichtig :D

Get-ChildItem liefert aber ganz andere Dinge als Get-Itemproperty
Ja ist klar! Auch wenn ich das (zuggeben) gerne mal verwechsle face-wink

Das Hauptproblem ist eigentlich, das ich in C# die korrekte Anzahl der SubKeys (x86 & x64) zurückbekomme, in PS mit original der gleichen Methode aber nicht, egal wie ich es wende und drehe.
Zur Veranschaulichung wollte ich das in PS mit Get-Item, Get-ChildItem, Get-ItemProperty halt aufzeigen um zu vermeiden, dass jemand empfiehlt ich soll das so oder so verwenden.

Die Catches geben nichts aus. Zumindest fällt er da weder in C# noch in PS rein. Ist meiner Ansicht auch klar; Ich hole ja alle Subkeys und verwende nur diese. Ist also eher nur Alibi.

Bin zufällig über diesen Post gestolpert: (Installierte Software auslesen). Liefert auch viel weniger. Bin am Ende meiner Weisheit.

OS: W10 1809 x64
PS-Ver: 5.1.17763.503

C# Bitness: x86
PS-Bitness: sowohl als auch


Ideen??
Member: colinardo
Solution colinardo Jul 06, 2019 updated at 08:43:04 (UTC)
Goto Top
C# Bitness: x86
Ideen??
Ja ist mir jetzt eigentlich vollkommen klar, bau deine c# exe mal als 64bit, und du wirst sehen das es geht (getestet, Ergebnisse absolut gleich, egal welches System ich heranziehe, waren mind. 4 unterschiedliche). Mit Workarounds kann man das auch mit Flags über RegOpenKeyEx in einem x86 Prozess machen.

Generell gilt aber folgendes:
.NET app kompiliert für "x86":  
    Auf 32-bit Platformen, nutzt es die 32-bit Registry
    Auf 64-bit Platformen, nutzt die 32-bit registry (in Wow6432Node)
    Zugriff auf die 64-bit Registry ist nicht möglich (ohne Workarounds)

.NET app kompiliert für "x64":  
    Läuft auf 32-bit platformen nicht
    Auf 64-bit Platformen, nutzt die 64-bit Registry (nicht in Wow6432Node)
    Zugriff auf die 32-Bit Registry über Workaround möglich
    
.NET app kompiliert für "AnyCpu"  
    Entweder 32 or 64 bit je nach Platform
    Auf 32-bit Platformen, nutzt die 32-bit registry
    Auf 64-bit Platformen, nutzt die 64-bit registry (nicht in Wow6432Node)
    Zugriff auf die 32-Bit Registry nur über Workaround möglich
Wenn man von einer 64-Bit / AnyCpu-App auf die 32-Bit-Registrierung zugreifen möchten, kann man wie du es tust den Pfad "Wow6432Node" fest codieren (da die 32-Bit-Registrierung von 64-Bit sichtbar ist, jedoch nicht umgekehrt.
MS empfiehlt es aber ausdrücklich nicht so vorzugehen.

Grüße Uwe
Member: mayho33
mayho33 Jul 15, 2019 at 12:57:27 (UTC)
Goto Top
Hi Uwe,

Nochmals sorry, wegen der verspäteten Rückmeldung. Einfach zu viel Arbeit in letzter Zeit.

.NET app kompiliert für "x86":
Auf 32-bit Platformen, nutzt es die 32-bit Registry
Auf 64-bit Platformen, nutzt die 32-bit registry (in Wow6432Node)
Zugriff auf die 64-bit Registry ist nicht möglich (ohne Workarounds)

.NET app kompiliert für "x64":
Läuft auf 32-bit platformen nicht
Auf 64-bit Platformen, nutzt die 64-bit Registry (nicht in Wow6432Node)
Zugriff auf die 32-Bit Registry über Workaround möglich

.NET app kompiliert für "AnyCpu"
Entweder 32 or 64 bit je nach Platform
Auf 32-bit Platformen, nutzt die 32-bit registry
Auf 64-bit Platformen, nutzt die 64-bit registry (nicht in Wow6432Node)
Zugriff auf die 32-Bit Registry nur über Workaround möglich

Da will ich dir jetzt nicht 100%ig widersprechen, aber es geht auch ohne Workarround. MS beschreibt das hier: https://docs.microsoft.com/en-us/dotnet/api/microsoft.win32.registryview ...


Wie so oft liegt der Teufel im Detail. Ich habe eine Fehler in meiner C# - Methode oben entdeckt. Jetzt werden sowohl in C# als auch im Powershell (wenn die C# - Methode verwendet wird) die gleichen Werte ausgeworfen.

Werden die Values PS-Like geholt, gibt es immer noch Unterschiede die dein letzter Kommentar nur bedingt erklären kann. Siehe Bild:

Ausgabe, wenn die C#-Methode in PS verwendet wird:
c#-like

Ausgabe, wenn die Values ps-like geholt werden:
pslike


Grundsätzlich scheint mein Problem nun geklärt zu sein. Damit, C# im PS zu verwenden, kann ich leben.

Hier noch die Korrektur! Eventuell kann das ja jemand brauchen face-wink

using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

public class RegistryKeyPathes
{
    public static List<RegistryKey_Model> Get()
        {
            RegistryKey currentRegKey = null;
            List<RegistryKey_Model> toReturn = new List<RegistryKey_Model>();

            List<RegistryView> regViews = new List<RegistryView> { { RegistryView.Registry32 } };
            if (Environment.Is64BitOperatingSystem)
                regViews.Add(RegistryView.Registry64);

            List<RegistryHive> regHives = new List<RegistryHive> { { RegistryHive.LocalMachine }, { RegistryHive.CurrentUser } };

            string KeyPath = @"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall";  

            foreach (RegistryHive hive in regHives)
            {
                foreach (RegistryView view in regViews)
                {
                    currentRegKey = null;
                    if (hive == RegistryHive.LocalMachine && (view == RegistryView.Registry32 || view == RegistryView.Default))
                    {
                        try
                        {
                            currentRegKey = RegistryKey.OpenBaseKey(hive, view).OpenSubKey(KeyPath);
                        }
                        catch (Exception) { }
                    }

                    else if (hive == RegistryHive.LocalMachine && (view == RegistryView.Registry64))
                    {
                        try
                        {
                            currentRegKey = RegistryKey.OpenBaseKey(hive, view).OpenSubKey(KeyPath);
                        }
                        catch (Exception) { }
                    }

                    else if (hive == RegistryHive.CurrentUser && (view == RegistryView.Registry32 || view == RegistryView.Default))
                        currentRegKey = Registry.CurrentUser.OpenSubKey("Software\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall"); //regTargetPathes[RegistryView.Registry32.ToString()]);  

                    else if (hive == RegistryHive.CurrentUser && view == RegistryView.Registry64)
                        currentRegKey = Registry.CurrentUser.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall"); //regTargetPathes[RegistryView.Registry64.ToString()]);  



                    if (currentRegKey != null)
                    {
                        foreach (var subKey in currentRegKey.GetSubKeyNames())
                        {
                            toReturn.Add(new RegistryKey_Model
                            {
                                RegHive = GetRegistryHive(currentRegKey.Name),
                                RegView = currentRegKey.View,
                                RegKey = Path.Combine(currentRegKey.Name.ToString(), subKey.ToString())
                            });
                        }
                    }
                }
            }
            return toReturn;
        }

        private static RegistryHive GetRegistryHive(string fullKeyOrValuePath)
        {
            RegistryHive regHive = RegistryHive.LocalMachine;

            if (Regex.Match(fullKeyOrValuePath, @"(HKCU|HKEY_CURRENT_USER)", RegexOptions.IgnoreCase).Success)  
                regHive = RegistryHive.CurrentUser;

            if (Regex.Match(fullKeyOrValuePath, @"(HKCR|HKEY_CLASSES_ROOT)", RegexOptions.IgnoreCase).Success)  
                regHive = RegistryHive.ClassesRoot;

            if (Regex.Match(fullKeyOrValuePath, @"(HKU|HKEY_USERS)", RegexOptions.IgnoreCase).Success)  
                regHive = RegistryHive.Users;

            if (Regex.Match(fullKeyOrValuePath, @"(HKCC|HKEY_CURRENT_CONFIG)", RegexOptions.IgnoreCase).Success)  
                regHive = RegistryHive.CurrentConfig;

            if (Regex.Match(fullKeyOrValuePath, @"(HKLM|HKEY_LOCAL_MACHINE)", RegexOptions.IgnoreCase).Success)  
                regHive = RegistryHive.LocalMachine;
            return regHive;
        }
}

public class RegistryKey_Model
{
    private RegistryHive _RegHive;
    public RegistryHive RegHive
    {
        get { return _RegHive; }
        set { _RegHive = value; }
    }

    private RegistryView _RegView;
    public RegistryView RegView
    {
        get { return _RegView; }
        set { _RegView = value; }
    }

    private string _RegKey;
    public string RegKey
    {
        get { return _RegKey; }
        set { _RegKey = value; }
    }
}


Danke für deine Unterstützung!

Grüße Mayho!