Netz-Weise Logo

Weisheiten - der Netz-Weise Blog

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

Hyper-V VM startet nicht mit Fehler "weil der Hypervisor nicht ausgeführt wird"

Ihre Hyper-V virtuellen Maschinen melden "Der virtuelle Computer konnte nicht gestartet werden, da der Hypervisor nicht ausgeführt wird" Dieses Problem kann auftreten, wenn die Virtualisierungsfunktionen im BIOS nicht freigeschaltet sind. Das kann man z.B. mit dem Sysinternals-Tool "Coreinfo" aus der Sysinternals-Suite testen. Eine weitere Ursache kann sein, dass der Hypervisor-Eintrag im Boot-Menü fehlt, z.B. nach einer Reparatur des Bootmenüs, oder wenn Sie von einer vhd aus Ihr Windows starten. Dann hilft folgender Aufruf in einer vom Administrator gestarteten Kommandozeile (rechte Maustaste auf cmd.exe und "Ausführen als Administrator):

bcdedit /set hypervisorlaunchtype Auto

Get-content und der RAW-Switch

"Mit Powershell 3.0 wurde der Get-Content-Befehl um einen Switch-Parameter erweitert, um Inhalte in einen einzigen String einzulesen statt zeilenweiseDer Get-Content-Befehl liest Textdateien normalerweise Zeilenweise ein. Der Inhalt einer Textdatei wird damit in ein Array eingelesen, wobei jede Zeile in einer einzelnen String-Variablen gespeichert wird. Das ist allerdings nicht nur langwierig, sondern oft auch nicht erwünscht. Mit dem -RAW Switch ignoriert get-content Newline-Zeichen und liest den Dateiinhalt in einen einzigen String ein. Das geht deutlich schneller, wenn man nicht auf die einzelnen Zeilen zugreifen möchte, sondern den Dateiinhalt braucht, wie er ist. Wenn es um sehr große Dateien geht, erweist sich die .net-Klasse [io.file] als noch deutlich schneller: $file = [io.file]::ReadAllLines('C:\temp\WindowsUpdate.log')"

Werte und Arrays aus Funktionen zurück liefern

Eine Funktion bei Powershell ist eigentlich nur ein benannter Scriptblock. Funktionen kann man nutzen, um Scripte übersichtlicher zu gestalten und bestimmte Funktionalitäten immer wieder aufrufbar in einen Block zu "giessen". Wenn Sie eine Funktion schreiben, soll diese fast immer auch Werte zurück liefern, mit denen Sie weiterarbeiten können. In vielen anderen Programmiersprachen verwendet man hierzu das Return-Statement. Powershell kann das grundsätzlich auch, allerdings ist das Return-Statement nicht wirklich notwendig, um Rückgaben zu erzeugen, da grundsätzlich jede Ausgabe von einer Funktion ausgegeben wird. Hierzu ein kleines Beispiel:

function Return-Value
{
    1
    Return 2
}
$Rueckgabe = Return-Value

Was befindet sich jetzt in der Variable $Rueckgabe? Nicht der Wert 2, wie man vermuten könnte, sondern $Rueckgabe ist ein Array, dass die Werte 1 und 2 enthält. Ein weiteres Beispiel:

function Return-Value
{
    1
    2 "Schoene Gruesse von Return-Value"
}
$Rueckgabe = Return-Value

$Rueckgabe ist wieder ein Array, das 3 Werte enthält, und das auch ohne Return. Return ist zur Rückgabe von Werten also nicht notwendig. Wofür benötigt man dann noch Return? Return beendet außerdem die Funktion. Befehle, die nach Return stehen, werden also nicht ausgeführt! Wenn Sie Arrays aus einer Funktion zurück liefern wollen, müssen Sie vorsichtig sein! Möchten Sie beispielsweise 2 Arrays zurückgeben, so fügt Powershell diese in der Rückgabe zu einem Array zusammen:&nb

function Return-Value 
{
$arr1 = 1,2,3,4
$arr2 = 5,6,7
$arr1
$arr2
}
$Rueckgabe = Return-Value

Rueckgabe enhält wiederum ein Array mit den Werten 1 bis 7. Geben Sie $Rueckgabe[0] an, so erhalten Sie aber nicht das erste Array, sondern nur den Werte 1. Um Powershell anzuweisen, die Arrays beizubehalten, müssen Sie der Ausgabe ein Komma voran stellen:

function Return-Value 
{
$arr1 = 1,2,3,4
$arr2 = 5,6,7
$arr1,$arr2
}
$Rueckgabe = Return-Value

Dann gibt $Rueckgabe[0] auch die Werte 1 bis 4 zurück.

Parametrisierte Programme in Powershell starten am Beispiel von 7Zip

Wenn man in Powershell ein ausführbares Programm starten möchte, kann man das normalerweise machen, indem man den direkten Pfad in der in der Konsole einfach aufruft. Genauso kann man ein Programm in einem Script direkt referenzieren.

C:\programme\7zip\7z.exe

Problematischer wird das, wenn der Pfad, in dem sich das Programm befindet, Leerzeichen enthält. Der Programmpfad muß dann in Anführungszeichen gesetzt werden, wird nun aber als String interpretiert und kann nicht mehr direkt aufgerufen. Powershell gibt stattdessen einfach nur den String zurück.

'C:\Program Files\7Zip\7z.exe'
C:\Program Files\7Zip\7z.exe

Die Lösung bietet der Ausführungsoperator &, der Powershell anweist, den folgenden String direkt auszuführen:

Weiterlesen

Gültigkeitsbereiche von Variablen und der Modul-Scope in Powershell

Vor kurzem bin ich auf einen interessanten Artikel von Mike Robbins gestoßen, den ich hier noch einmal kurz zusammengefasst wiedergeben möcht.

Variablen haben in Powershell normalerweise nur eine begrenzten Lebensdauer, die vom Scriptblock definiert ist, in dem Sie deklariert wurde. Sobald der Scriptblock beendet wird, in dem eine Variable deklariert wurde, wird auch die Variable wieder freigegeben. Hierzu ein kleine Beispiel:

$TestVariable = 'Hallo vom Script'
function Test-Scope
{
  $TestVariable = 'Hallo aus der Funktion'
  $TestVariable
}
Test-Scope
$Testvariable

Wie sieht die Ausgabe des Skripts aus und was ist der Inhalt der Testvariablen zu den unterschiedlichen Zeitpunkten?

Das Skript gibt diese Ausgabe zurück:

Weiterlesen

Emails mit Skripten oder Multifunktionsgeräten über Office 365 versenden

Wenn Sie mit "Fremdapplikationen" wie Multifunkitionsdruckern oder aus einem Skript Mails über die Microsoft-eigenen Office 365 Exchange-Server versenden wollen, haben Sie grundsätzlich drei Möglichkeiten: Den anonymen Mailversand, den Versand über ein authentifiziertes Benutzerkonto oder einen dezidierten Connector. In dieser Beschreibung möchte ich mich auf die ersten zwei, weil vermutlich häufigesten, konzentrieren. Den vollständigen Artikel von Microsoft zur Einrichtung aller drei Methoden inklusive des Connectors finden Sie unter "Links" am Ende des Textes.

Die einfachste Variante, um mails zu verschicken, ist ein Postfach in Office 365 anzulegen, also einen neuen Benutzer. Danach können Sie sowohl interne mails (also innerhalb Ihrer O365-Organisation) als auch externe Mails verschicken. Sie verwenden für den Mailversand den Server smtp.office365.com und müssen eine Anmeldung mit Benutzername und Kennwort des Postfachbenutzers durchführen. Hier ein kleines Beispiel mit Powershell:

$Password = Convertto-Securestring -String 'Passwort' -AsPlainText -Force
$credential = New-Object PSCredential("Diese E-Mail-Adresse ist vor Spambots geschützt! Zur Anzeige muss JavaScript eingeschaltet sein.",$Password)
Send-MailMessage -SmtpServer smtp.office365.com -Port 587 -UseSsl -Subject 'Ein Fehler ist aufgetreten' -Body 'fehler' -from Diese E-Mail-Adresse ist vor Spambots geschützt! Zur Anzeige muss JavaScript eingeschaltet sein.' -To Diese E-Mail-Adresse ist vor Spambots geschützt! Zur Anzeige muss JavaScript eingeschaltet sein.' -Credential $credential

Alternativ kann für den Versand auch Port 25 verwendet werden, bevorzugt ist aber Port 587, der für TLS-Verschlüsselung verwendet wird.

Der Nachteil dieser Variante ist, dass Sie ein Postfach und damit eine Benutzerlizenz benötigen. Außerdem ist die Menge der mails, die pro Minute verschickt werden können, auf 30 eingeschränkt. Alternativ können Sie aber auch direkt versenden, ohne eine Postfach zu verwenden. Diese Variante funktioniert aber nur für internen Mailversand - Office 365 leitet keine Mails an Benutzer außerhalb Ihrer Organisation weiter.

Weiterlesen
Markiert in:

Parameter in Powershell-Funktionen und Skripten vor Intellisense verstecken

Der Scriptblock in Powershell stellt standardmäßig einen Param-Block zur Verfügung, über den Parameter an Skripte und Funktionen übergeben werden können. Erweiterte Funktionen bieten darüber hinaus einen ganze Reihe von Parameter-Optionen, um das Verhalten der Parameter steuern zu können. Eine manchmal sehr hilfreiche, unbekannte Parameter-Option ist DontShow, mit der man verhindern kann, dass ein Parameter in Intellisense angezeigt wird.Das kann z.B. nütlich sein, wenn man Hilfsfunktionen baut, die allgemein nutzbar (öffentlich) sind, bei denen bestimmte Hilfsparameter aber nur unter ganz bestimmten Spezialfällen sinnvoll sind. Geben Sie bei den Parameter-Optionen einfach DontShow mit an:

function Test-HiddenParam
{
Param(
   [Parameter(DontShow)]
   [string]$hiddenParameter
)

$hiddenParameter
}

 

Send-Mailmessage erzeugt keine verwendbaren Fehler - und wie man damit umgeht

Send-Mailmessage ist ein sehr nützliches Cmdlet, um Emails direkt aus Powershell an einen Mailserver zu senden. Er steht seit Powershell 2.0 zur Verfügung und vermeidet so, dass man sich direkt mit dem [System.net.mail]-Typ herumschlagen muß. Allerdings zeigt das Cmdlet ein sehr merkwürdiges Fehlerverhalten.

Wenn man versucht, Verbindungsfehler abzufangen, ist ein erster vernünftiger Ansatz, einfach auf den Parameter -Errorvariable zurückzugreifen:

Send-Mailmessage -SmtpServer mail.meineFirma.de -Subject 'Warnung' -Body 'Hier kommt die Maus' -From 'Elefant@netz-weise.xyz' -to 'Maulwurf@netz-weise.xyz' -ErrorVariable Fehlermeldung
If ( $Fehlermeldung ) { $Fehlermeldung.Exception.Message }

Tritt ein Fehler auf, wird dieser direkt in der Variablen $Fehlermeldung gespeichert. Achtung, bei der Angabe der Fehlervariablen wird kein $-Zeichen angegeben!

Weiterlesen
Markiert in:

MDT - Autologon nach Installation aktiviert lassen

In letzter Zeit beschäftige ich mich wieder intensiv mit dem MDT, um unsere Schulungs-Rechner mit neuen Windows 10 Images zu versehen. Dafür habe ich ein kleine Powershell-Funktion geschrieben, den den Autologon für einen Benutzer setzt (s.u.). Sie kann den Autologon aktivieren. Leider funktioniert die Funktion nicht innerhalb eines Konfigurationsskriptes im MDT, da nach erfolgter Installation das Aufräumskript Scripts\LTICleanup.wsf den Autologon entfernt. Um den Autologon beizubehalten oder ändern zu können, suchen Sie den Text

     '//----------------------------------------------------------------------------
     '//  Clear the autologon registry keys
     '//----------------------------------------------------------------------------

und kommentieren Sie die nachfolgenden Zeilen bis zum nächsten Kommentarblock mit dem ' aus.

function Set-AutomaticLogon
{
<#
.Synopsis
    Enables Windows Autologon or removes it
.DESCRIPTION
    This function enables Windows Autologon via Registry-Keys or disables it. It is similar
    to the Netplwiz.exe Command
.EXAMPLE
    Set-AutomaticLogon -Enabled -Username Student -Password Password
    Adds an Autologon-Key to the Registry.
.EXAMPLE
    Set-AutomaticLogon -Disabled
    Disables the automatic Logon by removing the User-Password and disabling the Logon-key.
#>
param
(
    [parameter(Mandatory=$True,
               ParameterSetName='Enabled')]
    [switch]$Enabled,

    [parameter(Mandatory=$True,
               ParameterSetName='Disabled')]
    [Switch]$Disabled,

Weiterlesen

MDT: Sysprep und Catpure zeigt das Register "Capture Image" nicht an und der Task schlägt fehl

Das Microsoft Deyployment Toolkit 2013 hat in der aktuellen Version 8443 einen Bug, der die Tasksequenz "Sysprep and Capture" funtionsunfähig macht. Leider hat Microsoft den Bug bisher nicht durch eine aktualisierte Version bereinigt. Man kann sich aber schnell selbst behelfen, denn es handelt sich um fehlerhaften VBS-Code in der Datei ZTIUtility.vbs im Ordner Scripts im Root des Deployment-Shares. Ersetzen Sie in Zeile 3327 den Code 

If (oTS.SelectSingleNode("//step[@type='BDD_InstallOS']") is nothing) and (oTS.SelectSingleNode("//step[@type='BDD_UpgradeOS']") is nothing) then

durch

if (oTS.SelectSingleNode("//step[@type='BDD_InstallOS' and @disable='false']") is nothing) and (oTS.SelectSingleNode("//step[@type='BDD_UpgradeOS' and @disable='false']") is nothing) then

Danach sollte die Tasksequenz problemlos durchlaufen.

Links
https://community.spiceworks.com/topic/1924854-mdt-8443-sysprep-capture-task-not-working