2016 年 5 月

第 31 卷,第 5 期

本文章是由機器翻譯。

Windows PowerShell - 使用 PowerShell 撰寫 Windows 服務

Jean François François

Windows 服務通常是以 C、 c + +、 C# 或其他 Microsoft.NET Framework 為基礎的語言,撰寫的已編譯的程式並偵錯這類服務可能會相當困難。我開始猜想如果可能有更簡單的方法來建立它們在 Windows 中,以及幾個月前,藉由撰寫服務做為簡單的殼層指令碼,可讓其他作業系統。

本文將介紹這方面的最終結果 ︰ 嶄新簡便的方式來建立 Windows 服務,將它們寫入 Windows PowerShell 指令碼語言。不需編譯,就可以在任何系統上,不只是開發人員自己完成快速的編輯測試循環。

我提供一個稱為 PSService.ps1,可讓您建立並測試新的 Windows 服務,以分鐘為單位,與剛才在 [記事本] 之類的文字編輯器的一般服務指令碼範本。這項技術可以省下許多時間和開發工作的人想要試驗 Windows 服務,或甚至提供適用於 Windows 的實際服務效能不重要的因素。您可以從下載 PSService.ps1 bit.ly/1Y0XRQB

什麼是 Windows 服務?

Windows 服務是在沒有使用者互動的背景中執行程式。例如,Web 伺服器,以無訊息模式的 Web 網頁回應 HTTP 要求,從網路,為服務,是以無訊息模式記錄效能的度量或記錄硬體感應器事件的監視應用程式。

在系統開機時,可以自動啟動服務。或者可以隨選、 中啟動,依賴它們的應用程式的要求。服務會在他們自己的 Windows 工作階段,不同 UI 工作階段中執行。它們執行許多系統處理程序,以仔細選取權限來限制安全性風險。

Windows 服務控制管理員

服務管理的 Windows 服務控制管理員 (SCM)。SCM 會負責設定服務啟動,讓它們等等。

SCM 控制台是可以透過控制台存取 |系統及安全性 |系統管理工具] |服務。做為 [圖 1 所示,它會顯示所有已設定的服務,以其名稱、 描述、 狀態、 啟動型別和使用者名稱的清單。

在 Windows 10 的 Windows 服務控制管理員 GUI
圖 1] 在 Windows 10 的 Windows 服務控制管理員 GUI

另外還有 scm 的命令列介面 ︰

  • 舊的 net.exe 工具,其已知"net start"和"net stop"命令,日期的最多可回溯 MS-DOS ! 儘管其名稱,它可以用來啟動和停止任何服務,而不只是網路服務。輸入 「 網路說明 「 如需詳細資訊。
  • 更強大的工具,稱為導入 Windows NT 中的 sc.exe 提供服務管理的各個層面的良好控制。類型"sc /? 」 以取得詳細資料。

這些命令列工具,雖然仍會出現在 Windows 10,會立即被 Windows PowerShell 服務管理功能,稍後會加以說明。

陷阱 ︰ Net.exe 和 sc.exe 使用 [短] 一字服務名稱,而不幸的是,不是更具描述性 SCM 控制台中所顯示的名稱相同。若要取得這兩個名稱之間的對應關係,請使用 Windows PowerShell get-service 命令。

服務狀態

服務可以在各種狀態。需要某些州,有些則是選擇性。所有服務都必須都支援兩種基本狀態會停止並啟動。這些顯示分別 (空白) 或在執行中的 [狀態] 欄下方 [圖 1

第三個選擇性狀態已暫停。和另一個隱含的狀態,即使並未提及每個服務可支援解除安裝。

服務可以讓轉換之間的狀態,如所示 [圖 2

服務狀態
[圖 2 服務狀態

最後,還有數個服務可能會選擇性地支援的過渡狀態 ︰ StopPending,PausePending,ContinuePending 的 startpending 狀態。這些是時間的只有當狀態轉換需要花費大量很有用。

Windows PowerShell 服務管理功能

Windows PowerShell 已自 Windows Vista 建議的系統管理命令介面。其中包括強大的指令碼語言和大型的程式庫函數,用於管理作業系統的所有層面。Windows PowerShell 的優點包括 ︰

  • 一致的函式名稱
  • 物件導向
  • 便於管理的任何.NET 物件

Windows PowerShell 提供許多服務管理功能,也就是指令程式。[圖 3 顯示一些範例。

[圖 3 Windows PowerShell 服務管理功能

函數名稱 描述
啟動服務 啟動一或多個已停止服務
停止服務 停止一或多個執行中的服務
新服務 安裝新的服務
取得服務 取得服務的本機或遠端電腦上,使用其屬性
設定服務 啟動、 停止和暫停服務,並變更其內容

 

以字串名稱中的 「 服務 」 的所有命令的完整清單,請執行 ︰

Get-Command *service*

只是服務管理功能的清單,請執行 ︰

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

當然,沒有 Windows PowerShell 函式來移除 (也就,解除安裝) 服務。這是其中一個罕見的情況下仍需要使用舊的 sc.exe 工具時 ︰

sc.exe delete $serviceName

.NET ServiceBase 類別

所有服務都必須都建立衍生自 ServiceBase 類別的.NET 物件。Microsoft 文件描述所有的屬性和該類別的方法。[圖 4 列出幾個這些項目,此專案中最重要。

[圖 4,某些屬性和方法的 ServiceBase 類別

成員 描述
ServiceName 用來識別系統服務的簡短名稱
CanStop 是否可以停止服務一次它已啟動
Onstart () 在服務啟動時要採取的動作
Onstop 當服務停止時要採取的動作
Run () SCM 會向服務可執行檔

 

藉由實作這些方法,服務應用程式將會為在開機時,或視情況下,自動啟動,scm 容易管理它將是可管理由 SCM 控制台、 舊 net.exe 和 sc.exe 命令,或新 Windows PowerShell 服務管理功能,來啟動或手動停止。

從 C# 原始程式檔內嵌在 Windows PowerShell 指令碼中建立可執行檔

PowerShell 可讓您輕鬆使用.NET 物件的指令碼中。根據預設,它有內建支援許多.NET 物件類型,足以應付大部分的用途。儘管如此,進一步加以擴充,而且可讓內嵌簡短的 C# 程式碼片段加入任何其他.NET 功能支援使用 Windows PowerShell 指令碼。加入型別命令,這是,儘管其名稱,可以執行更多只將新的.NET 物件類型的支援加入至 Windows PowerShell 會提供這項功能。它甚至可以編譯及連結的完整 C# 應用程式到新的可執行檔。例如,此 hello.ps1 Windows PowerShell 指令碼 ︰

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

將建立 hello.exe 應用程式,會列印"Hello world !":

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

整體回顧

PSService.ps1 功能根據所有我到目前為止所討論,我就可以建立我了解 PSService.ps1 指令碼,可以夢該 Windows PowerShell 服務 ︰

  • 安裝和解除安裝本身 (使用 Windows PowerShell 服務管理功能)。
  • 啟動和停止本身 (使用相同的函式)。
  • 包含簡短 C# 程式碼片段,這會建立 PSService.exe SCM 預期 (使用加入型別命令)。
  • 請 PSService.exe 虛設常式回呼 PSService.ps1 指令碼 (在 OnStart、 OnStop 和其他事件的回應) 的實際服務作業。
  • 是可管理 SCM 控制台中,所有的命令列工具 (感謝 PSService.exe 虛設常式)。
  • 有彈性,並處理已成功在任何狀態中的任何命令。(比方說,它可以自動停止服務,再解除安裝,或執行任何動作時被要求開始已啟動的服務。)
  • 支援 Windows 7 和 Windows (使用 Windows PowerShell v2 功能) 的所有更新的版本。

請注意,我將涵蓋的重要部分 PSService.ps1 設計和實作,在這篇文章。範例指令碼也會包含偵錯的程式碼及一些選擇性的服務功能的支援,但其描述會不必要地讓問題更複雜的說明。

PSService.ps1 架構指令碼被組織的一系列區段 ︰

  • 描述檔案的標頭註解。
  • 註解說明區塊。
  • 定義命令列參數在參數區塊。
  • 全域變數。
  • Helper 常式 ︰ 現在,記錄檔。
  • C# PSService.exe 虛設常式的來源區塊。
  • 主常式中,處理每個命令列參數。

全域設定

立即 Param 區塊下方 PSService.ps1 包含定義全域設定,可以視需要變更的全域變數。預設值會顯示在 [圖 5

[圖 5 全域變數的預設值

變數 描述 預設
$serviceName 使用 net start 命令和其他人一字名稱 指令碼的基底名稱
$serviceDisplayName 服務的更具描述性名稱 範例 PowerShell 服務
$installDir 安裝服務檔案的位置 ${Env: windir} \System32
$logFile 用來記錄服務訊息的檔案名稱 ${ENV:windir}\Logs\$serviceName.log
$logName 用來記錄服務事件的事件記錄檔名稱 應用程式

 

使用檔案的基底名稱做為服務名稱 (例如,如 PSService.ps1 PSService) 可讓您從相同的指令碼,建立多個服務,只要複製指令碼、 重新命名複本,然後安裝的版本。

命令列引數

若要讓您輕鬆使用,指令碼支援比對所有的狀態轉換的命令列引數中所示 [圖 6

[圖 6 狀態轉換的命令列引數

交換器 描述
-開始 啟動服務
停駐點 停止服務
-安裝 自行安裝為服務
-移除 解除安裝服務

 

(已暫停狀態的支援未實作的但很容易新增,但是對應的狀態轉換選項)。

[圖 7 示範一些更多管理引數,這個指令碼支援。

[圖 7 支援管理引數

交換器 描述
重新啟動 停止服務,然後重新啟動
-狀態 顯示服務的目前狀態
-服務 執行的服務執行個體 (僅供 service.exe 虛設常式的使用)
版本 顯示服務版本
一般參數 -?-Verbose、-偵錯等等

 

每個狀態轉換參數有兩種作業模式 ︰

  • 當叫用使用者 ︰ 您可以使用 Windows PowerShell 的服務管理功能,觸發狀態轉換。
  • 當叫用 (間接透過 service.exe 虛設常式) SCM: 據以管理 service.ps1 服務執行個體。

藉由檢查使用者名稱,可以在執行階段區分兩種情況 ︰ 在第一個案例中是一般使用者 (系統管理員)。在第二個情況下就實際的 Windows 系統使用者。系統使用者的識別像這樣 ︰

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

安裝

服務安裝的目標是將服務檔的複本儲存在本機目錄,然後宣告這 SCM,,,讓它知道要執行以啟動服務的程式。

這裡的-安裝程式參數所執行的作業順序處理 ︰

  1. 如果有的話,請解除安裝任何先前的執行個體。
  2. 視需要建立的安裝目錄。(這不所需的預設值 ︰ C:\Windows\System32。)
  3. 將服務指令碼複製到安裝目錄。
  4. 建立該相同的安裝目錄,從 C# 程式碼片段的指令碼中的 service.exe 虛設常式。
  5. 註冊服務。

請注意,從單一 Windows PowerShell 來源指令碼 (PSService.ps1) 開始,我會得到安裝於 C:\Windows\System32 的三個檔案 ︰ PSService.ps1、 PSService.pdb 和 PSService.exe。這三個檔案必須在解除安裝期間移除。安裝被實作在指令碼中包含兩個程式碼片段 ︰

  • 定義的-Param 區塊開頭的指令碼中的安裝參數 ︰
[Parameter(ParameterSetName='Setup', Mandatory=$true)]
[Switch]$Setup,    # Install the service
  • If 區塊中所示 [圖 8 處理-在主常式中的指令碼結尾的安裝參數。

[圖 8 安裝程式的程式碼處理常式

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
}

啟動

SCM 會負責管理服務的授權單位。每個啟動作業必須通過 SCM,因此它可以追蹤的服務狀態。所以即使使用者想要手動起始啟動時,使用服務指令碼,必須該啟動透過要求 scm。在此情況下,是一系列的作業 ︰

  1. 使用者 (系統管理員身分) 執行的第一個執行個體 ︰ PSService.ps1-啟動。
  2. 這個第一個執行個體,它告訴 SCM 啟動服務 ︰ 啟動服務 $serviceName。
  3. SCM 會執行 PSService.exe。建立服務物件,其將 Main 常式,然後 Run 方法會叫用。
  4. SCM 會叫用的服務物件 OnStart 方法。
  5. C# OnStart 方法會執行第二個指令碼執行個體 ︰ PSService.ps1-啟動。
  6. 這個第二個執行個體,現在的系統使用者的背景中執行啟動第三個執行個體,它會保留在記憶體實際的服務 ︰ PSService.ps1-服務。這是上次的服務執行個體執行的實際服務工作中,您想要使用任何工作的自訂。

在結束時,就不會執行兩項工作 ︰ PSService.exe,並執行 PSService.ps1 的 PowerShell.exe 執行個體的服務。

這被實作指令碼中有三種程式碼 ︰

  • 定義的-Param 區塊開頭的指令碼中的啟動參數 ︰
[Parameter(ParameterSetName='Start', Mandatory=$true)]
[Switch]$Start, # Start the service
  • 在主常式中,結尾的指令碼,if 區塊處理-啟動參數 ︰
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
}
  • 在 C# 原始碼程式碼片段 」、 「 Main 常式與 「 執行 PSService.ps1 的 OnStart 方法的處理常式-啟動示 [圖 9

[圖 9 開始程式碼處理常式

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.
  }
}

取得服務狀態

處理常式只會 SCM 要求服務的狀態,並將它傳送至輸出管道-狀態 ︰

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

但在偵錯階段中,您可能會遇到指令碼失敗,由於,比方說,在指令碼和類似的語法錯誤。在這種情況下,SCM 狀態可能會變得很不正確。我已實際執行到此多次時撰寫這篇文章。若要協助您診斷此類的工作,因此最好能夠再次確認,並搜尋的服務執行個體 ︰

$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
}

停止和解除安裝

停止和移除作業基本上是復原解安裝和啟動在 ︰

  • 停駐點 (如果使用者叫用) 會指示 SCM 停止服務。
  • 如果叫用的系統,只要刪除 PSService.ps1-服務執行個體。
  • 移除停止服務、 取消註冊它使用 sc.exe 刪除 $serviceName,接著刪除安裝目錄中的檔案。

實作也是非常類似的設定和開始 ︰

  1. Param 區塊開頭的指令碼中的每個參數定義。
  2. If 區塊處理在主常式中,結尾的指令碼參數。
  3. 停止作業,在 C# 來源片段中,OnStop 方法的處理常式執行 PSService.ps1-停止。停止作業會以不同的方式,根據使用者是否為真實的使用者或系統的執行動作。

事件記錄

服務在背景中,不含 UI 的執行。這可讓它們難以偵錯 ︰ 您要如何診斷發生的問題,依設計看不到? 常用的方法是保留記錄的所有錯誤訊息的時間戳記和有沒有問題,例如狀態轉換的重要事件記錄。

PSService.ps1 指令碼範例會實作兩個不同記錄方法,並使用同時策略性的點 (包含在先前的程式碼擷取,以釐清的基本作業中移除以下的部分) ︰

  • 它會寫入事件物件到應用程式記錄檔中,服務名稱與來源名稱,如所示 圖 10。這些事件物件會顯示在事件檢視器可篩選和搜尋使用該工具的所有功能。您也可以取得這些項目使用 Get-eventlog cmdlet:

PSService 事件與事件檢視器
[圖 10 使用 PSService 事件的事件檢視器]

Get-Eventlog -LogName Application -Source PSService | select -First 10
  • 訊息列寫入文字檔案,在 Windows Logs 目錄中,${ENV:windir}\Logs\$serviceName.log 中所示 [圖 11。此記錄檔使用 「 記事本 」,可讀取,並使用 findstr.exe 或 Win32 的 grep、 結尾等等的連接埠可搜尋。

[圖 11 範例記錄檔

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 函式可讓您輕鬆地撰寫此類訊息,自動前面加上目前的使用者名稱與 ISO 8601 時間戳記 ︰

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

範例測試工作階段

以下是如何產生先前的記錄檔 ︰

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>

這會顯示如何在一般情況下使用服務。請記住,它必須由使用者以執行本機系統管理權限,系統管理員身分執行的 Windows PowerShell 工作階段。請注意 PSService.ps1 指令碼一開始,然後後-安裝作業是在路徑上的不是。(第一次的失敗狀態的呼叫,但未指定路徑; 第二層狀態呼叫成功。)

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>

自訂服務

若要建立您自己的服務,只要執行下列作業 ︰

  • 複製到新檔案中使用新的基底名稱,例如 C:\Temp\MyService.ps1 的範例服務。
  • 變更全域變數一節中的長時間的服務名稱。
  • 若要變更封鎖-服務處理常式中的指令碼結尾。目前,while ($true) 區塊只包含 dummy 喚醒每隔 10 秒,且記錄一個訊息,記錄檔中的程式碼 ︰
######### 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"
  • 安裝並開始進行測試 ︰
C:\Temp\MyService.ps1 -Setup
MyService.ps1 -Start
type C:\Windows\Logs\MyService.log

您不應該不必變更任何項目中其餘的指令碼,但若要加入新的 SCM 功能,例如 「 已暫停狀態的支援。

限制和問題

服務指令碼必須以系統管理員權限執行的 shell 中執行,否則您會得到各種拒絕存取錯誤。

範例指令碼的 Windows 版本為 10,XP 和對應的伺服器版本中運作。在 Windows XP 中,您必須安裝 Windows PowerShell v2,沒有預設。下載並安裝 Windows Management Framework v2 xp (bit.ly/1MpOdpV),其中包括 Windows PowerShell v2。請注意,我已經完成極少的測試,在該 OS 中,因為它不再支援。

許多系統上的預設會停用 Windows PowerShell 指令碼執行。如果您收到類似錯誤,「 指令碼的執行已停用在此系統上,「 執行 PSService.ps1 時,然後使用 ︰

Set-ExecutionPolicy RemoteSigned

如需詳細資訊,請參閱 [參考]。

很明顯地,這類服務指令碼不能與高效能,當做編譯的程式。撰寫 Windows PowerShell 中的服務指令碼將會很好的原型設計概念,以及與低效能成本,例如監視、 叢集等服務的系統。但對於任何高效能工作,建議使用重寫 c + + 或 C#。

記憶體耗用量並也不好的已編譯的程式,因為它需要在系統工作階段中載入成熟的 Windows PowerShell 直譯器。在現今的世界中,與系統有多個 gb 的 RAM,這不是什麼大不了的事。

此指令碼是 Mark Russinovich PsService.exe 完全無關。我知道 homonymy 之前,我選擇 PSService.ps1 名稱。我會予以保留此範例指令碼時想名稱可清除其用途。當然,如果您嘗試使用您自己的 Windows PowerShell 服務計劃,您必須將它重新命名,從唯一的指令碼基底名稱,取得唯一的服務名稱 !

參考資料


Jean François LarvoireHewlett-Packard 企業 Grenoble,法國的運作方式。他開發軟體 30 年來的 PC BIOS,Windows 驅動程式、 Windows 和 Linux 的系統管理。他可以到達 jf.larvoire@hpe.com

感謝以下技術專家對本文的審閱: Jeffery Hicks (JDH IT 解決方案)