基本的PowerShell功能没有输出

时间:2018-10-01 17:34:25

标签: function powershell

距我刚开始与PowerShell相处已经有一段时间了,到今天我可以说我已经完成了很多日常任务。每天在学校都是新的一天,而现在,当我开始使用各种功能时,我又一次跌跌撞撞... 这是我的问题:

即使使用许多初学者教程中最简单的功能,它也不能在我的工作PC,家用PC或工作的管理服务器上运行。

例如:

function MyDate {
    Get-Date
}

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

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

这就是PS-Functions-for-Dummies教程中确切解释的方式。 仅在本教程中,输出应显示日期。在我看来,什么都没有。没有错误,没有关于红色PS的信息,什么都没有! 如果我在这样的完整脚本中使用该函数:

function MyDate {
    Get-Date
}
MyDate

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

Montag, 1. Oktober 2018 19:28:32

好吧,然后我得到了日期输出。 想知道为什么不直接在提示符下不调用脚本内的函数,因为应该使用函数吗? 同样,在许多这些非常简单的示例中,它应该可以工作。 那我哪里错了?


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

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

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

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

C:\Scripts\Our-Printers -File D:\Servers\Windows2016.txt

Our-Printers将成为我的函数名称。

我已经尝试过了,但是却放弃了这些东西,尽管它在第一次尝试中不起作用,这就是为什么我想从一些基本的东西开始,但现在看来我不明白。但是,顺便说一句,在脚本中我的功能已经起作用了,只是它们没有以示例的方式要求输入。这意味着我可以在大型脚本中定义函数,并可以根据用户输入更改顺序甚至跳过某些函数...

2 个答案:

答案 0 :(得分:3)

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

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

调用脚本时,仅会自动执行脚本中的(脚本-)全局作用域代码。

取决于脚本的目的,这可能不是您想要的。例如,如果您打算仅从某个外部脚本或命令运行该脚本以使其执行某些操作,则在执行脚本时自动调用该函数是有意义的。另一方面,如果您打算将该脚本用作一种库,并存储希望分别调用的不同函数,则可以从脚本中忽略函数调用。然后,您可以点播脚本as Mathias described并调用所需的函数。

PS C:\> Get-Content .\a.ps1
function GetDate {
    Get-Date
}
PS C:\> . .\a.ps1    # ← load the function definition into the current scope
PS C:\> GetDate      # ← actually invoke the function

Montag, 1. Oktober 2018 19:50:32

编辑:您的最终目标可以通过两种方式实现。有些文件(称为profiles)在启动时PowerShell会自动提供。您可以定义一个函数,并将其放在适当的配置文件中(针对每个用户或整个系统)。重新启动PowerShell之后,人们便可以调用该功能。

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

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

另一个重要的问题是:用户会从PowerShell还是从其他地方(例如CMD)调用代码。对于后一种情况,通常会首选脚本而不是配置文件中的功能。

您可以parametrize这样的脚本或函数:

[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
}

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

添加comment-based help,以便人们可以运行Get-Help Our-PrintersOur-Printers -?来查看应该如何使用它,例如

<#
.SYNOPSIS
List printers.

.DESCRIPTION
List printers. The computers to check are read from a file.

.PARAMETER File
A file with a list of computer names (one per line).
#>

使用parameter validation强制执行有效的输入,例如

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

答案 1 :(得分:2)

当脚本文件中有函数定义并且要“导入”该函数时,需要使用点源(.)运算符:

PS C:\PS> . C:\PS\MyDate.ps1
PS C:\PS> MyDate
Montag, 1. Oktober 2018 19:39:18

使用.运算符和仅按名称调用脚本之间的区别在于,.运算符在调用范围内运行脚本-意味着函数定义在执行后仍保留在您的Powershell会话中脚本停止执行。

您可以在about_Scopes help file

中了解有关范围的更多信息