Haikos Blog Blog von Haiko Hertes zu allen Themen rund um Microsoft und Datacenter

12Mrz/180

PowerShell Core und Jenkins – Continuous Integration für PowerShell auf Linux

In letzter Zeit beschäftige ich mich immer mal wieder mit DevOps-Themen. Eines davon ist Continuous Integration und das dafür gemachte Jenkins. Einige meiner Erfahrungen hierzu möchte ich gerne teilen.

Dieser Artikel beschäftigt sich mit PowerShell Core und Jenkins. In einem vorherigen Artikel habe ich in Kurzform erläutert, wie man Jenkins unter Debian Linux installiert. Das ist für diesen Artikel eine Art Voraussetzung.

Auch ohne PS Core kann Jenkins PowerShell-Code und –Skripte ausführen – allerdings braucht es dazu immer einen sogenannten “Build Slave” (also einen weiteren Jenkins-Knoten) mit Windows als Betriebssystem,

Mit der Verfügbarkeit von PowerShell Core für Linux ist es künftig nicht mehr zwingend nötig, einen Windows Buildslave zu verwenden, wenn man PowerShell benutzen möchte. Was leider NICHT funktioniert (zumindest mit Stand Heute), ist das PowerShell-Plugin für Jenkins. Dieses ruft den Code in einer Art und Weise auf, wie es nur unter Windows funktioniert. Selbst wenn man den dort verwendeten Aufruf “powershell.exe” mittels symbolic Link oder Alias auf pwsh mappt, wird es nicht funktionieren.

Ein möglicher Weg führt aber über den Einsatz eines Batch-Skriptes. Und das könnte so aussehen:

jenkins9
jenkins10

Mit Hilfe von Parametern kann später flexibler mit dem Build Job umgegangen werden (siehe weiter unten):

jenkins11

Der Einfachheit halber sollte der Parametername keine Leer- oder Sonderzeichen enthalten.

Für den eigentlichen Build (also die Aktionen, die durch den Job auszuführen sind), muss man hier nun auf “Shell ausführen” zurückgreifen. Der Menüpunkt “Windows PowerShell” wird nicht funktionieren (er steht auch nur zur Verfügung, wenn das Plugin bereits installiert ist).

jenkins12

Mein Aufruf für die Shell lautet hier beispielhaft:

pwsh -command "(Get-Variable -Name ${VariableName}).Value"

Mit ${PARAMETER} kann man auf den oben definierten Parameter zurückgreifen.

jenkins17

Anschließend kann man den Buildjob über “Bauen mit Parametern” aufrufen. Dabei kann man dann den Wert des/der Parameter definieren (oder, falls man Defaultwerte definiert hat, diese einfach beibehalten):

jenkins18

Anschließend kann man mit einem Klick auf den kleinen Pfeil neben dem Buildjob unten bei “Build-Verlauf” die “Konsolenausgabe” aufrufen:

jenkins19

Dort sieht man dann entweder den/die Fehler, falls welche aufgetreten sind, oder eben die Ausgabe des Jobs:

jenkins20

7Mrz/180

Azure Cloud Shell – PowerShell für Azure

Auch wenn es nicht erst seit gestern verfügbar ist, wollte ich gern auf ein cooles Feature in Azure hinweisen: Azure Cloud Shell.

Kurz gesagt handelt es sich hier um ein Zugang zu Azure und seine Funktionen über PowerShell oder Linux Bash. Diese Shell läuft in einem Container auf Azure und kann ganz einfach über den Browser verwendet werden. Dazu ruft man einfach

https://shell.azure.com

auf. Nach der Anmeldung muss einmalig ein Storageaccount eingerichtet werden, der dann in die Shell gemountet wird

und dort als Speicher zur Verfügung steht:

image

Nach der Anmeldung bei Azure muss die gewünschte Subscription ausgewählt werden:

image

Dann erfolgt die Auswahl der gewünschten Shell – Bash auf Linux oder PwerShell auf Windows:

image

Außerdem muss ein Storageaccount ausgewählt oder angelegt werden, wozu die Auswahl des gewünschten Abonnements erfolgen muss:

image

image

Das Anlegen des Storage Accounts und der erste Start der Shell dauern dann leider etwas…

image

image

Fortan steht die Shell auch etwas schneller zur Verfügung. Sie kann auch aus dem Azure Portal aufgerufen werden – dazu ist der Button in der oberen Leiste gedacht:

image

Es gilt, ein paar Kleinigkeiten zu beachten:

  • Es gibt einen 20-Minuten-Timeout in der Shell. Nach 20 Minuten Inaktivität wird die Shell recycelt.
  • Änderungen im Dateisystem sind nur innerhalb von $Home und clouddrive persistent
  • Man kann jederzeit zwischen Bash und PowerShell umschalten – aber man kann immer nur eine Shell gleichzeitig laufen haben
  • Der Power-Button oben startet die Shell (bzw. deren Container) neu – dabei gehen dann z.B. die Variablen und deren Werte verloren
  • Das Starten einer auf PowerShell basierenden Cloudshell kann ca. 60 Sekunden dauern – Bash geht deutlich schneller

Weitere Details siehe hier:

https://docs.microsoft.com/en-us/azure/cloud-shell/overview

6Mrz/181

Win32 OpenSSH unter Windows 10 1709 aktivieren und nutzen

Im Zuge der Weiterentwicklung von PowerShell Core und der Ausrichtung auf Linux-Systeme hat Microsoft eine neue Strategie für die Remote-Verwaltung von Systemen entwickelt. Diese beinhaltet u.a. die Verwendung von OpenSSH unter Windows. Das an sich ist nicht wirklich neu – zumindest etwas neuer ist aber die Tatsache, dass diese Technologie jetzt seit dem 1709 Build (“Fall Creators Update”) als Beta im System integriert ist. Allerdings müssen die Komponenten bei Bedarf noch aktiviert / installiert werden. Und das geht so:

Startmenü / Einstellungen (Zahnrad) / Apps / Optionale Features verwalten / Feature hinzufügen:

image

image

Dort finden sich dann die beiden OpenSSH Optionen:

image

Beide Optionen sollten eigentlich selbst-erklärend sein…

Alternativ kann die Installation auch über PowerShell erfolgen:

# Installieren von Server und Client
Add-WindowsCapability -Online -Name OpenSSH*
# Nur Server
Add-WindowsCapability -Online -Name OpenSSH.Server*
# Nur Client
Add-WindowsCapability -Online -Name OpenSSH.Client*

image

image

Der SSH Client läuft jetzt völlig problemlos von der Kommandozeile – wenn man den vollen Pfad benutzt:

C:\Windows\System32\OpenSSH\ssh.exe

Spätestens nach dem nächsten Neustart ist dann der Pfad auch in PATH und damit von überall aus aufzurufen.

image

Die Konfiguration des OpenSSH-Servers ist ein kleines bisschen aufwändiger. Diesem Thema werde ich demnächst einen weiteren Blogartikel widmen. Stay tuned!

30Jan/180

PowerShell & Fotobox – Fotos zu einem bestimmten Hashtag von Instagaram laden

Auf meiner in den letzten Wochen und Monaten gebauten Fotobox (Mehr dazu hier) gibt es einen extra Bildschirm für eine Slideshow der aufgenommenen Fotos. Diese zeigt die neuesten x Fotos aus der Liste aller aufgenommenen Bilder, wobei ein neues Foto immer das älteste Bild ablöst (zu der technischen Realisierung hier werde ich später noch einen größeren Artikel schreiben).

Nun kam mir in diesem Zusammenhang die Idee, aus den sozialen Medien ebenfalls die aktuellsten Bilder zu einem bestimmten Hashtag abzurufen, damit die Gäste unter diesem Hashtag Handyfotos posten könnten, die dann wiederum in die Slideshow einfließen sollten. Hierzu gibt es ein paar Lösungen im Internet, die aber fast alle recht teuer sind und auch größtenteils nur im Browser ablaufen. Ich wollte aber gern die einzelnen Dateien lokal auf dem Rechner haben. Also habe ich mir ein PowerShell-Skript geschrieben, welches genau diese Anforderung erfüllt – allerdings vorerst nur für Instagram.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# What are you searching for?
$Hashtag = "PUTYOURHASHTAGHERE"
 
# How long to wait for the next retry - set to 0 to only search once
$SecondsBetweenRequests = 10
 
# Where do you want to store the downloaded pictures? Use no "\" at the end!
$WhereToStorePictures = "D:\Pictures\" 
 
### Don't change anything below here unless you know what you are doing! ###
 
# If the destination folder does not exist, we need to create it first
If(!(Test-Path $WhereToStorePictures -PathType Container)) 
{
    New-Item $WhereToStorePictures -ItemType Directory
}
 
$URI = "https://www.instagram.com/explore/tags/$Hashtag/"
 
# We are running this from now one until CTRL-C is pressed
Write-Host "To stop the process, press CTRL+C - otherwise it runs forever!" -ForegroundColor Yellow
While($true)
{
    # Get the whole content according to the hashtag search
    $HTML = Invoke-WebRequest -Uri $URI 
 
    # Get all the filenames of pictures with that hashtag from the HTML
    $URLs = ($HTML.Content | Select-String -Pattern '"display_url":\s.*?"edge_liked_by"' -AllMatches).Matches.Value | ForEach-Object {$_.Substring(16,$_.Length-34)}
 
    # Iterate through all the pics on the website
    ForEach($URL in $URLs)
    {
        # We need the filename to see if it was allready downloaded
        $Filename = $URL.Substring($URL.LastIndexOf('/')+1,$URL.length-$URL.LastIndexOf('/')-1) 
 
        # If the pic is not allready in the destination folder, download it
        If(!(Test-Path -PathType Leaf -Path "$WhereToStorePictures\$Filename"))
        {
            Write-Host "`nNew Picture found!" # You can remove this if you want
            Start-BitsTransfer $URL -Destination "$WhereToStorePictures\" # The actual download
        }
    }
    If($SecondsBetweenRequests -eq 0) # Then we just do the download-thing once
    {
        break
    }
    else
    {
        Start-Sleep -Seconds $SecondsBetweenRequests
        Write-Host "." -NoNewline # Just to let you know it is still working... - you can remove this if you want
    }
 
}

 

Das Skript ist wie üblich auch im Microsoft Script Center zu finden: https://gallery.technet.microsoft.com/scriptcenter/PowerShell-Get-Instagram-7d9ddb44

Viel Spaß beim Ausprobieren oder adaptieren!

23Jan/180

PowerShell – Geeigneten Host für neue VM finden

Wer kennt das nicht? Da will man eine neue VM installieren und stellt sich dabei unweigerlich folgende Frage:

Welcher meiner Hyper-V Hosts ist dafür am besten geeignet?

Klar, jetzt könnte man einfach im SCVMM nachsehen, ja gar die Bereitstellung darüber abwickeln und sich den besten Host vorschlagen lassen. Was aber, wenn man keinen SCVMM hat (so wie wir)? Dann hilft einem zum Glück die PowerShell – und mein kleines Script!

Dieses fragt alle aufgelisteten Hyper-V-Hosts nach deren Hardware-Ressourcen ab und listet diese dann auf. Dabei werden folgende Informationen ausgegeben:

  • Anzahl physischer und logischer Cores
  • Anzahl bereits verwendeter vCores
  • Verhältnis zwischen logischen und virtuellen Cores (Sollte 1:8 nicht übersteigen)
  • Vorhandener RAM gesamt
  • Belegter RAM

Im Script enthalten ist eine Funktion, die entsprechende Objekt liefert, wodurch sich das Script auch in andere Automatisierungen einbauen lässt. Ihr findet das Script als Download weiter unten. Hier erstmal das Listing:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
$AllHyperVHosts = "HOST1","HOST2","HOST3","HOST4"
 
function Get-HyperVHostInfo([string]$HyperVHost)
{
 
    $vCores = ((Get-VM -ComputerName $HyperVHost).ProcessorCount | Measure-Object -Sum).Sum
 
    $Property = "numberOfCores", "NumberOfLogicalProcessors"
    $CPUs = Get-Ciminstance -class Win32_Processor -Property  $Property -ComputerName $HyperVHost| Select-Object -Property $Property 
    $Cores = ($CPUs.numberOfCores | Measure-Object -Sum).Sum
    $logCores = ($CPUs.NumberOfLogicalProcessors | Measure-Object -Sum).Sum
 
    $os = Get-Ciminstance Win32_OperatingSystem -ComputerName $HyperVHost
    $MemFreePct = [math]::Round(($os.FreePhysicalMemory/$os.TotalVisibleMemorySize)*100,2)
 
    $object = New-Object -TypeName PSObject
    $object | Add-Member –MemberType NoteProperty –Name PhysicalCores –Value $Cores
    $object | Add-Member –MemberType NoteProperty –Name LogicalCores –Value $logCores
    $object | Add-Member –MemberType NoteProperty –Name VirtualCores –Value $vCores
    $object | Add-Member –MemberType NoteProperty –Name MemTotalGB -Value ([int]($os.TotalVisibleMemorySize/1mb))
    $object | Add-Member –MemberType NoteProperty –Name MemFreeGB -Value ([math]::Round($os.FreePhysicalMemory/1mb,2))
    $object | Add-Member –MemberType NoteProperty –Name MemFreePct -Value $MemFreePct
 
    Return $object
}
 
ForEach($OneHost in $AllHyperVHosts)
{
    $HostData = Get-HyperVHostInfo -HyperVHost $OneHost
 
    Write-Host "$OneHost has $($Hostdata.PhysicalCores) physical cores, $($Hostdata.LogicalCores) logical cores and $($Hostdata.VirtualCores) virtual cores are used in all VMs overall." -ForegroundColor Yellow
    Write-Host "The Core:vCore ratio is `t`t1:$([math]::Round(($Hostdata.VirtualCores) /  ($Hostdata.PhysicalCores),2))"
    Write-Host "The Log.Core:vCore ratio is `t1:$([math]::Round(($Hostdata.VirtualCores) /  ($Hostdata.LogicalCores),2))"
    Write-Host "The system has $($Hostdata.MemFreeGB)GB of free memory and $($Hostdata.MemTotalGB)GB memory at all, which is $($Hostdata.MemFreePct)% free"
    Write-Host ""
 
}
Write-Host "The conservative approach for logical cores is `t1:8 "

Das Script als *.ps1 Datei gibt es hier:

https://gallery.technet.microsoft.com/scriptcenter/PowerShell-Get-vCore-507be5dc

13Jan/180

PowerShell Core 6.0: Generally Available (GA)

Wie Microsoft vor wenigen Tagen berichtet hat (siehe Blogartikel), ist PowerShell Core 6.0 seit dem 10.01.2018 GA und wird von Microsoft voll supported!

Den Download für PowerShell Core 6.0 findet man hier:

PowerShell Core für Windows

PowerShell Core für Linux / macOS

Microsoft empfiehlt das Entfernen alter PS Core Versionen und eine saubere Neuinstallation:

sudo apt remove powershell && sudo apt-get install powershell

Die Liste der unterstützen Betriebssysteme ist lang:

  • Windows 7, 8.1, and 10
  • Windows Server 2008 R2, 2012 R2, 2016
  • Windows Server Semi-Annual Channel
  • Ubuntu 14.04, 16.04, and 17.04
  • Debian 8.7+, and 9
  • CentOS 7
  • Red Hat Enterprise Linux 7
  • OpenSUSE 42.2
  • Fedora 25, 26
  • macOS 10.12+

Wichtig ist ein Hinweise am Ende des Artikels:

Windows PowerShell 3.0, 4.0, and 5.1 will continue to be supported on supported versions of Windows and Windows Server.
(Note: While Windows PowerShell 2.0 is still in support, it has been deprecated, and it’s recommend that workloads be migrated to newer versions of PowerShell.)

Für Windows PowerShell ab Version 3.0 gibt es also weiterhin Support – aber Neuerungen/Verbesserungen darf man hier wohl nicht mehr erwarten.

Viel Spaß beim Ausprobieren!

28Nov/170

PowerShell: Alte Offline-Backups von Windows Server Sicherung entfernen

Mir ist kürzlich bei einem Server das Sicherungsziel der täglichen Windows Serversicherung gestorben, da dieser (sehr einfache) Hyper-V-Server nur auf eine USB-Disk sichert, deren Speicherplatz per iSCSI an die VMs durchgereicht wird. Dies hat zur Folge, dass die Windows Serversicherung die dort abgelegten Sicherungen für alle Ewigkeit weiterhin anzeigt und mitzählt. Bei dem Versuch einer Wiederherstellung von Daten auf der gestorbenen Platte würde angezeigt werden, dass das Sicherungsziel offline ist und man hätte die – praktisch nicht mehr umsetzbare – Möglichkeit, die Daten verfügbar zu machen.

wsbkp1

Wenn man jetzt die Infos über die nicht mehr vorhandenen Sicherungen löschen will, um eine saubere “Statistik” zu haben, kann man sich eines PowerShell-Cmdlets bedienen: Remove-WBBackupSet.

Der Aufruf dazu sieht so aus:

Remove-WBBackupSet –MachineName SERVERNAME -KeepVersions 4

Der Parameter –KeepVersions gibg dabei an, wieviele der letzten Sicherungen man behalten möchte. Alternativ kann man mit –DeleteOldest die X ältesten Sicherungen entfernen.

wsbkp2

Bei dem Aufruf wird es aber sehr wahrscheinlich zu vielen Fehlern kommen, wie man im Screenshot sieht. Da die Sicherungen nicht mehr erreichbar sind, das Cmdlet aber eigentlich die Files dazu löschen würde, muss man sich hier zusätzlich des –Force Parameters bedienen:

wsbkp3

Dabei wird die Tatsache, dass die Sicherungen auf der ausgefallenen Platte nicht mehr erreichbar sind, ignoriert und nur der Verweis auf diese Sicherungen entfernt.

Mit dem Aufruf Get-WBBackupSet kann man sich nochmal ausgeben lassen, wieviele Sicherungen Windows Server Backup “kennt”:

wsbkp4

22Nov/170

Hyper-V: Welcher Host ist am besten für eine neue VM geeignet?

Mir stellt sich im Administrations-Alltag immer wieder die Frage, welcher unserer Hyper-V-Hosts derzeit am besten für eine neue VM geeignet ist (Nein, wir verwenden leider kein VMM…). Anstatt aber dabei jedes Mal jeden Host hinsichtlich seiner freien Ressourcen “abzuklappern”, habe ich mir ein entsprechendes PowerShell-Skript geschrieben, was eine passende Function bereithält. Ihr könnt das Skript gerne für eure Zwecke anpassen oder direkt so übernehmen.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
$AllHyperVHosts = "HostNr1","HostNr2","HostNr3"
 
function Get-HyperVHostInfo([string]$HyperVHost)
{
 
    $vCores = ((Get-VM -ComputerName $HyperVHost).ProcessorCount | Measure-Object -Sum).Sum
 
    $Property = "numberOfCores", "NumberOfLogicalProcessors"
    $CPUs = Get-Ciminstance -class Win32_Processor -Property  $Property -ComputerName $HyperVHost| Select-Object -Property $Property 
    $Cores = ($CPUs.numberOfCores | Measure-Object -Sum).Sum
    $logCores = ($CPUs.NumberOfLogicalProcessors | Measure-Object -Sum).Sum
 
    $os = Get-Ciminstance Win32_OperatingSystem -ComputerName $HyperVHost
    $MemFreePct = [math]::Round(($os.FreePhysicalMemory/$os.TotalVisibleMemorySize)*100,2)
 
    $object = New-Object -TypeName PSObject
    $object | Add-Member –MemberType NoteProperty –Name PhysicalCores –Value $Cores
    $object | Add-Member –MemberType NoteProperty –Name LogicalCores –Value $logCores
    $object | Add-Member –MemberType NoteProperty –Name VirtualCores –Value $vCores
    $object | Add-Member –MemberType NoteProperty –Name MemTotalGB -Value ([int]($os.TotalVisibleMemorySize/1mb))
    $object | Add-Member –MemberType NoteProperty –Name MemFreeGB -Value ([math]::Round($os.FreePhysicalMemory/1mb,2))
    $object | Add-Member –MemberType NoteProperty –Name MemFreePct -Value $MemFreePct
 
    Return $object
}
 
ForEach($OneHost in $AllHyperVHosts)
{
    $HostData = Get-HyperVHostInfo -HyperVHost $OneHost
 
    Write-Host "$OneHost has $($Hostdata.PhysicalCores) physical cores, $($Hostdata.LogicalCores) logical cores and $($Hostdata.VirtualCores) virtual cores are used in all VMs overall." -ForegroundColor Yellow
    Write-Host "The Core:vCore ratio is `t`t1:$([math]::Round(($Hostdata.VirtualCores) /  ($Hostdata.PhysicalCores),2))"
    Write-Host "The Log.Core:vCore ratio is `t1:$([math]::Round(($Hostdata.VirtualCores) /  ($Hostdata.LogicalCores),2))"
    Write-Host "The system has $($Hostdata.MemFreeGB)GB of free memory and $($Hostdata.MemTotalGB)GB memory at all, which is $($Hostdata.MemFreePct)% free"
    Write-Host ""
 
}
Write-Host "The conservative approach for logical cores is `t1:8 "

 

Eine Beispielausgabe sieht dann so aus:

hyperv1

6Aug/170

PowerShell Core–Installation unter Debian Linux

In nächster Zeit möchte ich mich mehr mit dem Thema “PowerShell Core” (also PowerShell 6.0, der Version auf Grundlage von .NET Core, die auf Linux, Unix  und MacOS läuft) beschäftigen. Den Einstieg soll die Installation der PowerShell Core unter Debian Linux machen.

Zunächst brauch man eine unterstütze Linux-Version. Aktuell sind das:

  • Ubuntu 14.04
  • Ubuntu 16.04
  • CentOS 7
  • OpenSUSE 42.1
  • Arch Linux
  • RHEL 7.2/7.3
  • Debian 8
  • MacOS 10

Konkret für Debian bedeutet das, dass man “old stable” (Jessie) benutzen muss, weil Debian 9 “Stretch” noch nicht unterstützt wird.

Nach der frischen Installation von Debian 8 braucht man sinnvollerweise noch folgende Pakete:

  • sudo (Dazu muss man sich ggf. als root einloggen!)
  • SSH (damit der Zugang und das Übertragen der URLs einfacher wird)
  • curl
  • apt-transport-https

Diese Pakete installiert man am einfachsten mit

sudo apt-get update
sudo apt-get install openssh-server curl apt-transport-https –y

Nun können die Vorbereitungen und die eigentliche PowerShell-Installation durchgeführt werden:

# Import der GPG Schlüssel für das MS Repository 
curl https://packages.microsoft.com/keys/microsoft.asc | sudo apt-key add -
 
# Registrierung des Microsoft Repositories
curl https://packages.microsoft.com/config/debian/8/prod.list | sudo tee /etc/apt/sources.list.d/microsoft.list
# Oder alternativ:
# curl https://packages.microsoft.com/config/ubuntu/14.04/prod.list | sudo tee /etc/apt/sources.list.d/microsoft.list
 
# Update mit apt-get
sudo apt-get update
 
# Installation von PowerShell
sudo apt-get install -y powershell
 
# Start der PowerShell Core
powershell

 

Hierzu noch ein paar Screenshots:

 

2017-08-05 (1)

2017-08-05

ps_core_3

ps_core_4

Viel Spaß beim Nachmachen und Ausprobieren!

24Jul/170

Sysadminday 2017 in Leipzig – nur noch wenige Tage

In wenigen Tagen steigt der SysAdminDay (System Administrator Appreciation Day) 2017 in Leipzig. Es gibt noch freie Plätze für die kostenlose Veranstaltung, also meldet euch an:

https://www.sysadminday.it/

Wir sehen uns am Freitag!