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

wil*_*lem 214 powershell

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

想象一下,该文件名为MyFunctions.ps1,内容如下:

Write-Host "Installing functions"
function A1
{
    Write-Host "A1 is running!"
}
Write-Host "Done"
Run Code Online (Sandbox Code Playgroud)

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

.\MyFunctions.ps1
Run Code Online (Sandbox Code Playgroud)

这输出:

Installing functions
Done
Run Code Online (Sandbox Code Playgroud)

然而,当我尝试调用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
Run Code Online (Sandbox Code Playgroud)

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

请注意,我已将执行策略设置为"RemoteSigned".我知道使用文件名前面的点运行.ps1文件:.\ myFile.ps1

rsc*_*rsc 236

在PowerShell命令行上尝试此操作:

. .\MyFunctions.ps1
A1
Run Code Online (Sandbox Code Playgroud)

点运算符用于脚本包含.

  • 这意味着**源**这个文件的内容.与**bash**相同​​.http://ss64.com/bash/period.html (15认同)
  • 嗯,这意味着"在当前上下文中运行它而不是子上下文." (11认同)
  • 它的意思是"包括". (5认同)
  • @Spork` "$ PSScriptRoot\MyFunctions.ps1"`.可以从v3开始,之后再看http://stackoverflow.com/questions/3667238/how-can-i-get-the-file-system-location-of-a-powershell-script.这很常见. (4认同)
  • 它似乎不能很好地工作(至少从ISE),除非你先运行.\ MyFunctions.ps1使其可用.我不确定严格运行powershell.exe. (2认同)

Joe*_*oeG 204

你所说的是点源.这是邪恶的.但不用担心,有一个更好,更简单的方法来做你想要的模块(听起来比它更可怕).使用模块的主要好处是,如果需要,可以从shell中卸载它们,并且它可以使函数中的变量不再嵌入到shell中(一旦你点了一个函数文件,尝试调用一个变量来自一个在shell中运行,你会看到我的意思).

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

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

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

Get-Module -listavailable
Run Code Online (Sandbox Code Playgroud)

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

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

Import-Module MyFunctions
Run Code Online (Sandbox Code Playgroud)

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

Get-Command -module MyFunctions
Run Code Online (Sandbox Code Playgroud)

它非常甜美,在正面设置所需的一点点努力都是值得的.

  • 模块文件不必位于与PSM1文件名称完全相同的文件夹中.它可以像`Import-Module.\ buildsystem\PSUtils.psm1`那样完成 (12认同)
  • 如果您的功能仅与给定的PowerShell应用程序相关,那该怎么办?我的意思是,如果你安装PS1的软件包在某个地方做某个工作,你可能不想要你的个人资料中的每个功能,对吗? (5认同)
  • 在这种情况下,我将为该特定应用程序创建一个模块,然后在运行脚本之前加载它(如果是交互式工作),或者在脚本中加载它。但是通常来说,如果您的代码仅特定于给定任务,则需要脚本中的那些功能。就我个人而言,我只编写通常做一件事的函数。如果一段代码是高度专业化的,那么将其包装在一个函数或模块中就没有任何意义(除非有多个脚本使用同一代码,否则这才有意义)。 (2认同)
  • @MichaelFreidgeim如果只是简单地用`Import-Module`更改`.`并重命名扩展名,并且不需要将模块放在特定文件夹中,即我可以将它放在我想要的任何目录中就像点源一样,考虑到范围界定的好处,是否有任何理由甚至可以对模块进行点源采购?(除非那些范围"问题"是你想要的) (2认同)
  • @Abdul,点源更简单,模块更强大.见http://stackoverflow.com/questions/14882332/powershell-import-module-vs-dot-sourcing/14882447#14882447 (2认同)
  • 根据[这个问题](/sf/ask/448904501/),模块文件必须放在同名的文件夹中,例如`$modulesDir \MyFunctions\MyFunctions.psm1`。 (2认同)
  • 这对我有用`导入模块“$PSScriptRoot\GetTacos.psm1”` (2认同)

yzo*_*org 16

. "$PSScriptRoot\MyFunctions.ps1" MyA1Func

可以从v3开始,之前看看如何获取PowerShell脚本的文件系统位置?.这很常见.

PS我不赞成"一切都是模块"的规则.我的脚本被GIT中的其他开发人员使用,所以我不喜欢在我的脚本运行之前将内容放在特定的位置或修改系统环境变量.它只是一个脚本(或两个或三个).


ber*_*ter 7

如果您的文件只有一个要调用/公开的主要函数,那么您也可以使用以下命令启动该文件:

Param($Param1)
Run Code Online (Sandbox Code Playgroud)

然后您可以如下调用它:

.\MyFunctions.ps1 -Param1 'value1'
Run Code Online (Sandbox Code Playgroud)

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


Jon*_*nny 6

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

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

ls function:\ | where { $_.Name -eq "A1"  }
Run Code Online (Sandbox Code Playgroud)

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


小智 6

您可以将功能添加到:

c:\Users\David\Documents\WindowsPowerShell\profile.ps1
Run Code Online (Sandbox Code Playgroud)

该功能将可用。