要发布 NuGet 包,只需要执行命令 nuget push xxx.nupkg
即可,或者去 nuget.org 点鼠标上传。
不过,如果你有很多的 NuGet 包并且经常需要推送的话,也可以集成到 Directory Opus 或者 Total Commander 中。
NuGet 推送命令可直接在微软官方文档中阅读到:
在你已经设置了 ApiKey 的情况下:
nuget setapikey xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx -source https://api.nuget.org/v3/index.json
之后你只需要执行一句命令即可:
nuget.exe push Walterlv.Themes.FluentDesign.Source.0.8.0-alpha.nupkg -source https://api.nuget.org/v3/index.json
或者推送此文件夹下 0.8.0-alpha 版本的所有 NuGet 包:
nuget.exe push *.0.8.0-alpha.nupkg -source https://api.nuget.org/v3/index.json
要执行 NuGet 的推送命令,我们需要一个可以执行命令的终端,比如 PowerShell。命令的执行结果我们也可以直接在终端看到。
不过,如果命令是集成到其他工具里面,那么就不一定能够看得到命令的执行结果了。
这个时候,可以考虑用 PowerShell 间接执行这个命令:
# PowerShell 版本
powershell -NoExit -c "nuget push *.0.8.0-alpha.nupkg -Source https://api.nuget.org/v3/index.json"
# PowerShell Core 版本
pwsh -NoExit -c "nuget push *.0.8.0-alpha.nupkg -Source https://api.nuget.org/v3/index.json"
关于使用 PowerShell 间接执行命令的更多细节,可以参考我的另一篇博客:
我将这个命令集成到了 Directory Opus 中,这样,一次点击或者一个快捷键就能发布某个特定版本的所有的 NuGet 包了。
关于使用 Directory Opus 继承工具栏按钮的细节,可以阅读我的另一篇博客:
具体来说,就是安装上文中所述的方法添加一个按钮,在按钮当中需要执行的脚本如下:
cd "{sourcepath} "
pwsh -NoExit -c "$file=[Regex]::Match('{file}', '\.\d+\.\d+\.\d+.+.nupkg').Value; nuget push *$file -Source https://api.nuget.org/v3/index.json"
含义为:
nuget push *.xxx.nupkg -Source https://api.nuget.org/v3/index.json
{file}
文件名{file}
是 Directory Opus 当前选中的文件,我用正则表达式匹配出其版本号和后面的 .nupkg
后缀nuget push
的包,最终生成的命令会非常类似于本文一开始提到的命令 nuget push *.0.8.0-alpha.nupkg -Source https://api.nuget.org/v3/index.json
于是,当我选中了一个包,按下这个工具栏按钮之后,就可以推送与这个包相同版本的所有的 NuGet 包了。
毕竟我一次编译产生的 NuGet 包太多了,还是需要使用这样的方式来提高一点效率。至于为什么不用持续集成,是因为目前 SourceYard 还不支持在 GitHub 上集成。
参考资料
有一些程序不支持被直接启动,而要求通过命令行启动。这个时候,你就需要使用 PowerShell 或者 PowerShell Core 来启动这样的程序。我们都知道如何在命令行或各种终端中启动一个程序,但是当你需要自动启动这个程序的时候,你就需要知道如何通过 PowerShell 或其他命令行终端来启动一个程序,而不是手工输入然后回车运行了。
本文就介绍 PowerShell 的命令行启动参数。利用这些参数,你可以自动化地通过 PowerShell 程序来完成一些原本需要通过手工执行的操作或者突破一些限制。
一般来说,编译生成的 exe 程序都可以直接启动,即便是命令行程序也是如此。但是有一些程序就是要做一些限制。比如下面的 FRP 反向代理程序:
借助 cmd.exe 来启动的方法可以参见我的另一篇博客:
那么我们如何能够借助于 PowerShell 或者 PowerShell 来启动它呢?
先打开一个 PowerShell。
对于 Windows 自带的基于 .NET Framework 的 PowerShell,使用 powershell
命令可以直接启动 PowerShell。对于基于 .NET Core 版本的 PowerShell Core,使用 pwsh
命令可以直接启动。
关于 .NET Core 版本的 PowerShell Core 可以参见我的另一篇博客:
接下来输入下面三个命令中的任何一个:
PowerShell -Help
PowerShell -?
PowerShell /?
或者对于 PowerShell Core 来说,是下面三个命令中的任何一个:
pwsh -Help
pwsh -?
pwsh /?
你就可以看到 PowerShell 的使用说明:
下面的命令,使用 PowerShell 间接启动 frpc.exe 反向代理程序,并给 frpc.exe 程序传入 -c ./frpc.ini
的启动参数:
> pwsh -Command "D:\walterlv\frpc.exe -c ./frpc.ini"
或者简写为:
> pwsh -c "D:\walterlv\frpc.exe -c ./frpc.ini"
实际上使用 PowerShell 来做这些事情简直是用牛刀杀鸡,因为本身 PowerShell 非常强大。我们只是因为一些程序的限制不得不使用这样的方案来启动程序而已。
比如其中之一,执行脚本。
需要加上 -NoExit
参数。
> pwsh -NoExit -c "D:\walterlv\frpc.exe -c ./frpc.ini"
一定要注意,-c
和后面的命令必须放到最末尾,因为 -c
后面的所有字符串都会被解析为需要执行的命令。
多条脚本之间使用 ;
作为分隔:
> pwsh -c "D:\walterlv\frpc.exe -c ./frpc.ini"; "D:\walterlv\frps.exe -c ./frps.ini"
如果引号里面还需要写引号,则可以把里面的引号改成单引号 '
或者把外面的引号改为单引号 '
。
# Execute a PowerShell Command in a session
PowerShell -Command "Get-EventLog -LogName security"
# Run a script block in a session
PowerShell -Command {Get-EventLog -LogName security}
# An alternate way to run a command in a new session
PowerShell -Command "& {Get-EventLog -LogName security}"
PowerShell[.exe] [-PSConsoleFile <文件> | -Version <版本>] [-NoLogo] [-NoExit] [-Sta] [-Mta] [-NoProfile] [-NonInteractive] [-InputFormat {Text | XML}] [-OutputFormat {Text | XML}] [-WindowStyle <样式>] [-EncodedCommand <Base64 编码命令>] [-ConfigurationName <字符串>] [-File <文件路径> <参数>] [-ExecutionPolicy <执行策略>] [-Command { - | <脚本块> [-args <参数数组>] | <字符串> [<命令参数>] } ] PowerShell[.exe] -Help | -? | /? -PSConsoleFile 加载指定的 Windows PowerShell 控制台文件。若要创建控制台 文件,请在 Windows PowerShell 中使用 Export-Console。 -Version 启动指定版本的 Windows PowerShell。 使用参数输入版本号,如 "-version 2.0"。 -NoLogo 启动时隐藏版权标志。 -NoExit 运行启动命令后不退出。 -Sta 使用单线程单元启动 shell。 单线程单元(STA)是默认值。 -Mta 使用多线程单元启动 shell。 -NoProfile 不加载 Windows PowerShell 配置文件。 -NonInteractive 不向用户显示交互式提示。 -InputFormat 描述发送到 Windows PowerShell 的数据的格式。有效值为 "Text" (文本字符串)或 "XML" (序列化的 CLIXML 格式)。 -OutputFormat 确定如何设置 Windows PowerShell 输出内容的格式。有效值 为 "Text" (文本字符串)或 "XML" (序列化的 CLIXML 格式)。 -WindowStyle 将窗口样式设置为 Normal、Minimized、Maximized 或 Hidden。 -EncodedCommand 接受 base-64 编码字符串版本的命令。使用此参数 向 Windows PowerShell 提交需要复杂引号 或大括号的命令。 -ConfigurationName 指定运行 Windows PowerShell 的配置终结点。 该终结点可以是在本地计算机上注册的任何终结点,包括 默认的 Windows PowerShell 远程处理终结点或具有特定用户角色功能 的自定义终结点。 -File 在本地作用域("dot-sourced")中运行指定的脚本,以便 脚本创建的函数和变量可以在当前 会话中使用。输入脚本文件路径和任何参数。 File 必须是命令中的最后一个参数,因为在 File 参数 名称后面键入的所有字符都将解释 为后跟脚本参数的脚本文件路径。 -ExecutionPolicy 设置当前会话的默认执行策略,并将其保存 在 $env:PSExecutionPolicyPreference 环境变量中。 该参数不会更改在注册表中 设置的 Windows PowerShell 执行策略。 -Command 执行指定的命令(和任何参数),就好像它们是 在 Windows PowerShell 命令提示符下键入的一样,然后退出,除非 指定了 NoExit。Command 的值可以为 "-"、字符串或 脚本块。 如果 Command 的值为 "-",则从标准输入中读取 命令文本。 如果 Command 的值为脚本块,则脚本块必须 用大括号({})括起来。只有在 Windows PowerShell 中运行 PowerShell.exe 时, 才能指定脚本块。脚本块的结果将作为反序列化的 XML 对象 (而非活动对象)返回到父 Shell。 如果 Command 的值为字符串,则 Command 必须是命令中的 最后一个参数,因为在命令后面键入的所有字符 都将解释为命令参数。 若要编写运行 Windows PowerShell 命令的字符串,请使用以下格式: "& {<命令>}" 其中,引号表示一个字符串,调用运算符(&) 导致执行命令。 -Help, -?, /? 显示此消息。如果在 Windows PowerShell 中键入 PowerShell.exe 命令,请在命令参数前面添加连字符(-),而不是添加正 斜杠(/)。你可以在 Cmd.exe 中使用连字符或正斜杠。 示例 PowerShell -PSConsoleFile SqlSnapIn.Psc1 PowerShell -version 2.0 -NoLogo -InputFormat text -OutputFormat XML PowerShell -ConfigurationName AdminRoles PowerShell -Command {Get-EventLog -LogName security} PowerShell -Command "& {Get-EventLog -LogName security}" # To use the -EncodedCommand parameter: $command = 'dir "c:\program files" ' $bytes = [System.Text.Encoding]::Unicode.GetBytes($command) $encodedCommand = [Convert]::ToBase64String($bytes) powershell.exe -encodedCommand $encodedCommand
参考资料
有一些程序不支持被直接启动,而要求通过命令行启动。这个时候,你就需要使用 cmd.exe 来启动这样的程序。我们都知道如何在 cmd.exe 中启动一个程序,但是当你需要自动启动这个程序的时候,你就需要知道如何通过 cmd.exe 来启动一个程序,而不是手工输入然后回车运行了。
本文就介绍 cmd.exe 的命令行启动参数。利用这些参数,你可以自动化地通过 cmd.exe 程序来完成一些原本需要通过手工执行的操作或者突破一些限制。
一般来说,编译生成的 exe 程序都可以直接启动,即便是命令行程序也是如此。但是有一些程序就是要做一些限制。比如下面的 FRP 反向代理程序:
那么我们如何能够借助于 cmd.exe 来启动它呢?接下来说明。
顺便,使用 PowerShell 来启动的方法可以参见我的另一篇博客:
先打开一个 cmd,然后输入:
> cmd /?
你就可以看到 cmd.exe 的使用说明:
启动 Windows 命令解释器的一个新实例
CMD [/A | /U] [/Q] [/D] [/E:ON | /E:OFF] [/F:ON | /F:OFF] [/V:ON | /V:OFF] [[/S] [/C | /K] string]
你可以随时输入上面的 cmd /?
命令来查看这些参数详细说明,所以本文不会非常详细地列举各个参数的含义,只会列出一些常见的使用示例。
下面的命令,使用 cmd 间接启动 frpc.exe 反向代理程序,并给 frpc.exe 程序传入 -c ./frpc.ini
的启动参数:
> cmd /c D:\walterlv\frp\frpc.exe -c ./frpc.ini
关于为什么会用这种方式启动 frpc.exe,则是为了设置 frpc.exe 为开机自动启动。
因为我写了一些 Asp.NET Core 的服务,详见:
另外,间接启动一个程序的时候也可以传入 /k
参数。与 /c
参数不同的是:
/c
在执行完程序之后,cmd.exe 也会终止/k
在执行完程序之后,cmd.exe 依然会继续运行所以 /c
命令会更适用于自动化的脚本,而 /k
命令则更适用于半自动化的脚本。
在上面的例子中,我们的路径中不涉及到空格。我们知道,路径中有空格的话,在命令行中使用需要加上引号。但实际上如果你真的给路径加上了引号,会发现 cmd.exe 就开始不识别你的命令路径了。
这个时候,你需要在整个传给 cmd.exe 的命令外层再加一层引号:
> cmd /c " "D:\walterlv folders\frp\frpc.exe" -c ./frpc.ini "
以上,感谢 林德熙 挥泪踩出来的坑,详见:
启动 Windows 命令解释器的一个新实例
CMD [/A | /U] [/Q] [/D] [/E:ON | /E:OFF] [/F:ON | /F:OFF] [/V:ON | /V:OFF] [[/S] [/C | /K] string]
/C 执行字符串指定的命令然后终止 /K 执行字符串指定的命令但保留 /S 修改 /C 或 /K 之后的字符串处理(见下) /Q 关闭回显 /D 禁止从注册表执行 AutoRun 命令(见下) /A 使向管道或文件的内部命令输出成为 ANSI /U 使向管道或文件的内部命令输出成为 Unicode /T:fg 设置前台/背景颜色(详细信息见 COLOR /?) /E:ON 启用命令扩展(见下) /E:OFF 禁用命令扩展(见下) /F:ON 启用文件和目录名完成字符(见下) /F:OFF 禁用文件和目录名完成字符(见下) /V:ON 使用 ! 作为分隔符启用延迟的环境变量 扩展。例如,/V:ON 会允许 !var! 在执行时 扩展变量 var。var 语法会在输入时 扩展变量,这与在一个 FOR 循环内不同。 /V:OFF 禁用延迟的环境扩展。
注意,如果字符串加有引号,可以接受用命令分隔符 “&&” 分隔多个命令。另外,由于兼容性 原因,/X 与 /E:ON 相同,/Y 与 /E:OFF 相同,且 /R 与 /C 相同。任何其他开关都将被忽略。
如果指定了 /C 或 /K,则会将该开关之后的 命令行的剩余部分作为一个命令行处理,其中,会使用下列逻辑 处理引号(“)字符:
1. 如果符合下列所有条件,则会保留 命令行上的引号字符: - 不带 /S 开关 - 正好两个引号字符 - 在两个引号字符之间无任何特殊字符, 特殊字符指下列字符: &<>()@^| - 在两个引号字符之间至少有 一个空格字符 - 在两个引号字符之间的字符串是某个 可执行文件的名称。 2. 否则,老办法是看第一个字符 是否是引号字符,如果是,则去掉首字符并 删除命令行上最后一个引号,保留 最后一个引号之后的所有文本。
如果 /D 未在命令行上被指定,当 CMD.EXE 开始时,它会寻找 以下 REG_SZ/REG_EXPAND_SZ 注册表变量。如果其中一个或 两个都存在,这两个变量会先被执行。
HKEY_LOCAL_MACHINE\Software\Microsoft\Command Processor\AutoRun 和/或 HKEY_CURRENT_USER\Software\Microsoft\Command Processor\AutoRun
命令扩展是按默认值启用的。你也可以使用 /E:OFF ,为某一 特定调用而停用扩展。你 可以在机器上和/或用户登录会话上 启用或停用 CMD.EXE 所有调用的扩展,这要通过设置使用 REGEDIT.EXE 的注册表中的一个或两个 REG_DWORD 值:
HKEY_LOCAL_MACHINE\Software\Microsoft\Command Processor\EnableExtensions 和/或 HKEY_CURRENT_USER\Software\Microsoft\Command Processor\EnableExtensions
到 0x1 或 0x0。用户特定设置 比机器设置有优先权。命令行 开关比注册表设置有优先权。
在批处理文件中,SETLOCAL ENABLEEXTENSIONS 或 DISABLEEXTENSIONS 参数 比 /E:ON 或 /E:OFF 开关有优先权。请参阅 SETLOCAL /? 获取详细信息。
命令扩展包括对下列命令所做的 更改和/或添加:
DEL or ERASE COLOR CD or CHDIR MD or MKDIR PROMPT PUSHD POPD SET SETLOCAL ENDLOCAL IF FOR CALL SHIFT GOTO START (同时包括对外部命令调用所做的更改) ASSOC FTYPE
有关特定详细信息,请键入 commandname /? 查看。
延迟环境变量扩展不按默认值启用。你 可以用/V:ON 或 /V:OFF 开关,为 CMD.EXE 的某个调用而 启用或停用延迟环境变量扩展。你 可以在机器上和/或用户登录会话上启用或停用 CMD.EXE 所有 调用的延迟扩展,这要通过设置使用 REGEDIT.EXE 的注册表中的 一个或两个 REG_DWORD 值:
HKEY_LOCAL_MACHINE\Software\Microsoft\Command Processor\DelayedExpansion 和/或 HKEY_CURRENT_USER\Software\Microsoft\Command Processor\DelayedExpansion
到 0x1 或 0x0。用户特定设置 比机器设置有优先权。命令行开关 比注册表设置有优先权。
在批处理文件中,SETLOCAL ENABLEDELAYEDEXPANSION 或 DISABLEDELAYEDEXPANSION 参数比 /V:ON 或 /V:OFF 开关有优先权。请参阅 SETLOCAL /? 获取详细信息。
如果延迟环境变量扩展被启用, 惊叹号字符可在执行时间被用来 代替一个环境变量的数值。
你可以用 /F:ON 或 /F:OFF 开关为 CMD.EXE 的某个 调用而启用或禁用文件名完成。你可以在计算上和/或 用户登录会话上启用或禁用 CMD.EXE 所有调用的完成, 这可以通过使用 REGEDIT.EXE 设置注册表中的下列 REG_DWORD 的全部或其中之一:
HKEY_LOCAL_MACHINE\Software\Microsoft\Command Processor\CompletionChar HKEY_LOCAL_MACHINE\Software\Microsoft\Command Processor\PathCompletionChar 和/或 HKEY_CURRENT_USER\Software\Microsoft\Command Processor\CompletionChar HKEY_CURRENT_USER\Software\Microsoft\Command Processor\PathCompletionChar
由一个控制字符的十六进制值作为一个特定参数(例如,0x4 是Ctrl-D,0x6 是 Ctrl-F)。用户特定设置优先于机器设置。 命令行开关优先于注册表设置。
如果完成是用 /F:ON 开关启用的,两个要使用的控制符是: 目录名完成用 Ctrl-D,文件名完成用 Ctrl-F。要停用 注册表中的某个字符,请用空格(0x20)的数值,因为此字符 不是控制字符。
如果键入两个控制字符中的一个,完成会被调用。完成功能将 路径字符串带到光标的左边,如果没有通配符,将通配符附加 到左边,并建立相符的路径列表。然后,显示第一个相符的路 径。如果没有相符的路径,则发出嘟嘟声,不影响显示。之后, 重复按同一个控制字符会循环显示相符路径的列表。将 Shift 键跟控制字符同时按下,会倒着显示列表。如果对该行进行了 任何编辑,并再次按下控制字符,保存的相符路径的列表会被 丢弃,新的会被生成。如果在文件和目录名完成之间切换,会 发生同样现象。两个控制字符之间的唯一区别是文件完成字符 符合文件和目录名,而目录完成字符只符合目录名。如果文件 完成被用于内置式目录命令(CD、MD 或 RD),就会使用目录 完成。 用引号将相符路径括起来,完成代码可以正确处理含有空格 或其他特殊字符的文件名。同时,如果备份,然后从行内调用 文件完成,完成被调用时位于光标右方的文字会被调用。
需要引号的特殊字符是:
<space>
()[]{}^=;!'+,
~(&()`
Windows 自带一个强大的 PowerShell,不过自带的 PowerShell 一直是基于 .NET Framework 的版本。你可以下载安装一个 .NET Core 版本的 PowerShell,以便获得 .NET Core 的各种好处。包括跨平台,以及更好的性能。
本文将介绍在你的 Windows 系统上安装一个 .NET Core 版本的 PowerShell。
前往 .NET Core 版本 PowerShell 的发布页面来下载 PowerShell 全平台的安装包:
Windows 平台上建议下载 msi 格式的安装包,这样它可以帮助你完成大多数的安装任务。
在安装完成之后启动新的 .NET Core 版本的 PowerShell 可以看见新的 PowerShell。
在任何一个文件夹中右键可打开 PowerShell 或者以管理员权限打开 PowerShell。这与自带的 PowerShell 的玩法是类似的。
如果你要在其他的终端使用 PowerShell Core,直接输入 pwsh
即可。其原理可以参考我的另一篇博客:
在 WPF 开发时,有 Snoop 的帮助,UI 的调试将变得非常轻松。使用 Snoop,能轻松地查看 WPF 中控件的可视化树以及每一个 Visual 节点的各种属性,或者查看数据上下文,或者监听查看事件的引发。
不过,更强大的是支持使用 PowerShell 脚本。这使得它即便 UI 没有给你提供一些入口,你也能通过各种方式查看或者修改 UI。
常规 Snoop 的使用方法,将狮子瞄准镜拖出来对准要调试 UI 的 WPF 窗口松开。这里我拿 Visual Studio 2019 的窗口做试验。
在打开的新的 Snoop 窗口中我们打开 PowerShell 标签。
本文的内容将从这里开始。
在 Snoop 的 PowerShell 提示窗口中,我们可以得知有两个变量可以使用:$root
和 $selected
。包含这两个,还有其他的可以使用:
$root
拿到当前 Snoop 窗口顶层元素类型的实例$selected
拿到当前 Snoop 用鼠标或键盘选中的元素的实例$parent
拿到当前 Snoop 选中元素的可视化树父级$null
就是 .NET 中的 null当然,你也可以定义和使用其他的变量,后面会说。
# 获取属性
$selected.Visual.Content
# 将属性设置为 null
$selected.Visual.Content = $null
直接像 C# 语法那样一直在后面使用 .
可以访问实例中的属性。不需要关心实例是什么类型的,只要拥有那个属性,就可以访问到。
比如下面,上面的例子我们选中的是 MainWindow
,于是我们使用 $selected.Visual.Content
访问到 MainWindow
的 Content
属性,而后面 $selected.Visual.Content = $null
则是将 Window
的内容清空了。
# 创建对象
$button = New-Object System.Windows.Controls.Button -property @{ Content = "欢迎访问 blog.walterlv.com" }
$selected.Visual.Children.Add($button)
顶部的那个按钮就是通过上面的命令添加上去的。
调用静态方法用的是 [类名]::方法名(参数)
$button.Content = [System.Environment]::Version.ToString() + " running for blog.walterlv.com"
参考资料