Mai 2016

Band 31, Nummer 5

Dieser Artikel wurde maschinell übersetzt.

Windows PowerShell – Schreiben von Windows-Diensten in PowerShell

Durch Jean-François Larvoire | Mai 2016 | Code abrufen

Windows-Dienste sind normalerweise kompilierte Programme, die in C, C++, c# oder anderen Microsoft .NET Framework-basierten Sprachen geschrieben wurde, und solche Debugdiensten kann ziemlich schwierig sein. Einige Monate vor, inspiriert durch andere Betriebssysteme, die es ermöglichen, Dienste als einfache Shell-Skripts schreiben begann ich Fragen, wenn kann es eine einfachere Möglichkeit, auch unter Windows erstellen.

In diesem Artikel wird das Ergebnis diesem Unterfangen: Eine neuartige und einfache Möglichkeit, Windows-Dienste zu erstellen, indem sie in der Windows PowerShell-Skriptsprache geschrieben werden. Keine weitere Kompilierung nur einen Zyklus Schnelltest bearbeiten, der auf jedem System, nicht nur der Entwickler eigene durchgeführt werden können.

Ich gebe eine Standarddienst Skriptvorlage namens PSService.ps1, wodurch Sie zum Erstellen und testen neue Windows-Dienste in Minuten, sondern lediglich einen Texteditor wie Notepad. Diese Technik kann viel Zeit und Entwicklung Aufwand für Benutzer zum Experimentieren mit Windows-Dienste speichern – oder sogar realen Diensten für Windows bereitstellen, wenn Leistung ein wichtiger Faktor ist. PSService.ps1 stehen auf bit.ly/1Y0XRQB.

Was ist ein Windows-Dienst?

Windows-Dienste sind Programme, die im Hintergrund ohne Benutzereingriff ausgeführt. Ein Webserver, der im Hintergrund auf HTTP-Anforderungen für Webseiten aus dem Netzwerk antwortet, ist z. B. ein Dienst, wie eine Anwendung zur Überwachung, die im Hintergrund von Leistungsmesswerten oder Datensätze Hardware Sensorereignisse protokolliert.

Dienste beim Systemstart automatisch gestartet. Oder sie können bei Bedarf starten, wie von Clientanwendungen angefordert, die davon abhängig sind. Dienste, die in ihrer eigenen Windows-Sitzung von der UI-Sitzung ausgeführt werden. Diese Steuerelemente können in eine Anzahl von Systemprozessen sorgfältig ausgewählte Berechtigungen für die Sicherheitsrisiken einzuschränken.

Die Windows Service Control Manager

Die Dienste werden von Windows Service Control Manager (SCM) verwaltet. Der SCM ist verantwortlich für das Konfigurieren der Dienste starten, stoppen und so weiter.

Die SCM-Systemsteuerung ist über systemsteuerung | System und Sicherheit | Verwaltung | Dienste. Als Abbildung 1 zeigt eine Liste mit Name, Beschreibung, Status, starten und die Benutzer die Namen aller konfigurierten Dienste angezeigt.

Die Windows Service Control Manager-GUI in Windows 10
Abbildung 1 die Windows Service Control Manager-GUI in Windows 10

Es gibt auch Befehlszeilenschnittstellen zum SCM:

  • Das alte net.exe-Tool, mit dem bekannten "net Start" und "net Stop" Befehle, die Datumsangaben von bis zu MS-DOS! Trotz seines Namens können sie zum Starten und Beenden alle Dienste, nicht nur Netzwerkdienste verwendet werden. Geben Sie "net Help" für Details.
  • Ein leistungsstärkeres Tool namens sc.exe, eingeführt in Windows NT ermöglicht die präzise Kontrolle über alle Aspekte des Servicemanagement. Typ "sc /?" Weitere Informationen.

Diese Befehlszeilen-Tools sind zwar noch immer im Windows-10 zugunsten von Windows PowerShell Service Management-Funktionen, beschriebenen jetzt veraltet.

Problem: Net.exe und sc.exe verwenden den "short" Wort Dienstnamen, der jedoch nicht identisch mit den aussagekräftigeren Namen, die von der SCM-Systemsteuerung angezeigt. Um die Entsprechung zwischen den zwei Namen abzurufen, verwenden Sie die Windows PowerShell-Befehl Get-Service.

Dienststatus

Dienste können in einer Vielzahl von Zuständen befinden. In einigen Staaten sind erforderlich, andere sind optional. Die zwei grundlegende Zustände, die alle Dienste unterstützen müssen, werden beendet und gestartet. Diese angezeigt werden sollen bzw. (leer) oder in ausgeführt wird, unter der Spalte Status im Abbildung 1.

Ein dritter Optionaler Zustand wurde angehalten. Und einen anderen implizite Zustand jeder Dienst unterstützt, auch wenn es nicht erwähnt wird deinstalliert wird.

Ein Dienst kann Übergänge zwischen diesen Zuständen gemacht, siehe Abbildung 2.

Dienststatus
Abbildung 2-Dienststatus

Schließlich sind auch mehrere Zustände, die optional unterstützen kann: StartPending, StopPending, PausePending, ContinuePending. Dies sind nur hilfreich, wenn Statusübergänge eine viel Zeit in Anspruch nehmen.

Windows PowerShell Service Management-Funktionen

Windows PowerShell ist die empfohlene System-Verwaltungsshell seit Windows Vista. Es umfasst eine leistungsfähige Skriptsprache und eine umfangreiche Bibliothek von Funktionen für die Verwaltung aller Aspekte des Betriebssystems. Einige der Vorteile von Windows PowerShell sind:

  • Konsistente Funktionsnamen
  • Objektorientierte
  • Einfache Verwaltung eines beliebigen Objekts .NET

Windows PowerShell bietet viele Service Management-Funktionen, die als Cmdlets bezeichnet werden. Abbildung 3 zeigt einige Beispiele.

Abbildung 3 Windows PowerShell Service Management-Funktionen

Name der Funktion Beschreibung
Dienst starten Startet oder beendete Dienste
Dienst beenden Beendet eine oder mehrere ausgeführte Dienste
New-Service Installiert einen neuen Dienst
Get-Service Ruft die Dienste auf einem lokalen oder remote-Computer mit ihren Eigenschaften ab.
Set-Service Startet, beendet und hält einen Dienst und ändert seine Eigenschaften

 

Eine vollständige Liste aller Befehle mit der Zeichenfolge "Service" in ihren Namen führen Sie aus:

Get-Command *service*

Eine Liste von gerade Service Management-Funktionen führen Sie aus:

Get-Command -module Microsoft.PowerShell.Management *service*

Überrascht, dass keine Windows PowerShell-Funktion zum Entfernen (die Deinstallation wird) vorhanden ist ein Dienst. Dies ist einer der seltenen Fälle, wenn es dennoch erforderlich, verwenden Sie das Tool sc.exe alte ist:

sc.exe delete $serviceName

Die .NET ServiceBase-Klasse

Alle Dienste müssen ein .NET-Objekt, das Ableiten von der ServiceBase-Klasse erstellen. Microsoft-Dokumentation beschreibt alle Eigenschaften und Methoden dieser Klasse. Abbildung 4 sind einige dieser Elemente von besonderem Interesse für dieses Projekt.

Abbildung 4: Einige Eigenschaften und Methoden der ServiceBase-Klasse

Mitglied Beschreibung
ServiceName Kurzer Name zum Identifizieren des Diensts für das System verwendet
CanStop Ob der Dienst sie einmal beendet werden kann, wurde gestartet
OnStart() Aktionen an, die beim Starten des Diensts
OnStop() Aktionen an, die beim Beenden des Dienstes
Run() Registriert die ausführbare Dienstdatei beim SCM

 

Durch die Implementierung dieser Methoden wird eine Dienst-Anwendung vom SCM automatisch beim Start oder bei Bedarf gestartet; und es von der SCM-Systemsteuerung, von der alten net.exe und Befehle für sc.exe oder neue Windows PowerShell Service Management-Funktionen, zum Starten oder beenden Sie diesen manuell verwaltet.

Erstellen eine ausführbare Datei aus C#-Quellcode in eine Windows PowerShell-Skript eingebettet

PowerShell vereinfacht Verwendung .NET von Objekten in einem Skript. Er hat standardmäßig integrierten Unterstützung für zahlreiche .NET Objekttypen für die meisten Zwecke ausreichend. Noch besser: Es ist erweiterbar und ermöglicht das Einbetten von kurzen C#-Codeausschnitte in Windows PowerShell-Skript zum Hinzufügen der Unterstützung für alle anderen Features von .NET. Diese Funktion wird durch den Befehl Add-Type bereitgestellt, die trotz seines Namens ist viel mehr als nur Hinzufügen von Unterstützung für neue Objekttypen in .NET für Windows PowerShell ausführen können. Sie können sogar kompilieren und verknüpfen eine vollständige C#-Anwendung in eine neue ausführbare Datei. Angenommen, dieses hello.ps1 Windows PowerShell-Skript:

$source = @"
  using System;
  class Hello {
    static void Main() {
      Console.WriteLine("Hello World!");
    }
  }
"@
Add-Type -TypeDefinition $source -Language CSharp -OutputAssembly "hello.exe"
  -OutputType ConsoleApplication

erstellt eine hello.exe-Anwendung, die "Hello World!" ausgibt:

PS C:\Temp> .\hello.ps1
PS C:\Temp> .\hello.exe
Hello World!
PS C:\Temp>

Technologien kombinieren

PSService.ps1 Funktionen basierend auf Alles, was bisher besprochenen, kann ich nun diesen Windows PowerShell-Dienst erstellen, die ich spielidee haben, über ein PSService.ps1-Skript, das können:

  • Installieren Sie und deinstallieren Sie sich (mit Windows PowerShell Service Management-Funktionen).
  • Starten Sie und beenden Sie (mit den gleichen Satz von Funktionen).
  • Enthält einen kurze C#-Codeausschnitt, der die PSService.exe, die der SCM erwartet erstellt (mit dem Befehl Add-Type).
  • Stellen Sie die PSService.exe Stub Rückruf in das Skript PSService.ps1 für den eigentlichen Dienstvorgang (in der Antwort zu OnStart, OnStop und andere Ereignisse).
  • Werden Sie durch die SCM und alle Befehlszeilentools (Dank der Stub PSService.exe) verwaltet.
  • Stabil und erfolgreich für jeden Befehl in einem beliebigen Zustand verarbeiten. (Z. B. es kann automatisch beenden Sie den Dienst vor der Deinstallation oder keine Aktionen ausgeführt, wenn Sie gefragt werden, einen bereits gestarteten Dienst zu starten.)
  • Unterstützen Sie Windows 7 und allen späteren Versionen von Windows (nur Windows PowerShell v2-Funktionen mit).

Beachten Sie, dass ich nur die wichtigen Teile des PSService.ps1 Design und Implementierung in diesem Artikel erläutern werde. Das Beispielskript enthält auch das Debuggen von Code und Unterstützung für optionale Funktionen, aber deren Beschreibung würde die Erklärung hier unnötig erschweren.

PSService.ps1 Architektur das Skript wird in einer Reihe von Abschnitten organisiert:

  • Ein Headerkommentar zur Beschreibung der das.
  • Ein Kommentar-basierte Hilfe-Block.
  • Der Parameter-Block Befehlszeilenoptionen definieren.
  • Globale Variablen.
  • Hilfsroutinen: Jetzt und Protokolldateien.
  • Ein C#-Quellblock des PSService.exe-Stubs.
  • Der Hauptroutine, verarbeiten jede Befehlszeilenoption.

Globale Einstellungen

Unterhalb des Blocks Param enthält PSService.ps1 sofort globale Variablen definieren von globalen Einstellungen, die je nach Bedarf geändert werden können. Die Standardwerte im angezeigten Abbildung 5.

Abbildung 5-Standardwerte für globale Variablen

Variable Beschreibung Standard
$serviceName Ein Wort für die Startbefehle net und andere Der Basisname des Skripts
$serviceDisplayName Einen aussagekräftigeren Namen für den Dienst Ein Beispiel-PowerShell-Dienst
$installDir Wo die Dateien installiert werden. ${Env} \System32
$logFile Name der Datei, in der sich die Dienst Nachrichten ${ENV:windir}\Logs\$serviceName.log
$logName Name des Ereignisprotokolls,-Ereignisse protokolliert werden Anwendung

 

Verwenden den Namen der Datei als Name des Diensts (z. B. PSService für PSService.ps1) können Sie mehrere Dienste aus ein Skript erstellen, indem Sie einfach das Skript kopieren, die Kopie umbenennen, und installieren die Kopie.

Befehlszeilenargumente

Damit wird es einfach zu verwenden, das Skript unterstützt Befehlszeilenargumente, die alle Zustandsübergängen entsprechen, siehe Abbildung 6.

Abbildung 6 Befehlszeilenargumente für Zustandsübergänge

Wechseln Beschreibung
-Starten Starten Sie den Dienst
-Beenden Beenden Sie den Dienst
-Setup Sich selbst als Dienst installieren
-Entfernen Deinstallieren Sie den Dienst

 

(Unterstützung für den angehaltenen Zustand ist nicht implementiert wäre aber auf einfache Weise mit den entsprechenden Status Übergang hinzufügen.)

Abbildung 7 zeigt einige weitere Management-Argumente, die das Skript unterstützt.

Abbildung 7 unterstützten Management-Argumente

Wechseln Beschreibung
-Neustart Beenden Sie den Dienst, und klicken Sie dann erneut starten
-Status Zeigt den aktuellen Status des Diensts
-Dienst Führen Sie die Dienstinstanz (zur Verwendung nur durch die service.exe-Stub)
-Version Zeigt die Dienstversion
Allgemeine Parameter -? ,-Verbose, - Debug usw.

 

Jeder Status Übergang Switch verfügt über zwei Betriebsmodi:

  • Beim Aufrufen durch den Endbenutzer: Verwenden Sie Windows PowerShell Service Management-Funktionen, um ein Statusübergang auszulösen.
  • Wenn von der SCM (und indirekt über die service.exe-Stub) aufgerufen wird: Verwalten Sie die Dienstinstanz service.ps1 entsprechend.

Die beiden Fälle können zur Laufzeit bestimmt werden, überprüfen Sie den Benutzernamen ein: Im ersten Fall ist es als normaler Benutzer (der Systemadministrator); Im zweiten Fall ist es der eigentlichen Windows-System-Benutzer. System-Benutzer kann wie folgt identifiziert werden:

$identity = [Security.Principal.WindowsIdentity]::GetCurrent()
$userName = $identity.Name   # Ex: "NT AUTHORITY\SYSTEM" or "Domain\Administrator"
$isSystem = ($userName -eq "NT AUTHORITY\SYSTEM")

Installation

Das Ziel einer Dienst-Installation ist eine Kopie der Dateien in einem lokalen Verzeichnis, klicken Sie dann diese Deklaration für die SCM speichern, damit er weiß, dass das Programm ausführen, um den Dienst zu starten.

Hier ist die Abfolge der Vorgänge ausgeführt werden, von der Setup-Option Verarbeitung:

  1. Deinstallieren Sie alle vorherige Instanz, sofern vorhanden.
  2. Erstellen Sie das Installationsverzeichnis bei Bedarf. (Dies ist nicht erforderlich, für den standardmäßigen: C:\Windows\System32.)
  3. Kopieren Sie das Dienst-Skript in das Installationsverzeichnis ein.
  4. Erstellen Sie einen Stub service.exe in, dasselbe Installationsverzeichnis aus der C#-Codeausschnitt im Skript.
  5. Registrieren Sie den Dienst.

Beachten Sie, dass ein einzelnes Skript für Windows PowerShell-Quelle (PSService.ps1) ab, ich drei Dateien in C:\Windows\System32 installiert am Ende: PSService.ps1, PSService.pdb und PSService.exe. Diese drei Dateien müssen während der Deinstallation entfernt werden soll. Die Installation wird durch zwei Teile des Codes im Skript einschließlich implementiert:

  • Die Definition von der Setup-Option im Block Param am Anfang des Skripts:
[Parameter(ParameterSetName='Setup', Mandatory=$true)]
[Switch]$Setup,    # Install the service
  • Eine If-block, siehe Abbildung 8: für die Verarbeitung der Setup-Option in der Hauptroutine am Ende des Skripts.

Abbildung 8 Setup Codehandler

if ($Setup) {
  # Install the service
  # Check if it's necessary (if not installed,
  # or if this script is newer than the installed copy).
  [...] # If necessary and already installed, uninstall the old copy.
  # Copy the service script into the installation directory.
  if ($ScriptFullName -ne $scriptCopy) {
    Copy-Item $ScriptFullName $scriptCopy
  }
  # Generate the service .EXE from the C# source embedded in this script.
  try {
    Add-Type -TypeDefinition $source -Language CSharp -OutputAssembly $exeFullName
      -OutputType ConsoleApplication -ReferencedAssemblies "System.ServiceProcess"
  } catch {
    $msg = $_.Exception.Message
    Write-error "Failed to create the $exeFullName service stub. $msg"
    exit 1
  }
  # Register the service
  $pss = New-Service $serviceName $exeFullName -DisplayName $serviceDisplayName
    -StartupType Automatic
  return
}

Start

Die Autorität für die Verwaltung von Services verantwortlich ist der SCM. Die SCM muss jedem Startvorgang durchlaufen, damit es Dienststatus mitverfolgen kann. Also auch, wenn der Benutzer einen Start mithilfe des Dienst-Skripts manuell zu initiieren möchte, muss das Starten über eine Anforderung zum SCM erfolgen. In diesem Fall wird die Abfolge der Vorgänge aus:

  1. Der Benutzer (Administrator) führt eine erste Instanz: PSService.ps1-starten.
  2. Dieser erste Instanz weist die SCM, um den Dienst zu starten: Start-Service $serviceName.
  3. SCM führt PSService.exe. Die Hauptroutine ein Dienstobjekt erstellt, und ruft anschließend die Run-Methode.
  4. Die SCM Ruft das Dienstobjekt OnStart-Methode.
  5. Die C#-OnStart-Methode ausgeführt wird, eine zweite Skriptinstanz: PSService.ps1-starten.
  6. Diese zweite Instanz ist, für die Instanz jetzt im Hintergrund als Systembenutzer mit dem ausgeführt beginnt eine dritte, die verbleiben im Arbeitsspeicher als den eigentlichen Dienst: PSService.ps1-Dienst. Dieser letzte - Dienstinstanz, die ist der tatsächliche Aufgabe, die Sie für die Aufgabe wünschen anpassen.

Am Ende werden zwei Aufgaben ausgeführt: PSService.exe und eine PowerShell.exe-Instanz ausgeführt PSService.ps1-Dienst.

All dies wird über die drei Teile des Codes im Skript implementiert:

  • Die Definition von der Option Start im Block Param am Anfang des Skripts:
[Parameter(ParameterSetName='Start', Mandatory=$true)]
[Switch]$Start, # Start the service
  • In der Hauptroutine, am Ende des Skripts eine, wenn Sperren Verarbeitung der Start-Option:
if ($Start) {# Start the service
  if ($isSystem) { # If running as SYSTEM, ie. invoked as a service
    Start-Process PowerShell.exe -ArgumentList (
      "-c & '$scriptFullName' -Service")
  } else { # Invoked manually by the administrator
  Start-Service $serviceName # Ask Service Control Manager to start it
  }
  return
}
  • In der C#-Quellcode-Ausschnitt, ein Hauptroutine und einen Handler für die OnStart-Methode, die PSService.ps1 ausgeführt wird – starten, siehe Abbildung 9.

Abbildung 9 Start Codehandler

public static void Main() {
  System.ServiceProcess.ServiceBase.Run(new $serviceName());
}
protected override void OnStart(string [] args) {
  // Start a child process with another copy of this script.
  try {
    Process p = new Process();
    // Redirect the output stream of the child process.
    p.StartInfo.UseShellExecute = false;
    p.StartInfo.RedirectStandardOutput = true;
    p.StartInfo.FileName = "PowerShell.exe";
    p.StartInfo.Arguments = "-c & '$scriptCopyCname' -Start";
    p.Start();
    // Read the output stream first and then wait. (Supposed to avoid deadlocks.)
    string output = p.StandardOutput.ReadToEnd();
    // Wait for the completion of the script startup code,     // which launches the -Service instance.
    p.WaitForExit();
  } catch (Exception e) {
    // Log the failure.
  }
}

Abrufen des Status des Diensts

-Status Handler einfach den Dienststatus SCM abfragt und sendet diese an die ausgabepipe:

try {
  $pss = Get-Service $serviceName -ea stop # Will error-out if not installed.
} catch {
  "Not Installed"
  return
}
$pss.Status

Während der Phase Debuggen möglicherweise jedoch Skriptfehler, Fälligkeitsdatum, z. B. Syntaxfehler in das Skript und ähnliches. In solchen Fällen wird schließlich der SCM-Status möglicherweise falsch. Ich habe tatsächlich mehrmals auftreten während der Vorbereitung dieses Artikels. Um diese Art des Objekts, zu diagnostizieren, empfiehlt es sich zu überprüfen, und suchen Sie nach - Instanzen:

$spid = $null
$processes = @(gwmi Win32_Process -filter "Name = 'powershell.exe'" | where {
  $_.CommandLine -match ".*$scriptCopyCname.*-Service"
})
foreach ($process in $processes) { # Normally there is only one.
  $spid = $process.ProcessId
  Write-Verbose "$serviceName Process ID = $spid"
}
if (($pss.Status -eq "Running") -and (!$spid)) {
# This happened during the debugging phase.
  Write-Error "The Service Control Manager thinks $serviceName is started,
    but $serviceName.ps1 -Service is not running."
  exit 1
}

Beenden und Deinstallation

Beenden und Remove-Vorgänge rückgängig im Prinzip vorgegangen Setup, und starten:

  • -Stop (wenn vom Benutzer aufgerufen) weist die SCM, um den Dienst zu beenden.
  • Wenn vom System aufgerufen wird, bricht er einfach die PSService.ps1-Dienstinstanz.
  • -Remove beendet den Dienst, hebt die Registrierung mit sc.exe löschen $serviceName, und löscht die Dateien im Installationsverzeichnis.

Die Implementierung ist auch sehr ähnlich, mit der das Setup, und starten:

  1. Die Definition der einzelnen Schalter im Block Param am Anfang des Skripts.
  2. Eine Verarbeitung des Switches in der Hauptroutine am Ende des Skripts zu blockieren.
  3. Für den Beendigungsvorgang in der C#-Quelle Codeausschnitt, einen Handler für die OnStop-Methode, die ausgeführt wird PSService.ps1-beenden. Der Beendigungsvorgang wird Dinge unterschiedlich, abhängig davon, ob der Benutzer einen wirklichen Benutzer oder das System ist.

Ereignisprotokolle

Dienste, die im Hintergrund ohne Benutzeroberfläche ausgeführt werden. Dies erschwert schwierig zu debuggen: Wie können Sie diagnostizieren, Einzelheiten beim Entwurf nichts sichtbar ist? Die übliche Methode wird zum Aufzeichnen aller Fehlermeldungen mit Zeitstempeln sowie wichtige Ereignisse protokolliert, die z. B. Statusübergänge gut Lief.

Das Beispielskript für die PSService.ps1 implementiert zwei unterschiedliche Protokollierungsmethoden und verwendet beide an strategischen Punkten (einschließlich in Teile der vorherige Code extrahiert, hier verdeutlicht den grundlegenden Vorgang entfernt):

  • Siehe Ereignisobjekte in das Anwendungsprotokoll, mit dem Dienstnamen als Name der Datenquelle schreibt Abbildung 10. Diese Ereignisobjekte werden in der Ereignisanzeige angezeigt und gefiltert werden können und mit dem alle Funktionen, die von diesem Tool gesucht. Sie können auch diese Einträge mit dem Get-Eventlog-Cmdlet abrufen:

Ereignisanzeige mit PSService-Ereignissen
Abbildung 10 Ereignisanzeige mit PSService-Ereignissen

Get-Eventlog -LogName Application -Source PSService | select -First 10
  • Er schreibt Message-Zeilen in eine Textdatei im Windows-Protokollverzeichnis, ${ENV:windir}\Logs\$serviceName.log, siehe Abbildung 11. Diese Protokolldatei kann mit dem Editor gelesen und mithilfe von findstr.exe oder Win32-Anschlüssen Grep, Ende usw. durchsucht werden kann.

Abbildung 11 Beispiel-Protokolldatei

PS C:\Temp> type C:\Windows\Logs\PSService.log
2016-01-02 15:29:47 JFLZB\Larvoire C:\SRC\PowerShell\SRC\PSService.ps1 -Status
2016-01-02 15:30:38 JFLZB\Larvoire C:\SRC\PowerShell\SRC\PSService.ps1 -Setup
2016-01-02 15:30:42 JFLZB\Larvoire PSService.ps1 -Status
2016-01-02 15:31:13 JFLZB\Larvoire PSService.ps1 -Start
2016-01-02 15:31:15 NT AUTHORITY\SYSTEM & 'C:\WINDOWS\System32\PSService.ps1' -Start
2016-01-02 15:31:15 NT AUTHORITY\SYSTEM PSService.ps1 -Start: Starting script 'C:\WINDOWS\System32\PSService.ps1' -Service
2016-01-02 15:31:15 NT AUTHORITY\SYSTEM & 'C:\WINDOWS\System32\PSService.ps1' -Service
2016-01-02 15:31:15 NT AUTHORITY\SYSTEM PSService.ps1 -Service # Beginning background job
2016-01-02 15:31:25 NT AUTHORITY\SYSTEM PSService -Service # Awaken after 10s
2016-01-02 15:31:36 NT AUTHORITY\SYSTEM PSService -Service # Awaken after 10s
2016-01-02 15:31:46 NT AUTHORITY\SYSTEM PSService -Service # Awaken after 10s
2016-01-02 15:31:54 JFLZB\Larvoire PSService.ps1 -Stop
2016-01-02 15:31:55 NT AUTHORITY\SYSTEM & 'C:\WINDOWS\System32\PSService.ps1' -Stop
2016-01-02 15:31:55 NT AUTHORITY\SYSTEM PSService.ps1 -Stop: Stopping script PSService.ps1 -Service
2016-01-02 15:31:55 NT AUTHORITY\SYSTEM Stopping PID 34164
2016-01-02 15:32:01 JFLZB\Larvoire PSService.ps1 -Remove
PS C:\Temp>

Log-Funktion erleichtert es, solche Nachrichten, die automatisch mit einem Präfix der ISO 8601-Zeitstempel und den aktuellen Benutzernamen zu schreiben:

Function Log ([String]$string) {
  if (!(Test-Path $logDir)) {
    mkdir $logDir
  }
  "$(Now) $userName $string" |
    out-file -Encoding ASCII -append "$logDir\$serviceName.log"
}

Beispiel-Testsitzung

Hier ist wie die vorherigen Protokolle generiert wurden:

PS C:\Temp> C:\SRC\PowerShell\SRC\PSService.ps1 -Status
Not Installed
PS C:\Temp> PSService.ps1 -Status
PSService.ps1 : The term 'PSService.ps1' is not recognized as the name of a cmdlet, function, script file, or operable program.
[...]
PS C:\Temp> C:\SRC\PowerShell\SRC\PSService.ps1 -Setup
PS C:\Temp> PSService.ps1 -Status
Stopped
PS C:\Temp> PSService.ps1 -Start
PS C:\Temp>

Dies zeigt, wie Sie den Dienst im Allgemeinen verwenden. Bedenken Sie, die sie von einem Benutzer mit lokalen Administratorrechten in Windows PowerShell-Sitzung als Administrator ausgeführt werden muss. Beachten Sie, wie das Skript PSService.ps1 nicht auf den Pfad auf den ersten und dann nach dem - Setup-Vorgang ist. (Die zuerst - Status-Aufruf ohne Pfadangabe fehlschlägt; die zweite - Status-Aufruf erfolgreich ausgeführt wird.)

Calling PSService.ps1 -Status at this stage would produce this output: Running. And this, after waiting 30 seconds:
PS C:\Temp> PSService.ps1 -Stop
PS C:\Temp> PSService.ps1 -Remove
PS C:\Temp>

Anpassen des Diensts

Um einen eigenen Dienst zu erstellen, führen Sie nur folgende:

  • Kopieren Sie den-Beispieldienst in eine neue Datei mit dem neuen Basisnamen wie z. B. C:\Temp\MyService.ps1.
  • Ändern Sie den lange Service-Namen im globalen Variablen-Abschnitt.
  • Ändern der blockieren den - Dienst-Handler am Ende des Skripts. Derzeit While ($true)-Block enthält nur dummy Code, der alle 10 Sekunden und Protokolle eine Nachricht in der Protokolldatei wird:
######### TO DO: Implement your own service code here. ##########
###### Example that wakes up and logs a line every 10 sec: ######
Start-Sleep 10
Log "$script -Service # Awaken after 10s"
  • Installieren und testen:
C:\Temp\MyService.ps1 -Setup
MyService.ps1 -Start
type C:\Windows\Logs\MyService.log

Sie sollten keine nichts im Rest des Skripts, außer zum Hinzufügen von Unterstützung für neue SCM-Funktionen wie der Status "angehalten" ändern.

Einschränkungen und Probleme

Das Skript Dienst muss ausgeführt werden, in einer Shell mit Administratorrechten ausgeführt, oder erhalten Sie verschiedene Zugriffsverweigerungsfehler.

Das Beispielskript funktioniert in Versionen von Windows XP auf 10 und die entsprechenden Serverversionen. In Windows XP müssen Sie Windows PowerShell v2 installieren, die nicht standardmäßig verfügbar. Herunterladen und Installieren von Windows Management Framework v2 für XP (bit.ly/1MpOdpV), einschließlich Windows PowerShell v2. Beachten Sie, dass schon sehr wenige Tests in diesem Betriebssystem, da es nicht mehr unterstützt wird.

Auf vielen Systemen wird die Ausführung des Windows PowerShell-Skripts in der Standardeinstellung deaktiviert. Wenn Sie eine wie Fehlermeldung "das Ausführen von Skripts ist deaktiviert auf diesem System" beim Ausführen von PSService.ps1 verwenden:

Set-ExecutionPolicy RemoteSigned

Weitere Informationen finden Sie unter "Verweise".

Natürlich kann nicht Folgendes Skript Dienst als leistungsfähiger als kompiliertes Programm kann. Ein Dienst-Skript in Windows PowerShell geschrieben werden gut zum Erstellen von Prototypen ein Konzept, und für Vorgänge mit niedriger Leistungskosten wie System Überwachungsdienst, clustering und so weiter. Für jede Aufgabe hohe Leistung ein Schreiben in C++ oder c# wird jedoch empfohlen.

Der Speicherbedarf ist auch nicht so gut wie der kompiliertes Programm, da sie erfordert einen vollwertigen Windows PowerShell-Interpreter in der System-Sitzung laden. In der heutigen Welt mit Systemen mit vielen Gigabyte RAM ist dies kein aufwendig.

Dieses Skript ist vollständig unabhängig von Mark Russinovichs PsService.exe. Ich habe den Namen PSService.ps1, bevor ich, über die Homonymy wusste. Ich werden sie für dieses Beispielskript halten, wie ich glaube, dass der Name zwecks deaktivieren kann. Natürlich, wenn Sie mit einem eigenen Windows PowerShell-Dienst experimentieren möchten, müssen Sie es zu einem eindeutigen Dienstnamen aus einer eindeutigen Skript Basisnamen umbenennen!

Referenzen


Jean-François Larvoirefunktioniert bei Hewlett-Packard Unternehmen in Grenoble, Frankreich, angezeigt. Er verfügt über Software für 30 Jahre für PC-BIOS, Treiber für Windows, Windows und Linux-System-Management entwickeln. Er ist unter jf.larvoire@hpe.com.

Dank den folgenden technischen Experten für die Überprüfung dieses Artikels: Jeffery Hicks (JDH IT-Lösungen)