Powershell:函数的意外返回值,使用$args访问参数
好的,我已经用不同的语言编写了很长一段时间了,但是我没有得到PowerShell函数返回的概念 我对Powershell非常陌生,所以我确信我遗漏了一些非常基本的东西 我有以下功能:Powershell:函数的意外返回值,使用$args访问参数,powershell,parameters,return-value,Powershell,Parameters,Return Value,好的,我已经用不同的语言编写了很长一段时间了,但是我没有得到PowerShell函数返回的概念 我对Powershell非常陌生,所以我确信我遗漏了一些非常基本的东西 我有以下功能: function plGetKeyValue ([string] $FileName, [string] $SectionName, [string] $Key) { if ($PSBoundParameters.Count -lt 2 -or $PSBoundParameters.Count -gt 3
function plGetKeyValue ([string] $FileName, [string] $SectionName, [string] $Key)
{
if ($PSBoundParameters.Count -lt 2 -or $PSBoundParameters.Count -gt 3 )
{
"Invalid call to {0} in {1}" -f $MyInvocation.MyCommand.Name,
$MyInvocation.MyCommand.ModuleName
return
}
# Declaration
$lFileContents = ""
$lSections = ""
$lDataStart = ""
$lStart = -1
$lEnd = -1
$lFoundSection = ""
$lNextSection = ""
$lResults = ""
$lRetValue = ""
# Handle the optional parameter.
if ( $PSBoundParameters.Count -eq 2 ) {
$PSBoundParameters.Add('Key', $SectionName)
$PSBoundParameters.Remove('SectionName')
$Key = $SectionName
$SectionName = $null
}
# Read the file in
$lFileContents = Get-Content $FileName | Select-String -Pattern .*
# Get the sections.
$lSections = $lFileContents -match '\['
$lSections = $lSections -notmatch '#'
# Start of the data.
$lDataStart = $lFileContents | Select-String -Pattern "^#", "^$" -NotMatch `
| select-object -First 1
# We have a section.
if ( $PSBoundParameters.ContainsKey( 'SectionName' ) ) {
# Find the section.
$lFoundSection = $lSections | Select-String -Pattern "$lSectionName\b"
# If none found we are out.
if ( -Not $lFoundSection) { return $lRetValue }
# Starting point for the key search is the line following
# the found section.
$lStart = $lFoundSection[0].LineNumber
# Loop through the sections and find the one after the found one.
$lNextSection = $lSections | ForEach-Object {
# If we hit it, break.
if ($_.LineNumber -gt $lStart) {
break;
}
}
# Set the ending line for the search to the end of the section
# or end of file. Which ever we have.
if ($lNextSection) {
$lEnd = $lNextSection[0].LineNumber
} else {
$lEnd = $lFileContents[-1]
}
} else {
# No section.
$lStart = $lDataStart.LineNumber
# Set the ending line for the search to the end of the section
# or end of file. Which ever we have.
if ($lSections) {
$lEnd = $lSections[0].LineNumber
} else {
$lEnd = $lFileContents[-1]
}
}
# Extract the lines starting with the key.
$lResults = $lFileContents[$lStart..$lEnd] -match "$Key\b"
# We got results.
# Split the value off.
return $lRetValue = $lResults[0] | Select -ExpandProperty "Line"
}
创建此函数的过程引发了几个问题,我对此进行了研究并感到困惑
1) 文档指出,应该使用$args来确定参数。对我来说,它似乎从来都不存在?我正在使用版本4?作为替代,我使用$PSBoundParameters。这样做明智吗
2) 基于大量的阅读和理解,我发现函数rturn的返回值都是未捕获的输出到管道。有人能澄清一下吗
例如,我希望下面的函数在变量$lRetValue中返回一个字符串。目前,它正在返回True。基于这一点,我相信我有一些不被接受的东西?但我正在执行的所有操作都被捕获到一个变量中。我错过了什么
调用例程以以下形式调用代码:
$FileName = "S:\PS\Home\GlobalConfig\jobs.cfg"
$key = "Help"
$section = "Section"
$r = plGetKeyValue $FileName $Key
write-host "r is: $r"
输出如下所示:
PS C:>S:\PS\Home\Job\Test.ps1
r:是的
非常感谢您的帮助。术语说明:我将在下面区分参数和参数:-作为函数声明一部分定义的占位符的参数,
-与参数不同,就像在给定调用中绑定到占位符的值一样 概念信息: 1) 文档指出,应该使用$args来确定参数
$args
是一种回退机制,用于检查非高级(非cmdlet)函数中的未绑定参数
$args
已填充:
- 仅当您的函数不是高级函数时(函数通过存在
参数声明语句标记为高级函数,而不是在param(…)
中声明参数,如果使用function someFunc(…)
属性修饰)[CmdletBinding()]
- 即使如此,它也只包含未绑定的参数(未映射到已声明参数的参数)
$args
仅当您声明的函数没有任何参数时才会包含所有传递的参数
相反,在高级函数中不能有未绑定的参数,使用无法绑定到参数的参数调用高级函数将失败(生成错误)
由于定义高级功能通常是可取的,因为它们最好与PowerShell基础架构作为一个整体集成,因此最好不使用$args
。相反,使用多个和/或数组参数的组合来覆盖所有可能的有效输入参数场景
$PSBoundArguments
包含绑定到已声明参数的参数,通常不需要,因为与参数名称相对应的变量名称(例如,$SectionName
)可以直接使用。(它有专门用途,例如通过splat@PSBoundArguments
将所有绑定参数传递给另一个cmdlet/函数)
2) 通过大量阅读和讨论,我发现函数的返回值将所有未捕获的输出返回到管道。有人能澄清一下“不适应”吗
通常,默认情况下,生成输出的任何PowerShell语句或表达式都会发送到成功流(与Unix shell中的stdout大致类似),除非捕获了输出(例如,通过分配给变量)或重定向了输出(例如,通过将输出发送到文件)
因此,与大多数编程语言的行为相反,如果不希望语句产生输出,则必须采取措施
如果您对语句的输出不感兴趣(而不是捕获/重定向它以供以后使用),则可以重定向到$null
(相当于/dev/null
)、管道到cmdlet输出null
,或分配给伪变量$null
($null=…
)
因此,可以说,您可以调用发送到未捕获成功流的输出
但是,这与return
语句无关:
return
语句的工作方式与其他语言不同;它在PowerShell中的主要用途是作为一种控制流机制(退出函数或脚本块),而不是作为一种输出数据的机制(尽管它也可以用于此目的:使用参数是将输出发送到成功流的另一种方式)
诊断您的特定问题: 有许多方法可以使您的函数成为更好的PowerShell公民[1] ,但你眼前的问题是:
$PSBoundParameters.Remove('SectionName')
返回发送到输出流的布尔值,因为您既不抑制、捕获也不重定向它。在您的情况下,由于$SectionName
参数已绑定,因此它在$PSBoundParameters
中确实有一个条目,因此$PSBoundParameters.Remove('SectionName')
返回$true
要抑制此不需要的输出,请使用以下方法:
$null = $PSBoundParameters.Remove('SectionName')
一般来说,除非您知道某个语句不生成输出,否则最好是安全的,并在$null=
前面加上前缀(或者使用等效的机制来抑制输出)
特别是对于对象的直接方法调用,通常不清楚是否会返回一个值,该值将转换为输出(发送到成功流)
[1] 以下帮助主题提供了更多信息:
-参数的使用,包括如何使用
帮助检查参数-