我为我的脚本创建了一个 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 文档
也可以看看:
对简单字符串使用单引号,对变量扩展和一些其他输出格式化需求使用双引号。
- about_Quoting_Rules - PowerShell | Microsoft Docs
- PowerShell 引用规则的故事 - Trevor Sullivan
- 何时在 PowerShell 中使用引用 - 简单对话
在驱动器导航方面,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 语句依赖于所选浏览器的原因。
--- 再说一次,我只是展示了如何在没有额外代码的情况下获得结果,但要执行其他行,当然,您必须为此编写代码。
因此我仍然需要设置浏览器和选项。此外,现在单击按钮并打开浏览器后,它不会关闭窗口/脚本。不要认为这是一个“不满意”的评论 - 它不是。只是增加了一些小故障。–
--- 不用担心。这只是让您开始的信息。您可以对用例进行进一步更改,只有您自己知道那是什么。