Powershell:批量运行时调用函数失败

Powershell:批量运行时调用函数失败

我为我的脚本创建了一个 GUI。用户从两个列表中进行选择,然后单击按钮加载程序。在 ISE 中,一切正常。但是,当从批处理文件(或直接运行 *ps1 文件)运行时,它会打开 GUI...但当您单击按钮时,它找不到函数“RunOption”(???)

$tmp = Split-Path $script:MyInvocation.MyCommand.Path;
$ScriptDir=Split-Path $tmp  ## To move back up to parent folder from path quoted

if (!(Test-Path $ScriptDir/fnt_files/fontList.csv)){
    $reg = Get-ItemProperty "REGISTRY::HKLM\SOFTWARE\MICROSOFT\Windows NT\CurrentVersion\Fonts"
    $data = $reg.PSObject.Properties.Where({$_.MemberType -eq "NoteProperty" -and $_.Value -match "\..{3}$"}) | Select-Object Name, Value
    $data | Export-Csv -Path $ScriptDir/fnt_files/fontList.csv -NoTypeInformation
}

Add-Type -assembly System.Windows.Forms
$main_form = New-Object System.Windows.Forms.Form
$main_form.Text ='Subtitle Software Suite'
$main_form.Width = 450
$main_form.Height = 190
$main_form.BackColor='cyan'


$Label = New-Object System.Windows.Forms.Label
$Label.Text = "Select Browser to use:"
$Label.Location  = New-Object System.Drawing.Point(10,10)
$Label.Width = 150
$main_form.Controls.Add($Label)

$ComboBox = New-Object System.Windows.Forms.ComboBox
$ComboBox.Width = 100

$FileNames = Get-ChildItem -Path Registry::"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths"|Select-Object Name

    if ($FileNames -Match "firefox.exe"){
    $ComboBox.Items.Add('Firefox');
    }
    if ($FileNames -Match "chrome.exe"){
    $ComboBox.Items.Add('Chrome');
    }
     if ($FileNames -Match "edge.exe"){
    $ComboBox.Items.Add('Edge');
    }
    if ($FileNames -Match 'opera.exe'){
     $ComboBox.Items.Add('Opera');
    }
    

$ComboBox.Location  = New-Object System.Drawing.Point(160,10)
$main_form.Controls.Add($ComboBox)

$OptLabel = New-Object System.Windows.Forms.Label
$OptLabel.Text = "Select an option"
$OptLabel.Location  = New-Object System.Drawing.Point(10,50)
$OptLabel.Width = 150
$main_form.Controls.Add($OptLabel)

$Options = New-Object System.Windows.Forms.ComboBox
$Options.Width = 250
$Options.Items.Add('Select Fonts to use')
$Options.Items.Add('Audio To Text -Transcribe-')
$Options.Items.Add('Caption Timecode + Font Viewer')
$Options.Items.Add('SRT using FFMPEG')
$Options.Items.Add('SSA using FFMPEG')
$Options.Items.Add('SSA using FFMPEG + Drawbox')
$Options.Items.Add('Start Handbrake')

$Options.Location  = New-Object System.Drawing.Point(160,50)
$main_form.Controls.Add($Options)
  
$Button = New-Object System.Windows.Forms.Button
$Button.Location = New-Object System.Drawing.Size(290,90)
$Button.Size = New-Object System.Drawing.Size(120,25)
$Button.Text = "Load Software"
$Button.height=40
$Button.BackColor='red'
$Button.ForeColor='white'
$Button.Add_Click({RunOption})
$main_form.Controls.Add($Button)

$main_form.StartPosition = "manual"
$main_form.Location = New-Object System.Drawing.Size(500, 300)

$main_form.ShowDialog()

function RunOption(){
$browser=$ComboBox.SelectedIndex;
$choice=$Options.SelectedIndex;

    switch ($browser){
        0{
        $browserChoice='firefox'
        }
        1{
        $browserChoice='chrome'
        }
        2{
        $browserChoice='msedge'
        }
        3{
        $browserChoice='opera'
        }
        }
write-host $browserchoice

   switch ( $choice ) {      
        1{                              # Select fonts
        Start-Process $browserChoice "file:$ScriptDir/fnt_files/fontSelect.html" -WindowStyle Maximized  
        }

        2{                              # Audio to text transcribe
        Start-Process $browserChoice "file:$ScriptDir/Vid2Txt/vidTranscript.html" -WindowStyle Maximized
         }
        3{                             # Captions plus timecode
       Start-Process $browserChoice "file:$ScriptDir/fnt_files/fontView.html" -WindowStyle Maximized
       Start-Process $browserChoice "file:$ScriptDir/standard.html"  -WindowStyle Maximized
         }
        
        4{                             # SRT using FFMPEG
        #-WindowStyle Maximized
        write-host "You entered SRT FFMMEG"
        }

        5{                             # SSA using FFMPEG
        #-WindowStyle Maximized
        write-host "You entered SSA with FFMPEG"
        }

        6{                             # SSA using FFMEG+Drawbox
        #-WindowStyle Maximized
        write-host "You entered FFMPG-DRAWBOX"
        }

        7{                             # Start handbrake
        Start-Process "C:\Windows\Handbrake\handbreak.exe"
        }
    }
    

$main_form.Close();
}  

(运行时,控制台在一列中列出 0120123456 - 我可以看到这与切换命令有关,但不知道它们为什么显示)

为了完整性,批次是:

@ECHO OFF
SET ThisScriptsDirectory=%~dp0
SET PowerShellScriptPath=%ThisScriptsDirectory%sm.ps1
PowerShell -NoProfile -ExecutionPolicy Bypass -Command "& '%PowerShellScriptPath%'";

这样做是因为我不知道用户将把程序存储在电脑的哪里。批处理是从 cmd 快捷方式调用的(所以我可以更改桌面图标!)

这是我的第一个 Powershell 脚本,所以请对我友善一点 :-)

答案1

代码重构。

PowerShell 中不需要分号(例如您正在使用的分号)。这是从其他语言中传过来的习惯。PowerShell 会忽略/将其视为代码终止符。

因此,分号表示代码分隔,其中两边的内容没有操作关系。并且只有将不同的代码放在同一行时才真正需要。请参阅PowerShell 计算属性、哈希表、PSCustomObjects 作为示例。

仅供参考... 同一行上的所有代码的分号不会使该行成为一行。

PowerShell MS 文档

也可以看看:

对简单字符串使用单引号,对变量扩展和一些其他输出格式化需求使用双引号。

在驱动器导航方面,Powershell 也提供了原生的 FIleSytem 属性,甚至为注册表提供了原生的 FIleSytem 属性。有关详细信息,请参阅 Get-PSDrive 帮助。

# Get specifics for a module, cmdlet, or function
(Get-Command -Name Get-PSDrive).Parameters
(Get-Command -Name Get-PSDrive).Parameters.Keys
Get-help -Name Get-PSDrive -Examples
Get-help -Name Get-PSDrive -Full
Get-help -Name Get-PSDrive -Online

(Get-PSDrive).Provider | 
Format-Table -AutoSize
# Results
<#

Name        Capabilities                       Drives               
----        ------------                       ------               
Alias       ShouldProcess                      {Alias}              
FileSystem  Filter, ShouldProcess, Credentials {C, ...}
Certificate ShouldProcess                      {Cert}               
FileSystem  Filter, ShouldProcess, Credentials {C, ...}
FileSystem  Filter, ShouldProcess, Credentials {C, ...}
Environment ShouldProcess                      {Env}                
FileSystem  Filter, ShouldProcess, Credentials {C, ...}
Function    ShouldProcess                      {Function}           
FileSystem  Filter, ShouldProcess, Credentials {C, ...}
FileSystem  Filter, ShouldProcess, Credentials {C, ...}
Registry    ShouldProcess, Transactions        {HKLM, HKCU}         
Registry    ShouldProcess, Transactions        {HKLM, HKCU}         
FileSystem  Filter, ShouldProcess, Credentials {C, ...}
Variable    ShouldProcess                      {Variable}           
WSMan       Credentials                        {WSMan}              
#>

代码对齐只是为了便于阅读而采取的习惯。

您可以将 PowerShell 的快捷方式图标更改为您想要的任何内容、批处理文件或不更改。

Add-Type -assembly System.Windows.Forms

#region Begin GUI code ############################################

$main_form               = New-Object System.Windows.Forms.Form
$main_form.Text          ='Subtitle Software Suite'
$main_form.Width         = 450
$main_form.Height        = 190
$main_form.BackColor     ='cyan'


$Label                   = New-Object System.Windows.Forms.Label
$Label.Text              = 'Select Browser to use:'
$Label.Location          = New-Object System.Drawing.Point(10,10)
$Label.Width             = 150

$ComboBox                = New-Object System.Windows.Forms.ComboBox
$ComboBox.Width          = 100
$ComboBox.Location       = New-Object System.Drawing.Point(160,10)


$OptLabel                = New-Object System.Windows.Forms.Label
$OptLabel.Text           = 'Select an option'
$OptLabel.Location       = New-Object System.Drawing.Point(10,50)
$OptLabel.Width          = 150


$Options                 = New-Object System.Windows.Forms.ComboBox
$Options.Width           = 250
@(
'Select Fonts to use',
'Audio To Text -Transcribe-',
'Caption Timecode + Font Viewer',
'SRT using FFMPEG',
'SSA using FFMPEG',
'SSA using FFMPEG + Drawbox',
'Start Handbrake'
) | 
ForEach-Object {[void] $OPtions.Items.Add($PSItem)}


$Options.Location        = New-Object System.Drawing.Point(160,50)
  
$Button                  = New-Object System.Windows.Forms.Button
$Button.Location         = New-Object System.Drawing.Size(290,90)
$Button.Size             = New-Object System.Drawing.Size(120,25)
$Button.Text             = 'Load Software'
$Button.height           = 40
$Button.BackColor        = 'red'
$Button.ForeColor        = 'white'
$Button.Add_Click({Start-RunOption})

$main_form.StartPosition = 'manual'
$main_form.Location      = New-Object System.Drawing.Size(500, 300)


$main_form.controls.AddRange(@(
        $Label,
        $ComboBox,
        $OptLabel,
        $Options,
        $Button
    )
)


$tmp       = Split-Path $script:MyInvocation.MyCommand.Path
$ScriptDir = Split-Path $tmp

if (!(Test-Path $ScriptDir/fnt_files/fontList.csv))
{
    $reg  = Get-ItemProperty -Path 'HKLM:\SOFTWARE\MICROSOFT\Windows NT\CurrentVersion\Fonts'
    $data = $reg.PSObject.Properties.Where({$PSItem.MemberType -eq 'NoteProperty' -and 
            $PSItem.Value -match '\..{3}$'}) | 
            Select-Object Name, Value

    $data | 
    Export-Csv -Path "$ScriptDir/fnt_files/fontList.csv -NoTypeInformation"
}

$FileNames = Get-ChildItem -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths' | 
             Select-Object Name

'firefox.exe', 'chrome.exe', 'edge.exe', 'opera.exe' | 
ForEach {
    if ($FileNames -Match $PSItem)
    {
        $Combobox.Items.Add($PSItem) | 
        Out-Null
    }
}

#endregion End GUI code ############################################


#region Begin app logic code############################################

function Start-RunOption()
{
    $ComboBox.SelectedItem | 
    Out-Host

    $Options.SelectedItem | 
    Out-Host

<#
$StartProcessSplat = @{
    FilePath     = $ComboBox.SelectedItem 
    ArgumentList = $Options.SelectedItem 
    # WindowStyle  = Maximized
}
Start-Process @StartProcessSplat
#>


<#
    switch ($browser)
    {
        0 {$browserChoice = 'firefox'}
        1 {$browserChoice = 'chrome'}
        2 {$browserChoice = 'msedge'}
        3 {$browserChoice = 'opera'}
    }


   switch ( $choice ) 
   {      
        1 {Start-Process $browserChoice "file:$ScriptDir/fnt_files/fontSelect.html" -WindowStyle Maximized }
        2 {Start-Process $browserChoice "file:$ScriptDir/Vid2Txt/vidTranscript.html" -WindowStyle Maximized}
        3 {                            
           Start-Process $browserChoice "file:$ScriptDir/fnt_files/fontView.html" -WindowStyle Maximized
           Start-Process $browserChoice "file:$ScriptDir/standard.html"  -WindowStyle Maximized
          }
        
        4 {'You entered SRT FFMMEG'}
        5 {'You entered SSA with FFMPEG'}
        6 {'You entered FFMPG-DRAWBOX'}
        7 {Start-Process 'C:\Windows\Handbrake\handbreak.exe'}
    }
#>

}

#endregion End app logic code############################################

# App load
$main_form.ShowDialog()
$main_form.Close()

运行这个...

PowerShell -NoProfile -ExecutionPolicy Bypass -Command "D:\Scripts\formtest.ps1"

...从cmd.exe,按预期运行代码。

# Results from the function and closing the form
#>
<#
firefox.exe
Select Fonts to use
Cancel
#>

因此,正如您所看到的,您实际上不需要 switch case,只需调用 .SelectedItem 甚至 .Text 属性就可以满足您的需要。

长更新以涵盖您的所有评论。;-}

哇哦!这是我收到过的最详细的回复……

--- 不用担心,作为 MCT(微软认证培训师),我总是尝试解释什么是可能引起你兴趣的。

并且您重写了代码,所以我可以研究应该如何做。

--- 这只是一组建议,并进行了一些更正。当然,您需要进行更改和测试,因为我无法测试您的完整用例。Youtube 上有很多关于 UX/UI(WinForms 和 WPF)和 PowerShell GUI 设计和 PowerShell 最佳实践的文档/视频。

因此,设置严格模式, 这#requires 语句PSScript分析器和最佳实践。

有很多最佳/公认实践信息,但实际上都是关于选择、习惯和目标的。这里仅列举几个。

在我看来,上述每一种都有其优点和缺点,我并不赞同所有的观点,因为有些人会采取一些复杂的方法来证明自己的立场。同样,这都是关于信仰、选择和风格接受度。你选择适合你、你的团队、你的客户的东西,而忽略其他的东西/人。

当谈到 GUI 设计时,让工具完成大部分工作。请参阅我对此主题的回答。

由于我计划发布基于浏览器的字幕软件,您是否希望在指南中提及版权,也许是商业网站或类似网站?

--- 嗯,当然可以,我们可以离线联系,因为在论坛上我更喜欢匿名。不过这里有超级用户工具可以直接聊天。

哦,分号;回到 PERL。

--- 不只是 PERL 的问题。我有 VB/VB.Net/C#/JavaScript 开发背景,所以我也必须改掉这个习惯。

必须查看快捷方式。我只知道使用 CMD.exe,因为其他一切似乎都没有更改图标的按钮

-- 您可以从任何地方导出快捷方式,也可以创建自己的快捷方式以供使用。我在授课和企业活动中一直这样做/展示这一点。

(抱歉第三条评论)第一次使用 switch。通常,我会做一系列“如果-那么”条件哦,你的“运行这个”不起作用,因为它指定了“D”驱动器。我不知道用户将在哪里安装文件,所以必须将运行时设置为“通用”

--- 不用担心,我选择了一个真正的驱动器只是为了测试代码。PSSCriptRoot 是一种常见的方法。我并没有以任何方式表明你会使用特定的驱动器。

当我编写代码时,我会在开发过程中尽可能保持简单,然后重构以进行分发,以适应动态/未知的部署场景。这样我就知道什么在本机/静态下有效,什么在本机/静态下无效。因此,如果它在那种状态下不起作用,那么它就无法动态工作。如果它在静态下有效,但在动态下失败,那么它就是潜在的环境问题或正在使用的方法。

只需阅读这些链接,就可以获得一些非常有趣的阅读内容

---很高兴知道他们有帮助

刚刚尝试了脚本,但还不够好。(布局简洁,以后会尝试使用它)它将选项输出到控制台 - 正如 Out-Host 所期望的那样...

--- 只需删除 Out-Host。我把它放在那里,但它在那里是为了表明你需要得到的是符合预期的。如果没有必要,就不要输出。只要知道这一点,就可以抑制输出。

看:

不会启动选定的浏览器并加载 HTML 页面,这就是 switch 语句依赖于所选浏览器的原因。

--- 再说一次,我只是展示了如何在没有额外代码的情况下获得结果,但要执行其他行,当然,您必须为此编写代码。

因此我仍然需要设置浏览器和选项。此外,现在单击按钮并打开浏览器后,它不会关闭窗口/脚本。不要认为这是一个“不满意”的评论 - 它不是。只是增加了一些小故障。–

--- 不用担心。这只是让您开始的信息。您可以对用例进行进一步更改,只有您自己知道那是什么。

相关内容