使用右键单击运行脚本时,PowerShell 引发异常 使用 PowerShell 运行

PowerShell Throws Exception When Running Script With Right Click Run With PowerShell

提问人:Mikepedia 提问时间:11/7/2023 最后编辑:Mikepedia 更新时间:11/7/2023 访问量:47

问:

我有一个正在处理的 PowerShell 脚本,当从 ISE 中运行时,以及每当我将其粘贴到 PowerShell 窗口并按 Enter 键时,它都能正常运行。但是,每当我右键单击它并单击“使用 PowerShell 运行”时,我都会收到异常。调用函数时会引发异常。

函数如下:

function GUITitleTextBox_TextChanged
{
    [CmdletBinding()]
    param
    (
        [parameter(Mandatory=$True, Position=0)][System.Object]    $Sender,
        [parameter(Mandatory=$True, Position=1)][System.EventArgs] $EventArguments,
        [parameter(Mandatory=$True, Position=2)][String]           $Text,
        [parameter(Mandatory=$False, Position=3)][System.Object]   $Control1ToUpdate,
        [parameter(Mandatory=$False, Position=4)][System.Object]   $Control2ToUpdate
    )
    
    $Control1ToUpdate.Text = $Text
    $Control2ToUpdate.Text = $Text
}

下面是调用该函数的代码行:

$GUITitleTextBox_Handler = {GUITitleTextBox_TextChanged -Sender $GUITitleTextBox -EventArguments $_ -Text $GUITitleTextBox.Text -Control1ToUpdate $DefaultFormTab -Control2ToUpdate $FormLabel}.GetNewClosure()

$GUITitleTextBox.Add_TextChanged($GUITitleTextBox_Handler)

这是引发的异常(仅右键单击“使用 PowerShell 运行”,而不是在 ISE 中运行或将其粘贴到 PowerShell 窗口中时。(路径已删除,因为它发生在不同路径中的多台计算机上)。

GUITitleTextBox_TextChanged : The term 'GUITitleTextBox_TextChanged' is not recognized as the name of a cmdlet,
function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the
path is correct and try again.
At <Path>\PowerShell-GUI.ps1:899 char:33
+     $GUITitleTextBox_Handler = {GUITitleTextBox_TextChanged -Sender $ ...
+                                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (GUITitleTextBox_TextChanged:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

是什么导致了此异常,我该如何防止它?这是我目前看到的唯一导致脚本异常的函数。

PowerShell 异常

评论

0赞 Mathias R. Jessen 11/7/2023
确保所有函数定义都位于脚本其余部分的“顶部”,在解释器实际到达与其关联的关键字之前,它们将无法调用function
0赞 Mikepedia 11/7/2023
该函数位于调用上方。当我从ISE运行它或将其粘贴到PowerShell窗口中时,没有任何问题。仅当右键单击运行它时。
0赞 Mathias R. Jessen 11/7/2023
你能发布完整的剧本吗?
0赞 Mikepedia 11/7/2023
这是一个冗长的脚本(900+ 行),不适合评论。相关代码是我最初分享的。我主要是在寻找 ISE 的原因,复制粘贴它工作得很好,但通过右键单击运行它无法成功调用该函数。它似乎与 GetNewClosure() 函数有关,该函数允许我成功地将对象传递给该函数。
0赞 Mikepedia 11/7/2023
此答案(针对其他问题)给出了解决方法,但没有解释为什么会发生这种情况,或者是否有任何其他解决方法选项:stackoverflow.com/a/49443377/22859752

答:

0赞 suchislife 11/7/2023 #1

与作用域相关的问题可能导致在ISE外部运行脚本时无法识别该函数。

# Make sure the function is defined in the script scope
function Global:GUITitleTextBox_TextChanged {
    [CmdletBinding()]
    param (
        [parameter(Mandatory=$true, Position=0)][System.Object]    $Sender,
        [parameter(Mandatory=$true, Position=1)][System.EventArgs] $EventArguments,
        [parameter(Mandatory=$true, Position=2)][String]           $Text,
        [parameter(Mandatory=$false, Position=3)][System.Object]   $Control1ToUpdate,
        [parameter(Mandatory=$false, Position=4)][System.Object]   $Control2ToUpdate
    )
    
    $Control1ToUpdate.Text = $Text
    $Control2ToUpdate.Text = $Text
}

$script:GUITitleTextBox_Handler = {
    Global:GUITitleTextBox_TextChanged `
        -Sender $script:GUITitleTextBox `
        -EventArguments $_ `
        -Text $script:GUITitleTextBox.Text `
        -Control1ToUpdate $script:DefaultFormTab `
        -Control2ToUpdate $script:FormLabel
}.GetNewClosure()

$GUITitleTextBox.Add_TextChanged($script:GUITitleTextBox_Handler)

在函数和变量名称前面加上前缀可确保它们在全局范围内可用。作用域修饰符确保变量在定义处理程序的脚本作用域中可用。Global:$script:

也。。。

PowerShell 可以使用方法或操作委托(而不是脚本块)来处理 Windows 窗体中的事件。

# Define the function
function GUITitleTextBox_TextChanged($Sender, $EventArguments) {
    $Text = $Sender.Text
    $Global:DefaultFormTab.Text = $Text
    $Global:FormLabel.Text = $Text
}

# Create an Action delegate for the TextChanged event
$TextChangedAction = [System.Action[System.Object,System.EventArgs]]::new($GUITitleTextBox_TextChanged)

# Assign the delegate to the TextChanged event
$GUITitleTextBox.add_TextChanged($TextChangedAction)

此方法创建一个指向函数的委托,并将其分配给控件的事件。创建委托时,该函数应在范围内。GUITitleTextBox_TextChangedTextChanged$GUITitleTextBox

评论

0赞 Mikepedia 11/7/2023
不幸的是,我仍然遇到同样的例外。
0赞 Mikepedia 11/7/2023
我想我应该问:PowerShell 有没有办法在不使用脚本块的情况下将事件处理程序用于 Windows 窗体 GUI 事件?我在网上看到的 PowerShell 的每个示例都使用脚本块方法。
0赞 Mikepedia 11/7/2023
谢谢!因此,看起来我要么需要将我所有的 GUI 控件声明为全局控件,以便函数可以更新它们(委托方法),要么将我的所有函数声明为全局控件,以便脚本块可以使用它们?如果是这种情况,我可能会将函数声明为全局函数,因为它较少重做脚本,并且每个函数都有一个唯一的名称,因此它不应该覆盖我需要的任何其他内容。