Archive for the ‘Aktivierung’ Category

Softwarelizensinformationen in Windows mittels Powershell auslesen

7 Januar 2018

Eigentlich wollte ich nur etwas mit dem KIOSK-Modus bzw. “Sperrmodus für Geräte” (Device Lockdown) von Windows herumspielen und den “Einheitlichen Schreibfilter” (Unified Write Filter) testen. Hier ein schöner Artikel über die Möglichkeiten: http://woshub.com/using-unified-write-filter-uwf-windows-10/. Bei der Recherche bin ich dann auf ein Script gestoßen, welches Softwarelizenzinformationen abruft: https://docs.microsoft.com/de-de/windows/configuration/set-up-a-kiosk-for-windows-10-for-desktop-editions#shell-launcher.

Mich hat vor allem Interessiert, wenn man SLGetWindowsInformationDWORD mit dem Parameter "EmbeddedFeature-ShellLauncher-Enabled" aufruft, dann gibt es da sicherlich noch weitere Parameter. Zunächst wurde also das Script aus dem MSDN-Artikel etwas modifiziert:

$source = @"
using System;
using System.Runtime.InteropServices;

public class CheckLicense
{
    public const int S_OK = 0;

    [DllImport("Slc.dll")]
    public static extern int SLGetWindowsInformationDWORD([MarshalAs(UnmanagedType.LPWStr)]string valueName, out int value);

}
"@

Add-Type -TypeDefinition $source –PassThru

Dadurch kann man SLGetWindowsInformationDWORD direkt aufrufen:

function Check-LicenseEnabled ([String]$License)
{
$enabled=[int]0
If ([CheckLicense]::SLGetWindowsInformationDWORD($license, [ref]$enabled) -ne [CheckLicense]::S_OK) {
  $enabled = 0
}

$enabled -ne 0
}

Durch die Funktion Check-LicenseEnabled kann man nun also den Aufruf durchführen:

Check-LicenseEnabled -License "EmbeddedFeature-ShellLauncher-Enabled"

Aber welche anderen Werte sind noch möglich? Bei der Suche nach EmbeddedFeature-ShellLauncher-Enabled bin ich dann auf diese Liste gestoßen: https://forums.mydigitallife.net/threads/discussion-windows-server-2016-14393-1607.70435/page-39#post-1285324. D. h. da geht extrem viel. Durch obige Funktion kann man nun beliebige Abfragen starten:

Check-LicenseEnabled CodeIntegrity-AllowConfigurablePolicy

Wenn man allerdings die Liste bei mydigitallife.net anschaut, dann fellen einem auch Werte auf die nicht nur 0 oder 1 sind, wie z. B. AppXDeploymentServer-License-MaxSideloadedPackagesCount. D. h. es gibt neben der SLGetWindowsInformationDWORD-Funktion noch eine weitere Funktion, nämlich SLGetWindowsInformation. Eigentlich gibt es eine ganze Palette von Funktionen, hier die Beschreibungen https://msdn.microsoft.com/en-us/library/windows/desktop/aa965829, allerdings wollen wir bei der SLGetWindowsInformation bleiben. Deshalb wurde der obige C#-Code etwas ergänzt:

$source = @"
using System;
using System.Runtime.InteropServices;

public class CheckLicense
{
    public const int S_OK = 0;

    public enum SLDATATYPE
    {
       SL_DATA_NONE      = 0, /* REG_NONE */
       SL_DATA_SZ        = 1, /* REG_SZ */
       SL_DATA_DWORD     = 4, /* REG_DWORD */
       SL_DATA_BINARY    = 3, /* REG_BINARY */
       SL_DATA_MULTI_SZ  = 7, /* REG_MULTI_SZ */
       SL_DATA_SUM       = 100
    };

    [DllImport("Slc.dll", CharSet = CharSet.Unicode)]
    public static extern uint SLGetWindowsInformation(
    string ValueName,
    out SLDATATYPE DataType,
    out uint cbValue,
    out IntPtr Value
    );

    [DllImport("Slc.dll")]
    public static extern int SLGetWindowsInformationDWORD([MarshalAs(UnmanagedType.LPWStr)]string valueName, out int value);

}
"@

Add-Type -TypeDefinition $source -PassThru

Damit steht uns nun SLGetWindowsInformation zur Verfügung. Allerdings ist der Aufruf ziemlich kompliziert, hier ein Beispiel:

# zunächst Variablen initialisieren
$DataType=[CheckLicense+SLDATATYPE]::SL_DATA_NONE
$cbValue=[uint32]0
$ValuePtr=[System.IntPtr]::Zero

# Aufruf, um z. B. "Kernel-EditionName" zu ermitteln:
$res = [uint32][CheckLicense]::SLGetWindowsInformation("Kernel-EditionName",[ref]$DataType,[ref]$cbValue,[ref]$ValuePtr)

Wenn $res 0 bzw. S_OK ist, dann hat man in $cbValue die Anzahl der Bytes, auf welche $ValuePtr zeigt, die vom Typ $DataType sind. Um diese zu erhalten, braucht man noch diese Zeilen:

$Value=New-Object Byte[] $cbValue
[System.Runtime.InteropServices.Marshal]::Copy($ValuePtr, $Value, 0, $Value.Length)
[System.Runtime.InteropServices.Marshal]::FreeHGlobal($ValuePtr)
[System.Text.Encoding]::Unicode.GetString($Value)

Am Ende hat man bei einem Windows 10 Professional die Ausgabe Professional stehen. Die Basis für die Vorgehensweise lieferte dieser Artikel: https://stackoverflow.com/questions/31180457/how-to-pinvoke-slgetwindowsinformation-from-c-sharp. Packen wir die Aufrufe in eine Funktion:

Function Get-LicenseInformation ([string]$License) {
  $DataType=[CheckLicense+SLDATATYPE]::SL_DATA_NONE
  $cbValue=[uint32]0
  $ValuePtr=[System.IntPtr]::Zero
  $res = [uint32][CheckLicense]::SLGetWindowsInformation($License,[ref]$DataType,[ref]$cbValue,[ref]$ValuePtr)
  If ($res -eq [CheckLicense]::S_OK) {
    $Value=New-Object Byte[] $cbValue
    [System.Runtime.InteropServices.Marshal]::Copy($ValuePtr, $Value, 0, $Value.Length)
    [System.Runtime.InteropServices.Marshal]::FreeHGlobal($ValuePtr) # Calls Localfree!
    [System.Text.Encoding]::Unicode.GetString($Value)
  }
}

Damit kann man nun diese einfachen Aufrufe starten:

Get-LicenseInformation -License Kernel-EditionName

oder

Get-LicenseInformation -License Kernel-MUI-Language-SKU

Allerdings fällt auf, dass noch nicht alle Aufrufe funktionieren. Denn teilweise kommt Müll zurück, wie z. B. bei

Get-LicenseInformation -License Kernel-ExpirationDate

Aus diesem Grund muss Get-LicenseInformation noch etwas verbessert werden, vor allem muss auf $DataType reagiert werden:

Function Get-LicenseInformation ([string]$License) {
  $DataType=[CheckLicense+SLDATATYPE]::SL_DATA_NONE
  $cbValue=[uint32]0
  $ValuePtr=[System.IntPtr]::Zero
  $res = [uint32][CheckLicense]::SLGetWindowsInformation($License,[ref]$DataType,[ref]$cbValue,[ref]$ValuePtr)
  If ($res -eq [CheckLicense]::S_OK) {
    $Value=New-Object Byte[] $cbValue
    [System.Runtime.InteropServices.Marshal]::Copy($ValuePtr, $Value, 0, $Value.Length)
    [System.Runtime.InteropServices.Marshal]::FreeHGlobal($ValuePtr) # Calls Localfree!
    Switch ($DataType) {
      ([CheckLicense+SLDATATYPE]::SL_DATA_SZ)     {[System.Text.Encoding]::Unicode.GetString($Value)}
      ([CheckLicense+SLDATATYPE]::SL_DATA_BINARY) {$Value -join ‚-‚}
      ([CheckLicense+SLDATATYPE]::SL_DATA_DWORD)  {[System.BitConverter]::ToInt32($Value,0)}
      default       {Write-Error "Unknown DatatType: $DataType"}
    }
   
  }
}

Damit können nun alle gängigen Werte abgefragt werden. Wenn SL_DATA_BINARY zurückgegeben werden soll, könnte man ein Bytearray zurückgeben, aber ich habe mich entschieden gleich einen String zurückzugeben. Der einfacheren Lesbarkeit wegen. Damit man alles beieinander hat hier nochmal der Code komplett:

$source = @"
using System;
using System.Runtime.InteropServices;

public class CheckLicense
{
    public const int S_OK = 0;

    public enum SLDATATYPE
    {
       SL_DATA_NONE      = 0, /* REG_NONE */
       SL_DATA_SZ        = 1, /* REG_SZ */
       SL_DATA_DWORD     = 4, /* REG_DWORD */
       SL_DATA_BINARY    = 3, /* REG_BINARY */
       SL_DATA_MULTI_SZ  = 7, /* REG_MULTI_SZ */
       SL_DATA_SUM       = 100
    };

    [DllImport("Slc.dll", CharSet = CharSet.Unicode)]
    public static extern uint SLGetWindowsInformation(
    string ValueName,
    out SLDATATYPE DataType,
    out uint cbValue,
    out IntPtr Value
    );

    [DllImport("Slc.dll")]
    public static extern int SLGetWindowsInformationDWORD([MarshalAs(UnmanagedType.LPWStr)]string valueName, out int value);

}
"@

Add-Type -TypeDefinition $source -PassThru

Function Check-LicenseEnabled ([String]$License)
{
$enabled=[int]0
If ([CheckLicense]::SLGetWindowsInformationDWORD($license, [ref]$enabled) -ne [CheckLicense]::S_OK) {
  $enabled = 0
}

$enabled -ne 0
}

Function Get-LicenseInformation ([string]$License) {
  $DataType=[CheckLicense+SLDATATYPE]::SL_DATA_NONE
  $cbValue=[uint32]0
  $ValuePtr=[System.IntPtr]::Zero
  $res = [uint32][CheckLicense]::SLGetWindowsInformation($License,[ref]$DataType,[ref]$cbValue,[ref]$ValuePtr)
  If ($res -eq [CheckLicense]::S_OK) {
    $Value=New-Object Byte[] $cbValue
    [System.Runtime.InteropServices.Marshal]::Copy($ValuePtr, $Value, 0, $Value.Length)
    [System.Runtime.InteropServices.Marshal]::FreeHGlobal($ValuePtr) # Calls Localfree!
    Switch ($DataType) {
      ([CheckLicense+SLDATATYPE]::SL_DATA_SZ)     {[System.Text.Encoding]::Unicode.GetString($Value)}
      ([CheckLicense+SLDATATYPE]::SL_DATA_BINARY) {$Value -join ‚-‚}
      ([CheckLicense+SLDATATYPE]::SL_DATA_DWORD)  {[System.BitConverter]::ToInt32($Value,0)}
      default       {Write-Error "Unknown DatatType: $DataType"}
    }
   
  }
}

Werbeanzeigen

Abgelaufene Aktivierungen erschweren einem das Leben unter Windows und wie man diese zurücksetzen kann

30 August 2015

Wer viel mit virtuellen Maschinen zu tun hat, der kennt vielleicht das Problem, man macht schnell eine Kopie eine VHD oder VHDX und setzt eine neue Maschine auf um etwas zu testen. Dann gerät die Sache in Vergessenheit und später fragt man sich, um was ging es eigentlich genau. Es ist ja kein Problem das System nochmals hochzufahren und nachzuschauen. Blöd nur, wenn dann auf einmal Microsoft nach der Aktivierung fragt. Noch blöder ist es, wenn man keine Aktivierung durchführen kann, weil man keine ordentliche Internetverbindung zustande bekommt.

Eine Lösung ist seit Windows Vista die Sache mit UTILMAN.EXE. Man benennt UTILMAN.EXE unter WinPE oder WinRE um und kopiert einfach CMD.EXE auf UTILMAN.EXE. Danach kann man am Anmeldebildschirm die Eingabehilfen aktivieren und schwupps öffnet sich die Eingabeaufforderung. Hier eine ausführliche Beschreibung, wie man zum Ziel kommt: https://www.petri.com/bypass-windows-server-2008-activation, hier etwas einfacher: https://www.technibble.com/bypass-windows-logons-utilman/.

Soweit so gut. Aktuell war aber eine Small Business Server 2003 R2 zur Mitarbeit zu überreden. Nur leider funktionierte obige Variante dort nicht. Zum Glück gibt es auch hier eine Alternative, die hier beschrieben steht: https://cyberwaves.wordpress.com/2011/06/20/windows-server-2003-aktivierung-umgehen-circumvent-activation/.

Hier nochmal die wesentlichen Punkte: Beim Aktivierungsassistenten drückt man STRG+L, dann auf Durchsuchen, dort gibt man C:\WIDNOWS\SYSTEM32\*.* ein und sucht dann CMD.EXE, klickt dort mit der rechten Maustaste und wählt “Ausführen als” aus. Man muss zwingend den unteren Eintrag mit der expliziten Anmeldung wählen und seine Anmeldedaten eingeben. Nun öffnet sich eine Eingabeaufforderung.

Leider bleibt diese nicht ewig erhalten, sondern LSASS.EXE sorgt dafür, dass nach einiger Zeit die Shell wieder geschlossen wird. Man kann problemlos wieder eine Shell öffnen. Wenn man etwas mehr Zeit braucht, kann man den Sysinternals Prozessexplorer starten, auch Regedit bleibt dauerhaft erhalten. Warum keine Ahnung, aber scheinbar kann man etwas aktivieren, damit die Programme erhalten bleiben. Durch den Prozessexplorer kann man auch LSASS auf den Suspendstatus setzen allerdings gibt es dadurch später irgendwann stress, durch ungewollte Blockierung.

Hier noch weiteres, interessantes Material: http://blog.didierstevens.com/2006/08/21/playing-with-utilmanexe/

Per Zufall bin ich nun noch auf etwas anderes gestoßen, damit ist die Variante perfekt. Also, wie oben die Eingabeaufforderung öffnen und dann diesen Befehl eingeben:

rundll32.exe syssetup,SetupOobeBnk

Der sorgt dafür, dass nach dem erneuten Start des Servers die Anmeldung ganz normal funktioniert!!

Office 2013 Key Verwirrung zwischen Online Download und Datenträger Version, Office 2013 Key auslesen

5 Dezember 2013

Wer ein Office 2013 Paket mit einer Product Key Card ohne Datenträger kauft, der wird mal wieder von Microsoft zwangsverwirrt. Ich könnte gerade laut schreiend Amok laufen. Aber der Reihe nach:

Die Erfahrung zeigt, dass die Aktiviererei bei Kunden irgendwann immer daran scheitert, wenn ein Rechner neu eingerichtet werden muss: Wie? Passwort? Öhm, welche E-Mail-Adresse hatte ich da? Keinen Plan für sowas hab ich doch meinen ITler! Es könnte so schön sein, Office.com/setup aufrufen, anmelden und installieren klicken.

Also übernimmt man für die Kunden die Aktivierungsgeschichte. Nach ein paar Versionen wird es verdammt unübersichtlich. Aber was nun erschwerend hinzu kommt: Der Produktkey auf den Keykarten unterscheidet sich von dem Online dargestellten Key!! Wie soll ich später bei einer Neuinstallation jemals nachvollziehen können welcher Key zu welchem Kunden gehört? Warum müssen die Mädels von MS einen ständig so gängeln? Die IT soll helfen und das Leben einfacher machen doch genau das Umgekehrte ist der Fall.

Um nun bei einem installierten System den Officekey zuordnen zu können, sollte man zumindest Teile des Keys einsehen können. Normalerweise hilft Nirsoft’s ProduKey http://www.nirsoft.net/utils/product_cd_key_viewer.html, allerdings unterstützt dies momentan noch nicht Office 2013. Was bleibt? Zum Glück bietet Microsoft ähnlich dem SLMGR.VBS für Windows bei Office OSPP.VBS an.

So kann man bei einer aktuellen, üblichen Installation von Office 2013 32-Bit unter einem 64-Bit Windows, den Key über diesen Befehl in der Eingabeaufforderung auslesen:

cscript "C:\Program Files (x86)\Microsoft Office\Office15\OSPP.VBS" /dstatus

es erscheint dann sowas:

Microsoft (R) Windows Script Host, Version 5.8
Copyright (C) Microsoft Corporation 1996-2001. Alle Rechte vorbehalten.

—Processing————————–
—————————————
SKU ID: 71234424-9126-4312-2369-123123e23271
LICENSE NAME: Office 15, OfficeProPlus-Retail edition
LICENSE DESCRIPTION: Office 15, RETAIL channel
LICENSE STATUS:  —LICENSED—
ERROR CODE: 0 as licensed
Last 5 characters of installed product key: H234T
—————————————
—————————————
—Exiting—————————–

Man bekommt zwar nicht den gesamten Key angezeigt aber doch soviel, dass man die Keys mit den Online Keys vergleichen kann. Damit kann man zuordnen, welcher Key der richtige für die Neuinstallation ist.