Ausführen von PowerShell über eine Batch

PowerShell Skripte oder CmdLets lassen sich auch über eine Batchdatei (.cmd / .bat) ausführen. Das geht recht einfach und sogar Parameter können mit angegeben werden. Es muss lediglich auf korrekte gesetzte Quoten (Anführungszeichen) geachtet werden.

:: Variables
set log="%temp%\Expand-Raw.log"

:: Header
echo Expand-Raw ...
echo Expand-Raw ... >%log%
echo.

for /f "tokens=*" %%a in ('dir RAW*.zip /b') do (

	rem  PowerShell -NoExit "&" ""P:\Code\Distribute-Pictures.ps1" -Action dis -File '.\%%a'"
	PowerShell ""P:\Code\Distribute-Pictures.ps1" -Action dis -File '.\%%a'"
	echo [RC=%ERRORLEVEL%], PowerShell -NoExit "&" ""P:\Code\Distribute-Pictures.ps1" -Action dis -File '.\%%a'" >>%log%

)

:_End

Schauen wir uns das PowerShell-Skript genauer an, dann sehen wir das insgesamt 4 Parameter übergeben werden:

  • -Action und die entsprechende Aktion, also –Action dis
  • -File und Dateiname, also –File ‘RAW 2017-01-08-01, Huskies auf der Alb.zip’

Der Aufruf unter PowerShell (also nicht über eine Batch sieht wie folgt aus):

.\Distribute-Pictures.ps1 -Action dis -File 'RAW 2017-01-08-01, Huskies auf der Alb.zip'

Die Batch Datei, welche nun drum herum abläuft, soll das PowerShell-Skript einfach mehrfach für eine Reihe von Dateien im gleichen Verzeichnis ausführen. Darum erfolgt ein Aufruf von PowerShell.exe mit dem Script und den Parametern aus der Batch heraus.

PowerShell ""P:\Code\Distribute-Pictures.ps1" -Action dis -File '.\%%a'"

PowerShell ruft die PowerShell.exe auf, danach wird der vollständige Aufruf für PowerShell in normale Anführungszeichen gesetzt.

""P:\Code\Distribute-Pictures.ps1" -Action dis -File '.\%%a'"

Innerhalb dieser Anführungszeichnen (“) steht dann das PowerShell-Script in weiteren Anführungszeichen, gefolgt von den Parametern. Der letzte Parameter, welcher den Dateinamen darstellt, wird in einfache Anführungszeichen (‘) gesetzt, da ihn PowerShell dann literal behandelt.

Enjoy it, b!

Konvertierung von m4a Dateien nach mp3

Leider können nicht alle Car-Audio Systeme M4A-Dateien abspielen. Darum bin ich gelegentlich mit der Aufgabe konfrontiert M4A-Dateien nach MP3 zu konvertieren, was mit ffmpeg.exe und einem kleinen Script an der Eingabeaufforderung ohne große Probleme funktioniert.

Dazu habe ich den aktuellsten Windows-Build von ffmpeg herunter geladen und in ein Verzeichnis auf meinem Server (SBS) entpackt.

https://ffmpeg.zeranoe.com/builds/

Danach in das Verzeichnis mit den M4A-Dateien gewechselt und folgenden Aufruf ausgeführt:

for /f "tokens=1,2 delims=." %a in ('dir *.m4a /b') do \\sbs\xapps\ffmpeg\bin\ffmpeg.exe -i "%a.%b" -b:a 256K -vn "%a.mp3"
  • dir *.m4a /b liefert mir alle M4A-Dateien zurück
  • for /f …. zerlegt die Dateien in den eigentlichen Dateinamen und die Endung (welche nach der Konvertierung .mp3 sein soll)
  • ffmpeg.exe erstellt die entsprechende mp3 Datei mit einer Sampling-Rate von 256Kbit/s

That’s it … ging recht einfach Smile Die M4A-Dateien habe ich dann noch im Anschluss gelöscht.

Enjoy it, b!

Windows 10, Installation des .NET Frameworks 3.5

Liegt der Inhalt des Windows 10 ISOs auf einer Dateifreigabe im Netzwerk so kann das .NET Framework 3.5, über den folgenden Aufruf, von einer Eingabeaufforderung mit Adminrechten installiert werden.

Dism /online /enable-feature /featurename:NetFx3 /All /Source:\server\w10\sources\sxs /LimitAccess

Das geht deutlich einfacher und scheller als über den Dialog der Windows Features.

image

Enjoy it, b!

Windows SBE 2012 R2 Dashboard

Für den Windows Server Small Business Essentials 2012 R2 hat Microsoft das Management mit PowerShell nochmals deutlich verbessert und liefert eine Reihe hilfreicher PowerShell Befehle mit.

https://technet.microsoft.com/en-us/library/dn205088(v=wps.630).aspx

Im Gegensatz zu früheren Versionen, lässt sich damit z.B. das Dashboard nach einer Migration auf SBE 2012 R2 von Benutzerkonten säubern welche dort nicht angezeigt werden sollen (Service Accounts, zusätzliche Admins, etc.).

Dazu wird einfach PowerShell als Administrator gestartet und die vorhandenen Benutzer des Dashboards ermittelt:

# Ermittlung der im Dashboard angezeigten Benutzer
Get-WssUser | fl UserName

image

Die beiden grün markierten Benutzer sollen nicht mehr im Dashboard angezeigt werden (das eine ist mein Administrator, der andere DHCP2DNS ist der Proxy-Account für DNS Updates).

# Deaktivieren der Anzeige von Benutzern im Dashboard
Set-WssUserDashboardVisibility -Name bernd-adm -Hidden

Set-WssUserDashboardVisibility -Name DHCP2DNS-Update -Hidden

image

Damit zeigt das Dashboard lediglich den Administrator und die eigentlichen SBE Benutzer an.

Enjoy it, b!

Server hängt beim herunterfahren

Nach der Installation einer großen Anzahl von Updates wollten einige Server nicht mehr sauber herunter fahren, bzw. neu starten.

Gut 20min musste ich mir den folgenden Bildschirm anschauen.

image

Dabei habe ich mir die Frage gestellt – was tun? Gut, eine VM kann ich über das Hyper-V Management einfach ausschalten, einen Hyper-V Host oder anderen physikalischen Server kann ich über das ILO-Board ausschalten. Die Konsequenzen sind aber nicht immer absehbar.

Die Ursache des Problems war bei allen Systemen (3x virtuell und 1x Hyper-V Host), dass sich ein Services nicht korrekt beenden wollte.

Eine Abfrage der Services …

sc \\server queryex >c:\temp\process.txt

… welche remote noch möglich war lieferte folgendes Ergebnis.

SERVICE_NAME: TrkWks
DISPLAY_NAME: Distributed Link Tracking Client
        TYPE               : 20  WIN32_SHARE_PROCESS  
        STATE              : 4  RUNNING 
                                (STOPPABLE, NOT_PAUSABLE, ACCEPTS_SHUTDOWN)
        WIN32_EXIT_CODE    : 0  (0x0)
        SERVICE_EXIT_CODE  : 0  (0x0)
        CHECKPOINT         : 0x0
        WAIT_HINT          : 0x0
        PID                : 12
        FLAGS              : 

SERVICE_NAME: TrustedInstaller
DISPLAY_NAME: Windows Modules Installer
        TYPE               : 10  WIN32_OWN_PROCESS  
        STATE              : 3  STOP_PENDING 
                                (NOT_STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN)
        WIN32_EXIT_CODE    : 0  (0x0)
        SERVICE_EXIT_CODE  : 0  (0x0)
        CHECKPOINT         : 0x2
        WAIT_HINT          : 0x36ee80
        PID                : 4124
        FLAGS              : 

SERVICE_NAME: UmRdpService
DISPLAY_NAME: Remote Desktop Services UserMode Port Redirector
        TYPE               : 20  WIN32_SHARE_PROCESS  
        STATE              : 4  RUNNING 
                                (STOPPABLE, NOT_PAUSABLE, ACCEPTS_SHUTDOWN)
        WIN32_EXIT_CODE    : 0  (0x0)
        SERVICE_EXIT_CODE  : 0  (0x0)
        CHECKPOINT         : 0x0

Da die Ausgabe in eine Textdatei erfolgte konnte ich hier einfach eine Suche durchführen und bin dabei mehrfach auf den TrustedInstaller Service gestoßen welcher mit STOP_PENDING das Herunterfahren, bzw. den Neustart des Servers verhinderte.

Ein Beenden des Prozesses mit taskkill half sofort und das Problem war gelöst.

taskkill /S server /PID 4124

Nach dem Neustart wurden nochmals wenige ausstehende Updates installiert und der Server läuft wieder ohne Probleme.

Auf einem Hyper-V Host hatte ich das gleiche Problem, hier wollte eine VM sich nicht beenden und nach über 1h Warten habe ich mich entschlossen den Prozess der VM zu beenden.

SERVICE_NAME: vds
DISPLAY_NAME: Virtual Disk
        TYPE               : 10  WIN32_OWN_PROCESS  
        STATE              : 4  RUNNING 
                                (STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN)
        WIN32_EXIT_CODE    : 0  (0x0)
        SERVICE_EXIT_CODE  : 0  (0x0)
        CHECKPOINT         : 0x0
        WAIT_HINT          : 0x0
        PID                : 1076
        FLAGS              : 

SERVICE_NAME: vmms
DISPLAY_NAME: Hyper-V Virtual Machine Management
        TYPE               : 10  WIN32_OWN_PROCESS  
        STATE              : 3  STOP_PENDING 
                                (STOPPABLE, NOT_PAUSABLE, ACCEPTS_PRESHUTDOWN)
        WIN32_EXIT_CODE    : 0  (0x0)
        SERVICE_EXIT_CODE  : 0  (0x0)
        CHECKPOINT         : 0xdcb
        WAIT_HINT          : 0x7d0
        PID                : 1112
        FLAGS              : 

SERVICE_NAME: W32Time
DISPLAY_NAME: Windows Time
        TYPE               : 20  WIN32_SHARE_PROCESS  
        STATE              : 4  RUNNING 
                                (STOPPABLE, NOT_PAUSABLE, ACCEPTS_SHUTDOWN)
        WIN32_EXIT_CODE    : 0  (0x0)
        SERVICE_EXIT_CODE  : 0  (0x0)
        CHECKPOINT         : 0x0
        WAIT_HINT          : 0x0
        PID                : 844
        FLAGS              : 

Das Beenden erfolgt wiederum über taskkill.exe und der entsprechenden Prozess-ID (1112).

Nach dem Neustart des Hyper-V Hosts hat lediglich die VM einen “unexpected shutdown” gemeldet, alle anderen VMs waren davon nicht betroffen.

Generell erscheint mir diese Vorgehensweise (auch bei Hyper-V Hosts) die deutlich sinnvollere als einfach den Server aus zu schalten. Ein Power-Reset betrifft gleich immer alle darauf laufenden Systeme was auch mal einige VMs beschädigen kann.

Enjoy it, b!

Password will never expire …

In Workgroups oder Zuhause ist es oft mühselig (bei den Home Editions über die GUI gar nicht möglich) das Ablaufen von Passwörtern zu deaktivieren. Neulich hatte ich das Problem, dass 20 Notebooks in einem Schulungscenter mit drei lokalen Benutzern mit ablaufenden Passwörter zu kämpfen hatten. Daher habe ich ein Script geschrieben um die Konfiguration zu automatisieren.

Eigentlich reicht es einfach das Script mit erhöhten Admin-Rechten aus zu führen. ich habe aber noch eine Möglichkeit eingebaut Accounts von dieser Änderung aus zu schließen. Diese müssen dazu lediglich in Zeile 7 eingetragen werden.

set account-filter=administrator gast guest Default

Das Script funktioniert mit Windows 7 aufwärts (darunter habe ich es nicht getestet) und ist als einfache Batch realisiert.

@echo off

:: Set-PasswordWillNeverExpire.cmd

set alog-unicode=%temp%\local-accounts-unicode.txt
set alog-ansi=%temp%\local-accounts-ansi.txt
set account-filter=gast guest Default
set alog-ansi-2beSet=%temp%\local-accounts-2beSet.txt

echo.
echo !!! Run this script as Administrator !!!
echo.

:: get local user accounts from wmi as unicode
WMIC USERACCOUNT WHERE LocalAccount='true' GET Name >%alog-unicode%
:: convert unicode to ansi
type %alog-unicode% >%alog-ansi%

:: excluding some accounts
for /f "tokens=1,* skip=1 delims= " %%a in (%alog-ansi%) do (
 
	echo %%a | findstr /v /i "%account-filter%" >>%alog-ansi-2beSet%

)

:: setting remaining accounts to never expire
for /f "tokens=1" %%a in (%alog-ansi-2beSet%) do (

	WMIC USERACCOUNT WHERE "Name='%%a'" SET PasswordExpires=FALSE

)

del %alog-unicode%
del %alog-ansi%
del %alog-ansi-2beSet%

Hier noch ein paar Hinweise zum Script:

Das Auslesen der Benutzer über das WMI erzeugt erst einmal eine Datei im Unicode Format. Mit dieser kann FOR aber nichts anfangen, wir müssen diese also nach ANSI konvertieren. Das geschieht mit einem einfachen TYPE .

type UNICODE-DATEI > ANSI-DATEI

Am Ende des Scripts werden alle erstellten Dateien wieder gelöscht, wer diese zur Dokumentation behalten will kann einfach die letzten drei Zeilen mit einem :: oder REM versehen und findet diese dann unter %TEMP%\NAME-DER-LOGDATEI.EXT.

:: del %alog-unicode%
:: del %alog-ansi%
:: del %alog-ansi-2beSet%

Enjoy it, b!

Lange Pfade in Windows

Schon vor ein paar Jahren hatte ich einen Post welcher sich mit langen Pfaden und deren Löschung über Robocopy beschäftigt hatte. Lange Pfade stellen einen Admin aber nicht nur beim Löschen sonder auch z.B. bei der Änderung von ACLs vor Probleme. Hier hilft dann der Umweg über die Windows API, z.B. mit icacls.

icacls "\\?\H:\Shares\verzeichnis1\00_B....t" /grant users:(m) /t /c /q /inheritance:e

Hier noch ein wenig Hintergrund zu der Problematik.

Windows hat immer noch eine Begrenzung von maximal 260 Zeichen im Pfad:

D:\some 256-character path string<NUL>

“D:\” = 3-character; 256-character; NUL = 1-character ergibt 260-character string

https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx

Die Verwendnug der Windows API hingegen ermöglicht die Verarbeitung von bis zu 32767 Zeichen langen Pfaden, wie oben im Beispiel mit icacls dargestellt.

Enjoy it, b!