当前位置:网站首页 > 更多 > 玩电脑 > 正文

[玩转系统] 了解 PowerShell CmdletBinding 如何增强功能

作者:精品下载站 日期:2024-12-14 13:10:04 浏览:14 分类:玩电脑

了解 PowerShell CmdletBinding 如何增强功能


您是否曾经想要创建 PowerShell cmdlet,但不了解 C# 或其他 Microsoft .NET Framework 语言?当 PowerShell CmdletBinding 触手可及时,为什么还要“想要”呢?

在本教程中,您将学习如何使用 PowerShell CmdletBinding 属性来增强功能并使它们的行为类似于 cmdlet。

准备好?深入挖掘并让您的函数以前所未有的方式运行!

先决条件

本教程将是一个实践演示。只要您拥有安装了 PowerShell v5.1 或更高版本的 Windows 或 Linux PC,就可以开始使用 — 本教程使用安装了 PowerShell v5.1 的 Windows 10 计算机。

创建使用 PowerShell 组织文件的基本函数

在某些情况下,一个目录中可能有很多不同类型的文件,而没有良好的组织。保持文件井井有条始终是一个好习惯,因此您将创建一个基本函数来按文件扩展名将文件移动到指定文件夹。

基本的 PowerShell 函数并不被定义为只有几行代码。在这种情况下,“基本”意味着该函数缺乏 PowerShell cmdlet 的功能。该函数没有通用参数,并且无法完全控制可用参数。

1. 以管理员身份打开 Windows PowerShell ISE。

2. 将以下代码复制并粘贴到代码编辑器中,然后运行代码。下面的代码将桌面上的所有 .pdf.doc.txt 文件移动到名为“文档”的单个文件夹中。

从本教程的这一点开始,请务必将桌面文件夹路径 (C:\Users\ADMIN\Desktop\) 中的 ADMIN 替换为您的计算机用户名。

Function Group-Files
{    
    Param(
    [string]$Path,
    [string]$Folder
    )
    # Check if the destination folder exists. If not, then create it
    If ((Test-Path -Path ($Path + "\" + $Folder)) -eq $False) {        
        New-Item -Name $Folder -Path $Path -ItemType Directory
    }
    # Move Items
    Get-ChildItem $Path | ForEach-Object {
				# If the last four characters of the filename ends with .pdf, .doc, .txt
        If ($_.FullName.Substring($_.FullName.Length -4) -in ".pdf", ".doc", ".txt") 
				{
            Move-Item -Path $_.FullName -Destination ($Path + $Folder)
        }
    }
}
# Call the Group-Files function
Group-Files -Path C:\Users\ADMIN\Desktop\ -Folder "Documents"

[玩转系统] 了解 PowerShell CmdletBinding 如何增强功能

运行上面的代码后,您可能已经注意到所有文件都已移动,而没有要求您确认。此外,该函数没有告诉您如果运行该代码会发生什么。您将在以下部分中了解有关使用 CmdletBinding 增强功能的更多信息。

3. 最后,运行下面的 Get-Command 列出您创建的 Group-Files 函数可用的所有参数。

(Get-Command Group-Files).Parameters

[玩转系统] 了解 PowerShell CmdletBinding 如何增强功能

使用 CmdletBinding 属性访问通用参数

您已经看到基本功能运行良好。但也许您更喜欢强制参数或添加确认操作对话框?如果是这样,CmdletBinding 属性就可以解决问题! CmdletBinding 属性允许您使用可用于 PowerShell cmdlet 的常用参数。

以下代码表示 CmdletBinding 属性的语法,包括其所有参数。

{
   [CmdletBinding(
        ConfirmImpact=<string>,
				# Default parameter set name you want PowerShell to use 
				# if there is no parameter set.
        DefaultParameterSetName=<string>, 
				# uri to online help, must begin with http or https
        HelpURI=<uri>, 
				# Used when you’re trying to return data from a large database suchas MySQL.
        SupportsPaging=<boolean>, 
				# Adds three parameters - First, Skip, and IncludeTotalCount to the function.
        SupportsShouldProcess=<boolean>,
				# positional binding binds positions to parameters 
        PositionalBinding=<boolean>) as defined
   ]
	 # It's important to use the Param keyword
   Param ($Parameter1)

   Begin{}
   Process{}
   End{}
}

现在,运行下面的 Group-Files 函数,添加 CmdletBinding 属性,以使其能够访问常用参数并显示所有可用参数。

Function Group-Files
{   
    [CmdletBinding()]
    Param(
    [string]$Path,
    [string]$Folder
    )
		#...   
}

# Gets all parameters available for the Group-Files function
(Get-Command Group-Files).Parameters

您现在可以在下面看到 Group-Files 函数具有比您之前定义的更多的参数。所有常用参数现在都可供该函数使用。

[玩转系统] 了解 PowerShell CmdletBinding 如何增强功能

添加 -WhatIf 开关以双重检查任务

您已经了解了基本函数的工作原理,但函数还可以用于更令人难以置信的事情。您可以通过多种方式创建高级函数,例如使用开关参数。

PowerShell 中的开关参数允许您向函数添加控件。如果开关为 True,则将运行一个操作;如果开关为 False,则将运行另一个操作。

高级功能的工作方式类似于 PowerShell cmdlet。通过高级功能,您可以访问 cmdlet 可用的所有常用参数。但正如您所见,高级功能是用 PowerShell 语言编写的,而 cmdlet 是用 Microsoft .NET Framework 语言(例如 C#)编写的。

用于风险缓解的高级开关只有两个:WhatIfConfirm 开关。但您将开始使用本教程中的 -WhatIf 开关。通过此开关,您可以检查如果运行影响较大的函数会发生什么情况(空运行)。

要了解该开关的工作原理,请在 PowerShell 上使用 -WhatIf 开关运行以下命令。该命令显示“What if”消息,解释运行 New-Item 命令的操作。

New-Item -Name AdamBertram -Path C:\Users\ADMIN\Desktop -ItemType Directory -WhatIf

[玩转系统] 了解 PowerShell CmdletBinding 如何增强功能

现在,运行下面的代码并添加 CmdletBinding,以便在调用函数时可以访问 -WhatIf

从现在开始,您将学习如何逐步增强 Group-Files 功能并使用 Write-Host 命令确认操作。在本教程的最后,您将看到增强功能的最终结构。

Function Group-Files
{   # Set SupportsShouldProcess to True, to make -WhatIf and -Confirm accessible
    [CmdletBinding(SupportsShouldProcess=$True)]
    Param(
    [string]$Path,
    [string]$Folder
    )
    
    If ($PSCmdlet.ShouldProcess($Path)) {
        Write-Host "WhatIf wasn't used, moving files..."
    }
    Else {
        Write-Host "WhatIf has been used! Doing nothing..."
    } 
}
# Calls the Grou-File function
Group-Files -Path C:\Users\ADMIN\Desktop\ -Folder "Documents" -WhatIf

有一个名为 $WhatIfPreference 的系统变量,默认设置为 false。但是当变量为true时,Group-Files函数将被自动调用 -WhatIf

您可以在下面的屏幕截图中看到,该函数根据您是否使用 -WhatIf 开关打印出两条不同的消息。

[玩转系统] 了解 PowerShell CmdletBinding 如何增强功能

[玩转系统] 了解 PowerShell CmdletBinding 如何增强功能

使用 -Confirm 开关确认操作

-WhatIf 开关类似,-Confirm 开关告诉您特定函数或命令将执行什么操作。但是,在函数中添加 -Confirm 开关的好处是,您将收到确认要执行的操作的提示。

当您的函数需要执行高风险操作(例如移动或删除文件)时,添加 -Confirm 开关会派上用场。

在执行指定操作之前,运行以下代码以提示确认 (-Confirm)。 -Confirm 参数仅在 SupportsShouldProcess 为 true 时才起作用,类似于 -WhatIf

Function Group-Files
{
		# Set SupportsShouldProcess to True to make -WhatIf and -Confirm accessibly
    [CmdletBinding(SupportsShouldProcess=$True)]
    Param([string]$Path, [string]$Folders)

    # If the user confirmed Yes, or user didn't use -Confirm
    If ($PSCmdlet.ShouldProcess($Path)) {
        Write-Host "Files Moved"
    }
    # If the user confirmed No
    Else {
        Write-Host "Action Declined"
    }
}

# Calls the Group-Files function
Group-Files -Path C:\Users\ADMIN\Desktop\ -Folder "Documents" -Confirm

现在,选择是否执行该操作的选项。 $PSCmdlet 自动变量中的 ShouldProcess 方法将用于控制是否移动文件。

[玩转系统] 了解 PowerShell CmdletBinding 如何增强功能

如果您选择确认操作,您将在 PowerShell 终端中看到下面显示的消息。否则,您将收到“操作被拒绝”的消息。

[玩转系统] 了解 PowerShell CmdletBinding 如何增强功能

设置功能的影响级别

也许您想为您的函数设置影响级别,而不仅仅是依赖 -Confirm 开关。如果是这样,通过在 CmdletBinding 中添加ConfirmImpact 参数来设置对函数的确认影响即可解决问题。

以下是 CmdletBinding 的语法。 ConfirmImpact 参数的级别决定了函数要执行的操作的“破坏性”。

[CmdletBinding(SupportsShouldProcess=$True, ConfirmImpact='level')]

您可以将 ConfirmImpact 参数的级别设置为以下之一:

  • None - PowerShell 不会提示确认任何操作,除非您使用 -Confirm 开关。
  • - 低、中、高风险的操作将被自动确认。
  • Medium - ConfirmImpact 参数的默认级别,其中 PowerShell 提示确认具有中度或高风险的操作,例如删除文件。
  • - PowerShell 提示用户,就像使用 -Confirm 参数调用该函数一样。

现在,运行下面的代码来查看 ConfirmImpact 参数和首选项 $ConfirmPreference 变量如何并行工作。

ConfirmImpact 的操作取决于 $ConfirmPreference 变量的值。如果您将 ConfirmImpact 级别设置为等于或大于 $ConfirmPreference 变量的值,您将收到确认提示。

$ConfirmPreference='High' # Sets confirmation preference
Function Group-Files
{
		# Sets -WhatIf, -Confirm and ConfirmImpact accessible
    [CmdletBinding(SupportsShouldProcess=$True, ConfirmImpact='High')]
    Param([string]$Path, [string]$Folders)

    # If the user confirmed Yes, or user didn't use -Confirm
    If ($PSCmdlet.ShouldProcess($Path)) {
        Write-Host "Files Moved"
    }
    # If the user confirmed No
    Else {
        Write-Host "Action Declined"
    }
}

# Calls the Group-Files function
Group-Files -Path C:\Users\ADMIN\Desktop\ -Folder "Documents"

由于 ConfimImpact 级别等于 $ConfirmPreference 变量值,因此即使不使用 -Confirm 开关,PowerShell 也会提示确认,如下所示。

[玩转系统] 了解 PowerShell CmdletBinding 如何增强功能

使用 Write-Verbose 语句显示更多信息

除了您在前面的示例中看到的参数之外,CmdletBinding 还提供了许多其他常见参数,例如 -Verbose

-Verbose 参数显示有关代码中正在执行的操作的更多信息。但是你如何在你的函数中使用它呢?通过在函数中添加 Write-Verbose 语句。

运行下面的代码以查看 Write-Verbose 语句如何在函数上工作以显示消息。

Function Group-Files
{
    [CmdletBinding(SupportsShouldProcess=$True)]
    Param([string]$Path, [string]$Folder)
    
		Write-Verbose "Creating the folder if it doesn't exist..."

    # If the user confirmed Yes, or user didn't use -Confirm switch
    If ($PSCmdlet.ShouldProcess($Path)) {
        Write-Host "Files will be moved"
				Write-Verbose "Moving files..."
    }
    # If the user confirmed No
    Else {
        Write-Host "Files will not be moved"
    }
}

# Calls the Group-Files function
Group-Files -Path C:\Users\ADMIN\Desktop\ -Folder "Documents"

您可以在下面看到,当使用 -Verbose 参数调用函数时,PowerShell 在输出中显示 VERBOSE 消息。

在函数运行时打印详细消息有助于在出现问题时进行故障排除,因为您事先确切知道函数当前正在执行的操作。

[玩转系统] 了解 PowerShell CmdletBinding 如何增强功能

需要注意的一个关键问题是,虽然 cmdlet 随处可用,但高级功能只能在当前会话中访问。并且在高级函数中只能使用少数自动变量。例如,$args 自动变量对于高级函数不可用。

使用 Parameter 属性控制参数

Group-Files 函数只有两个参数,这就是该函数所需的全部内容。但明确定义这两个参数的行为是一种很好的做法。

例如,如果没有参数,运行Group-Files函数将无法工作,因此您将$Path参数设置为强制参数。同时,您将为 $Folders 参数设置默认值。

以下是 Parameter 属性及其所有参数的语法。

Param
(
    [Parameter(
        Mandatory=<Boolean>,
        Position=<Integer>,
        ParameterSetName=<String>,
        ValueFromPipeline=<Boolean>,
        ValueFromPipelineByPropertyName=<Boolean>,
        ValueFromRemainingArguments=<Boolean>,
        HelpMessage=<String>,
     )]
    [string[]]
    $Parameter1
)

现在,运行以下代码以使 $Path 参数成为必需参数。

Function Group-Files
{
		[CmdletBinding(
				SupportsShouldProcess=$True # Since you're using the common parameters
		)]
    Param(
		[Parameter(
        Mandatory=$True,
        Position=0,
				# Since the Path parameter can also get its value from a pipeline input, 
				# provide access to the pipeline input
        ValueFromPipeline=$True,
        ValueFromPipelineByPropertyName=$True
     )]
    [string]$Path,

    [Parameter(
				Mandatory=$False, 
				Position=1
		)]
    [string]$Folder = "Documents" # Default value of $Folder parameter
    )

    # If the user confirmed Yes, or user didn't use -Confirm
    If ($PSCmdlet.ShouldProcess($Path)) {
        Write-Host "Files will be moved"
				Write-Verbose "Moving files..."
    }
    # If the user confirmed No
    Else {Write-Host "Files will not be moved"}
}

# Calls the Group-Files function without the -Path parameter
Group-Files -Folder "Documents"

[玩转系统] 了解 PowerShell CmdletBinding 如何增强功能

使用 CmdletBindingParameter 属性改进功能

到目前为止,您已经尝试了 CmdletBindingParameter 属性,因此是时候为 Group-Files 添加最后的润色了功能。您将使用所有必要的参数和属性来改进该函数。

此外,您将在下面添加验证属性,以确保用户输入正确的参数值。

  • ValidateScript - 用于$Path 参数,以确保路径是文件夹而不是文件。
  • ValidateCount - 确保$Folder 的最小和最大参数。

运行以下代码,其中包含 Group-Files 函数的所有必要详细信息,使其更像高级函数一样工作。

下面的代码检查您的桌面上是否有以 .doc.pdf.txt 结尾的文件,并在将它们移动到 文档文件夹。

Function Group-Files
{   
    [CmdletBinding(
        SupportsShouldProcess=$True, # Allows the use of -Confirm and -Whatif
        PositionalBinding=$True, # Binds Path and Folder by their position
        ConfirmImpact="Medium" # Confirms before moving files
    )]  
    Param(
    [Parameter(
        Mandatory=$True,
        ValueFromPipeline=$True,
        ValueFromPipelineByPropertyName=$True,
        HelpMessage="Enter a source folder path"
     )]
  	# Validate the path is a folder and not a file
    [ValidateScript({Test-Path $_ -PathType Container})]
    [String]$Path,

    [Parameter(
        Mandatory=$False,
        HelpMessage="Enter a destination path"
     )]

    [ValidateCount(1,1)] # Must provide 1 argument/folder name
    [String]$Folder = "Documents"
    )
		Begin {
	    # Uncomment the line below to activate -whatif
	    # $WhatIfPreference = $True
	
	    # Uncomment the line below not to ask for confirmation when moving each file
			# $ConfirmPreference = "High"
		}

		# Contains the main part of the function
	  Process { 
        # Check if folders exist. If not, then create them
        If ((Test-Path -Path ($Path + "\" + $Folder)) -eq $False) {
            #Write-Host ($Path+"\"+$_) does not exist!
            Write-Verbose "Creating folder $($Path+"\"+$Folder) since it does not exist."
            New-Item -Name $Folder -Path $Path -ItemType Directory
        }
        # Debug message
        Write-Debug "Make sure files are not opened with any program before moving."
        # If the user confirmed Yes, or user didn't use -Confirm
        If ($PSCmdlet.ShouldProcess($Path)) {
            Write-Host "Files will be moved"
            # Get all the files in the $Path directory
						Write-Verbose "Moving files..."
            Get-ChildItem $Path | ForEach-Object {
		        # Documents
		        If ($_.FullName.Substring($_.FullName.Length -4) -in ".pdf", ".doc", ".txt") {
								Write-Verbose "Moving file $($_.FullName) to $($Path + $Folder)"
		            Move-Item -Path $_.FullName -Destination ($Path + $Folder)
								}
            }
        }
        # If the user confirmed No
        Else {
            Write-Host "Files will not be moved"
        }
    }
}
# Call the Group-Files function
Group-Files -Verbose -Debug

[玩转系统] 了解 PowerShell CmdletBinding 如何增强功能

结论

本教程旨在教您如何增强基本功能。做得好吗?您已经逐步创建了高级功能并获得了已编译 cmdlet 的功能。此时,您已经可以使用 PowerShell 函数创建自己的 cmdlet。

现在,为什么不增强旧脚本中的功能以使其更先进!

您需要 登录账户 后才能发表评论

取消回复欢迎 发表评论:

关灯