我有以下代码:
$srv_range = 29..30+40+50..52
$srv_range.GetType()
$NewVMTemplate = New-Object psobject
$NewVMTemplate | Add-Member -MemberType NoteProperty -Name Name -Value $null
$srv_range | % {
$pod= $_
$servers = @()
1..2 | % {
$server = $NewVMTemplate | Select-Object *
$server.Name = "pod" + "{0:D2}" -f $pod + "-srv" + $_
$servers += $server
}
ForEach ( $server in $servers) {
write-host $server.Name
}
}
输出:
PowerCLI C:\ .\eraseme.ps1
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Object[] System.Array
pod29-srv1
pod29-srv2
pod30-srv1
pod30-srv2
pod40-srv1
pod40-srv2
pod50-srv1
pod50-srv2
pod51-srv1
pod51-srv2
pod52-srv1
pod52-srv2
我想从CLI输入范围,但是我使用此代码获得以下输出
param(
[Parameter(Mandatory=$False)] $srv_range
)
#$srv_range = 29..30+40+50..52
$srv_range.GetType()
$NewVMTemplate = New-Object psobject
$NewVMTemplate | Add-Member -MemberType NoteProperty -Name Name -Value $null
$srv_range | % {
$pod= $_
$servers = @()
1..2 | % {
$server = $NewVMTemplate | Select-Object *
$server.Name = "pod" + "{0:D2}" -f $pod + "-srv" + $_
$servers += $server
}
ForEach ( $server in $servers) {
write-host $server.Name
}
}
PowerCLI C:\ .\eraseme.ps1 29..30+40+50..52
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True String System.Object
pod29..30+40+50..52-srv1
pod29..30+40+50..52-srv2
如何从CLI输入范围并获得与第一个代码相同的结果?
答案 0 :(得分:11)
您的问题是论坛 29..30+40+50..52
在.\eraseme.ps1 29..30+40+50..52
来电中被视为字符串文字 - 表达。
要强制识别为表达式,只需将参数括在(...)
中:
.\eraseme.ps1 (29..30+40+50..52)
请注意,您可以通过使用更具体的类型声明参数来使脚本更加健壮,在这种情况下,尝试使用字符串调用它会立即失败:
[Parameter(Mandatory=$False)] [int[]] $srv_range
(其他优化也可以应用于您的脚本。)
至于何时将未加引号的标记视为表达式与参数中的(可扩展)字符串模式 (参见about_Parsing):
(...)
,$(...)
和@(...)
自己或在令牌的开头创建新的解析上下文 ,其中可以使用表达式甚至嵌套命令:
(...)
足以支持单个表达式或命令。 $(...)
(子表达式运算符)可以包含多个表达式/命令;所以可以@()
(数组子表达式运算符),并且它还确保其输出始终被视为数组。
值得注意的是,以下表达式 未被包含在以上某个内容中
:[...]
(输入文字)并访问其成员,例如[Environment]::Version
..
(范围表达式),例如1..10
如果在令牌的开头,(...)
,$(...)
或@(...)
后面跟着其他字符,则第一个附加字符被视为新的单独参数的开始。
$(...)
内部(可扩展字符串),"..."
启动一个新参数,它是一个表达式,(...)
被视为文字@(...)
@
再次启动一个表达式的新参数。 (...)
后跟变量的名称(例如,@
),其中包含参数值的集合或哈希表,启动parameter splatting。
@params
可用于传递哈希表文字(例如@{ ... }
)。
@{ key = 'value' }
创建一个脚本块({ ... }
)。
自己或在令牌开头,变量引用,包括成员访问(属性访问,方法调用,索引)可以按原样使用:
[scriptblock]
,$HOME
,$PSVersionTable.PSVersion
和$someArray[0]
等表达式被识别,并作为其固有类型返回。
没有成员访问权限,即使用简单的变量引用(例如$someString.ToUpper()
),后续字符(可能)被视为相同的一部分然后将该参数解释为可扩展字符串 - 请参阅下文。
使用成员访问权限,任何其他字符中的第一个被视为新参数的开头(例如,$HOME
会导致两个参数:$foo.Length-more
和字符串文字$foo.Length
)的值。
其他所有内容都被视为可扩展字符串 ,即类似到双引号字符串的内容,< em>除 元字符 [1] 仍然需要转义和某些令牌被解释为多个参数
可扩展表示嵌入式简单变量引用(例如,-more
或$HOME\Desktop
)插值(用其字符串值替换)。
请注意,这可能会导致表示与控制台中显示的给定值的默认输出格式不同(例如,有关详细信息,请参阅this answer)。
$env:APPDATA\Test
中附加变量名称,以便在必要时将其与后续字符消除歧义(例如{...}
)。 访问变量值属性或使用索引或调用方法或嵌入任意命令,您必须将表达式括在${HOME}
中,例如$(...)
通常,最安全的是在v$($PSVersionTable.PSVersion)
中包含嵌入了变量引用/表达式的标记,因为它避免了以下边缘情况:
"..."
在 start 的未加引号的标记不被解释为可扩展字符串的一部分,它被视为一个单独的参数(例如,$(...)
会产生两个参数:Write-Output $('ab')c
和文字$('ab')
的结果。)c
在令牌的 start 后紧跟一个简单的变量引用或子表达式会导致单独的参数太。.
会产生两个参数:文字.$HOME
,以及.
的值<)注意:即使扩展的结果是一个字符串,它也不一定保持一个:最终类型由其类型决定参数是扩展值绑定的手头命令。
转义/引用
PowerShell比$HOME
有更多元字符,值得注意的陷阱是cmd.exe
必须被转义才能被视为文字,因为{{1}是PowerShell的数组构造运算符。
要转义单个字符,请在其前面添加 ,
(反引号)。
要避免需要单独转发元字符 ,请将值括在 ,
(双引号)或 `
(单引号):
如果您希望字符串插入(扩展),请使用双引号,即,如果您希望能够嵌入变量引用和子表达式。
"..."
- 转义以下字符。将它们视为文字:'...'
使用单引号将值视为文字 。
`
转义为` " $
单引号或双引号通常是在值中转义空格的最简单方法。
最后,请注意 '
,即所谓的停止解析符号(PSv3 +),完全改变了所有剩余参数的解释:设计用于遗留''
命令行,停止解释除--%
- 样式cmd.exe
环境变量的扩展之外的其余部分。请参阅Get-Help about_Parsing
至于使用引用的代币:
cmd.exe
或%...%
自己或在令牌的开头:
'...'
)或可扩展("..."
)字符串。 '...'
或"..."
[1] 参数模式元字符(具有特殊句法含义的字符)是:
'...'
。
其中,"..."
仅适用于令牌的 start 。
<强>实施例强>
<space> ' " ` , ; ( ) { } | & < > @ #