ChatGPT解决这个技术问题 Extra ChatGPT

在 PowerShell 中,如何在文件中定义函数并从 PowerShell 命令行调用它?

我有一个 .ps1 文件,我想在其中定义自定义函数。

想象一下这个文件叫MyFunctions.ps1,内容如下:

Write-Host "Installing functions"
function A1
{
    Write-Host "A1 is running!"
}
Write-Host "Done"

要运行此脚本并在理论上注册 A1 函数,我导航到 .ps1 文件所在的文件夹并运行该文件:

.\MyFunctions.ps1

这输出:

Installing functions
Done

然而,当我尝试调用 A1 时,我只是收到错误消息,指出没有该名称的命令/函数:

The term 'A1' 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 line:1 char:3
+ A1 <<<<
    + CategoryInfo          : ObjectNotFound: (A1:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

我必须误解一些 PowerShell 概念。我不能在脚本文件中定义函数吗?

请注意,我已经将执行策略设置为“RemoteSigned”。而且我知道在文件名前使用一个点来运行 .ps1 文件:.\myFile.ps1

PS 启动时加载函数的好链接:sandfeld.net/powershell-load-your-functions-at-startup

T
The Red Pea

在 PowerShell 命令行上试试这个:

. .\MyFunctions.ps1
A1

点运算符用于脚本包含,也称为“点源”(或 "dot source notation"


好吧,它的意思是“在当前上下文而不是子上下文中运行它”。
这意味着 source 这个文件的内容。与 bash 中的相同。 ss64.com/bash/period.html
除非您首先运行 .\MyFunctions.ps1 以使其可用,否则它似乎不能很好地工作(至少来自 ISE)。我不确定是否严格从 powershell.exe 运行。
我认为点源使用相对于密码而不是脚本的路径是违反直觉的,所以我会敦促人们改用 JoeG 的答案并使用模块。
@Spork . "$PSScriptRoot\MyFunctions.ps1"。从 v3 开始可用,在此之前请参阅 stackoverflow.com/questions/3667238/…。这是很常见的。
D
Dave F

您所说的称为dot sourcing。这是邪恶的。不过不用担心,使用 modules 有一种更好、更简单的方法来做你想做的事(听起来比实际更可怕)。使用模块的主要好处是,如果需要,您可以从外壳中卸载它们,并且它可以防止函数中的变量潜入外壳(一旦您点源函数文件,请尝试从在 shell 中运行,你会明白我的意思)。

因此,首先,将包含所有函数的 .ps1 文件重命名为 MyFunctions.psm1(您刚刚创建了一个模块!)。现在要正确加载模块,您必须对文件执行一些特定操作。首先要让 Import-Module 查看模块(您使用此 cmdlet 将模块加载到 shell 中),它必须位于特定位置。模块文件夹的默认路径是 $home\Documents\WindowsPowerShell\Modules。

在该文件夹中,创建一个名为 MyFunctions 的文件夹,并将 MyFunctions.psm1 文件放入其中(模块文件必须位于与 PSM1 文件同名的文件夹中)。

完成后,打开 PowerShell,然后运行以下命令:

Get-Module -listavailable

如果您看到一个名为 MyFunctions 的功能,那么您做对了,并且您的模块已准备好加载(这只是为了确保设置正确,您只需执行一次)。

要使用该模块,请在 shell 中键入以下内容(或将此行放在 $profile 中,或将其作为脚本的第一行):

Import-Module MyFunctions

您现在可以运行您的函数。很酷的一点是,一旦你有 10-15 个函数,你就会忘记一对夫妇的名字。如果您将它们放在模块中,则可以运行以下命令来获取模块中所有函数的列表:

Get-Command -module MyFunctions

它非常可爱,而且在前端设置所需的一点点努力是值得的。


如果您的函数仅与给定的 PowerShell 应用程序相关,那该怎么办?我的意思是,如果您在某处安装 PS1 软件包来完成工作,您可能不希望配置文件中的所有功能,对吧?
在这种情况下,我会为该特定应用程序创建一个模块,并在运行脚本之前加载它(如果以交互方式工作),或者在脚本中加载它。但一般来说,如果您有特定于给定任务的代码,您会希望脚本中包含这些函数。就我个人而言,我只编写通常做一件事的函数。如果一段代码是高度专业化的,那么将它包装在一个函数或模块中是没有意义的(除非有几个脚本使用相同的代码,那么它可能是有意义的)。
模块文件不必位于与 PSM1 文件同名的文件夹中。可以像 Import-Module .\buildsystem\PSUtils.psm1 一样完成
@MichaelFreidgeim,如果它像用 Import-Module 更改 . 并重命名扩展名一样简单,并且不需要将模块放置在特定文件夹中,即我可以将它放在我想要的任何目录中,只需与点源一样,考虑到范围界定的好处,是否有任何理由甚至对模块进行点源? (当然,除非那些范围“问题”是你想要的)
@Abdul,点源更简单,模块更强大。请参阅stackoverflow.com/questions/14882332/…
C
Community

. "$PSScriptRoot\MyFunctions.ps1" MyA1Func

从 v3 开始可用,在此之前请参阅 How can I get the file system location of a PowerShell script?。这是很常见的。

PS 我不订阅“一切都是模块”规则。我的脚本被 GIT 之外的其他开发人员使用,所以我不喜欢在我的脚本运行之前将东西放在特定的地方或修改系统环境变量。它只是一个脚本(或两个,或三个)。


FWIW,您不必为了在模块中运行脚本而做任何这些事情。
@NickCox 我很想看到一些例子。你有什么? +10 如果示例来自 OSS 项目。具体来说,通过相对路径(不是 PSModulePath 或没有自定义 PSModulePath)加载 PS 模块的示例,以及不平凡的示例(即,模块比普通脚本作用域更有优势的地方)。
我经常从相对路径导入 FluentMigrator.PowerShell 模块。这让我们可以将它检查到源代码控制中,并确保每个人都使用相同的版本。它运作良好。
我不确定将其打包为模块与脚本的相对优缺点:也许这是与作者讨论的问题?我猜对 Get-Command -Module FluentMigrator.PowerShell 的能力非常好?
@NickCox您没有完全限定该命令中的模块路径,这意味着除非您将模块复制到全局模块文件夹或将GIT文件夹添加到全局环境变量中,否则找不到它。我想你只是证明了我的观点。
J
Jonny

您当然可以在脚本文件中定义函数(然后我倾向于在加载时通过我的 Powershell 配置文件加载它们)。

首先,您需要检查以确保通过运行加载该函数:

ls function:\ | where { $_.Name -eq "A1"  }

并检查它是否出现在列表中(应该是 1 的列表!),然后让我们知道你得到了什么输出!


在 PowerShell 中,函数被视为一个目录,因此它与 c:\ 或 d:\ 相同。同样,您可以在没有反斜杠的情况下使用 ls 函数:|其中 { $_.Name -eq "A1" }
s
sɐunıɔןɐqɐp

您可以将功能添加到:

c:\Users\David\Documents\WindowsPowerShell\profile.ps1

该功能将可用。


b
bergmeister

如果您的文件只有一个您想要调用/公开的主要功能,那么您也可以使用以下方式启动文件:

Param($Param1)

然后你可以调用它,例如如下:

.\MyFunctions.ps1 -Param1 'value1'

如果您想轻松调用该函数而无需导入该函数,这将更加方便。


我还应该注意,我今天发现(在我的一位同事告诉我之后)PowerShell 会自动添加 [CmdletBinding()] 属性并将其免费升级为高级功能。 :-)
B
Bytekoder

假设您有一个名为 Dummy-Name.psm1 的模块文件,其中有一个名为 Function-Dumb() 的方法

Import-Module "Dummy-Name.psm1";
Get-Command -Module "Function-Dumb";
#
#
Function-Dumb;

关注公众号,不定期副业成功案例分享
关注公众号

不定期副业成功案例分享

领先一步获取最新的外包任务吗?

立即订阅