• Hallo liebe Userinnen und User,

    nach bereits längeren Planungen und Vorbereitungen sind wir nun von vBulletin auf Xenforo umgestiegen. Die Umstellung musste leider aufgrund der Serverprobleme der letzten Tage notgedrungen vorverlegt werden. Das neue Forum ist soweit voll funktionsfähig, allerdings sind noch nicht alle der gewohnten Funktionen vorhanden. Nach Möglichkeit werden wir sie in den nächsten Wochen nachrüsten. Dafür sollte es nun einige der Probleme lösen, die wir in den letzten Tagen, Wochen und Monaten hatten. Auch der Server ist nun potenter als bei unserem alten Hoster, wodurch wir nun langfristig den Tank mit Bytes vollgetankt haben.

    Anfangs mag die neue Boardsoftware etwas ungewohnt sein, aber man findet sich recht schnell ein. Wir wissen, dass ihr alle Gewohnheitstiere seid, aber gebt dem neuen Board eine Chance.
    Sollte etwas der neuen oder auch gewohnten Funktionen unklar sein, könnt ihr den "Wo issn da der Button zu"-Thread im Feedback nutzen. Bugs meldet ihr bitte im Bugtracker, es wird sicher welche geben die uns noch nicht aufgefallen sind. Ich werde das dann versuchen, halbwegs im Startbeitrag übersichtlich zu halten, was an Arbeit noch aussteht.

    Neu ist, dass die Boardsoftware deutlich besser für Mobiltelefone und diverse Endgeräte geeignet ist und nun auch im mobilen Style alle Funktionen verfügbar sind. Am Desktop findet ihr oben rechts sowohl den Umschalter zwischen hellem und dunklem Style. Am Handy ist der Hell-/Dunkelschalter am Ende der Seite. Damit sollte zukünftig jeder sein Board so konfigurieren können, wie es ihm am liebsten ist.


    Die restlichen Funktionen sollten eigentlich soweit wie gewohnt funktionieren. Einfach mal ein wenig damit spielen oder bei Unklarheiten im Thread nachfragen. Viel Spaß im ngb 2.0.

[C#] Installierte Programmversionen ermitteln

Cyperfriend

Der ohne Avatar

Registriert
14 Juli 2013
Beiträge
1.123
Ich versuche von ausgewählten Programmen die wichtig sind die Versionsnummer zu ermitteln.

Mittels PowerShell kann ich beispielsweise die Office-Version wie folgt ermitteln:
[src=powershell] Get-WmiObject win32_product | where{$_.Name -like "Microsoft Office *"} | select Name,Version[/src]

Klappt. PowerShell sagt, dass Microsoft Office Professional Plus 2016 in Version 16.0.4266.1001 bei mir installiert ist. Stimmt.


Nun wollte ich das Ganze in C#-Code übertragen, aber die Abfrage ist immer ungültig. Was habe ich verbockt? Ich hoffe ihr könnt mir helfen.
[src=csharp] // Office Version ermitteln
try
{
ManagementObjectCollection motReturn;
ManagementObjectSearcher motSearch;

motSearch = new ManagementObjectSearcher("Select * from Win32_Product where Name like 'Microsoft Office * '");

motReturn = motSearch.Get();
foreach (ManagementObject mo in motReturn)
{
label22.Text = mo["Version"].ToString();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}[/src]
 
Zuletzt bearbeitet:

KaPiTN

♪♪♫ wild at heart ♪♫♫♪

Registriert
14 Juli 2013
Beiträge
29.138
label22.Text wird bei foreeach immer nur das letzte Element aus motReturn enthalten.

Aber mal eine ketzerische Frage. Kann die 7.5 schon vorher zugewiesen worden sein?

Ich versteh überhaupt nicht, wie da bei Dir ein Ergebnis kommt. Ich habe den Code für // Office Version ermitteln auf 2 Rechnern ausgeführt, war zwischenzeitlich weg und nach fast 20 Minuten hatte die Abfrage immer noch kein Ergebnis.
 

Cyperfriend

Der ohne Avatar

Registriert
14 Juli 2013
Beiträge
1.123
  • Thread Starter Thread Starter
  • #3
Ja, da habe ich offenbar den falschen Code gepostet. Kommt davon, wenn man das Projekt auf zwei Rechnern (einmal Remote) testen möchte

Der oben genannte Code macht tatsächlich einfach nix. Wenn man die Abfrage etwas umbaut bekommt man die MessageBox "Die Abfrage ist ungültig"
[src=csharp]motSearch = new ManagementObjectSearcher("Select * from Win32_Product where Name like Office ");[/src]
[src=csharp]motSearch = new ManagementObjectSearcher("Select * from Win32_Product where Name = Office ");[/src]

Es hat sich dann aber noch herausgestellt, dass es sehr schwer zu unterscheiden ist, ob Office 2016/2019 oder gar Office 365 installiert ist, denn Office 365 wird in der Systemsteuerung / unter Apps als Microsoft 365 Apps for Enterprice gelistet - und das in Version 16.xxx. Die Abfrage über die Version beispielsweise der WINWORD.exe wie auf stackoverflow vorgeschlagen bringt also nichts, weil Office 2016/2019/365 jeweils als Version 16 gekennzeichnet sind.

Vielleicht noch wichtig zu wissen: Am Ende möchte ich die Programmversionen von Citrix Workspace, Starface UCC-Client und F-Secure. Ich schätze aber mal die grundsätzliche Abfragesyntax bleibt gleich.
 
Zuletzt bearbeitet:

KaPiTN

♪♪♫ wild at heart ♪♫♫♪

Registriert
14 Juli 2013
Beiträge
29.138
Kannst Du die Versionen nicht der registry entnehmen?
 

Cyperfriend

Der ohne Avatar

Registriert
14 Juli 2013
Beiträge
1.123
  • Thread Starter Thread Starter
  • #5
Registrypfade können sich mit jeder Version ändern. Über WMI erhalte ich immer die Versionnummer.

Was ich etwas nervig finde ist, dass die WMI-Abfrage furchtbar lange dauert, aber ich schätze damit muss man leben.

Ich habe es mittlerweile auch hinbekommen. Ich bin leider übelst darauf reingefallen, dass in C# ein %, anstatt eines * verwendet werden muss. Das hat Zeit gekostet. Der Code sieht jetzt so aus:

[src=csharp] // Office Version ermitteln
try
{
searcher = new ManagementObjectSearcher("Select * from Win32_Product where Name like 'Microsoft Office Professional%'");
foreach (ManagementObject ggg in searcher.Get())
{
label22.Text = ggg["Name"].ToString() + " " + ggg["Version"].ToString();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}[/src]

Jetzt brauche ich nur noch den Code, dass falls das gesuchte Programm nicht gefunden wird, also kein Ergebnis zurückgeliefert wird. Kann mir da bitte jemand behilflich sein?
 
Zuletzt bearbeitet:

KaPiTN

♪♪♫ wild at heart ♪♫♫♪

Registriert
14 Juli 2013
Beiträge
29.138
Bei keinem Ergebnis wäre searcher.Get().Count =0. Das könntest Du abfragen

Ich bin jetzt nicht in der Materie drin, aber mal ein paar Anmerkungen.

Unabhängig davon, daß mein Rechner mal neu gestartet werden sollte, so braucht die Abfrage bei mir über 2 Minuten.

Ich hatte bereits erwähnt, daß Du bei foreach nur das letzte Element aus searcher.Get() im label22 sehen wirst, weil das ja immer überschrieben wird.
Und da steht möglicherweise einiges drin.

Ich habe hier kein MS Office extra zu Windows 10 installiert, dennoch habe ich da 13 Elemente in der Ergebnismenge.Wahrscheinlich kostenlose Webversionen von Word, Excel und PowerPoint und wer weiß noch etwas.(?)
 

Cyperfriend

Der ohne Avatar

Registriert
14 Juli 2013
Beiträge
1.123
  • Thread Starter Thread Starter
  • #7
Ja, deswegen habe ich die Abfrage angepasst auf "Microsoft Office Professional%"

Jetzt muss da nur irgendwie noch ne Abfrage rein in der Art
[src=csharp]Name like "Microsoft Office Professional%" or Name like "Microsoft 365 Apps%"){
if(Name == "Microsoft Office Professional%"
variable = "Office 2016";
if(Name == "Microsoft 365 Apps%")
variable = "Office 365";
[/src]

Kann mir bitte wer sagen, wie man das umsetzt?
 

drfuture

Zeitreisender
Teammitglied

Registriert
14 Juli 2013
Beiträge
8.728
Ort
in der Zukunft
Die Abfrage auf Win32_Product geht auf div. stellen in der Registry. Die Quelle ist per WMI also schon die Registry, aber ist so etwas universeller zu benutzen da sonst im Programm nach 32/64bit und bei zukünftigen Versionen im Zweifel auf neue Pfade geachtet werden müsste. Die WIM Aufrufe funktionieren schon sehr lange.

Du kannst auf die Klasse Win32Reg_AddRemovePrograms wechseln. Diese ist deutlich schneller und sollte für deinen Zweck auch passen. Zusätzlich würde die die abgefragten Werte auf das anpassen was du benötigst (Name, Version?)

Mit Office hast du dir wirklich ein Paradebeispiel ausgesucht ;D
Da du vermutlich so oder so eine Abfrage über AddRemovePrograms wegen div. anderen Anwendungen machst würde ich hier im Ergebnis schauen ob ein Office installiert ist.

Wenn ja:
Schaue im Dateisystem unter Environment-Variable "Programfiles" > \Microsoft Office\* und Environment-Variable "ProgramFiles(x86)" > Microsoft Office\* eine der Office-Programm-Dateien finde (winword.exe, excel.exe,outlook.exe powerpnt.exe) sobald 1. gefunden > abbruch (Oder, da man mehrere Office-Versionen parallel installieren kann weiter suchen) und jeweils von jeder gefunden .exe die Version auslesen.

Office 2016 und Office 2019 sind im großen und Ganzen nur Snapshots von Office365 abzüglich einer Hand voll Feature die nur mit Online-Account funktionieren (z.B. Übersetzung von Folien in Powerpoint).
Daher sind hier die Build-Versionen ein Marker (Auch für Office-365).

https://docs.microsoft.com/de-de/officeupdates/update-history-microsoft365-apps-by-date
https://docs.microsoft.com/de-de/officeupdates/update-history-office-2019

@Problem mit der Abfrage:
Da du ja mehrere Anwendungen Prüfen möchtest und die Abfrage a) Zeit braucht und sich b) in den wenigen Sekunden vermutlich nicht ändert würde ich einmal eine Abfrage über alles aus Win32Reg_AddRemovePrograms machen also

[src=csharp] // Office Version ermitteln

public class AddRemovePrograms
{
public string Publisher { get; set; }
public string DisplayName { get; set; }
public string Version { get; set; } //Hier könnte man überlegen einen Versions-Datentyp zu nehmen, leider halten sich aber nicht alle Softwarefirmen an eine passende Notation der Version)
}


List<AddRemovePrograms> AddRemoveProgramsItems = new List<AddRemovePrograms>();

try
{
searcher = new ManagementObjectSearcher("Select DisplayName, Publisher, Version from Win32Reg_AddRemovePrograms'");
foreach (ManagementObject ggg in searcher.Get())
{
AddRemoveProgramsItems.Add(new AddRemovePrograms{ Publisher = ggg["Publisher"].Tostring(), Displayname = ggg["DisplayName"].tostring(), Version = ggg["Version"].ToString() });

}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}[/src]

Und dann erst die Liste durchgehen und dort auf die jeweiligen Programmnamen suchen.
 

Cyperfriend

Der ohne Avatar

Registriert
14 Juli 2013
Beiträge
1.123
  • Thread Starter Thread Starter
  • #9
Ich habe Win32Reg_AddRemovePrograms ausprobiert. Office Professional Plus 2016 wird nicht gefunden. Auch Citrix Workspace wird nicht gelistet. Man kann das auch einfach kontrollieren in deman in die PowerShell "get-wmiobject -Class Win32Reg_AddRemovePrograms" eingibt. Bei meinem zweiten Arbeitgeber bekam ich ein Ergebnis. Hier bei mir zu Hause bekomme ich
Get-WmiObject : Ungültige Klasse "Win32Reg_AddRemovePrograms"
In Zeile:1 Zeichen:1
+ Get-WmiObject -Class Win32Reg_AddRemovePrograms
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidType: (:) [Get-WmiObject], ManagementException
+ FullyQualifiedErrorId : GetWMIManagementException,Microsoft.PowerShell.Commands.GetWmiObjectCommand
Alles in allem scheint die Klasse aber nicht das zu bieten, was ich brauche.

Bei Office geht es mir vornehmlich darum die Lizenz zuordnen zu können. Office 365 bekommen wir von einer uns übergeordneten Organisation und müssen keine Lizenzkosten für bezahlen.
Office Professional Plus 2016 müssen wir hingegen selbst beschaffen und Lizenzgebühren bezahlen.
Deswegen brauche ich die klare Unterscheidung.

Ich habe auch schon im nuget-Marketplace geguckt, ob ich dort vielleicht was finde, was die Auflistung der installierten Programme einfacher und schneller macht. Ich konnte aber leider nichts finden. Habt ihr da vielleicht eine Idee?
 

drfuture

Zeitreisender
Teammitglied

Registriert
14 Juli 2013
Beiträge
8.728
Ort
in der Zukunft
Man merke:
Es kommt auf die Testumgebung an wenn man etwas schreibt.
Hatte das ja vorher getestet - bei mir gabs die auch > daheim nicht... > recherge:
Die gehört zum Microsoft ConfigManager - der muss installiert sein... das trifft in der Firma zu, zu Hause nicht.

Wenn das bei dir aber bei der einen Firma funktioniert - dann ist der dort wohl installiert?
Gibt es Dienste die mit sms... anfangen?

Dann hättest du dort schon mehr als genug Infos in dessen Inventuren. Die Frage ist ob du dort dann Zugriff bekommst.
Nur im anderen Laden bringt dir das nichts.

Die Klasse kann als 32-bit und 64bit prozess aufgerufen werden und gibt jeweils das andere Ergebnis.

Aber die Office-Version kannst du eben anhand der Exe auslesen.
Wenn du eh weißt wohin die jeweiligen Programme installiert werden - auch bei Citrix - könnte man, statt alle Programme einzulesen in der Registry in den passenden Bereichen nach Citrix, Microsoft etc. direkt suchen. Das ist dann weit weniger Dynamisch aber dafür eben deutlich performanter.
 

Cyperfriend

Der ohne Avatar

Registriert
14 Juli 2013
Beiträge
1.123
  • Thread Starter Thread Starter
  • #11
Naja das Tool programmiere ich für meinen ersten Arbeitgeber und dort gibt es 13 Dienststellen mit ganz vielen Arbeitsgruppenrechnern und Laptops. Ich bin da nur gerade im Homeoffice und bei meinem zweiten Arbeitgeber habe ich zwischendrin die Möglichkeit an dem Programm weiter zu arbeiten, bzw. auch zu testen.
Also nix SCCM
 

Cyperfriend

Der ohne Avatar

Registriert
14 Juli 2013
Beiträge
1.123
  • Thread Starter Thread Starter
  • #12
Leider scheint es über WMI / Win32_Product nicht möglich zu sein zwischen Office Pro und Office 365 zu unterscheiden. Also der Weg über die Registry.
Anbei der Code. Hoffe er stößt auf Zustimmung:
[src=csharp] string whichOffice;
// Office Version ermitteln
try {
// Suche nach Office 365
string findOffice365 = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\O365ProPlusRetail - de-de";
RegistryKey office365Key = Microsoft.Win32.Registry.LocalMachine;
RegistryKey office365Subkey = office365Key.OpenSubKey(findOffice365);

if (office365Subkey != null) {
string office365Name = office365Subkey.GetValue("DisplayName").ToString();
if (office365Name.Trim().Contains("Microsoft 365 Apps for Enterprise")) {
whichOffice = "Office 365";
}
} else { }

// Suche nach Office 2016
string findOfficePro = @"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\Office16.PROPLUS";
RegistryKey officeProKey = Microsoft.Win32.Registry.LocalMachine;
RegistryKey officeProSubkey = officeProKey.OpenSubKey(findOfficePro);

if (officeProSubkey != null) {
string officeProName = officeProSubkey.GetValue("DisplayName").ToString();
if (officeProName.Trim().Contains("Microsoft Office Professional Plus 2016")) {
whichOffice = "Office Professional Plus 2016";
}
} else { }
}
catch (Exception ex) {
MessageBox.Show(ex.Message);
}

if (whichOffice == null) {
lblSoftwareOffice.Text = "Nicht installiert";
} else {
lblSoftwareOffice.Text = whichOffice.ToString();
}[/src]
 

Cyperfriend

Der ohne Avatar

Registriert
14 Juli 2013
Beiträge
1.123
  • Thread Starter Thread Starter
  • #13
Ich habe den Code nochmals überarbeitet. Eigentlich möchte ich prüfen, ob ein Registry-Pfad überhaupt existiert. Die Suche danach ist aber irgendwie die Suche nach der Nadel im Heuhaufen. Ich konnte aber in dem Fall die Abfrage, welche Office-Version vorhanden ist vereinfachen. Eure Meinung? Was ist besser? Wie sollte es aussehen?

Edit: Achja. Wie muss ich vorgehen sollten beide Office-Versionen gefunden werden? (Eigentlich nicht möglich, aber zumindest in der Theorie möglich.)
[src=csharp] string whichOffice;
// Office Version ermitteln
try {
// Suche nach Office 365
var findOffice365 = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\O365ProPlusRetail - de-de");
if (findOffice365 == null) {
MessageBox.Show("Kein Office 365");
} else {
whichOffice = "Office 365";
}

// Suche nach Office 2016
var findOfficePro = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\Office16.PROPLUS");
if (findOfficePro == null) {
MessageBox.Show("Kein Office Pro");
} else {
whichOffice = "Office Professional Plus 2016";
}
}
catch (Exception ex) {
MessageBox.Show(ex.Message);
}

if (whichOffice == null) {
lblSoftwareOffice.Text = "Nicht installiert";
} else {
lblSoftwareOffice.Text = whichOffice.ToString();
}[/src]
 
Zuletzt bearbeitet:

drfuture

Zeitreisender
Teammitglied

Registriert
14 Juli 2013
Beiträge
8.728
Ort
in der Zukunft
So unrealistisch ist das gar nicht das er beide findet.
z.B. ist die letzte OneNote Version die Version 2016 (Die komische neue App mal außen vor) - diese funktioniert auch mit aktuellem Office365. Dann würden wohl beide Versionen gefunden werden.

Ich würde global ein Objekt "SoftwareFindings" erstellen mit den Eingenschaften "Hersteller, Produkt, Version, (evtl. Erkannt über Reg, Dateisystem etc.)"
Und alle gefundenen Produkte - egal über welche "Suche" dort hinzufügen.

Am Ende erfolgt dann die Ausgabe - in was auch immer... Tabelle, Listen, CSV, Excel, Datenbank

Prüfen ob ein Pfad existert:
[src=csharp]using (var hklm = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64))
using (var key = hklm.OpenSubKey(@"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\Office16.PROPLUS"))
{
if (key == null)
{
// Doesn't exist...
}
else
{
// Exists...
}
}[/src]
 
Oben