Netz-Weise Logo

Weisheiten - der Netz-Weise Blog

Hier finden Sie Tipps und Tricks für vor, während und nach der Schulung.

Binärdateien einlesen und Base64-Codieren mit Powershell

Grundsätzlich unterscheidet man zwischen Textdateien und Binärdateien. Technisch gesehen sind beide Dateitypen Bitströme, also Reihen von aufeinanderfolgenden Bits. Textdaten werden allerdings nach einem festen Muster kodiert. Jeweils ein Block von 8 oder 16 Bits (oder je nach Codierung auch mehr) werden zu einem Zeichen zusammengefasst. Die klassische Codierung ist dabei die sehr alte ASCII-Codierung, die ein Zeichen in jeweils 7 Bit codiert und insgesamt 8 Bit für die Speicherung verwendet. Wenn man Get-Content verwendet, um eine Textdatei einzulesen, versucht Get-Content automatisch, die Datei als Text zu interpretieren und darzustellen. 

get-content -Path $einv:Windir\lsasetup.log
[ 1 1 / 4 1 5 : 3 1 : 1 4 ] 5 9 6 . 6 0 0 > - I n L s a p S e t R a n d o m D o m a i n S i d ( )

[ 1 1 / 4 1 5 : 3 1 : 1 4 ] 5 9 6 . 6 0 0 > - L s a p G e n e r a t e R a n d o m D o m a i n S i d : R t l A l l o c a t e A n d I n i t i a l i z e S i d r e t u r n e d 0 x 0

Die Ausgabe dieses Beispiels sieht allerdings sehr merkwürdig aus - Powershell hat zwischen jedes Zeichen ein Leerzeichen gesetzt. Das liegt daran, dass die Datei in UTF16 und nicht in ASCII codiert ist. UTF16 ist eine Form der Unicode-Codierung, die statt 8 16 Bit verwendet, um ein Zeichen zu speichern. Dadurch wird es möglich, eine deutlich größere Zahl von Zeichen zu codieren. UTF16 ist abwärtskompatibel zu ASCII, verwendet also für die ersten 127 Zeichen die gleiche Muster. Das zweite Bit wird beim Einlesen mit ASCII-Codierung dann als Leerzeichen interpretiert. Das Problem lässt sich lösen, indem man Get-Content mti dem Parameter -Endoding anweist, den Text als UTF16 zu dekodieren. 

get-content -Path .\lsasetup.log -Encoding Unicode
[11/ 4 15:31:14] 596.600> - In LsapSetRandomDomainSid()
[11/ 4 15:31:14] 596.600> - LsapGenerateRandomDomainSid: RtlAllocateAndInitializeSid returned 0x0

Das sieht schon viel besser aus. Wenn man mit Get-Content allerdings versucht, eine Binärdatei einzulesen, versucht Get-Content, auch den Binärcode in Textzeichen zu übersetzen. Das ist allerdings sinnlos, da der Binärcode ein Bitstrom ist und keinen Text darstellt. Das Ergebnis ist Kauderwelsch. 

Weiterlesen
Markiert in:
  5011 Aufrufe

Virtuelle Festplatten (vhdx) als Datencontainer verwenden - nicht nur für VMs

Virtuelle Festplatten (Vhdx-Dateien) in Windows sind sehr praktisch. Man kann Sie nämlich nicht nur für virtuelle Maschinen verwenden, sondern auch als universelles Containerformat, um Daten zu transportieren oder sogar, um Windows aus einer VHD-Datei zu booten (s. https://www.netz-weise-it.training/weisheiten/tipps/item/377-boot-von-vhd-auf-einem-leeren-datentraeger-einrichten.html). Das Erstellen einer VHD-Datei ist allerdings etwas mühselig, weil man erst die Datei erstellen, dann einrichten und anschließend eine Partition erstellen muss. Da man das aber auch mit Powershell erledigen kann, und ich dieses Feature sehr oft verwende, habe ich eine kleine Funktion dafür geschrieben. 

#requires -Modules Hyper-V, Storage -RunAsAdministrator

function Get-Freedrive
{
<#
  .SYNOPSIS
  Get-Freedrives lists the first free driveletter in the alphabet.
  .DESCRIPTION 
  Get-Freedrive can be used to test for the first available free driveletter. The Parameter $inverse searches backwards through the alphabet.
  .EXAMPLE
  get-freedrive -inverse -startLetter Z
  Starts the search with letter z searching backwards. Returns a character.
  .NOTES
  Version: 1.0
  Author: Holger Voges
  Date: 2018-08-17
  www.netz-weise-it.training/weisheiten/
#>

[cmdletbinding()]
param(
  # The letter to start the search from - default is C or Z, if -inverse is chosen
  [char]$startLetter = 'C',

  # Inverse forces a backwards search through the alphabet
  [switch]$inverse

Weiterlesen
  3596 Aufrufe

Powershell-Skriptmodule erstellen

Ein extrem cooles Features sind die in Powershell 2.0 eingeführten Module. Module sind Erweiterungen, die in Powershell geladen werden und weitere Cmdlets zur Verfügung stellen. Ab Powershell 3.0 können über das Modul-Autoloading Module sogar ohne weiteres zutun des Benutzers beim Starten einer Powershell automatisch geladen werden. 

Module gibt es in Form von Binärmodulen, die z.B. in C# geschrieben werden, und in Form von sogenanten Skriptmodulen. Ein Skriptmodul ist dabei eigentlich nichts anderes als ein Powershell-Skript, dass global aufgerufen wird und im Normalfall Funktionen enthält, die dann wie Cmdlets gestartet werden können. Funktionen verhalten sich dabei wie ein Skript, dass überall in der Powershell-Konsole mit über den Namen aufgerufen werden kann, ohne dass man sich im Skriptpfad befinden müsste, da die Funktionen direkt in den Arbeitsspeicher geladen und von dort aus gestartet werden. 

Ein Skriptmodule zu erstellen, ist sehr einfach und braucht auch keine erweiterten Powershell-Kenntnisse. Prinzipiell kann jedes beliebige Powershell-Skript wie ein Module verwendet werden, indem man es einfach über das Cmdlet Import-Module <Skriptdatei> startet. Sinniger ist es aber, das Skript als automatisch ladendes Skript abzulegen. Dazu muß die Skriptdatei in einem der Module-Ordner abgelegt werden, die von Powershell automatisch beim Starten geprüft werden. Welche Ordner Module-Ordner sind, legt dabei die Umgebungsvariable PSModulePath fest. Sie können die Modulorder in Powershell dabei übersichtlich anzeigen lassen, indem Sie sich mit der String-Methode Split() den String in seine Einzelpfade aufsplitten lassen. Geben Sie dafür folgende Codezeile in und bestätigen Sie mit Enter:

$env:psModulePath.split(";")
C:\Users\admin.NETZ-WEISE\Documents\WindowsPowerShell\Modules
C:\Program Files\WindowsPowerShell\Modules
C:\Windows\system32\WindowsPowerShell\v1.0\Modules

Wie Sie im Beispiel sehen können, verwendet Powershell standardmäßig drei Modul-Pfade - einen für Windows-eigene Module im Powershell-Ordner, einen für Nicht-Windows-Module unter "Program Files" und einen benutzerspezifischen im Dokumente-Ordner des Benutzers. Sie können Ihre eigenen Skripte als Module unter "Program Files" oder unter Documents ablegen, wenn das Module nur für den Benutzer zur Verfügung stehen soll. Legen Sie hierfür im Module-Ordner einen neuen Unterordner an, und speichern Sie Ihr Skript innerhalb dieses Ordners mit der Endung .psm1. Sie können als Beispiel die Funktion Replace-SharePath aus dem Tipp Windows Freigaben auf einen neuen Pfad migrieren verwenden. Als Dateinamen verwenden Sie den gleichen Namen wie für den Ordner. Das Modul "KleineHelfer" muß also als "%ProgramFiles%\WindowsPowershell\Modules\KleineHelfer\KleineHelfer.psm1" gepeichert werden. Beim Start der nächsten Powershell-Konsole wird Ihr Modul automatisch geladen. Ist das nicht der Fall, können Sie die Fehlermeldung erzwingen, indem Sie das Modul von Hand mit dem Parameter -force laden:

Weiterlesen
Markiert in:
  4549 Aufrufe

Windows Freigaben auf einen neuen Pfad migrieren mit Powershell

Wenn Sie auf einem Dateiserver Ordner umziehen müssen, kann das Anpassen der Freigaben auf untergeordneten Ordnern sehr aufwändig werden, z.B. wenn es sich um eine große Menge von Home-Shares handelt. Einfacher als über die GUI geht es, wenn Sie die Registry-Schlüssel unter HKEY_LocalMachine\SYSTEM\CurrentControlSet\Services\LanmanServer\Shares\ anpassen. Alternativ können einfach die folgende Powershell-Funktion verwenden, die einen gegebenen Pfad in dem Registry-Schlüssel durch einen neuen ersetzt. Da es sich um eine reine Musterersetzung handelt, können Sie beliebige Teilpfade ersetzen lassen.

function Replace-SharePath
{
<#
    .SYNOPSIS
    Replace the Filesystem-Path of a Share

    .Description
    Replace-Sharepath can change the Filesystem-Path of shares. This can be helpful if you need to move
    Files to a new Drive or have to move files to a subfolder and you have multiple Shares to touch. The
    Script will change the given String into the new string, so all shares under the given Path will be
    affected.
             
    .EXAMPLE
    To move Files from C:\Shares to D:\NewSharesFolder:
    Replace-SharePath -Path c:\Shares -NewPath D:\NewSharesFolder
#>
param(
    [ValidateScript({ if ( ! ( Test-Path -path $_ -PathType Container )) {Throw "Bitte den Quellpfad prüfen!"}; $true })]
    [Parameter(mandatory=$true)]
    # The Path to Change.
    $Path,

    [ValidateScript({ if ( ! ( Test-Path -path $_ -PathType Container )) {Throw "Bitte den Quellpfad prüfen!"}; $true })]
    [Parameter(mandatory=$true)]
    # The New Path
    $Newpath
)

    $path = $Path.Replace('\','\\')
    $Newpath = $Newpath.Replace('\','\')
    $ShareList = Get-Item HKLM:\SYSTEM\CurrentControlSet\Services\LanmanServer\Shares\
    ForEach ( $Share in $ShareList.Property )
    {
        Get-ItemProperty -Path $ShareList.pspath -Name $share
        $newValue = ( Get-ItemProperty -Path $ShareList.pspath -Name $share ).$Share -replace "(^Path=)($path)","Path=$newpath"
        Set-ItemProperty -Path $ShareList.pspath -Name $Share -Value $Newvalue -PassThru
    }
}

Weiterlesen
  5128 Aufrufe

Geschweifte Klammern im Powershell Format-Operator benutzen am Beispiel GUIDs

Powershell hat mit dem Format-Operator -f eine geniale Möglichkeit, Texte zu formatieren. Der Format-Operator erlaubt es, Daten in einen Text zu "kopieren" und Zahlen auch gleich nach Bedarf in ein passendes Format zu bringen. Hier ein kleines Beispiel, um das Ergebnis einer Berechnung zu runden und in einen Text einzufügen:

$FolderSize = Get-Childitem -Path $env:programFiles -file -recurse | Measure-Object -Property Length -Sum
'Der Ordner {0} ist {1:0.000} MB groß' -f $env:programFiles,($Foldersize.Sum/1MB)
Der Ordner C:\Program Files ist 9169,447 MB groß

Die Syntax ist recht simpel - Sie generieren einen String, schreiben aber statt der Variablen, die in den Text eingefügt werden sollen, Platzhalter. Die Platzhalter sind durchnummeriert, beginnen bei 0 und sind in geschweifte Klammern eingefasst. Genau genommen sind die Nummern in geschweiften Klammern der Index eines Arrays, nämlich des Arrays, das Sie hinter dem Format-Operator -f angeben. {0} entspricht also dem ersten Wert hinter -f, {1} dem zweiten usw. Zahlen können Sie formatieren lassen. Geben Sie hierfür hinter dem Platzhalter einen Doppelpunkt an, und dann für jede Pflichtstellt vor dem Komma eine 0, und für jede Pflichtstelle hinter dem Komma ebenfalls eine Null. Komma wird aufgrund der amerikanischen Schreibweise mit . (Punkt) angegeben. Damit eine Zahl immer mit einer Stelle vor und drei Stellen hinter dem Komma angegeben wird, schreiben Sie also: {0:0.000}. Es gibt auch eine ganze Reihe anderer Optionen. So können Sie mit {0:C} z.B. automatisch ein Währungsformatierung (Currency) mit zwei Stellen hinter dem Komme und dem Währungssymbol der einstellten Sprache erzwingen. Eine Auflistung der Operatoren finden Sie unter https://social.technet.microsoft.com/wiki/contents/articles/7855.powershell-using-the-f-format-operator.aspx

Der Format-Operator lässt sich auch prima zum Einfügen von Zeichen verwenden, z.B. um eine Variable in Klammern oder Anführungszeichen einzufassen:

'[{0}]' -f "Ein Text in Klammern"
'"{0}"' -f "Ein Text in Anführungszeichen"

Weiterlesen
Markiert in:
  5320 Aufrufe

Kontoinformationen über den angemeldeten Benutzer ausgeben

Sie hätten gerne Informationen über Ihre Benutzerkonto, wie Gruppenmitgliedschaften, SID usw? Wenn Sie Informationen über den gerade angemeldeten Benutzer haben möchten, wie z.B., ob der User als Gastkonto angemeldet ist, den Benutzernamen, die Domäne oder die Gruppenmitgliedschaften, hilft Ihnen die Funktion getcurrent() aus der Klasse [system.security.principal.windowsidentity] weiter.

[system.security.principal.windowsidentity]::getcurrent()

liefert folgende Properties zurück:

Name
----
Actor
AuthenticationType
BootstrapContext
Claims
DeviceClaims
Groups
ImpersonationLevel
IsAnonymous
IsAuthenticated
IsGuest
IsSystem
Label
Name
NameClaimType
Owner
RoleClaimType
Token
User
UserClaims

Eine Variante, die Ihnen entweder den Benutzer oder die Benutzermitgliedschaften zurückliefert, ist das Kommandozeilentool whoami. Mit den Parameter /User erhalten Sie Ihre SID, mit /Groups Ihre Gruppenmitgliedschaften. Alle wichtigen Informationen inklusive der Benutzerrechte spuckt der Parameter /all aus. Mit dem Parameter /Fo können Sie auch die Ausgabe im CSV-Format erzwingen, so dass Sie die Ausgabe mit Powershell direkt in Objekte konvertieren können:

Whoami.exe /groups /fo csv | ConvertFrom-CSV | Out-Gridview

Weiterlesen
  4788 Aufrufe

Mit Powershell ein Kennwort gegen AD prüfen

Wenn Sie mit Powershell überprüfen möchten, ob eine gegebene Kombination aus einem AD-Benutzernamen und Kennwort korrekt ist (z.B. aus einer GUI-Eingabe), hilft Ihnen die .NET-Assembly System.Directore.Accountmanagement weiter (mind. .NET-Framwork 3.5). Die Klasse "PrincipalContext" enthält eine Methode ValidateCredentials, die die Überprüfung übernimmt. Die Funktion check_AdUserPassword liefert True oder False zurück und kann z.B. direkt in einem IF-Statement weiter genutzt werden.

Function Test-AdUserPassword
{

param (
    [string]
    $UserName,
    [string]
    $Password,
    [string]
    $UserDomain)

   # Lädt die Assembly "System.DirectoryServices.AccountManagement" in Powershell
   $Null = Add-Type -AssemblyName System.DirectoryServices.AccountManagement
   $ContextType = [System.DirectoryServices.AccountManagement.ContextType]::Domain
   $PrincipalContext = New-Object System.DirectoryServices.AccountManagement.PrincipalContext($ContextType, $UserDomain)
   $PrincipalContext.ValidateCredentials($UserName,$Password)

}

 

  4084 Aufrufe

Zwei XML-Dateien mit Powershell vergleichen und einen HTML-Report erzeugen

Das XML-Format ist allgegenwärtig. Als Windows-Administrator stolpert man regelmäßig über Eventlogs im XML-Format, Anweisungsdateien für die unbeaufsichtigte Installation, Vorlagen für Gruppenrichtlinien usw. Und manchmal wäre es ganz schön, wenn man sich den Unterschied zwischen zwei ähnlichen XML-Dateien einfach anzeigen lassen könnte. Mit Powershell und ein bißchen .net ist das in der Tag auch gar kein Problem, denn Microsoft hat vor fast 15 Jahren eine .Net-Bibliothek zur Verfügung gestellt, die genau das tut - das XML Diff & Patch GUI Tool. Das Tool stellt eine Klasse zur Verfügung, über die es möglich ist, zwei XML-Dateien zu vergleichen und die Unterschiede in der XML DIfference Language (Diffgram) auszugeben. Mit einer weiteren Klasse kann man aus einer Diffgram-Datei und einer der beiden Vergleichsdateien eine HTML-Datei erzeugen, die die Unterschiede grafisch darstellt.

Wenn Sie die heruntergeladene Bibliothek entpacken, finden Sie im zwei .dlls, die Sie laden müssen, die XmlDiffPath.dll, die die Compare()-Methode zur Verfügung stellt, und die XmlDiffPath.View.dll, die die Methode GetHtml() bereitstellt. GetHtml erstellt aus einer Diffgram-Datei eine HTML-Datei. Laden Sie die Klassen und erstellen Sie zwei neue Objekte.

Add-Type -Path "xmldiffpatch.dll"
$XmlDiff = New-Object -TypeName Microsoft.XmlDiffPatch.XmlDiff
Add-Type -Path "XmlDiffPatch.View.dll"
$XmlDiffView = New-Object -TypeName Microsoft.XmlDiffPatch.XmlDiffView

Anschließend können Sie die Methode Compare() aufrufen. Compare hat eine Reihe von Überladungen (verschiedene Parameter-Kombinationen). Zum Erstellen eines Diffgramwriters benötigen Sie die beiden zu vergleichenden XML-Dateien, $false und einen .Net-Streamwriter zum Schreiben der Diffgram-Datei:

$DiffGramWriter = [System.Xml.XmlWriter]::Create( 'C:\temp\Diffgram.xml' )
#call Compare method from Microsoft.XmlDiffPatch.XmlDiff object
$XmlDiff.Compare('C:\temp\File1.xml','C:\Temp\File2.xml',$false,$DiffGramWriter)
$DiffGramWriter.Close()

Weiterlesen
Markiert in:
  6012 Aufrufe

USB-Geräte mit Powershell und WMI auslesen

Am USB angeschlossene Geräte kann man per WMI auslesen. WMI stellt dafür die WMI Association Klasse Win32_USBControllerDevice zur Verfügung, die zwei Klassen miteinander verbindet - in diesem Fall die Daten des USB-Controllers und die installierten Treiber. Die verknüpften Treiber kann man aus der Eigenschaft Dependent auslesen.

Get-WmiObject Win32_USBControllerDevice | Foreach-Object { [Wmi]$_.Dependent }

[WMI] Wandelt den String, der in der Eigenschaft $_.Dependent hinerlegt ist, wieder eine WMI-Klasse um. Um einen überschaubaren Überblick über die installierten Geräte zu bekommen, wählt man am Besten erst einmal die Eigenschaften Descritption und DeviceID aus.

Get-WmiObject Win32_USBControllerDevice | ForEach-Object { [wmi]$_.dependent } | select-Object description,deviceid

Das Ergebnis sieht dann ungefähr so aus:

Weiterlesen
  14518 Aufrufe

Den Windows Lizenzkey aus der Firmware aka Bios auslesen und aktivieren per Powershell

Letzte Woche habe ich durch Zufall festgestellt, dass der Rechner einer Kollegin, der schon vor Jahren per automatischem Update auf Windows 10 aktualisiert worden ist, immer noch nicht aktiviert war, obwohl das vorher installierte Windows 8.1 es war und Windows 10 sich außerdem den Key automatisch aus der Firmware ziehen soll, wenn er da hinterlegt ist. Glücklicherweise ist die Aktivierung von Windows 10 immer noch mit den Keys voriger Versionen möglich. Der Key selbst ist im BIOS nicht einsehbar, läßt sich aber über WMI einfach auslesen. Er ist in der Klasse SoftwareLicensingService in der Eigenschaft OA3xOriginalProductKey hinterlegt. Mit Powershell nutzen Sie für das Auslesen einfach Get-WMIObject oder Get-CIMClass:

(Get-WmiObject -Class SoftwareLicensingService).OA3xOriginalProductKey

oder ab Powershell 4 auch

(Get-CimInstance -ClassName SoftwareLicensingService ).OA3xOriginalProductKey

Mit dem Tool slmgr.vbs können Sie die LIzenz auch gleich installieren und aktivieren:

Weiterlesen
  6215 Aufrufe