Ziel ist es, die aktuellste Version Adobe Reader auf allen Computern eines AD Netzwerks zu verteilen. Es handelt sich um die Version 11.0.10 (Update 13.3.2015), die speziell angepasst (deutsche Sprache, keine EULA, paar Features deaktiviert) installiert werden soll. Da ich bei diesem Prozess auf verschiedenste Fehler und Probleme stieß, werde ich die Verteilung hier detailliert erläutern.

Seit 2010/2011 gibt es ja den Hintergrundupdater in Adobe Produkten. Eigentlich gehören Verteilungen dieser Art also der Geschichte an. Jedoch kann es trotzdem notwendig werden, wenn erstmal eine Basis geschaffen werden muss, weil beispielsweise kein einheitlicher Standard des Produkts installiert ist. Einige haben Version X, andere Version Y, einige PCs haben die Software nicht einmal installiert. In diesem Fall ist ein komplettes Rollup inklusive Cleaning, also Deinstallation aller Versionen vor der Verteilung, sinnvoll und empfehlenswert.

Wie üblich gibt es mehrere Herangehensweisen, bei Adobe habe ich im Laufe der Jahre folgende Methode als sicherste empfunden:
Installer laden -> AIP lokal erstellen -> Patches slipstreamen -> mit Customization Wizard anpassen -> mit Orca optimieren -> Verteilen,
wobei der Verteilen-Punkt je nach Produkt und Situation natürlich zwischen Script oder GPO Installation unterschieden wird.
Das hier sagt Adobe zu den „Best Practices“.

Schritt 1: Installer laden

Adobe bietet für ihre Produkte teilsweise 2 verschiedene Downloadseiten an. Die typisch einfache Seite und die Seite für Administratoren, hier am Beispiel vom Reader (bei Acrobat ist das ebenfalls so).
adobe-reader-scriptbased-deployment-mst-changes-cleaning-logging-installerIhr braucht natürlich das komplette Paket: 11.0.0 Basis plus aktuellstes Update, am besten in der MUI Variante.
Für die Pro’s auch ohne viel Schickschnack via FTP.

Schritt 2: AIP erstellen

Falls die Grundversion (z.B. 11.0.0) eine .zip Datei war, entpackt diese. Geht per CMD in diesen Ordner und führt den Befehl

msiexec /a "AcroRead.msi"

Der Installer startet, installiert am besten lokal, C:/Reader11/ oder so. AIP fertig!

Schritt 3: Patches integrieren

Geht per CMD in den Ordner des Updates und führt den Befehl aus:

msiexec /a "C:\Reader11\AcroRead.msi" /p "AdbeRdrUpd11004_MUI.msp"

(ihr müsst natürlich Pfade und Dateinamen entsprechend anpassen…)
Der grafische Installer für den Patch erscheint, durchklicken, fertig. Verfahrt so mit allen Patches, wenn ihr mehrere habt. Für gewöhnlich lässt sich aber das aktuellste Update auf die Basisversion anwenden, mehr dazu steht auf der Detailseite des Updates bei den „Installation Instructions“ („This update requires that Adobe Reader 11.0 MUI or later is installed on your system.“).
adobe-reader-scriptbased-deployment-mst-changes-cleaning-logging-update-slipstream

Schritt 4: mit dem Customization Wizard anpassen

Wie bei Acrobat kann man auch den Reader mit dem Adobe Customization Wizard anpassen:
adobe-reader-scriptbased-deployment-mst-changes-cleaning-logging-customization-wizard
EULA deaktivieren, Sprache wählen, Deinstallation alter Versionen aktivieren, paar Online Features deaktivieren, Shortcuts anpassen, tobt euch aus und speichert das Ergebnis als MST Anpassungsdatei ab.

Fertig, ihr habt jetzt eine geupdatete AIP Installation, C:/Reader11. Die könnt ihr auf das Netzlaufwerk schieben. Dazu die gerade erstellte MST. Beides zusammen könnt ihr nun Verteilen. Entweder via GPO Softwareinstallation oder per Script. Letzteres bevorzuge ich aus Gründen der Funktionalität.
Kommen wir also zum letzten Schritt.

Schritt 5: Verteilung via Script

Hier wird es nochmal spannend.
Das Installer-Script
– hat einen Clientfilter, kann also einzelne Rechner zulassen oder ignorieren
– räumt alte Reader Installationen auf (Version 9 und 10) – siehe Acrobat & Reader Cleaner Tools
– besitzt umfangreiche Logging-Möglichkeiten
reagiert auf die Fehlercodes 1618 (Installer Prozess wird gerade verwendet), 1602 (Installation vom Nutzer abgebrochen) und 1603 (Installationsfehler) mit einem Retry nach 5 Minuten

Update: 28.07.2015 Version 11.0.12, getestet und läuft.

@echo on & Color 9f & setlocal
set wd=\\server\Deployment\Software\Reader
set log=%wd%\reader-log.txt
set readerEL=999
set retry=0
set forcecleanup=yes
REM:: ******************
set version=11.0.12
REM:: ******************

REM:: Clientfilter: nur die Computer aus der allowedPCs.txt dürfen installieren
::for /f %%f in (%wd%\allowedPCs.txt) do if "%computername%"=="%%f" goto start
::goto end

REM:: Clientfilter: die Computer aus der deniedPCs.txt dürfen nicht installieren
for /f %%f in (%wd%\deniedPCs.txt) do if "%computername%"=="%%f" goto end

:start
if not exist %wd%\deploy\%version%\complete md %wd%\deploy\%version%\complete
if exist %wd%\deploy\%version%\complete\%computername% goto end

if "%forcecleanup%"=="yes" goto cleanup
goto install

:cleanup
echo %date% %time:~0,8% - %computername% deinstalliert alle Reader Versionen... >> %log%
REM:: uninstall all reader versions
start /w %wd%\cleaner\reader-cleaner-9.exe /silent /product=1
start /w %wd%\cleaner\reader-cleaner-10-above.exe /silent /product=1
echo %date% %time:~0,8% - %computername% hat alle Reader Versionen deinstalliert... >> %log%
goto install

:install
echo %date% %time:~0,8% - %computername% startet die Installation... >> %log%
start /w msiexec /i "%wd%\deploy\%version%\AcroRead.msi" /qn TRANSFORMS="%wd%\deploy\%version%\AcroRead.mst"
set readerEL=%errorlevel%

if %readerEL%==1618 goto retry REM:: msiexec process in use, installation already in progress
if %readerEL%==1602 goto retry REM:: user canceled installation
if %readerEL%==1603 goto retry REM:: fatal error, some use it for "already installed" (eg. java)
echo %date% %time:~0,8% - %computername% hat die Installation abgeschlossen, Errorlevel: %readerEL%... >> %log%
if %readerEL%==0 md %wd%\deploy\%version%\complete\%computername%
goto end

:retry
if %retry%==1 goto retryfailed
echo %date% %time:~0,8% - %computername% hat die Installation abgeschlossen, Errorlevel: %readerEL%, retry in 5min... >> %log%
set retry=1
ping localhost -n 300 > nul
goto install

:retryfailed
echo %date% %time:~0,8% - %computername% hat die Installation abgeschlossen, Errorlevel: %readerEL%, retry failed, end >> %log%
goto end

:end
endlocal
exit

Damit das Script funktioniert, braucht ihr allerdings eine spezielle Ordnerstruktur. Ich skizziere sie mal eben schriftlich, ggf. mit Dateien:
Reader\cleaner\reader-cleaner-10-above.exe (Cleanup Tools, umbenannt)
Reader\cleaner\reader-cleaner-9.exe (Cleanup Tools, umbenannt)
Reader\deploy\[version](die in der Batch als Variable gesetzt wird)\[Dateien: AIP,.mst,usw]
Reader\deploy\[version]\complete\

Wenn ihr also in der Batch beispielsweise die Version 11.0.04.63 verteilen wollt, tragt die Version in Zeile 11 so ein und der Ordner lautet:
Reader\deploy\11.0.04.63\
adobe-reader-scriptbased-deployment-mst-changes-cleaning-logging-deploy-dir

Hier ein Beispielausschnitt der Logdatei:
adobe-reader-scriptbased-deployment-mst-changes-cleaning-logging-logfile

Probleme mit der Sprache?

acrobat-multilanguage-testsIst das Produkt trotz Anpassung nicht auf Deutsch? Das Problem hatte ich auch und habe einige Stunden mit verschiedensten Tests an der MST, der setup.ini und den MSI Parametern verbracht. So richtig klar wurde mir das alles nicht, ich habe nun aber einige Anpassungstipps, die das Sprachproblem beheben sollten. Lest vorher nochmal die paar Infos des Admin Guides zu den Sprachen, das erleichtert das Verständnis der folgenden Punkte.

Also, MSI in Orca laden, über Transform -> „Apply Transform“ die angepasste MST des Customization Wizards laden und ab in die Property Tabelle.
(Das ginge übrigens auch über den Customization Wizard -> Direct Editor)
Schaut hier nach folgenden Schlüsseln und passt diese ggf. an, um die deutsche Sprache einzustellen:

Propertyalter Wertneuer Wert
ProductLanguage10331031
ISLANGFLAGen_USde_DE
ProductCode{AC76BA86-7AD7-FFFF-7B44-AB0000000001}{AC76BA86-7AD7-1031-7B44-AB0000000001}

(zum Product Code lest bitte den Admin Guide)
Speichert diese Anpassungen über Transform -> Generate Transform am besten in einer seperaten MST.

Editiert dann die setup.ini vorsichthalber, sodass sie nur noch die deutsche Sprache und die neue Transorm enthält:
adobe-reader-scriptbased-deployment-mst-changes-cleaning-logging-setup-ini

[Product]
msi=AcroRead.msi
Languages=1031
1031=German (Germany)	
CmdLine=TRANSFORMS="AcroRead-deu.mst"

Installiert dann den Reader entsprechend dem oben gezeigten Script, dann sollte die Installation die Anpassungen der MST beinhalten und auf deutsch sein.

Kürzer, schneller, härter

Die richtigen Pro’s werden bei den ersten Schritten den Kopf schütteln, „das geht ja alles viel einfacher, schneller, in weniger Schritten“ usw.
Ja, man kann die Anpassungen, AIP und Patches mit viel weniger Schritten abarbeiten. Der Admin Guide hat an vielen Stellen diese komplizierteren Schritte beschrieben.
2 Beispiele:
Gleich am Anfang nach dem Download per Customization Wizard die Version angepasst und dann direkt diesen Befehl genutzt:

msiexec /i AcroRead.msi PATCH="AdbeRdrUpd11001.msp; AdbeRdrSecUpd11002.msp" TRANSFORMS="AcroRead.mst"

Damit wird der angepasste Reader installiert und daraufhin mit den Patches versehen. Mehrere Patches lassen sich wie gezeigt aneinanderreihen, die Pfade sollte man lieber noch ergänzen; habe ich der Übersicht wegen weggelassen.
Oder: alternativ kann man ohne Anpassung auch die wichtigsten Eigenschaften direkt bei der Installation mit den Property-Parametern setzen:

msiexec /i AcroRead.msi PATCH="AdbeRdrUpd11004_MUI.msp" LANG_LIST=de_DE SUPPRESSLANGSELECTION=1 REMOVE_PREVIOUS=YES EULA_ACCEPT=YES SYNCHRONIZER=NO

Die CMD Möglichkeiten beim Erstellen des AIP und der Installation sind vielfältig, aber benötigen auch weit mehr Expertise.
Außerdem machen sie die Fehlersuche viel komplizierter, sollte es während eines 1-Liner zu einem Fehler kommen.
Ich war deswegen immer der Freund von ausführlichen Schritt-für-Schritt Herangehensweisen. Entscheidet selbst.

Die Windows Indizierung verbessert die Windows Suche und ergänzt sie um Dateien, Dateiinhalte und sogar E-Mails, Kalendereinträge und andere Daten, falls Microsoft Produkte wie Outlook genutzt werden.
Sollte es bei der Suche (sowohl in Windows als auch in Outlook) zu Problemen kommen, hilft das Zurücksetzen der Windows Suche bzw. das Neuerstellen des Suchkatalogs.

Händisch:
Dies geht relativ einfach über Start -> Indizierungsoptionen -> Erweitert -> Neu erstellen.
Dadurch wird der Suchkatalog gelöscht und alle gespeicherten Orte neu indiziert.

Für Administratoren ist es aber viel wichtiger, diese Aktion verteilen zu können. Dafür gibt es eine Registry Lösung, die bewirkt, dass die komplette Windows Suche zurückgesetzt wird. Hierbei werden alle Orte gelöscht, Einstellungen zurückgesetzt und der Katalog neu erstellt.

Registry:
Der Schlüssel

HKLM\SOFTWARE\Microsoft\Windows Search

enthält das Wertepaar „SetupCompletedSuccessfully“, welches für gewöhnlich auf „1“ gestellt ist. Den Wert auf 0 zu setzen kommt einem Reset des Dienstes gleich.

Am besten eignet sich hierfür ein Script:

@echo on & Color 9f & setlocal
set regEL=9

REM stop windows search service
net stop wsearch

REM reset search settings/catalog by resetting reg key
reg add "HKLM\SOFTWARE\Microsoft\Windows Search" /f /v "SetupCompletedSuccessfully" /t REG_DWORD /d "0"
set regEL=%errorlevel%
move "%programdata%\microsoft\search\data\applications\windows\Windows.edb" "%programdata%\microsoft\search\data\applications\windows\Windows.edb.bak"
REM to be sure:
del "%programdata%\microsoft\search\data\applications\windows\Windows.edb"

REM start windows search service
net start wsearch

endlocal

Ich habe heute ein Script zusammengebastelt, welches den Windows 7 und den Office 2007 Lizenz-Key des Computers ausliest und ihn in eine Textdatei speichert. Die Textdatei entspricht dem Computernamen zur einfachen Zuordnung von PC und Key. Das Script läuft komplett selbstständig, kann also z.B per Gruppenrichtlinie automatisch ausgeführt werden.
Code-Grundlage ist dieser Forum Post.

Ich habe den Code bereinigt, gekürzt und um die Erkennung von Office 2007 erweitert. Das Script erkennt außerdem, ob das System mit 32bit oder 64bit läuft und passt die Erkennung dementsprechend an.

Hier der verbesserte Code:

On Error Resume Next
Dim WshNetwork
Set WshNetwork = CreateObject("WScript.Network")
cName = WshNetwork.ComputerName
Set WshShell = CreateObject("WScript.Shell")
' detect processor architecture, returns 32 or 64
pa = GetObject("winmgmts:root\cimv2:Win32_Processor='cpu0'").AddressWidth
' get current path
set fso = CreateObject("Scripting.FileSystemObject")
logpath = fso.BuildPath(fso.GetAbsolutePathName("."), "Keys.txt")
'logpath = "\\server\path\to\log.txt" 'for servers

' ----------- Windows 7 Key -----------
wkey = "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\"
wdigitalId = WshShell.RegRead(wkey & "DigitalProductId")
wProductName = "Product Name : " & WshShell.RegRead(wkey & "ProductName") & vbNewLine 
wProductId   = "Product Id   : " & WshShell.RegRead(wkey & "ProductId") & vbNewLine 
wProductKey  = "Install Key  : " & Converted(wdigitalId)

windowsData = wProductName & wProductId & wProductKey
' ----------- Windows 7 END -----------

' ----------- Office 2007 Key -----------
'32bit or 64bit?
If pa = "32" Then
	okey = "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Office\12.0\ Registration\{90120000-0011-0000-0000-0000000FF1CE}\DigitalProductID\"
Else
	okey = "HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Office\12.0\Registration\{91120000-00CA-0000-0000-0000000FF1CE}\"
End if

odigitalId = WshShell.RegRead(okey & "DigitalProductID")    
If (IsEmpty(odigitalId)) Then 
    officeData = "Office 2007 not found"
Else
    oProductKey  = "Install Key  : " & Converted(odigitalId)
    oProductName = "Product Name : " & WshShell.RegRead(okey & "ProductName") & vbNewLine 
    oProductId   = "Product Id   : " & WshShell.RegRead(okey & "ProductId") & vbNewLine 
    officeData = oProductName & oProductId & oProductKey
End If

' ----------- Office 2007 END -----------

Save()

Function Converted(id)
    Const OFFSET = 52
    i = 28
    Chars = "BCDFGHJKMPQRTVWXY2346789"
    Do
        Cur = 0
        x = 14
        Do
            Cur = Cur * 256
            Cur = id(x + OFFSET) + Cur
            id(x + OFFSET) = (Cur \ 24) And 255
            Cur = Cur Mod 24
            x = x -1
        Loop While x >= 0
        i = i - 1
        Converted = Mid(Chars, Cur + 1, 1) & Converted
        If (((29 - i) Mod 6) = 0) And (i <> -1) Then
            i = i -1
            Converted = "-" & Converted
        End If
    Loop While i >= 0
End Function

Function Save()
  WScript.Echo "Save to: " & logpath
  Set file = CreateObject("Scripting.FileSystemObject").CreateTextFile(logpath,2,0)
  file.Writeline(FormatDateTime(Date, vbLongDate) & vbNewLine)
  file.Writeline(windowsData & vbNewLine) 'Windows 7
  file.Writeline(officeData & vbNewLine) 'Office 2007
  file.close
End Function

Ergebnis:
windows-7-office-2007-key-reading-decrypting-script

Den Logpath in Zeile 7 müsst ihr anpassen. Ihr könnt diese Zeile auch komplett entfernen und die Zeile 61 anpassen („logpath &“ entfernen), dann wird die Logdatei immer im selben Ordner mit der .vbs erstellt. Dann ist das Script allerdings nicht mehr GPO tauglich. Für GPO Verteilung via Computer-Startscript müsst ihr den Pfad im Script explizit angeben.

Hinweis: Die Erkennung des Windows Keys funktioniert bei der Enterprise Version voraussichtlich nicht. Bei Windows Server 2008 R2 (Standard) funktioniert es.
Es ist etwas erschreckend wie schlecht die Keys geschützt waren. Ich weiß nicht, ob sich diese Methode auch für andere Versionen von Windows oder Office verwenden ließe. Vielleicht ist hier ein ITler mit WinXP, Office 2k3 o.Ä. und schaut mal in der Registry nach.

Batch Löschtaktiken

Nur Unterordner eines Zielordners löschen:

for /D %%a in ("zielordner\*.*") do rd /q /s "%%a"

Nur Dateien eines Zielordners löschen, Unterordner (+Inhalt) nicht löschen:

del zielordner\*.* /q

Gesamten Inhalt eines Ordners löschen:
Entweder löscht man den gesamten Ordner und erstellt ihn leer neu:

rd zielordner /s /q && md zielordner

oder man leer den Inhalt ohne den Ordner selbst anzufassen:

del zielordner /s /f /q
for /D %%a in ("zielordner\*.*") do rd /q /s "%%a"

Falschen Produkt Key in Office 2007 eingegeben? Nachträglich doch einen anderen Key nutzen? Aktivierung funktioniert nicht richtig oder nimmt den Key nicht an?
Ein Reset des Produkt Keys in Office 2007 ist total easy.

  1. Schließt alle Office Programme.
  2. Öffnet die Registry („regedit.exe“) und sucht dort nach
    [plain]
    64bit: HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Office\12.0\Registration
    32bit: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Office\12.0\Registration
    [/plain]
  3. Öffnet den darin enthaltenen Schlüssel, der entweder so aussehen dürfte: {91120000-00CA-0000-0000-0000000FF1CE}
    oder so: {90120000-0030-0000-0000-0000000FF1CE}
  4. Löscht die darin enthaltenen Einträge DigitalProductID und ProductID

office2007-product-key-reset-registry

Fertig. Beim nächsten Start eines Office Programms muss ein neuer Lizenzschlüssel eingegeben werden.
Es soll auch relativ einfach sein Office 2007 ohne Produkt Schlüssel zu aktivieren. Das habe ich aber nicht getestet und werde es hier auch nicht beschreiben. Siehe hier.

Update:

Download

Ich habe euch sogar 2 einfache .reg Dateien erstellt, die genau das tun: diese 2 Keys löschen. Einmal für 64bit und einmal für 32bit. Doppelklick während alle Office Programme geschlossen sind, fertig!
delete-office2007-activation-64bit [.reg]
delete-office2007-activation-32bit [.reg]
(Rechtsklick -> [Link/Ziel] speichern unter…)

Als Hobby-Webentwickler und fanatischer Batch Scripter musste das Thema Batch HTML Reports ja irgendwann mal kommen. Heißt: Batch führt irgendwelche Aktionen aus und visualisiert das Ergebnis in einer schönen HTML Datei.

Eigentlich straight forward: in der Batch Datei wird ein

echo

mit HTML Code in eine .html Datei umgeleitet, fertig. Naja, ganz so einfach ist es leider nicht.
Hier ein Beispiel:

echo "<html><body>" > t.html
echo "Ein Test " >> t.html
echo "<span>Fehlerlevel: %errorlevel%</span>" >> t.html
echo "</body></html>" >> t.html

Ergebnis:
html-berichte-mit-batch-problem-einfaches-beispiel

Der Batch

echo

Befehl würde an eckigen Klammern und Slashes abstürzen, daher muss jeglicher HTML Code in Anführungsstrichen eingebettet werden. Leider schreibt Batch diese Anführungszeichen mit in das Dokument.
Nun gibt es sicherlich einige Lösungsansätze:

1. (nicht empfohlen) Alle Sonderzeichen escapen und Anführungszeichen weglassen:

echo ^<html^>^<body^> > t.html
echo Ein Test  >> t.html
echo ^<span^>Fehlerlevel: %errorlevel%^<^/span^> >> t.html
echo ^<^/body^>^<^/html^> >> t.html

Alle Sonderzeichen, die den Batch

echo

Befehl in die Knie zwingen würden, werden mit dem Escapezeichen ^ neutralisiert. Funktioniert, but… seriously? Ich hoffe aber niemand denkt ernsthaft darüber nach diese Technik zu verwenden…

2. (nicht empfohlen) HTML Code nicht über das Batch sondern über eine externe Komponente schreiben:
Wenn Batch ungern HTML schreibt könnte man auch ein externes Programm oder Script aufrufen und den gewünschten HTML String irgendwie übergeben. Klingt aber schon im Ansatz irgendwie uncool.

3. HTML mit Anführungszeichen schreiben und diese dann rausfiltern:
Also so mache ich das zumindest!
Der HTML Code wird wie im Beispiel oben geschrieben und danach nutze ich mein Zeichen-suchen-und-ersetzen-vbs-Script aus dem letzten Artikel und filtere die Anführungszeichen raus.
Batch:

echo "<html><body>" > t.html
echo "Ein Test " >> t.html
echo "<span>Fehlerlevel: %errorlevel%</span>" >> t.html
echo "</body></html>" >> t.html

cscript //nologo deleteChar.vbs "t.html" "t-neu.html"

deleteChar.vbs:

Set objFSO = CreateObject("Scripting.FileSystemObject")
Const ForReading = 1
Const ForWriting = 2
' Parameter einlesen
inputFile = WScript.Arguments(0)
outputFile = WScript.Arguments(1)

' Datei öffnen und Text einlesen und schließen
Set objFile = objFSO.OpenTextFile(inputFile, ForReading)
strText = objFile.ReadAll
objFile.Close

' Anführungszeichen rauslöschen
strNewText = Replace(strText, """", "")

' Neue Datei erstellen mit neuen Inhalten füllen
set resultFile = objFSO.CreateTextFile(outputFile, true)
resultFile.WriteLine strNewText
resultFile.Close

Resultat:
html-berichte-mit-batch-vbs-workaround


Ping Test HTML Report

Nun kann ich also HTML schreiben. Der Weg zum schönen HTML Bericht ist aber noch nicht geschafft. Ich empfehle einen gewissen Projekt-Aufbau um bessere HTML Berichte zu erstellen.
Vorschlag:

  • vorlage.html – enthält bereits ein halbes HTML Gerüst
  • style.css – für das Design
  • script.bat – das Script
  • deleteChar.vbs – siehe oben, löscht die Anführungszeichen
  • temp.html – temporär für die Batch
  • report.html – fertiger Report nachdem deleteChar.vbs die temp.html bearbeitet hat

Batch:

Color 9f
@echo on
setlocal

REM Vorlage nach temp.html kopieren, damit der HTML Code nicht jedes Mal komplett
REM geschrieben werden muss. Vor allem wenn der <head> und der Aufbau größer ist.
REM Kann alles schon fertig in die vorlage.html geschrieben werden.
cmd /c echo d | xcopy "vorlage.html" "temp.html" /c /v /i /y

REM optionaler Timestamp
echo "<span id="timestamp">%date% %time%</span>" >> "temp.html"

REM Bericht füllen, Code from: http://stackoverflow.com/a/3870183/516047
for /f "tokens=1,2 delims=[]" %%a IN ('ping -n 1 www.google.de') DO (
 if "%%b" NEQ "" set ip=%%b
)
echo "<div class='computer'><span class='name'>www.google.de</span><span class='comment'>IP: %ip%</span></div>" >> temp.html

for /f "tokens=1,2 delims=[]" %%a IN ('ping -n 1 www.microsoft.com') DO (
 if "%%b" NEQ "" set ip=%%b
)
echo "<div class='computer'><span class='name'>www.microsoft.com</span><span class='comment'>IP: %ip%</span></div>" >> temp.html

for /f "tokens=1,2 delims=[]" %%a IN ('ping -n 1 www.facebook.de') DO (
 if "%%b" NEQ "" set ip=%%b
)
echo "<div class='computer'><span class='name'>www.facebook.de</span><span class='comment'>IP: %ip%</span></div>" >> temp.html

for /f "tokens=1,2 delims=[]" %%a IN ('ping -n 1 www.hannes-schurig.de') DO (
 if "%%b" NEQ "" set ip=%%b
)
echo "<div class='computer'><span class='name'>www.hannes-schurig.de</span><span class='comment'>IP: %ip%</span></div>" >> temp.html

for /f "tokens=1,2 delims=[]" %%a IN ('ping -n 1 http://studium.hannes-schurig.de') DO (
 if "%%b" NEQ "" set ip=%%b
)
echo "<div class='computer'><span class='name'>http://studium.hannes-schurig.de</span><span class='comment'>IP: %ip%</span></div>" >> temp.html

echo "</div><!--#wrapper--></body></html>" >> "temp.html"

REM Anführungszeichen aus der temp.html löschen und in report.html schreiben
cscript //nologo "deleteChar.vbs" "temp.html" "report.html"

REM temp.html löschen
if exist temp.html del /f /q temp.html

:end
endlocal

vorlage.html:

<!DOCTYPE html>
<html lang='de'>
  <head><title>PC Monitor</title><link rel='stylesheet' type='text/css' href='style.css' /></head>
  <body>
  <div id='wrapper'>

Ergebnis:
html-berichte-mit-batch-fertiger-bericht

Download

Ping HTML Report Beispiel herunterladen
html-berichte-mit-batch-aufbau

Hier ein weiteres Beispiel, wie ich mit einigen zusätzlichen Programmierungen (Download gibts auf Anfrage) die Konnektivität von Arbeitsrechnern überprüfe und anzeigen lasse:
html-bericht-mit-batch-computer-status-report

Ziel ist es in einer beliebigen Datei – der Inhalt sollte aber schon irgendeine Art von Text sein – scriptgesteuert Text oder Zeichen suchen und ersetzen zu können; und zwar ohne Installation von Tools wie grep/sed sondern nur mit dem Script.
Eine pure Batch-Lösung halte ich für zu riskant, da Batch mit zu vielen Sonderzeichen Schwierigkeiten hat. Statt dessen greifen wir auf ein einfaches .vbs Script zurück.

Für Einsteiger: VBS (Visual Basic Script) Scripts sind Batch Scripts sehr ähnlich. Es ist praktisch nur Text in einer Datei mit der Dateiendung .vbs. Ausgeführt werden .vbs Scripts mit folgendem Code aus der CMD heraus, ggf. mit Parametern:

cscript //nologo script.vbs "parameter1"

zeichen-einfachen-text-suchen-ersetzen-vbs-batch-vbs-execution
VBS Scripts, im Vergleich zu Batch, laufen allerdings etwas stabiler, liefern notfalls Fehlermeldungen und bieten auch mehr Features. An dieser Stelle nutzen wir also diese Vorteile aus.

Hier der Code für ein einfaches .vbs Script zum Auslesen einer Datei, Suchen und Ersetzen 3 verschiedener Zeichen/Texte und Schreiben in eine andere Datei:

Set objFSO = CreateObject("Scripting.FileSystemObject")
Const ForReading = 1
Const ForWriting = 2

' Datei öffnen und Text einlesen und schließen
Set objFile = objFSO.OpenTextFile("test.html", ForReading)
strText = objFile.ReadAll
objFile.Close

' Änderungen am Inhalt
strNewText = Replace(strText, """", "'")
strNewText = Replace(strNewText, "lang='de'", "lang='en'")
strNewText = Replace(strNewText, "Hannes Schurig", "Max Mustermann")

' Neue Datei erstellen mit neuen Inhalten füllen
set resultFile = objFSO.CreateTextFile("test-neu.html", true)
resultFile.WriteLine strNewText
resultFile.Close

Relativ straight forward. Hier ein Beispielresultat:
zeichen-einfachen-text-suchen-ersetzen-vbs-batch-simple-script

Für eine bessere Handhabung lässt sich nun dieses Script optimieren. Die Eingabe- und Ausgabedatei könnte man parametirisieren. Wenn immer nur 1 Sache ersetzt werden soll, sich diese aber während der Scriptlaufzeit ändert oder erst währenddessen entschieden wird, könnte man auch diese Daten als Parameter übergeben.

Hier der Code für ein komplexeres .vbs Script:

Set objFSO = CreateObject("Scripting.FileSystemObject")
Const ForReading = 1
Const ForWriting = 2
' Parameter einlesen
inputFile = WScript.Arguments(0)
outputFile = WScript.Arguments(1)
searchText = WScript.Arguments(2)
replaceText = WScript.Arguments(3)

' Datei öffnen und Text einlesen und schließen
Set objFile = objFSO.OpenTextFile(inputFile, ForReading)
strText = objFile.ReadAll
objFile.Close

' Änderungen am Inhalt
strNewText = Replace(strText, searchText, replaceText)

' Neue Datei erstellen mit neuen Inhalten füllen
set resultFile = objFSO.CreateTextFile(outputFile, true)
resultFile.WriteLine strNewText
resultFile.Close

Hier das Resultat:
zeichen-einfachen-text-suchen-ersetzen-vbs-batch-complex-script

Eigentlich recht easy. In meinem nächsten Beitrag werden ich dieses Script nutzen um mit Batch dynamische HTML Reports zu erstellen. Wait for it!