April 28 2016

User State Migration schlägt fehl – DismApi.DLL fehlt

Problem: Während einer ConfigMgr 2012 R2 Task Sequence crashed das User State Migration Tool (USMT) mit einem Fehler, weil die DismApi.DLL nicht auf dem Zielrechner vorhanden ist:

Error_USM

Lösung: Die fehlenden Dateien müssen in das USM Package kopiert werden.

Diese sollten sich auf dem dem Server mit dem installierten Windows Assessment and Deployment Toolkit (ADK) befinden, normalerweise unter %programfiles(x86)\Windows Kits\10\Assessment and Deployment Tools\amd64\DISM (für 64bit).

Die dann in den Source Ordner des USM Package kopieren und dieses dann im ConfigMgr neu einlesen.

Error_USM2

Folgende Dateien müssen kopiert werden:

  • dismapi.dll
  • api-ms-win-downlevel-advapi32-l1-1-1.dll
  • api-ms-win-downlevel-kernel32-l1-1-0.dll
  • api-ms-win-downlevel-kernel32-l2-1-0.dll
  • api-ms-win-downlevel-ole32-l1-1-1.dll
  • api-ms-win-downlevel-user32-l1-1-1.dll
  • api-ms-win-downlevel-version-l1-1-0.dll

 

Siehe Microsoft KB3084782

April 7 2016

VDI Maintenance Mode Switcher Powershell Script

Problem: VDI Maschinen in unserer Farm werden bei Inaktivität heruntergefahren und nur bei Bedarf gestartet. Dadurch kann es vereinzelt Maschinen geben, die nur sehr selten Online sind. Daher fehlen hier aktuelle Polices, Patches und Softwarepakete.

Lösung: Ich habe ein PowerShell Script geschrieben, welches über den Aufgabenplaner am Wochenende ausgeführt werden kann. Das Script aktiviert/deaktiviert den Maintenance Mode und (neu-)stratet die entsprechenden Maschinen.

Mal sehen ob sich das bewährt… :-)
Dies ist so nebenbei auch mein erstes handgeklöppeltes Powershell Script, für Fehler übernehme ich keine Haftung.

 

-> get the script <-

 

VDI_MM_Switcher_v1.4.ps1

<#
.SYNOPSIS
    This script enable or disable Maintenance Mode for Citrix VDI machines.
.DESCRIPTION
    The script read a static text file with hostnames and enable or disable maintance mode for each machine.
    The script will wait 60 seconds after each machine.
    If a target VDI is powered off it will be started automatically, if a target VDI is powered on it will be restarted if not in use.
.PARAMETER MaintenanceMode
    Specifies if the Maintenance Mode should be switched on or off. Options: Enable, Disable.
.PARAMETER HostListFile
    List of target Host names without Domain.
.EXAMPLE
    powershell.exe '.\VDI_MM_Switcher_v1.4.ps1' -MaintenanceMode "Enable" -HostListFile "C:\VDI_MM_Switcher\hosts.txt"
.EXAMPLE
    powershell.exe '.\VDI_MM_Switcher_v1.4.ps1' -MaintenanceMode "Disable" -HostListFile "C:\VDI_MM_Switcher\hosts.txt"
.NOTES
    Change Log
    V1.0 - 05.04.2016 - Manuel Kuss - frist release
    V1.1 - 05.04.2016 - Manuel Kuss - added logging
    V1.3 - 06.04.2016 - Manuel Kuss - added param()
    V1.4 - 07.04.2016 - Manuel Kuss - added SummaryState check
.LINK 
    http://www.nova17.de
#>

param(
    [string]$MaintenanceMode,
    [string]$HostListFile
)

Clear

## Load Addins
Add-PSSnapin Citrix.*

## Syntax Checker
If (($MaintenanceMode -eq "") -or ($HostListFile -eq "")) {
    Write-Host "ERROR MISSING PARAMETER`nSyntax: .\VDI_MM_Switcher_v1.4.ps1 -MaintenanceMode `"Enable/Disable`" -HostListFile `"C:\Path\hosts.txt`"" -ForegroundColor Red
    Exit
} 

## Variables (customize)
$AdminServer = 'hostname.domain.tld'
$ADDomain = 'YOUR-AD-DOMAIN'
## Variables
$HostList = Get-Content $HostListFile
$Logfile = "$HostListFile" + "_$MaintenanceMode" + ".log"

## Output
Write-Host "Executing..." -ForegroundColor Yellow
$starttime = Get-Date -Format G
write "--------------------------------------------------------" | Out-File $Logfile
Write "Script Start Time: $starttime" | Out-File $Logfile -Append
write "--------------------------------------------------------" | Out-File $Logfile -Append

## Enable Maintenance Mode Loop ##
if ($MaintenanceMode -eq 'Enable') 
    {
    foreach ($item in $HostList)
        {
            ## Write DOMAIN\HOSTNAME to $TargetVDI
            $TargetVDI = "$ADDomain" + "\" + "$item"
            
            ## Enable Maintenance Mode
            Write "Enable MaintenanceMode for $TargetVDI" | Out-File $Logfile -Append
            Set-BrokerMachineMaintenanceMode -InputObject $TargetVDI $true -adminaddress $AdminServer

            ## Restart if TargetVDI is not in use
            foreach ($item in Get-BrokerDesktop | Where-Object{($_.MachineName -eq "$TargetVDI") -and ($_.PowerState -eq "On") -and ($_.SummaryState -ne "InUse")} | Select-Object -Property MachineName)
                { New-BrokerHostingPowerAction -MachineName $TargetVDI -Action Restart -adminaddress $AdminServer | Out-File $Logfile -Append }

            ## If TargetVDI is powered off
            foreach ($item in Get-BrokerDesktop | Where-Object{($_.MachineName -eq "$TargetVDI") -and ($_.PowerState -eq "Off")} | Select-Object -Property MachineName)
                { New-BrokerHostingPowerAction -MachineName $TargetVDI -Action TurnOn -adminaddress $AdminServer | Out-File $Logfile -Append }
            
            ## Pause
            Write "--------------------------------------------------------" | Out-File $Logfile -Append
            Start-Sleep 60
        }
    }

## Disable Maintenance Mode Loop ##
if ($MaintenanceMode -eq 'Disable') 
    {
    foreach ($item in $HostList)
        {
            ## Write DOMAIN\HOSTNAME to $TargetVDI
            $TargetVDI = "$ADDomain" + "\" + "$item"
          
            ## Disable MaintenanceMode
            Write "Disable MaintenanceMode for $TargetVDI" | Out-File $Logfile -Append
            Set-BrokerMachineMaintenanceMode -InputObject $TargetVDI $false -adminaddress $AdminServer
            
            ## Restart if TargetVDI is not in use
            foreach ($item in Get-BrokerDesktop | Where-Object{($_.MachineName -eq "$TargetVDI") -and ($_.PowerState -eq "On") -and ($_.SummaryState -ne "InUse")} | Select-Object -Property MachineName)
                { New-BrokerHostingPowerAction -MachineName $TargetVDI -Action Restart -adminaddress $AdminServer | Out-File $Logfile -Append }
                           
            ## Pause
            Write "--------------------------------------------------------" | Out-File $Logfile -Append
            Start-Sleep 60
        }
    }

## Output
$endtime = Get-Date -Format G
Write "Script End Time: $endtime" | Out-File $Logfile -Append
write "--------------------------------------------------------" | Out-File $Logfile -Append
Write-Host "Script Execuded." -ForegroundColor Yellow
April 4 2016

Let’s Encrypt bei All-Inkl

All-Inkl.com hat als Beta Test LET'S ENCRYPT eingebunden. Somit kann nun direkt über das KAS Backend ein Let's Encrypt Zertifikat pro Domain kostenlos ausgestellt werden. Die Zertifikate sind jeweils immer 90 Tage gültig und werden automatisch verlängert, d.h. es ist kein weiterer manueller Eingriff notwendig. Der Bestell-/Einbindevorgang ist denkbar einfach:

Zu bearbeitende Domain ausw&auml;hlen
Zu bearbeitende Domain ausw&auml;hlen
SSL Schutz bearbeiten
SSL Schutz bearbeiten
Let's Encrypt ausw&auml;hlen und Hinweise lesen
Let’s Encrypt ausw&auml;hlen und Hinweise lesen
Dann wird das Zertifikat beantragt und eingebunden
Dann wird das Zertifikat beantragt und eingebunden

Es werden starke 2048 Bit Zertifikate mit allem und scharf eingebunden, daher an All-Inkl.com: Alles richtig gemacht!

le5

Februar 12 2016

ConfigMgr Client – Downloading 0%

An einen Client hatte ich soeben das Problem, dass seit Tagen keine Updates und Anwendungen über den ConfigMgr Client installiert bzw. heruntergeladen werden. Der Download bleibt einfach bei 0% stehen, im %windir%\ccmcache Verzeichniss findet man entsprechend auch nur *.BDRTEMP Ordner.

Ein Blick ins LocationServices.log zeigte regelmässige "Unable to retrieve AD site membership" Fehler, dadurch findet der Client dann seinen zugeordneten Distribution Point nicht und der Download bleibt bei 0% stehen (sofern man seine Landschaft ohne automatischen Failover auf andere Distribution Points konfiguriert hat).

Die AD Site Zuordnung kann man schnell mit dem Befehl nltest /dsgetsite prüfen:

12-02-_2016_10-03-46

Getting DC name failed: Status = 1919 9x77f ERROR_NO_SITENAME

 

In diesem Fall sollte man sich mal anschauen: Client IP Addresse & Subnet und der AD Site zugeordnete Subnets. In meinem Fall war das alles in Ordnung, die Lösung war letztlich sogar recht trivial: Ich habe den Client neu in die AD Domain aufgenommen und nach einem Neustart passt die Site Zuordnung wieder, die fehlenden Updates und Anwendungen wurden nach ein paar Minuten geladen und installiert.

 

Passend zum Thema: Man kann anstehende BITS Jobs mit dem Befehl bitsadmin /list /allusers anzeigen lassen.

Februar 9 2016

ConfigMgr: Netzwerkkarte mehrfach für OSD nutzen

Fährt man sein OS-Deployment auf Unbekannte Geräte (Unknown Devices) wird die MAC Adresse der verwendeten Netzwerkkarte im ConfigMgr am Gerät zusammen mit der GUID gespeichert und kann nicht wieder verwendet werden (weil das Gerät dann ja nicht mehr unbekannt ist…).

Will man nun mehrere Geräte deployen, welche keine Onboard NIC haben (Tablets, Surface, …) hat man nun das Problem, dass man jeden USB-Ethernet Adapter nur einmalig verwenden kann. Eine Abhilfe schafft hier der Regkey ExcludeMACAddress welcher auf der Primary Site definiert werden kann. Damit kann man einen oder mehrere spezielle "OSD Netzwerk Adapter" einrichten da sich die Geräte dann vorerst nur mit der GUID im ConfigMgr anmelden.

Eine Umfangreiche Erklärung gibt es dazu im Technet von Wilhelm Kocher.

Januar 18 2016

Windows 10 Offline Feature Installation

feature1

Meldung: Von einer App auf dem PC wird das folgende Windows-Feature benötig: .NET Framework 3.5 (enthält .NET 2.0 und 3.0)

Problem: Der Client hat keinen online Zugriff auf Windows Update

Lösung: Offline Feature Installation mittels DISM und der install.wim (=Windows Installationsdatenträger)

feature2

Dism /online /enable-feature /featurename:NetFX3 /All /Source:D:\sources\sxs /LimitAccess

 

Kurze Zeit später, ist das fehlende Feature installiert:

feature3

Dezember 8 2015

Windows 10 Built-In Apps

Wer die Built-In Apps von Windows 10 (teilweise) deinstallieren möchte, kann dies am einfachsten per PowerShell erledigen. Hier sind die jeweiligen Befehle:

3D Builder: Get-AppxPackage *3dbuilder* | Remove-AppxPackage
Alarms and Clock: Get-AppxPackage *windowsalarms* | Remove-AppxPackage
Calculator: Get-AppxPackage *windowscalculator* | Remove-AppxPackage
Calendar and Mail: Get-AppxPackage *windowscommunicationsapps* | Remove-AppxPackage
Camera: Get-AppxPackage *windowscamera* | Remove-AppxPackage
Get Office: Get-AppxPackage *officehub* | Remove-AppxPackage
Get Skype: Get-AppxPackage *skypeapp* | Remove-AppxPackage
Get Started: Get-AppxPackage *getstarted* | Remove-AppxPackage
Groove Music: Get-AppxPackage *zunemusic* | Remove-AppxPackage
Maps: Get-AppxPackage *windowsmaps* | Remove-AppxPackage
Microsoft Solitaire Collection: Get-AppxPackage *solitairecollection* | Remove-AppxPackage
Money: Get-AppxPackage *bingfinance* | Remove-AppxPackage
Movies & TV: Get-AppxPackage *zunevideo* | Remove-AppxPackage
News: Get-AppxPackage *bingnews* | Remove-AppxPackage
OneNote: Get-AppxPackage *onenote* | Remove-AppxPackage
People: Get-AppxPackage *people* | Remove-AppxPackage
Phone Companion: Get-AppxPackage *windowsphone* | Remove-AppxPackage
Photos: Get-AppxPackage *photos* | Remove-AppxPackage
Store: Get-AppxPackage *windowsstore* | Remove-AppxPackage
Sports: Get-AppxPackage *bingsports* | Remove-AppxPackage
Voice Recorder: Get-AppxPackage *soundrecorder* | Remove-AppxPackage
Weather: Get-AppxPackage *bingweather* | Remove-AppxPackage
Xbox: Get-AppxPackage *xboxapp* | Remove-AppxPackage

Nicht entfernen kann man „Support Contact“, „Cortana“, „Windows Feedback“ und den „Edge“ Browser.

Mit folgendem Befehl kann man sich wieder alle Apps automatisch installieren:

Get-AppxPackage -AllUsers| Foreach {Add-AppxPackage -DisableDevelopmentMode -Register “$($_.InstallLocation)\AppXManifest.xml”}
November 6 2015

ConfigMgr 2012 OSD mit UI++ und Task Sequence Variables

tl;dr
Ein längerer Artikel über meine Vorgehensweise beim OS-Deployment in einer mehrsprachigen, standardisierten Systemlandschaft mit dem Configuration Manager 2012 und UI++.

 

Bislang hatte ich unterschiedliche OSD Task Sequenzen im Einsatz, je nach Art des Zielrechners. Dies konnte ich nun mit Hilfe von Task Sequence Variablen und dem Tool UI++ auf eine einzige dynamische Task Sequenze reduzieren und somit den administrativen Aufwand minimieren und einen großen Schritt weiter in Richtung Standardisierung vornehmen.

In der von mir verwalteten Umgebung wird standartisierte Hardware eingesetzt, die Client Installationen unterscheiden sich jedoch anhand ihres Einsatzgebietes:

  • Workstation
  • Notebook Standard
  • Notebook Spezial
  • CAD Workstation

Die Basis ist bei allen System indentisch: Windows 7 Enterprise, Office 2013 und eine Sammlung an Tools wie dem PDF Reader, SAP FrontEnd usw. Dies entspricht dann einer klassischen "Workstation".
Notebooks und CAD Workstations erhalten dann noch weitere Anwendungen wobei die "Notebook Spezial" eine Untermenge von "Notebook" darstellt.

Unabhängig davon gibt es noch unterschiedliche Standorte die wiederum teilweise eigene Anwendungen und Einstellungen erhalten.

Das ganze ist natürlich Multilingual aufgebaut…

 

In der OSD Task Sequence schaut das dann so aus (vereinfachte Darstellung):

 

Install Operating System

Zuerst wird das WinPE System gestartet und die Festplatte wird formatiert, hier prüfe ich ab ob BIOS oder UEFI. Danach wird UI++ ausgeführt um die benötigten Task Sequenzce Variablen zu befüllen.

Verwendete Variablen:

  • %OSDUILanguage% = Sprache des Zielsystems: de-DE, en-US, fr-Fr, it-IT, ..
  • %OSDTargetType% = Art des Zielsystems: Notebook, NotebookSpecial, CAD
  • %OSDSitePackage% = Standort des Zielsystems: Site001, Site002, Site003

 

Beim Punkt "Apply Operating System Image with Office 2013" wird ein Capture-WIM inkl. Office 2013 installiert. Der Capture PC bring auch gleiche eine Menge an Middleware mit wie .NET Framework, C++ Runtimes sowie einen relativ aktuellen Patchlevel (das Capture WIM tausche ich ca. alle 6 Monate aus). In der unattended.xml verwende ich auch gleich die erste Task Sequence Variable nämlich %OSDUILanguage% um die Anzeigesprache von Windows vorzugeben:

Danach folgt die Konfiguration der Netzwerkkarte sowie der Domain Join.

Bei den Treibern verwende ich immer ein spezifisches Driver Package pro Gerät, die Abfrage erfolgt per WMI. Bei einigen Geräten müssen Treiber teilweise als Applications im Windows 7 installiert werden, auch hier prüfe ich das Model per WMI Abfrage:

 

 

Nach der Betrriebsssysteminstallation folgen die Anwendungen. Hierzu werden nur die Gruppen ausgeführt, wo die entsprechende Task Sequenze Variable gesetzt ist:

[TargetType = All] –> Wird bei allen Rechnern installiert
[TargetType = Notebook] –> Wird installiert, wenn die Variable OSDTargetType "Notebook" oder "NotebookSpezial" ist
[TargetType = NotebookSpezial] –> Wird installiert, wenn die Variable OSDTargetType "NotebookSpezial" ist
[TargetType = CAD] –> Wird installiert, wenn die Variable OSDTargetType "Notebook" oder "NotebookSpezial" ist

 

Auf jeder Gruppe ist eine entsprechende Bedingung gesetzt, hier das Beispiel "Notebook":

 

Zuletzt folgende dann noch Anwendungen / Scripte bezogen auf den jeweiligen Standort. Selbige Taktik nur mit der Variable %OSDSitePackage%.

 

 

… so far … so good aber woher kommen die TS-Variablen?

Hier kommt das kostenlose Tool UI++ zum Einsatz!

Das präsentiert während der WinPE Phase dem Anwender eine einfach UI mit Dropdowns:


(Screenshot als Beispiel… Hier würde noch die Abfrage nach dem Standort fehlen)

 

 

Fazit

Statt mehrerer gibt es so nur noch eine Core Client Installationsroutine. Die Kollegen, welche im Feld die Installationen durchführen müssen im WinPE nur noch den Gerätenamen eintippen und die richtige Auswahl treffen – danach läuft alles automatisiert durch und es fällt ein fertiger Rechner raus.

 

In einem zweiten Beitrag werde ich dann mal noch darauf eingehen, wie man das OS-Deployment auch Remote über den Config Manager Client starten kann, das Zauberwort an dieser Stelle ist "Collection Variables". Dazu aber ein anderes mal mehr. :-)