Archiv der Kategorie: English

Blog entries in english

Convert a hashtable into its string representation

Recently I had to find a technique to update a module manitest file (psd1). Using the Update-ModuleManifest cmdlet is the official way to achieve this. Although using this command is really simple it completely overwrites the current psd1 file and inserts all the „junk“ that I want to keep out from that file.

Another approach is to load the psd1 file with the Import-LocalizedData cmdlet which results to a hashtable.

Updating single entries is easy:

But how do you turn the the whole hashtable with all its keys and values into a string again? Not so easy. Luckily I found an old blog entry by June Blender (when she was still working for Sapien Technologies):

https://www.sapien.com/blog/2014/10/21/a-better-tostring-method-for-hash-tables/

But June restricted her function to simple hashtables with no values that are hashtables themselves.

So I have extend her function so that it works also with hashtable that contains other hashtable values which is necessary to convert a hashtable that represents a psd1 file. Ny function calls itself recursively which which is not hard to accomplish in PowerShell. The difficult part can be to find an exit condition or threat the last value differently. For this reason I am not using foreach but the for command with an index variable to enumerate all the values. For the last value I add „}“ to complete the hashtable string.

As PowerShell expert Kirk Munro suggested in his comments to Junes blog post converting the hashtable to json might be a simpler solution. I have not tried this yet although it probably could have saved me a lot of typing and trying. But hey, why choosing a simple solution if you can spend a couple of hours fiddling with Powershell script code;)

So this should work. I have tested the function with a specific psd1 file. If not please leave a comment or send me a mail.

Kleine Tipps für Zwischendurch: Warum beim Vergleich $null links stehen sollte

Wer mit Visual Studio Code scriptet oder öfter den PSScriptAnalyzer verwendet, was immer eine gute Idee ist, wird sich schon öfter über folgende Warnung gewundert haben:

$null should be on the left side of equality comparisons. (PSPossibleIncorrectComparisonWithNull)

Warum sollte es eine Rolle spielen, ob $null links oder rechts vom -eq Operator steht? In praktisch jeder Programmiersprache, spielt dies keine Rolle. Nun, PowerShell ist einigen Kleinigkeiten etwas anders („seltsam“ wäre als Umschreibung wohl etwas zu subjektiv;).

Hier ist ein kleines Beispiel.

Im ersten Schritt lege ich ein leeres Array an.

Die Variable $Zahlen ist eigentlich leer, daher sollte die folgende Abfrage einen $true-Wert liefern.

Es kommt aber weder $true noch $false heraus, es kommt gar nichts heraus. Was zunächst sehr seltsam erscheint (warum liefert ein Vergleich kein Ergebnis?), ergibt einen Sinn, wenn man das Prinzip des Vergleichs kennt. Da das Array leer ist, wird kein Vergleich durchgeführt. Also kein Ergebnis. Der Vergleich wird also nicht mit der Variablen $Zahlen durchgeführt, sondern mit allen Elementen des Arrays. Und da das Array kein Element enthält, wird kein Vergleich durchgeführt. Und damit resultiert kein Ergebnis. Was am Anfang eventuell noch als etwas seltsam erschien, ergibt jetzt einen Sinn. So sollte es sein.

Möchte man die Variable $Zahlen richtig vergleichen, muss $null auf der linken Seite stehen:

Jetzt wird das Array als Ganzes verglichen. Der Vergleich führt zu einem $false, da die Variable mit einem leeren Array einen Wert besitzt.

Kleine Tipps für Zwischendurch: ForEach-Wiederholung mit Zählvariable

Ein kleiner Nachteil der praktischen ForEach-Methode von Arrays ist, dass es keine Zählvariable gibt. Mit dem ++-Operator spart man sich zumindestens einen weiteren Befehl, der die Variable inkrementiert.

Kleine Tipps für Zwischendurch: Wird ein Skript als Administrator ausgeführt?

Diese (harmlose) Frage „verfolgt“ mich seit der ersten PowerShell-Version. Es hat eine Weile gedauert bis mir der Hintergrund klar war.

Man holt sich zuerst die aktuelle Identität über [Security.Principal.WindowsIdentity]::GetCurrent() und macht daraus ein neues WindowsPrincipal-Objekt, das für den aktuell angemeldeten Benutzer steht. Dann muss nur noch geprüft werden, ob dieser Mitglied der Administratorengruppe ist.

Unter einem englischen Windows heißt die Gruppe „Administrators“, unter einem Französischen vermutlich „Le Administrateurs“ usw.

Mit der neuen statischen New-Methode, die es ab Version 5.0 bei jedem RuntimeType-Objekt gibt, wird der Aufruf noch etwas einfacher als in der Vergangenheit.

Noch einfacher wird es, wenn das Carbon-Modul geladen wurde, das mir insgesamt sehr gut gefällt. Dann genügt ein Test-AdminPrivilege.

Die ersten Schritte mit den AWS-Cmdlets (inkl. Problemlösung)

Amazon stellt für die Nutzung ihrer inzwischen sehr umfangreichen Amazon Webservices (AWS) ein sehr umfangreiches Modul (über 2.500 Cmdlets!) zur Verfügung. Die AWS Tools for Windows PowerShell stehen u.a. über die PowerShell Gallery zur Verfügung.

Eine ausführliche Übersicht gibt es unter der folgenden Adresse: https://aws.amazon.com/de/powershell/. Dort gibt es auch einen Button für den direkten Download einer Msi-Datei, über die das .NET SDK und die Cmdlets installiert werden.

Die Dokumentation ist, typisch für AWS, vorbildlich mit ein paar kleineren Abstrichen.

Das Modul muss direkt per Import-Module geladen werden.

Ein kleiner „Trick“ zählt die Anzahl der Cmdlets, in dem die Verbose-Ausgabe auf den Standardausgabekanal umgeleitet und damit in die Pipeline gelegt wird.

Die Authentifizierung erfolgt über einen Access Key und einen Secret Key, die man zuvor in der AWS-Konsole im Browser anlegen muss. Der Secret Key wird nur einmalig beim Anlegen eines neuen Key angezeigt und kann als Csv-Datei heruntergeladen werden.

Mit den beiden Zutaten wird per Set-AWSCredentials ein Profil angelegt.

Hier kam es bei mir zu einer Fehlermeldung, die besagte, dass der Pfad %userprofile%\.asws\credentials nicht gefunden werden konnte. Dieser Fehler muss wohl mit der Version der AWS-Tools (3.3.45.0) und anderen Faktoren zu tun haben. Der Fehler trat nicht mehr auf, nachdem ich im Benutzerprofil ein Verzeichnis mit dem Namen .aws angelegt hatte.

Interessant ist, dass die Keys aber nicht in diesem Verzeichnis, sondern als Json-Datei RegisteredAccounts.json unter %userprofile%\AppData\Local\AWSToolkit abgelegt werden.

Anschließend wurde das Profil per Get-AWSCredentials -ListStoredCredentials aufgelistet. Per Clear-AWSCredentials kann ein Profil wieder gelöscht werden.

Die weitere Vorgehensweise ist dann sehr einfach. Bei allen Cmdlets wie z.B. Get-S3Bucket erfolgt die Authentizierung über das Profil, das per ProfileName-Parameter angegeben wird.

Turn PowerShell scripts into an exe with Posh2Exe (update 12/14/2016)

I recently relased a small Windows console application that turns any ps1 script file into an exe file by embedding the ps1 as a resource into the exe.

Get the source code and compile the exe in Visual Studio

The project is on github:

https://github.com/pemo11/Posh2Exe

Right now you have to use Visual Studio (any of the current releases will do – I recommend Visual Studio 2015 Community Edition as the latest release) to create the exe file Posh2Exe.exe. I will provide a download link for the exe in the near future and also a small extension for the ISE so that making an exe out of the currently loaded ps1 will be very simple because you only have to click on a button.

Calling Posh2Exe in the Console Window (not in the ISE) is really simple:

This will embed test.ps1 into an exe test.exe (the name is not very original of course;). The exe can be run everywhere where WMF 4.0 or above and .NET 4.0 (which is a prerequisite for WMF 4.0) is installed.

If the ps1 file uses parameters the parameters has to be written like parametername:value separated by at least one blank.

I tested the current version of posh2exe with several scripts and it worked well for me.

Since its a kind of bare bone PowerShell host implementation some things do not work at the moment like Read-Host with the AsSecureString-Parameter or the different prompt-methods of the InternalHostUserInterface.

Another thing to consider is the fact that the PSScriptRoot variable has no value because there is no script file that will be executed just text. The workaround is to use [System.AppDomain]::CurrentDomain.BaseDirectory to get the path the exe is started from and [Environment]::CurrentDirectory to get the current path for the executing exe instead of $PSScriptRoot. For my own scripts that runs either as a ps1 file or inside an exe I using a simple query to decide how to get the path either the ps1 file or the exe is running in.

Big plans for the future…

One more thing I would like to add is a debug mode with the help of the „Debugger API“. So it will be possible to debug the script that is executed as part of the exe file with the PowerShell Debugger.

Feststellen, wer die Remote-Session benutzt

Möchte man in einer mit RunAsCredential-Parameter angelegten Remoting-Sitzung den Namen des Benutzerkontos abfragen, mit dem die Verbindung hergestellt wurde, liefert z.B. whoami nur den Benutzer des Administratorkontos dessen Credentials bei RunAsCredential angegeben wurden. Den Namen des Benutzerkontos, mit dem die Verbindung hergestellt wurde, erhält man über die Variable $PSSenderInfo und dessen ConnectedUser- (oder UserInfo-) Eigenschaft.