模块
模块是 PowerShell 代码的组织和分发单元。通过模块,可以将相关的函数、变量、别名等打包在一起,方便复用和分享。PowerShell 拥有丰富的模块生态系统,PowerShell Gallery 提供了数以万计的社区模块。
模块概述
模块类型
PowerShell 支持四种模块类型:
脚本模块(.psm1):最常用的模块类型,包含 PowerShell 脚本代码。
二进制模块(.dll):用 C# 等语言编译的 .NET 程序集。
清单模块:包含模块元数据的 .psd1 文件,可以组合其他模块。
动态模块:在内存中创建,不持久化到文件。
模块位置
PowerShell 在以下路径搜索模块:
$env:PSModulePath -split ';'
默认路径包括:
- 当前用户的模块目录:
$HOME\Documents\PowerShell\Modules - 系统模块目录:
C:\Program Files\PowerShell\Modules - Windows 系统模块:
C:\Windows\System32\WindowsPowerShell\v1.0\Modules
使用模块
查找模块
在 PowerShell Gallery 搜索模块:
Find-Module -Name "Az"
Find-Module -Name "*azure*" | Select-Object Name, Description
Find-Module -Tag "ActiveDirectory"
安装模块
Install-Module -Name "Az"
Install-Module -Name "Az" -Scope CurrentUser
Install-Module -Name "Az" -RequiredVersion 9.0.0
Install-Module -Name "Az" -Force
导入模块
Import-Module -Name "Az"
Import-Module -Name "C:\Modules\MyModule"
Import-Module -Name "Az" -Version 9.0.0
查看已安装模块
Get-Module -ListAvailable
Get-Module -ListAvailable -Name "Az"
Get-Module
更新模块
Update-Module -Name "Az"
Update-Module
卸载模块
Uninstall-Module -Name "Az"
Uninstall-Module -Name "Az" -AllVersions
保存模块(离线安装)
Save-Module -Name "Az" -Path "C:\OfflineModules"
Save-Module -Name "Az" -Path "\\Server\Share\Modules"
创建脚本模块
基本模块结构
创建一个简单的模块:
MyModule/
├── MyModule.psm1
├── MyModule.psd1
└── Functions/
├── Get-Info.ps1
└── Set-Config.ps1
模块文件(.psm1)
创建 MyModule.psm1:
$script:ModuleRoot = $PSScriptRoot
. $PSScriptRoot\Functions\Get-Info.ps1
. $PSScriptRoot\Functions\Set-Config.ps1
$MyModuleVersion = "1.0.0"
function Get-ModuleVersion {
return $script:MyModuleVersion
}
function Get-ModuleInfo {
[CmdletBinding()]
param()
return [PSCustomObject]@{
Name = "MyModule"
Version = $script:MyModuleVersion
Path = $script:ModuleRoot
}
}
Export-ModuleMember -Function Get-ModuleVersion, Get-ModuleInfo
Export-ModuleMember -Variable MyModuleVersion
模块清单(.psd1)
使用 New-ModuleManifest 创建清单:
New-ModuleManifest -Path "C:\Modules\MyModule\MyModule.psd1" `
-RootModule "MyModule.psm1" `
-ModuleVersion "1.0.0" `
-Author "Your Name" `
-Description "My PowerShell Module" `
-FunctionsToExport @("Get-ModuleVersion", "Get-ModuleInfo") `
-VariablesToExport @("MyModuleVersion")
手动编辑清单文件:
@{
RootModule = 'MyModule.psm1'
ModuleVersion = '1.0.0'
GUID = '12345678-1234-1234-1234-123456789012'
Author = 'Your Name'
Description = 'My PowerShell Module'
PowerShellVersion = '7.0'
FunctionsToExport = @('Get-ModuleVersion', 'Get-ModuleInfo')
VariablesToExport = @('MyModuleVersion')
FileList = @('MyModule.psm1', 'Functions\Get-Info.ps1')
PrivateData = @{
PSData = @{
Tags = @('Utility', 'Automation')
LicenseUri = 'https://opensource.org/licenses/MIT'
ProjectUri = 'https://github.com/user/MyModule'
}
}
}
导出成员
使用 Export-ModuleMember 控制导出的函数和变量:
function Get-PublicFunction {
return "Public"
}
function Invoke-PrivateFunction {
return "Private"
}
Export-ModuleMember -Function Get-PublicFunction
或者使用清单文件控制:
FunctionsToExport = @('Get-PublicFunction')
模块作用域
变量作用域
模块内的变量默认是模块私有的:
$PrivateVar = "Only in module"
$script:ModuleVar = "Module scope"
$global:GlobalVar = "Global scope"
函数作用域
function Private-Helper {
}
function Public-Function {
Private-Helper
}
Export-ModuleMember -Function Public-Function
模块初始化和清理
模块初始化
在 .psm1 文件顶部的代码在导入时执行:
$script:ConfigPath = Join-Path $PSScriptRoot "config.json"
if (Test-Path $script:ConfigPath) {
$script:Config = Get-Content $script:ConfigPath | ConvertFrom-Json
} else {
$script:Config = @{}
}
模块清理
注册卸载事件:
$ExecutionContext.SessionState.Module.OnRemove = {
Write-Host "模块正在卸载"
}
高级模块特性
嵌套模块
在清单中指定嵌套模块:
NestedModules = @('SubModule1.psm1', 'SubModule2.psm1')
模块依赖
指定模块依赖:
RequiredModules = @(
@{ModuleName = 'Az.Accounts'; ModuleVersion = '2.0.0'}
)
RequiredAssemblies = @('MyLibrary.dll')
类型格式化
添加自定义类型格式:
TypesToProcess = @('MyTypes.ps1xml')
FormatsToProcess = @('MyFormats.ps1xml')
脚本初始化
ScriptsToProcess = @('Initialize.ps1')
发布模块
准备发布
确保模块清单完整:
Test-ModuleManifest -Path "C:\Modules\MyModule\MyModule.psd1"
发布到 PowerShell Gallery
首先注册 API 密钥:
Publish-Module -Path "C:\Modules\MyModule" -NuGetApiKey "your-api-key"
发布到私有仓库:
Register-PSRepository -Name "MyRepo" -SourceLocation "https://myrepo.com/nuget"
Publish-Module -Path "C:\Modules\MyModule" -Repository "MyRepo" -NuGetApiKey "key"
模块最佳实践
目录结构
推荐的标准目录结构:
MyModule/
├── MyModule.psd1
├── MyModule.psm1
├── en-US/
│ └── MyModule-help.xml
├── Functions/
│ ├── Get-Item.ps1
│ └── Set-Item.ps1
├── Classes/
│ └── MyClass.ps1
├── Private/
│ └── Helper.ps1
├── Tests/
│ └── MyModule.Tests.ps1
└── Resources/
└── config.json
函数组织
在 .psm1 中点源加载函数:
$PublicFunctions = Get-ChildItem -Path "$PSScriptRoot\Public\*.ps1" -Recurse
$PrivateFunctions = Get-ChildItem -Path "$PSScriptRoot\Private\*.ps1" -Recurse
foreach ($function in @($PublicFunctions + $PrivateFunctions)) {
. $function.FullName
}
Export-ModuleMember -Function $PublicFunctions.BaseName
帮助文档
使用基于注释的帮助:
function Get-UserInfo {
<#
.SYNOPSIS
获取用户信息
.DESCRIPTION
根据用户名获取详细的用户信息
.PARAMETER Username
要查询的用户名
.EXAMPLE
Get-UserInfo -Username "admin"
获取 admin 用户的信息
.OUTPUTS
System.Management.Automation.PSCustomObject
#>
param(
[Parameter(Mandatory=$true)]
[string]$Username
)
}
实用示例
完整模块示例
MyUtils.psm1:
$script:ModuleRoot = $PSScriptRoot
$script:Version = "1.0.0"
$PublicFunctions = Get-ChildItem -Path "$PSScriptRoot\Public\*.ps1" -ErrorAction SilentlyContinue
$PrivateFunctions = Get-ChildItem -Path "$PSScriptRoot\Private\*.ps1" -ErrorAction SilentlyContinue
foreach ($function in @($PublicFunctions + $PrivateFunctions)) {
. $function.FullName
}
$ExecutionContext.SessionState.Module.OnRemove = {
Write-Verbose "MyUtils 模块已卸载"
}
Export-ModuleMember -Function $PublicFunctions.BaseName
Public/Write-Log.ps1:
function Write-Log {
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[string]$Message,
[ValidateSet("Info", "Warning", "Error")]
[string]$Level = "Info",
[string]$LogFile
)
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$entry = "[$timestamp] [$Level] $Message"
switch ($Level) {
"Info" { Write-Host $entry -ForegroundColor Green }
"Warning" { Write-Host $entry -ForegroundColor Yellow }
"Error" { Write-Host $entry -ForegroundColor Red }
}
if ($LogFile) {
Add-Content -Path $LogFile -Value $entry
}
}
Public/Invoke-Batch.ps1:
function Invoke-Batch {
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[scriptblock]$ScriptBlock,
[int]$ThrottleLimit = 5
)
$jobs = @()
$results = @()
$jobs = Start-ThreadJob -ScriptBlock $ScriptBlock -ThrottleLimit $ThrottleLimit
$results = $jobs | Wait-Job | Receive-Job
$jobs | Remove-Job
return $results
}
下一步
掌握了模块后,接下来学习 远程管理,了解如何使用 PowerShell 管理远程计算机。