PowerShell ISE 与 Powershell.exe - 寻找更好的解决方案

PowerShell ISE 与 Powershell.exe - 寻找更好的解决方案

我对 PowerShell 还不太熟悉,目前无法找到以下问题的其他(更好的?)解决方案:

这是我的代码:(测试用例)

Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing

function Add-Item ([string]$fItem) {
    Write-Host "Do black magic with $fItem here"
}

$MyListOfItems=@()
$MyListOfItems+="foo"
$MyListOfItems+="bar"
$MyListOfItems+="foobar"
$MyListOfItems+="barfoo"
$MyListOfItems+="boofar"

$Form = New-Object System.Windows.Forms.Form 
$Form.AutoSize = $True
$Form.AutoSizeMode = "GrowAndShrink"
$Form.Add_Shown({$Form.Activate()})

$Counter=0
ForEach ($Item in $MyListOfItems) {
    $AddButton = New-Object System.Windows.Forms.Button
    $AddButton.Size = New-Object System.Drawing.Size(100,23)
    $AddButton.Location = New-Object System.Drawing.Point(10,(10+25*$Counter))
    $AddButton.Text = $Item
    #$Command = "Add-Item $Item"
    #$AddButton.Add_Click({ Invoke-Expression -command $Command }.GetNewClosure())
    $AddButton.Add_Click({ Add-Item $Item }.GetNewClosure())
    #$AddButton.Add_Click({ Add-Item $Item })
    $Form.Controls.Add($AddButton)
    $Counter++
}


[void]$Form.ShowDialog()

在 PowerShell ISE 中它运行完美:

Do black magic with foo here
Do black magic with bar here
Do black magic with foobar here
Do black magic with barfoo here
Do black magic with boofar here

另一方面,当我使用 Powershell.exe 运行它(阅读:“使用 Powershell 运行”上下文菜单)时,每个按钮都会出现错误:

Add-Item : The term 'Add-Item' 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 C:\Scripts\buttontest.ps1:62 char:24
+ $AddButton.Add_Click({ Add-Item $Item }.GetNewClosure())
+                        ~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (Add-Item:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

如果我将按钮的 Add_Click 事件更改为:

$AddButton.Add_Click({ Add-Item $Item })

我没有收到错误,但却遇到了常见的陷阱,即每次按下按钮时只能返回最后一项:

Do black magic with boofar here
Do black magic with boofar here
Do black magic with boofar here
Do black magic with boofar here
Do black magic with boofar here

我设法通过将函数范围更改为全局范围来实现这一点。虽然这确实有效,但这并不适合我。修改后的函数:

function global:Add-Item ([string]$fItem) {
    Write-Host "Do black magic with $fItem here"
}

有没有办法让这段代码工作,同时避免使用函数的全局范围?我搜索了几个论坛,发现了很多关于实现 add_click 事件的不同方法以及 Powershell ISE 和命令行之间的差异的主题,但无法找到它们之间的答案

注意:虽然我在 PowerShell 3 环境中开发这个,但它仍然需要与 PowerShell 2 兼容

提前谢谢你,Wim。

答案1

ISE 和“使用 Powershell 运行”之间的区别在于 ISE 在全局范围内运行脚本,而“使用 Powershell 运行”为脚本创建新范围。来自其他模块的代码(GetNewClosure创建新模块并将脚本块绑定到它)可以看到全局范围,但看不到嵌套范围。作为解决方案,您可以自己创建模块并Add-Item在该模块内定义函数:

Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing

$MyListOfItems=@(
    "foo"
    "bar"
    "foobar"
    "barfoo"
    "boofar"
)

$Form = New-Object System.Windows.Forms.Form 
$Form.AutoSize = $True
$Form.AutoSizeMode = "GrowAndShrink"
$Form.Add_Shown({$Form.Activate()})

$Counter=0
ForEach ($Item in $MyListOfItems) {
    $AddButton = New-Object System.Windows.Forms.Button
    $AddButton.Size = New-Object System.Drawing.Size(100,23)
    $AddButton.Location = New-Object System.Drawing.Point(10,(10+25*$Counter))
    $AddButton.Text = $Item
    $Module = New-Module {
        param($Item)
        function Add-Item ([string]$fItem) {
            Write-Host "Do black magic with $fItem here"
        }
    } $Item -Function @()
    $AddButton.Add_Click($Module.NewBoundScriptBlock({ Add-Item $Item }))
    $Form.Controls.Add($AddButton)
    $Counter++
}

[void]$Form.ShowDialog()

您还可以使用不同的方法并将相关数据保存在Tag以下属性中Control

Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing

function Add-Item ([string]$fItem) {
    Write-Host "Do black magic with $fItem here"
}

$MyListOfItems=@(
    "foo"
    "bar"
    "foobar"
    "barfoo"
    "boofar"
)

$Form = New-Object System.Windows.Forms.Form 
$Form.AutoSize = $True
$Form.AutoSizeMode = "GrowAndShrink"
$Form.Add_Shown({$Form.Activate()})

$Counter=0
ForEach ($Item in $MyListOfItems) {
    $AddButton = New-Object System.Windows.Forms.Button
    $AddButton.Size = New-Object System.Drawing.Size(100,23)
    $AddButton.Location = New-Object System.Drawing.Point(10,(10+25*$Counter))
    $AddButton.Text = $Item
    $AddButton.Tag = @{Item = $Item}
    $AddButton.Add_Click({param($sender) Add-Item $sender.Tag.Item })
    $Form.Controls.Add($AddButton)
    $Counter++
}

[void]$Form.ShowDialog()

答案2

我将您的代码粘贴到文件中按钮.ps1,然后使用 运行该文件 powershell -File buttons.ps1。我得到了一个包含所有按钮的新表单窗口,正如预期的那样。我还尝试通过“使用 powershell 打开”打开该文件,效果也很好。

我没有“使用 powershell 运行”的上下文菜单项 - 但显然该上下文条目以与上述两种方式不同的方式执行您的脚本。您可以尝试从 Windows 命令行执行您的脚本吗?

相关内容