基本 PowerShell 功能无输出

Obs*_*let 2 powershell function

自从我开始使用 PowerShell 以来已经有一段时间了,到今天我可以说我已经完成了很多日常任务。不过,在学校每天都是新的一天,现在,当我开始使用函数时,我再次绊倒......这是我的问题:

即使使用许多初学者教程中的最简单的功能,它也无法在我的工作电脑、家庭电脑和工作管理服务器上运行。

例如:

function MyDate {
    Get-Date
}
Run Code Online (Sandbox Code Playgroud)

将名为 MyDate.ps1 的 PS1 文件保存到本地文件夹,然后从 PowerShell 提示符中运行这个小东西,如下所示

PS C:\PS> C:\PS\MyDate.ps1
Run Code Online (Sandbox Code Playgroud)

这就是 PS-Functions-for-Dummies 教程中准确解释的方式。就在教程中,输出应该显示日期。在我的情况下,什么都没有。没有错误,没有红色 PS 特定信息,什么都没有!如果我在完整脚本中使用该函数,如下所示:

function MyDate {
    Get-Date
}
MyDate

PS C:\PS> C:\PS\MyDate.ps1

Montag, 1. Oktober 2018 19:28:32
Run Code Online (Sandbox Code Playgroud)

好吧,然后我得到日期输出。想知道为什么不直接从提示符处调用而不调用脚本中的函数,因为应该使用函数?再说一遍,在许多非常简单的例子中,它应该可以工作。那么我错在哪里呢?


编辑:不确定现在这是否是向问题添加更多更新的正确政策?

我可能会分享一个更具体的脚本示例以及我如何将其“转换”为函数。简短的例子是:

$myServers = Get-Content D:\Servers\Windows2016.txt
foreach ($myServer in $myServers) {
    Get-Printer -ComputerName $myServer |
        Where-Object {$_.DeviceType -eq "Printer"} |
        Select Name, PortName
}
Run Code Online (Sandbox Code Playgroud)

对于其他支持团队来说,它必须尽可能简单。所以我的想法是围绕这几行“包装”一个函数,以便另一个人可以像这样执行它

C:\Scripts\Our-Printers -File D:\Servers\Windows2016.txt
Run Code Online (Sandbox Code Playgroud)

Our-Printers当然,这将是我的函数名称。

我已经尝试过,但放弃了这些东西,因为它在第一次尝试中不起作用,这就是为什么我想从非常基本的东西开始,目前看来我不明白。但顺便说一句,在脚本中我的函数已经可以工作了,只是它们不需要以示例的方式进行输入。这意味着我在一个大脚本中定义了函数,这样我就可以根据用户输入更改顺序甚至跳过某些函数......

Ans*_*ers 5

在脚本中定义函数意味着您编写可以通过符号名称调用的代码块。不过,该函数不会通过运行脚本自动调用。你仍然需要实际这样做。

PS C:\>获取内容 .\a.ps1
函数获取日期{
    获取日期
}
PS C:\> .\a.ps1 
PS C:\>获取内容 .\b.ps1
函数获取日期{
    获取日期
}
GetDate # ← 实际上调用函数
PS C:\> .\b.ps1

蒙塔格,1.2018 年 10 月 19:50:32

当调用脚本时,只有脚本中的(脚本)全局范围代码才会自动执行。

根据脚本的目的,这可能是也可能不是您想要的。例如,如果您打算仅从某些外部脚本或命令运行脚本以使其执行某些操作,则在执行脚本时自动调用该函数是有意义的。另一方面,如果您打算将脚本用作一种库,存储您希望能够单独调用的不同函数,则可以从脚本中省略函数调用。然后,您可以按照 Mathias 的描述对脚本进行点源并调用您需要的函数。

PS C:\>获取内容 .\a.ps1
函数获取日期{
    获取日期
}
PS C:\> . .\a.ps1     # ← 将函数定义加载到当前作用域
PS C:\> GetDate       # ← 实际调用该函数

蒙塔格,1.2018 年 10 月 19:50:32

编辑:无论哪种方式都可以实现您的最终目标。PowerShell 在启动时会自动获取一些文件(称为profile )。您可以定义一个函数并将其放入适当的配置文件中(每个用户或系统范围)。重新启动 PowerShell 后,人们就可以调用该函数了。

或者,您可以将代码放入脚本中(无需将其包装在函数中),然后将该脚本放在目标用户可以执行的位置。

这两种方法中哪一种更适合您的情况取决于多种因素。您有域或工作组吗?如果是域,您可以更改 AD 吗?您有可以放置文件的共享位置吗?你们有软件部署系统吗?等等。

另一个重要的问题是:用户将仅从 PowerShell 还是从其他地方(例如 CMD)调用代码。如果是后一种情况,通常会更喜欢脚本而不是配置文件中的函数。

无论哪种方式,您都可以像这样参数化您的脚本或函数:

[CmdletBinding()]
Param(
    [Parameter(Mandatory=$true)]
    [string]$File
)

$myServers = Get-Content $File
foreach ($myServer in $myServers) {
    Get-Printer -ComputerName $myServer |
        Where-Object {$_.DeviceType -eq "Printer"} |
        Select-Object Name, PortName
}
Run Code Online (Sandbox Code Playgroud)

参数定义分别位于脚本或函数的开头。

添加基于评论的帮助,以便人们可以运行Get-Help Our-PrintersOur-Printers -?查看他们应该如何使用它,例如

PS C:\> Get-Content .\a.ps1
function GetDate {
    Get-Date
}
PS C:\> .\a.ps1
PS C:\> Get-Content .\b.ps1
function GetDate {
    Get-Date
}
GetDate                  # ← actually invoke the function
PS C:\> .\b.ps1

Montag, 1. Oktober 2018 19:50:32

使用参数验证来强制输入有效,例如

[CmdletBinding()]
Param(
    [Parameter(Mandatory=$true)]
    [ValidateScript({Test-Path -LiteralPath $_})]
    [string]$File
)
Run Code Online (Sandbox Code Playgroud)