PowerShell脚本模版
PowerShell 是一个强大的脚本环境,用于系统管理和其他任务自动化。
模块脚本模板
一个标准的 PowerShell 模块通常具有如下目录结构:
<ModuleName>/
├── <ModuleName>.psd1 # 模块清单文件(Module Manifest)
├── <ModuleName>.psm1 # 模块主脚本文件(可选,也可用多个 .ps1 文件)
├── Public/ # 公共函数目录(对外暴露的命令)
│ └── Get-HelloWorld.ps1
├── Private/ # 私有函数目录(内部使用,不导出)
│ └── Write-Log.ps1
└── main.ps1 # (可选)用于本地测试的入口脚本
💡 说明:
.psd1
是模块清单(manifest),用于声明模块元数据和导出内容。.psm1
是模块脚本文件,可直接包含函数,或通过Import-Module
加载Public/
和Private/
中的脚本。main.ps1
并非模块必需文件,仅用于本地开发测试。
模块定义规范
1. 模块命名
- 模块文件夹名、
.psd1
和.psm1
文件名必须一致(如MyModule
)。 - 推荐使用 PascalCase 命名(如
NetworkTools
、DataProcessor
)。
2. 模块清单(.psd1)关键字段
@{
ModuleVersion = '1.0.0'
GUID = 'a1b2c3d4-e5f6-7890-1234-567890abcdef' # 使用 New-Guid 生成
Author = 'Cikaros'
CompanyName = 'CI科技有限责任公司'
Description = '简单Demo模板'
PowerShellVersion = '5.1' # 或 '7.0' 等
FunctionsToExport = @('Get-HelloWorld')
CmdletsToExport = @()
VariablesToExport = @()
AliasesToExport = @()
RootModule = '<ModuleName>.psm1'
PrivateData = @{
PSData = @{
Tags = @('Demo', 'Tutorial')
LicenseUri = ''
ProjectUri = ''
}
}
}
3. 函数命名规范
- 使用标准 PowerShell 动词 + 名词格式,如
Get-Item
、Set-Config
。 - 动词应来自官方批准动词列表:
Get-Verb
4. 导出控制
- 只有在
FunctionsToExport
中列出的函数才会被用户使用Import-Module
后可见。 - 私有函数(如日志、辅助函数)放在
Private/
目录,不在清单中导出。
main.ps1 模板内容(用于本地测试)
注意:
main.ps1
不是模块的一部分,仅用于开发时快速测试模块功能。
# main.ps1 - 本地测试脚本模板
# 设置错误处理
$ErrorActionPreference = 'Stop'
# 获取当前脚本所在目录
$ModuleRoot = Split-Path -Parent $MyInvocation.MyCommand.Path
# 构建模块路径
$ModuleName = 'MyModule'
$ManifestPath = Join-Path $ModuleRoot "$ModuleName.psd1"
# 如果模块已加载,先移除
if (Get-Module -Name $ModuleName -ErrorAction SilentlyContinue) {
Remove-Module $ModuleName
}
# 从清单导入模块(开发模式)
Import-Module $ManifestPath -Force
# 调用模块中的函数进行测试
Get-HelloWorld
# 可选:列出模块导出的命令
Get-Command -Module $ModuleName
快速创建步骤
- 创建目录
MyModule
- 在目录中创建
Public/
和Private/
子目录 - 编写函数脚本(如
Public/Get-HelloWorld.ps1
) - 创建
MyModule.psm1
,内容如下:
# MyModule.psm1
$Public = @( Get-ChildItem -Path $PSScriptRoot\Public\*.ps1 -ErrorAction SilentlyContinue )
$Private = @( Get-ChildItem -Path $PSScriptRoot\Private\*.ps1 -ErrorAction SilentlyContinue )
foreach ($import in @($Public + $Private)) {
try {
. $import.FullName
} catch {
Write-Error "Failed to import function $($import.FullName): $_"
}
}
Export-ModuleMember -Function $Public.BaseName
- 生成模块清单(首次):
New-ModuleManifest -Path .\MyModule.psd1 -RootModule MyModule.psm1 -FunctionsToExport 'Get-HelloWorld' -Author 'Your Name' -Description 'Demo module'
- 手动编辑
.psd1
补充GUID
、PowerShellVersion
等字段。 - 运行
main.ps1
测试模块。
安装与使用模块
将模块文件夹复制到 PowerShell 模块路径之一,例如:
- 当前用户:
$HOME\Documents\PowerShell\Modules\
- 所有用户:
$env:ProgramFiles\PowerShell\Modules\
然后在任意 PowerShell 会话中:
Import-Module MyModule
Get-HelloWorld
工具脚本模版
# 脚本名称: <脚本名称>
# 描述: <脚本描述>
# 版本: <版本>
# 作者: Cikaros
# 邮箱: Cikaros<at>qq.com
# 日期: <日期>
# 版权: (C) 2024 Your Company. All rights reserved.
# 定义参数
param (
[string]$Param1, # 第一个参数
[string]$Param2, # 第二个参数
[switch]$Flag1, # 开关参数1
[switch]$Flag2, # 开关参数2
[int]$Number, # 数字参数
[string[]]$List, # 列表参数
[switch]$Help # 显示帮助信息
)
# 显示帮助信息
function Show-Help {
Write-Output "Usage: script.ps1 -Param1 <value> -Param2 <value> -Flag1 -Flag2 -Number <value> -List <value1,value2,...> -Help"
Write-Output ""
Write-Output "Parameters:"
Write-Output " -Param1 第一个参数"
Write-Output " -Param2 第二个参数"
Write-Output " -Flag1 开关参数1"
Write-Output " -Flag2 开关参数2"
Write-Output " -Number 数字参数"
Write-Output " -List 列表参数(逗号分隔)"
Write-Output " -Help 显示帮助信息"
}
# 检查是否需要显示帮助信息
if ($Help) {
Show-Help
exit
}
# 处理参数
if ($Param1) {
Write-Output "Param1: $Param1"
}
if ($Param2) {
Write-Output "Param2: $Param2"
}
if ($Flag1) {
Write-Output "Flag1 is set"
}
if ($Flag2) {
Write-Output "Flag2 is set"
}
if ($Number) {
Write-Output "Number: $Number"
}
if ($List) {
Write-Output "List: $($List -join ', ')"
}
交互类脚本模版
main.ps1
# 脚本名称: <脚本名称>
# 描述: <脚本描述>
# 版本: <版本>
# 作者: Cikaros
# 邮箱: Cikaros<at>qq.com
# 日期: <日期>
# 版权: (C) 2024 Your Company. All rights reserved.
# Powershell 2.0兼容
if ($PSVersionTable.PSVersion.Major -lt 3) {
$PSScriptRoot = Split-Path -Parent $MyInvocation.MyCommand.Path
}
# =============全局定义================
# =============函数定义================
Import-Module -Name "Module1.psm1"
# Import-Module -Name "Module2.psm1"
# -------------------------------------
# function XXX { ... }
# =============脚本逻辑================
# 日志记录
Start-Transcript -Path "$PSScriptRoot\maker.log"
Clear-Host
# 窗口标题
$Host.UI.RawUI.WindowTitle = "Windows 映像创建器"
# 欢迎语
Write-Host "👏欢迎使用 Windows 映像创建器!"
# --------TODO 核心业务流程-------------
# --------TODO 核心业务流程 END---------
Stop-Transcript
Module1.psm1
function XXX-XXXXXX {
<#
.SYNOPSIS
<提示信息>
.DESCRIPTION
<功能详情>
.PARAMETER None
<参数介绍>
.EXAMPLE
<示例代码>
.OUTPUTS
<返回值>
.NOTES
作者: Cikaros
创建日期: 2024-9-19
版本: 1.0
#>
...
}
常用的功能型脚本模板
1. 获取操作系统信息
$os = Get-CimInstance -ClassName Win32_OperatingSystem
Write-Output "操作系统名称: $($os.Caption)"
Write-Output "版本: $($os.Version)"
Write-Output "安装日期: $($os.InstallDate)"
2. 检查服务状态
$serviceName = 'Spooler' # 打印队列服务
$service = Get-Service -Name $serviceName -ErrorAction SilentlyContinue
if ($service) {
Write-Output "服务 '$($service.Name)' 当前状态: $($service.Status)"
} else {
Write-Output "未找到服务 '$serviceName'"
}
3. 创建目录并设置权限
$folderPath = 'C:\Temp\NewFolder'
if (-not (Test-Path -Path $folderPath)) {
New-Item -ItemType Directory -Path $folderPath
$acl = Get-Acl -Path $folderPath
$rule = New-Object System.Security.AccessControl.FileSystemAccessRule("Users", "ReadAndExecute", "ContainerInherit,ObjectInherit", "None", "Allow")
$acl.SetAccessRule($rule)
Set-Acl -Path $folderPath -AclObject $acl
Write-Output "目录已创建并设置了权限"
} else {
Write-Output "目录已存在"
}
4. 判断变量是否为空
$variable = 'Hello World'
if ([string]::IsNullOrEmpty($variable)) {
Write-Output "变量是空的"
} else {
Write-Output "变量不是空的,值为: $variable"
}
5. 判断文件是否存在
$filePath = 'C:\Path\To\File.txt'
if (Test-Path -Path $filePath) {
Write-Output "文件存在"
} else {
Write-Output "文件不存在"
}
6. 判断网络连接
$pingResult = Test-Connection -ComputerName 'www.example.com' -Count 1 -Quiet
if ($pingResult) {
Write-Output "网络连接成功"
} else {
Write-Output "无法连接到网络"
}
7. 使用 Switch 进行多条件判断
$number = 2
switch ($number) {
1 { Write-Output "数字是1" }
2 { Write-Output "数字是2" }
3 { Write-Output "数字是3" }
default { Write-Output "数字不在1, 2, 3中" }
}
8. 判断文件(夹)是否存在
$filePath = 'C:\Path\To\File.txt'
$folderPath = 'C:\Path\To\Folder'
if (Test-Path -Path $filePath) {
Write-Output "文件存在"
} else {
Write-Output "文件不存在"
}
if (Test-Path -Path $folderPath) {
Write-Output "文件夹存在"
} else {
Write-Output "文件夹不存在"
}
9. 判断是否为普通文件
$filePath = 'C:\Path\To\File.txt'
if (Test-Path -Path $filePath -PathType Leaf) {
Write-Output "这是一个普通文件"
} elseif (Test-Path -Path $filePath -PathType Container) {
Write-Output "这是一个文件夹"
} else {
Write-Output "路径不存在"
}
10. 判断变量是否为空
$variable = $null
if ([string]::IsNullOrEmpty($variable)) {
Write-Output "变量是空的"
} else {
Write-Output "变量不是空的,值为: $variable"
}
11. 用户输入数据
$ userInput = Read-Host "请输入一些文本"
Write-Output "您输入的是: $userInput"
12. 判断指令是否存在
$command = 'Get-Process'
if (Get-Command -Name $command -ErrorAction SilentlyContinue) {
Write-Output "命令 '$command' 存在"
} else {
Write-Output "命令 '$command' 不存在"
}
13. 判断关键字是否存在
$text = "这是一个测试字符串"
$keyword = "测试"
if ($text -match $keyword) {
Write-Output "关键字 '$keyword' 存在"
} else {
Write-Output "关键字 '$keyword' 不存在"
}
14. 文件夹递归处理
$folderPath = 'C:\Path\To\Folder'
if (Test-Path -Path $folderPath) {
Get-ChildItem -Path $folderPath -Recurse | ForEach-Object {
if (Test-Path -Path $_.FullName -PathType Leaf) {
Write-Output "文件: $($_.FullName)"
} else {
Write-Output "文件夹: $($_.FullName)"
}
}
} else {
Write-Output "文件夹不存在"
}
15. 下载文件
$url = 'https://example.com/path/to/file.zip'
$destination = 'C:\Path\To\DownloadedFile.zip'
Invoke-WebRequest -Uri $url -OutFile $destination
Write-Output "文件已下载到: $destination"
16. 切换至管理员运行
# 检查是否以管理员身份运行
$currentPrincipal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())
if (-NOT $currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
Write-Warning "当前脚本未以管理员身份运行,正在尝试以管理员权限重新启动..."
Start-Process Powershell -ArgumentList $PSCommandPath -Verb RunAs
exit
} else {
Write-Host "当前脚本已以管理员身份运行" -ForegroundColor Green
}
17. 选择驱动器
function Select-DriveLetter {
<#
.SYNOPSIS
提示用户输入一个有效的 Windows 驱动器号(C-Z),并返回格式化后的驱动器号字符串。
.DESCRIPTION
此函数会循环提示用户输入一个驱动器号,直到输入的是字母 'C' 到 'Z'(大小写不敏感)。
输入有效后,函数会将该字母与冒号 (:) 组合,形成标准的驱动器号格式(例如 "C:")。
如果输入无效,函数会显示错误提示,并继续要求用户重新输入。
.PARAMETER None
此函数不接受任何参数。
.EXAMPLE
$drive = Select-DriveLetter
# 用户被提示输入驱动器号
# 如果用户输入 'd',则函数输出 "驱动器号设置为D:" 并返回 "D:"
.OUTPUTS
[string]
返回一个表示驱动器号的字符串,格式为 "X:",其中 X 是 C 到 Z 之间的大写字母。
.NOTES
作者: Cikaros
创建日期: 2024-9-19
版本: 1.0
#>
do {
$DriveLetter = Read-Host "请输入 Windows 映像的驱动器号"
if ($DriveLetter -match '^[c-zC-Z]$') {
$DriveLetter = $DriveLetter + ":"
Write-Output "驱动器号设置为$DriveLetter"
} else {
Write-Output "⚠️驱动器号无效。请在 C 和 Z 之间输入一个字母。"
}
} while ($DriveLetter -notmatch '^[c-zC-Z]:$')
return $DriveLetter
}
PowerShell脚本模版
https://blog.cikaros.top/doc/7da56ef8.html