PowerShell Skripts als geplante Tasks in der Aufgabenplanung starten

Es gibt ein Update zu diesem Artikel: https://www.ugg.li/powershell-scripts-starten-in-der-aufgabenplanung-nicht-ergebnis-0x1/

Powershell-Script lassen sich an der (Powershell-) Kommandozeile komfortabel starten, jedoch nicht ohne weiteres in geplanten Tasks.

Das geht schnell, einfach und Fehlertolerant so:
powershell-aufgabenplanung-startenFeld Programm/Script:

%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe

Argumente:

-noninteractive -file "C:\PF AD\SCRIPT.ps1" -ExecutionPolicy Bypass

Mehr Details dazu hat das MSDN in diesem Artikel, aber im Prinzip ist es das schon.

PowerShell: Liste alle Dienste auf allen Servern auf, die als Benutzer (oder Administrator) starten

Bei einer Kennwortänderung in kleinen Domänen, also wenn das „Administrator“ Kennwort nach laaaanger Laufzeit geändert wird, müssen einige Dienste, die im Laufe der Zeit als solcher eingerichtet wurden, ebenfalls geändert werden. In den meisten Fällen ist im Laufe der Zeit auch die Anzahl der Server gewachsen.

Wie kommt der faule Administrator als nun an eine Liste der Server, wo die Anmeldedaten von Diensten angepasst werden müssen?

Lösung

Unter der Voraussetzung, dass PowerShell Remoting eingerichtet und funktionsfähig ist, hilft dieses kleine aber feine Script.

Zuerst wird eine Liste aller Server aus dem AD geholt und dann via WMIC eine gefilterte Liste der Dienste geholt, die nicht als „LocalSystem“ oder „NT Author%“ gestartet werden. Letzteres ist ein Trick, um sowohl „NT Authorität“ als auch „NT Authority“ auf Deutsch und Englisch zu erwischen.

Import-Module ActiveDirectory

$Servers = ( (Get-ADComputer -Filter 'operatingsystem -like "*server*" -and enabled -eq "true"').dnshostname )
$ServiceName =  @{ Name = 'ServiceName'; Expression = {$_.Name}}
$ServiceDisplayname = @{ Name = 'Service DisplayName';  Expression = {$_.Caption}}

foreach ($server in $servers) {
    Invoke-Command $server -ScriptBlock {
        Get-CimInstance -Class Win32_Service -filter "StartName != 'LocalSystem' AND NOT StartName LIKE 'NT Author%' " } | 
            Select-Object SystemName, $ServiceName, $ServiceDisplayname, StartMode, StartName, State | format-table -autosize
}

PowerShell startet nicht mehr (System.ArgumentException, SHostUserInterface.GetTranscriptOptionFromSettings, System.IO.Directory.CreateDirectory)

Unter Windows Server 2012R2 startet die PowerShell „auf einmal“ nicht mehr. Nach dem Start erscheint direkt „powershell funktioniert nicht mehr“ und der Konsolenhost schießt sich wieder.

Server 2012R2 ist zwar bekanntermaßen EOL und muss weg, aber manchmal braucht man für den Wechsel auf ein neues System nun ebenjene PowerShell.

Die PowerShell stürzt ab mit diesem Fehler:

Problemsignatur:
  Problemereignisname:	PowerShell
  NameOfExe:	powershell.exe
  FileVersionOfSystemManagementAutomation:	6.3.9600.21616
  InnermostExceptionType:System.ArgumentException
  OutermostExceptionType:System.ArgumentException
  DeepestPowerShellFrame:SHostUserInterface.GetTranscriptOptionFromSettings
  DeepestFrame:System.IO.Directory.CreateDirectory
  ThreadName:	Consol.. main thread
  Betriebsystemversion:	6.3.9600.2.0.0.400.8
  Gebietsschema-ID:	1031

Lesen Sie unsere Datenschutzbestimmungen online:
  http://go.microsoft.com/fwlink/?linkid=280262

Wenn die Onlinedatenschutzbestimmungen nicht verfügbar sind, lesen Sie unsere Datenschutzbestimmungen offline:
  C:\Windows\system32\de-DE\erofflps.txt

Lösung

In diesem Fall war es die Gruppenrichtlinie „PowerShell-Aufzeichnung aktivieren“ (Computer > Administrative Vorlagen > Windows-Komponenten/Windows PowerShell > PowerShell-Aufzeichnung aktivieren).

Die GPO setzt diesen Registry-Schlüssel:

[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\PowerShell\Transcription]
"EnableTranscripting"="1"

Server 2012R2 erwartet aber nicht nur diesen Key, sondern auch noch den Ausgabepfad als Zeichenkette (OutputDirectory). Bleibt die Zeichenkette leer, startet die PowerShell nicht mehr. Als Gegenprobe: Setzt man den Eintrag „EnableTranscripting“ auf „0“ funktioniert sofort wieder alles – bis die GPO den Eintrag wieder zurückändert.

Also gibt es als schnelle Lösung eine *.reg-Datei, die einfach dort einen Pfad (den es geben sollte!) hinzufügt:

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\PowerShell\Transcription]
"OutputDirectory"="C:\\Windows\\Temp"

Solle die GPO beim nächsten gpupdate den Pfad wieder leeren, müsste man seine Richtlinie entsprechend anpassen. Oder (empfohlen) die Migration des 2012R2-Systems ASAP abschießen.

Wie man FSLogix automatisch aktualisiert (FSLogix Update)

Leider ist FSLogix nicht in Windows-Update(s) enthalten. Der Admin einer RDS-Farm muss also selbstständig für seine Updates sorgen.

Da es aber in der Tat häufiger mal Updates für FSLogix gibt (Siehe Hotfix-Liste), die beispielsweise Fehler mit der Microsoft Office 365 Aktivierung beheben, lohnt es sich diese auch wirklich zu installieren. Man kann das Setup in der selben Version auch mehrfach ausführen, es wird nur installiert wenn wirklich etwas neues dabei ist.

Der Vorgang ist prinzipiell einfach: Neue Version herunterladen, ZIP-Datei auspacken, App-Installer ausführen und Server neu starten. Wäre das nicht toll, wenn das auch automatisch geht?

Lösung

Bei dem letzten Einsatz, der das Problem „Leeres Microsoft 365 Anmeldefenster“ behebt, ist ein PowerShell Script das selbiges tut entstanden. Einsatz auf eigene Gefahr ☺️

# Update FSLogix to "latest", 20231115
# [email protected] mit input von @j_vanneuville
#
# Achtung: Startet bei Erfolg den Server neu!

# URL zur aktuellen Version
$FslogixUrl= "https://aka.ms/fslogix_download"

# Download hierher
# Die literalen Pfade sind Absicht, anders waere RDS auch nicht supported
Remove-Item "C:\Windows\Temp\fslogix\install" -Force -Recurse
mkdir "C:\Windows\Temp\fslogix\install" -Force | Out-Null
Set-Location "C:\Windows\Temp\fslogix\install"
Write-Host "Download von" $FslogixUrl "... (180Mbyte)"
# Ausblenden der ProgressBar macht den Download 50x schneller m(
$ProgressPreference = 'SilentlyContinue'
Invoke-WebRequest -Uri $FslogixUrl -OutFile "C:\Windows\Temp\fslogix\install\FSLogixAppsSetup.zip" -UseBasicParsing

# Auspacken hierher
Write-Host "Auspacken von FSLogixAppsSetup.zip ..."
Expand-Archive -LiteralPath "FSLogixAppsSetup.zip" -DestinationPath "C:\Windows\Temp\fslogix\install" -Force -Verbose

# Installieren + Neustart
Set-Location "C:\Windows\Temp\fslogix\install\FSLogix_Apps_*\x64\release"
Start-Process "FSLogixAppsSetup.exe" -ArgumentList "/install /quiet" -Wait -Passthru

Wir finde ich schnell heraus, welcher Prozess auf einem Port lauscht?

Manchmal muss ein Admin „mal eben“ wissen, welcher Prozess einen listening Port blockiert nutzt. Auf Servern mit vielen abhörenden Ports in TCP und UDP wird die Ausgabeliste von netstat nur schnell unübersichtlich

Lösung

An der CMD- oder PowerShell geht das schneller als gedacht. ⚠️ Achtung: da die Shell international übersetzt ist, muss man find das jeweilig passende Suchwort mitgeben (English: „LISTEN“, deutsch „ABHÖREN“).

(CMD/PS) Zuerst die PID des lauschenden Prozesses finden …

netstat -ano | find "<PORT>" | find "ABH"

(PS) … dann den Prozess mit Pfad auflisten:

Get-WmiObject Win32_Process | Select ProcessId,CommandLine | findstr <PID>

(CMD) Das geht natürlich auch mit tasklist, allerdings nur ohne Pfad:

tasklist /fi "PID eq <PID>"

Die allerschnellste und PowerShell-Only Variante geht so:

Get-Process -Id (Get-NetTCPConnection -LocalPort <PORT>).OwningProcess