跳到主要内容

模块

模块是 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"

首先注册 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 管理远程计算机。