如果您發現自己經常使用相同的PowerShell單行程式或腳本,將它們轉換成可重複使用的工具就更加重要。 將您的函式封裝於腳本模組中,不僅可提供更專業的外觀,還讓它們更容易支援和與他人分享。
點來源函式
上一章未涵蓋的其中一件事是點來源函式。 當您在腳本中定義函式,但不是模組的一部分時,將函式載入記憶體的唯一方法是點載其 .ps1
檔案。
例如,將下列函式儲存在名為 Get-MrPSVersion.ps1
的檔案中。
function Get-MrPSVersion {
$PSVersionTable
}
當您執行腳本時,它看起來沒有任何反應。
.\Get-MrPSVersion.ps1
嘗試呼叫函式會導致錯誤,因為它未載入記憶體中。
Get-MrPSVersion
Get-MrPSVersion : The term 'Get-MrPSVersion' is not recognized as the name
of a cmdlet, function, script file, or operable program. Check the spelling
of the name, or if a path was included, verify that the path is correct and
try again.
At line:1 char:1
+ Get-MrPSVersion
+ ~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (Get-MrPSVersion:String) [],
CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
您可以確認函式是否存在於 函式: PSDrive,以確認函式是否已載入記憶體中。
Get-ChildItem -Path Function:\Get-MrPSVersion
Get-ChildItem : Cannot find path 'Get-MrPSVersion' because it does not
exist.
At line:1 char:1
+ Get-ChildItem -Path Function:\Get-MrPSVersion
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (Get-MrPSVersion:String) [Get
-ChildItem], ItemNotFoundException
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.Ge
tChildItemCommand
執行定義函式的腳本問題在於它會將它載入 腳本 範圍。 腳本完成執行之後,PowerShell 會捨棄該範圍以及 函式。
若要讓函式在腳本執行之後保持可用,它必須載入 至全域 範圍。 您可以透過點來源腳本檔來完成此作業。 您可以為此使用相對路徑。
. .\Get-MrPSVersion.ps1
您也可以在執行腳本時使用其完整路徑。
. C:\Demo\Get-MrPSVersion.ps1
如果路徑的一部分儲存在變數中,您可以將它與路徑的其餘部分結合。 不需要使用字串串連來執行此動作。
$Path = 'C:\'
. $Path\Get-MrPSVersion.ps1
現在,如果您檢查 函式 PSDrive,您會顯示 Get-MrPSVersion
函式可用。
Get-ChildItem -Path Function:\Get-MrPSVersion
CommandType Name Version
----------- ---- -------
Function Get-MrPSVersion
腳本模組
在 PowerShell 中,腳本模組只是包含一或多個函式的檔案,就像一 .psm1
般腳本,但擴展名不同。
如何建立腳本模組? 您可能會假設有一個命令名為類似 New-Module
。 該假設是合理的猜測,但該命令實際上會建立動態模組,而不是腳本模組。
此情境是一個很好的提醒,即使命令名稱看起來與您所需的完全相同,也要一如既往地閱讀幫助文件。
help New-Module
NAME
New-Module
SYNOPSIS
Creates a new dynamic module that exists only in memory.
SYNTAX
New-Module [-Name] <System.String> [-ScriptBlock]
<System.Management.Automation.ScriptBlock> [-ArgumentList
<System.Object[]>] [-AsCustomObject] [-Cmdlet <System.String[]>]
[-Function <System.String[]>] [-ReturnResult] [<CommonParameters>]
DESCRIPTION
The `New-Module` cmdlet creates a dynamic module from a script block.
The members of the dynamic module, such as functions and variables, are
immediately available in the session and remain available until you
close the session.
Like static modules, by default, the cmdlets and functions in a dynamic
module are exported and the variables and aliases are not. However, you
can use the Export-ModuleMember cmdlet and the parameters of
`New-Module` to override the defaults.
You can also use the **AsCustomObject** parameter of `New-Module` to return
the dynamic module as a custom object. The members of the modules, such
as functions, are implemented as script methods of the custom object
instead of being imported into the session.
Dynamic modules exist only in memory, not on disk. Like all modules,
the members of dynamic modules run in a private module scope that is a
child of the global scope. Get-Module cannot get a dynamic module, but
Get-Command can get the exported members.
To make a dynamic module available to `Get-Module`, pipe a `New-Module`
command to Import-Module, or pipe the module object that `New-Module`
returns to `Import-Module`. This action adds the dynamic module to the
`Get-Module` list, but it does not save the module to disk or make it
persistent.
RELATED LINKS
Online Version: https://learn.microsoft.com/powershell/module/microsoft.
powershell.core/new-module?view=powershell-5.1&WT.mc_id=ps-gethelp
Export-ModuleMember
Get-Module
Import-Module
Remove-Module
about_Modules
REMARKS
To see the examples, type: "Get-Help New-Module -Examples".
For more information, type: "Get-Help New-Module -Detailed".
For technical information, type: "Get-Help New-Module -Full".
For online help, type: "Get-Help New-Module -Online"
上一章提到函式應該使用已核准的動詞。 否則,PowerShell 會在匯入模組時產生警告。
下列範例會用 New-Module
cmdlet 在記憶體中建立動態模組,特別用來示範當您不使用已核准動詞時會有什麼結果。
New-Module -Name MyModule -ScriptBlock {
function Return-MrOsVersion {
Get-CimInstance -ClassName Win32_OperatingSystem |
Select-Object -Property @{Label='OperatingSystem';Expression={$_.Caption}}
}
Export-ModuleMember -Function Return-MrOsVersion
} | Import-Module
WARNING: The names of some imported commands from the module 'MyModule' include
unapproved verbs that might make them less discoverable. To find the commands with
unapproved verbs, run the Import-Module command again with the Verbose parameter. For a
list of approved verbs, type Get-Verb.
雖然您在 New-Module
上一個範例中使用 Cmdlet,如先前所述,但它不是在 PowerShell 中建立腳本模組的命令。
若要建立腳本模組,請將函式儲存於.psm1
檔案中。 例如,將下列兩個函式儲存在名為 MyScriptModule.psm1
的檔案中。
function Get-MrPSVersion {
$PSVersionTable
}
function Get-MrComputerName {
$env:COMPUTERNAME
}
嘗試執行其中一個函式。
Get-MrComputerName
當您呼叫函式時,您會收到錯誤,指出 PowerShell 找不到它。 就像之前一樣,檢查 函式: PSDrive 會確認它未載入記憶體中。
Get-MrComputerName : The term 'Get-MrComputerName' is not recognized as the
name of a cmdlet, function, script file, or operable program. Check the
spelling of the name, or if a path was included, verify that the path is
correct and try again.
At line:1 char:1
+ Get-MrComputerName
+ ~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (Get-MrComputerName:String) [
], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
若要讓此功能可供使用,您可以使用 MyScriptModule.psm1
cmdlet 手動匯入 Import-Module
檔案。
Import-Module C:\MyScriptModule.psm1
PowerShell 引進了第 3 版的模組自動載入。 若要利用這項功能,腳本模組必須儲存在與檔案相同的基底名稱 .psm1
資料夾中。 該資料夾必須位於環境變數中指定的 $env:PSModulePath
其中一個目錄。
$env:PSModulePath
的 $env:PSModulePath
輸出難以讀取。
C:\Users\mike-ladm\Documents\WindowsPowerShell\Modules;C:\Program Files\Wind
owsPowerShell\Modules;C:\Windows\system32\WindowsPowerShell\v1.0\Modules;C:\
Program Files (x86)\Microsoft SQL Server\130\Tools\PowerShell\Modules\
若要讓結果更容易閱讀,請分割分號路徑分隔符上的路徑,讓每個路徑都出現在自己的行上。
$env:PSModulePath -split ';'
清單中的前三個路徑是預設模組位置。 SQL Server Management Studio 會在您安裝時新增最後一個路徑。
C:\Users\mike-ladm\Documents\WindowsPowerShell\Modules
C:\Program Files\WindowsPowerShell\Modules
C:\Windows\system32\WindowsPowerShell\v1.0\Modules
C:\Program Files (x86)\Microsoft SQL Server\130\Tools\PowerShell\Modules\
若要讓模組自動載入能夠運作,您必須將 MyScriptModule.psm1
檔案放在名為 MyScriptModule
的資料夾中,而且該資料夾必須直接位於所列其中一個路徑內
$env:PSModulePath
。
並非所有路徑都同樣有用。 例如,我系統上目前的用戶路徑不是清單中的第一個路徑。 這是因為我以不同於我用來執行PowerShell的帳戶登入 Windows。 因此,它不會指向使用者的文件資料夾。
第二個路徑是 AllUsers 路徑,也就是我儲存所有模組的位置。
第三個路徑指向 C:\Windows\System32
,這是受保護的系統位置。 只有Microsoft應該將模組放在該處,因為它落在作系統的目錄結構之下。
一旦您將檔案放在 .psm1
其中一個路徑內的適當資料夾中,PowerShell 會在您第一次呼叫其中一個命令時自動載入模組。
模組指令清單
每個模組都應該包含模組指令清單,這是 .psd1
包含模組相關元數據的檔案。
.psd1
擴充功能用於清單檔,但並非所有.psd1
檔案都是模組清單檔。 您也可以將其用於其他用途,例如在 DSC 中定義環境數據
配置。
您可以使用 Cmdlet 建立模組指令清單 New-ModuleManifest
。 唯一必要的參數是 Path,但讓模組正常運作,您也必須指定 RootModule 參數。
最好包含 如 Author 和 Description 之類的值,特別是當您打算使用 PowerShellGet 將模組發佈至 NuGet 存放庫時。 該案例中需要這些欄位。
判斷模組是否缺少指令清單的一個快速方式是檢查其版本。
Get-Module -Name MyScriptModule
的版本號碼 0.0
是模組缺少指令清單的明確標誌。
ModuleType Version Name ExportedCommands
---------- ------- ---- ----------------
Script 0.0 MyScriptModule {Get-MrComputer...
建立模組指令清單時,您應該包含所有建議的詳細數據,以確保您的模組已做好記錄,並準備好進行共用或發佈。
$moduleManifestParams = @{
Path = "$env:ProgramFiles\WindowsPowerShell\Modules\MyScriptModule\MyScriptModule.psd1"
RootModule = 'MyScriptModule'
Author = 'Mike F. Robbins'
Description = 'MyScriptModule'
CompanyName = 'mikefrobbins.com'
}
New-ModuleManifest @moduleManifestParams
如果您在一開始建立模組指令清單時省略任何值,則可以稍後使用 Update-ModuleManifest
Cmdlet 來新增或更新它。 避免在建立後使用 New-ModuleManifest
重新建立指令清單,因為這樣做會產生新的 GUID。
定義公用和私人函式
有時候,您的模組可能包含您不想向使用者公開的協助程式函式。 模組中的其他函式會在內部使用這些私用函式,但不會公開給使用者。 有幾種方式可以處理此案例。
如果您未遵循最佳做法,而且只有一個沒有適當模組結構的 .psm1
檔案,則唯一的選項是使用 Export-ModuleMember
cmdlet 來控制可見度。 此選項可讓您明確定義應該直接從腳本模組檔案中 .psm1
公開哪些函式,並預設保留其他所有函式。
在下列範例中,只有函 Get-MrPSVersion
式會公開給模組的使用者,而函 Get-MrComputerName
式在內部仍可供模組內的其他函式存取。
function Get-MrPSVersion {
$PSVersionTable
}
function Get-MrComputerName {
$env:COMPUTERNAME
}
Export-ModuleMember -Function Get-MrPSVersion
判斷 MyScriptModule 模組中公開可用的命令。
Get-Command -Module MyScriptModule
CommandType Name Version
----------- ---- -------
Function Get-MrPSVersion 1.0
如果您將模組指令清單新增至模組,最佳做法是明確列出您想要在 FunctionsToExport 區段中導出的函式。 此選項可讓您控制從 .psd1
模組指令清單檔公開給使用者的內容。
FunctionsToExport = 'Get-MrPSVersion'
您不需要在Export-ModuleMember
檔案與.psm1
模組指令清單的區段中同時使用 FunctionsToExport
。 任一種方法本身就足夠了。
總結
在本章中,您已瞭解如何在PowerShell中將函式轉換成腳本模組。 您也探索了建立腳本模組的最佳做法,包括新增模組指令清單來定義元數據和管理匯出命令的重要性。
回顧
- 如何在PowerShell中建立腳本模組?
- 為什麼對函式名稱使用已核准的動詞很重要?
- 如何在 PowerShell 中建立模組指令清單?
- 僅從模組匯出特定函式的兩種方式為何?
- 當您執行其中一個命令時,模組必須符合哪些條件才能自動載入?