如何编写 PowerShell 脚本模块

脚本模块是保存在扩展中的任何 .psm1 有效的 PowerShell 脚本。 此扩展允许 PowerShell 引擎在文件中使用规则和模块 cmdlet。 其中大多数功能都可以帮助你在其他系统上安装代码,以及管理范围。 还可以使用模块清单文件,该文件描述更复杂的安装和解决方案。

编写 PowerShell 脚本模块

若要创建脚本模块,请将有效的 PowerShell 脚本保存到 .psm1 文件中。 存储脚本的脚本和目录必须使用同一名称。 For example, a script named MyPsScript.psm1 is stored in a directory named MyPsScript.

模块的目录需要位于指定的路径中 $env:PSModulePath。 模块的目录可以包含运行脚本所需的任何资源,以及描述模块工作原理的模块清单文件。

创建基本 PowerShell 模块

以下步骤介绍如何创建 PowerShell 模块。

  1. 使用 .psm1 扩展保存 PowerShell 脚本。 为脚本和保存脚本的目录使用相同的名称。

    使用 .psm1 扩展保存脚本意味着可以使用模块 cmdlet,例如 Import-Module。 模块 cmdlet 主要存在,以便可以将代码导入和导出到其他用户的系统。 备用解决方案是在其他系统上加载代码,然后将其点源到活动内存中,这不是可缩放的解决方案。 有关详细信息,请参阅了解Windows PowerShell模块。 默认情况下,当用户导入 .psm1 文件时,脚本中的所有函数都可访问,但变量不可用。

    本文末尾提供了一个 PowerShell 脚本示例(已 Show-Calendar授权)。

    function Show-Calendar {
    param(
        [DateTime] $start = [DateTime]::Today,
        [DateTime] $end = $start,
        $firstDayOfWeek,
        [int[]] $highlightDay,
        [string[]] $highlightDate = [DateTime]::Today.ToString('yyyy-MM-dd')
        )
    
        #actual code for the function goes here see the end of the topic for the complete code sample
    }
    
  2. 若要控制用户对某些函数或变量的访问,请在脚本末尾调用 Export-ModuleMember

    文章底部的示例代码只有一个函数,默认情况下会公开该函数。 但是,建议显式调用想要公开哪些函数,如以下代码中所述:

    function Show-Calendar {
          }
    Export-ModuleMember -Function Show-Calendar
    

    可以使用模块清单限制导入的内容。 有关详细信息,请参阅 导入 PowerShell 模块 以及如何 编写 PowerShell 模块清单

  3. 如果你有自己的模块需要加载的模块,则可以在模块顶部使用 Import-Module

    Import-Module cmdlet 将目标模块导入到系统上,可以在后续过程中使用该模块来安装自己的模块。 本文底部的示例代码不使用任何导入模块。 但是,如果这样做,它们将列在文件顶部,如以下代码所示:

    Import-Module GenericModule
    
  4. 若要将模块描述到 PowerShell 帮助系统,可以使用文件中的标准帮助注释,也可以创建其他帮助文件。

    本文底部的代码示例包括注释中的帮助信息。 还可以编写包含其他帮助内容的扩展 XML 文件。 有关详细信息,请参阅为 Windows PowerShell 模块编写帮助

  5. 如果你有其他模块、XML 文件或其他要与模块一起打包的内容,则可以使用模块清单。

    模块清单是一个文件,其中包含其他模块、目录布局、版本号、作者数据和其他信息片段的名称。 PowerShell 使用模块清单文件来组织和部署解决方案。 有关详细信息,请参阅 如何编写 PowerShell 模块清单

  6. 若要安装和运行模块,请将模块保存到相应的 PowerShell 路径之一,并使用 Import-Module

    可在其中安装模块的路径位于全局变量中 $env:PSModulePath 。 例如,在系统上保存模块的常见路径是 %SystemRoot%/users/<user>/Documents/PowerShell/Modules/<moduleName>。 请确保为模块创建一个目录,该目录使用与脚本模块相同的名称,即使它只是一个 .psm1 文件。 如果未将模块保存到其中一个路径,则必须在 Import-Module 命令中指定模块的位置。 否则,PowerShell 将无法找到模块。

    备注

    从 PowerShell 3.0 开始,如果已将模块置于其中一个 PowerShell 模块路径中,则无需显式导入它。 当用户调用函数时,会自动加载模块。 有关模块路径的详细信息,请参阅 导入 PowerShell 模块about_PSModulePath

  7. 若要从当前 PowerShell 会话中的活动服务中删除模块,请使用 Remove-Module

    备注

    Remove-Module 从当前 PowerShell 会话中删除模块,但不卸载模块或删除模块的文件。

Show-Calendar代码示例

以下示例是一个包含名为 Show-Calendar 的单个函数的脚本模块。 此函数显示日历的可视表示形式。 此示例包含 Synopsis、description、参数值和代码的 PowerShell 帮助字符串。 导入模块时,该 Export-ModuleMember 命令可确保将 Show-Calendar 函数导出为模块成员。

<#
 .Synopsis
  Displays a visual representation of a calendar.

 .Description
  Displays a visual representation of a calendar. This function supports multiple months
  and lets you highlight specific date ranges or days.

 .Parameter Start
  The first month to display.

 .Parameter End
  The last month to display.

 .Parameter FirstDayOfWeek
  The day of the month on which the week begins.

 .Parameter HighlightDay
  Specific days (numbered) to highlight. Used for date ranges like (25..31).
  Date ranges are specified by the Windows PowerShell range syntax. These dates are
  enclosed in square brackets.

 .Parameter HighlightDate
  Specific days (named) to highlight. These dates are surrounded by asterisks.

 .Example
   # Show a default display of this month.
   Show-Calendar

 .Example
   # Display a date range.
   Show-Calendar -Start "March, 2010" -End "May, 2010"

 .Example
   # Highlight a range of days.
   Show-Calendar -HighlightDay (1..10 + 22) -HighlightDate "2008-12-25"
#>
function Show-Calendar {
param(
    [DateTime] $start = [DateTime]::Today,
    [DateTime] $end = $start,
    $firstDayOfWeek,
    [int[]] $highlightDay,
    [string[]] $highlightDate = [DateTime]::Today.ToString('yyyy-MM-dd')
    )

## Determine the first day of the start and end months.
$start = New-Object DateTime $start.Year,$start.Month,1
$end = New-Object DateTime $end.Year,$end.Month,1

## Convert the highlighted dates into real dates.
[DateTime[]] $highlightDate = [DateTime[]] $highlightDate

## Retrieve the DateTimeFormat information so that the
## calendar can be manipulated.
$dateTimeFormat  = (Get-Culture).DateTimeFormat
if($firstDayOfWeek)
{
    $dateTimeFormat.FirstDayOfWeek = $firstDayOfWeek
}

$currentDay = $start

## Process the requested months.
while($start -le $end)
{
    ## Return to an earlier point in the function if the first day of the month
    ## is in the middle of the week.
    while($currentDay.DayOfWeek -ne $dateTimeFormat.FirstDayOfWeek)
    {
        $currentDay = $currentDay.AddDays(-1)
    }

    ## Prepare to store information about this date range.
    $currentWeek = New-Object PsObject
    $dayNames = @()
    $weeks = @()

    ## Continue processing dates until the function reaches the end of the month.
    ## The function continues until the week is completed with
    ## days from the next month.
    while(($currentDay -lt $start.AddMonths(1)) -or
        ($currentDay.DayOfWeek -ne $dateTimeFormat.FirstDayOfWeek))
    {
        ## Determine the day names to use to label the columns.
        $dayName = "{0:ddd}" -f $currentDay
        if($dayNames -notcontains $dayName)
        {
            $dayNames += $dayName
        }

        ## Pad the day number for display, highlighting if necessary.
        $displayDay = " {0,2} " -f $currentDay.Day

        ## Determine whether to highlight a specific date.
        if($highlightDate)
        {
            $compareDate = New-Object DateTime $currentDay.Year,
                $currentDay.Month,$currentDay.Day
            if($highlightDate -contains $compareDate)
            {
                $displayDay = "*" + ("{0,2}" -f $currentDay.Day) + "*"
            }
        }

        ## Otherwise, highlight as part of a date range.
        if($highlightDay -and ($highlightDay[0] -eq $currentDay.Day))
        {
            $displayDay = "[" + ("{0,2}" -f $currentDay.Day) + "]"
            $null,$highlightDay = $highlightDay
        }

        ## Add the day of the week and the day of the month as note properties.
        $currentWeek | Add-Member NoteProperty $dayName $displayDay

        ## Move to the next day of the month.
        $currentDay = $currentDay.AddDays(1)

        ## If the function reaches the next week, store the current week
        ## in the week list and continue.
        if($currentDay.DayOfWeek -eq $dateTimeFormat.FirstDayOfWeek)
        {
            $weeks += $currentWeek
            $currentWeek = New-Object PsObject
        }
    }

    ## Format the weeks as a table.
    $calendar = $weeks | Format-Table $dayNames -AutoSize | Out-String

    ## Add a centered header.
    $width = ($calendar.Split("`n") | Measure-Object -Maximum Length).Maximum
    $header = "{0:MMMM yyyy}" -f $start
    $padding = " " * (($width - $header.Length) / 2)
    $displayCalendar = " `n" + $padding + $header + "`n " + $calendar
    $displayCalendar.TrimEnd()

    ## Move to the next month.
    $start = $start.AddMonths(1)

}
}
Export-ModuleMember -Function Show-Calendar