不能在函数中调用管道属性。电源外壳
Can't call piped properties in a function. Powershell
所以我正在尝试创建一个“下载”函数,它使用管道对象 属性 来确定下载方法(sftp 或 http)。然后为 putty/winscp 或 curl the http url 创建一个 sftp 脚本。我定义对象如下:
#WinSCP
$winscp = new-object psobject
$winscp | add-member noteproperty name "WinSCP"
$winscp | add-member noteproperty dltype "http"
$winscp | add-member noteproperty file "winscp.exe"
$winscp | add-member noteproperty url "https://cdn.winscp.net/files/WinSCP-5.17.8-Setup.exe"
$winscp | add-member noteproperty path "$env:ProgramFiles(x86)\WinSCP"
$winscp | add-member noteproperty install 'msiexec /i "$DataPath$winscp.file" /quiet /norestart'
#Database
$db = new-object psobject
$db | add-member noteproperty name "Client Database"
$db | add-member noteproperty dltype "sftp"
$db | add-member noteproperty file "database_"
$db | add-member noteproperty ver "check"
$db | add-member noteproperty ext ".csv"
$db | add-member noteproperty dir "db"
#DatabaseVersion
$db_ver = new-object psobject
$db_ver | add-member noteproperty name "Database Version File"
$db_ver | add-member noteproperty dltype "sftp"
$db_ver | add-member noteproperty file "current_version.txt"
$db_ver | add-member noteproperty dir "db"
目前,函数中的 $Input 变量有问题。它只能使用一次并且不会转换为 if 语句。由于它包含一个具有多个属性的对象,因此我认为首先需要在函数内将其转换为一个新对象。我是 powershell 的新手,还没有找到这样做的方法。这是我制作并尝试使用的功能:
function Download () {
#HTTP Download Method
if ($input.dltype -eq "http") {
curl $input.url -O $DataPath$input.file
#HTTP Success or Error
$curlResult = $LastExitCode
if ($curlResult -eq 0)
{
Write-Host "Successfully downloaded $input.name"
}
else
{
Write-Host "Error downloading $input.name"
}
pause
}
#SFTP Download Method
if ($input.dltype -eq "sftp") {
sftpPassCheck
#Detect if version required
if ($input.ver = "check") {
#Download the objects version file
"$+$Input+_ver" | Download
#Update the object's ver property
$input.ver = [IO.File]::ReadAllText("$DataPath\current_version.txt")
#Build the new filename
$input.file = "$input.file"+"$input.ver"+"$input.ext"
#Delete the version file
Remove-Item "$DataPath\current_version.txt"
}
& "C:\Program Files (x86)\WinSCP\WinSCP.com" `
/log="$DataPath\SFTP.log" /ini=nul `
/command `
"open sftp://ftpconnector:$script:sftp_pass@$input.ip/ -hostkey=`"`"ssh-ed25519 255 SETvoRlAT0/eJJpRhRRpBO5vLfrhm5L1mRrMkOiPS70=`"`" -rawsettings ProxyPort=0" `
"cd /$input.dir" `
"lcd $DataPath" `
"get $input.file" `
"exit"
#SFTP Success or Error
$winscpResult = $LastExitCode
if ($winscpResult -eq 0)
{
Write-Host "Successfully downloaded $input.name"
}
else
{
Write-Host "Error downloading $input.name"
}
}
}
我可能遗漏了一些简单的东西,但我现在一无所知。哦用法应该是:
WinSCP | download
将来自管道的输入绑定到函数参数的正确方法是声明一个高级函数 - 请参阅 about_Functions_Advanced_Parameters 和此答案底部的实施。
然而,在简单的情况下,filter
会执行 ,这是一种函数的简化形式,它将管道输入隐式绑定到 automatic $_
variable 和为每个输入对象调用:
filter Download {
if ($_.dltype -eq "http") {
# ...
}
}
$input
is another automatic variable,在 simple(非高级)function
s 中是一个 enumerator 对于 所有 管道输入 正在接收,因此必须 循环 .
即下面的简单function
相当于上面的filter
:
function Download {
# Explicit looping over $input is required.
foreach ($obj in $input) {
if ($obj.dltype -eq "http") {
# ...
}
}
}
如果你想把它变成一个高级函数(注意我已经改变了名字以符合PowerShell的动词-名词命名约定):
function Invoke-Download {
param(
# Declare a parameter explicitly and mark it as
# as pipeline-binding.
[Parameter(ValueFromPipeline, Mandatory)]
$InputObject # Not type-constraining the parameter implies [object]
)
# The `process` block is called for each pipeline input object
# with $InputObject referencing the object at hand.
process {
if ($InputObject.dltype -eq "http") {
# ...
}
}
}
- $input
并不是真的要直接使用,你可能最好明确声明你的输入参数!
除了该答案中显示的 $InputObject
模式之外,您还可以按名称将输入对象 属性 值绑定到参数:
function Download
{
param(
[Parameter(ValueFromPipelineByPropertyName = $true)]
[Alias('dltype')]
[string]$Protocol = 'http'
)
process {
Write-Host "Choice of protocol: $Protocol"
}
}
注意虽然这个参数的名字是$Protocol
,但是[Alias('dltype')]
属性会保证输入对象上dltype
属性的值是绑定的.
这样的效果是:
PS ~> $WinSCP,$db |Download
Choice of protocol: http
Choice of protocol: sftp
对任何必需的输入参数重复此模式 - 声明一个映射到 属性 名称的命名参数(如有必要),您可能会得到如下结果:
function Download
{
[CmdletBinding()]
param(
[Parameter(ValueFromPipelineByPropertyName = $true)]
[ValidateSet('sftp', 'http')]
[Alias('dltype')]
[string]$Protocol,
[Parameter(ValueFromPipelineByPropertyName = $true)]
[Alias('dir')]
[string]$Path = $PWD,
[Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
[Alias('url','file')]
[string]$Uri
)
process {
Write-Host "Downloading $Uri to $Path over $Protocol"
}
}
现在你可以做:
PS ~> $WinSCP,$db |Download
Downloading https://cdn.winscp.net/files/WinSCP-5.17.8-Setup.exe to C:\Program Files(x86)\WinSCP over http
Downloading database_ to db over sftp
我们不再依赖直接访问 $input
、$InputObject
或 $_
,非常干净。
有关参数声明的详细信息,请参阅about_Functions_Advanced_Parameters
help file。
所以我正在尝试创建一个“下载”函数,它使用管道对象 属性 来确定下载方法(sftp 或 http)。然后为 putty/winscp 或 curl the http url 创建一个 sftp 脚本。我定义对象如下:
#WinSCP
$winscp = new-object psobject
$winscp | add-member noteproperty name "WinSCP"
$winscp | add-member noteproperty dltype "http"
$winscp | add-member noteproperty file "winscp.exe"
$winscp | add-member noteproperty url "https://cdn.winscp.net/files/WinSCP-5.17.8-Setup.exe"
$winscp | add-member noteproperty path "$env:ProgramFiles(x86)\WinSCP"
$winscp | add-member noteproperty install 'msiexec /i "$DataPath$winscp.file" /quiet /norestart'
#Database
$db = new-object psobject
$db | add-member noteproperty name "Client Database"
$db | add-member noteproperty dltype "sftp"
$db | add-member noteproperty file "database_"
$db | add-member noteproperty ver "check"
$db | add-member noteproperty ext ".csv"
$db | add-member noteproperty dir "db"
#DatabaseVersion
$db_ver = new-object psobject
$db_ver | add-member noteproperty name "Database Version File"
$db_ver | add-member noteproperty dltype "sftp"
$db_ver | add-member noteproperty file "current_version.txt"
$db_ver | add-member noteproperty dir "db"
目前,函数中的 $Input 变量有问题。它只能使用一次并且不会转换为 if 语句。由于它包含一个具有多个属性的对象,因此我认为首先需要在函数内将其转换为一个新对象。我是 powershell 的新手,还没有找到这样做的方法。这是我制作并尝试使用的功能:
function Download () {
#HTTP Download Method
if ($input.dltype -eq "http") {
curl $input.url -O $DataPath$input.file
#HTTP Success or Error
$curlResult = $LastExitCode
if ($curlResult -eq 0)
{
Write-Host "Successfully downloaded $input.name"
}
else
{
Write-Host "Error downloading $input.name"
}
pause
}
#SFTP Download Method
if ($input.dltype -eq "sftp") {
sftpPassCheck
#Detect if version required
if ($input.ver = "check") {
#Download the objects version file
"$+$Input+_ver" | Download
#Update the object's ver property
$input.ver = [IO.File]::ReadAllText("$DataPath\current_version.txt")
#Build the new filename
$input.file = "$input.file"+"$input.ver"+"$input.ext"
#Delete the version file
Remove-Item "$DataPath\current_version.txt"
}
& "C:\Program Files (x86)\WinSCP\WinSCP.com" `
/log="$DataPath\SFTP.log" /ini=nul `
/command `
"open sftp://ftpconnector:$script:sftp_pass@$input.ip/ -hostkey=`"`"ssh-ed25519 255 SETvoRlAT0/eJJpRhRRpBO5vLfrhm5L1mRrMkOiPS70=`"`" -rawsettings ProxyPort=0" `
"cd /$input.dir" `
"lcd $DataPath" `
"get $input.file" `
"exit"
#SFTP Success or Error
$winscpResult = $LastExitCode
if ($winscpResult -eq 0)
{
Write-Host "Successfully downloaded $input.name"
}
else
{
Write-Host "Error downloading $input.name"
}
}
}
我可能遗漏了一些简单的东西,但我现在一无所知。哦用法应该是:
WinSCP | download
将来自管道的输入绑定到函数参数的正确方法是声明一个高级函数 - 请参阅 about_Functions_Advanced_Parameters 和此答案底部的实施。
然而,在简单的情况下,filter
会执行 ,这是一种函数的简化形式,它将管道输入隐式绑定到 automatic $_
variable 和为每个输入对象调用:
filter Download {
if ($_.dltype -eq "http") {
# ...
}
}
$input
is another automatic variable,在 simple(非高级)function
s 中是一个 enumerator 对于 所有 管道输入 正在接收,因此必须 循环 .
即下面的简单function
相当于上面的filter
:
function Download {
# Explicit looping over $input is required.
foreach ($obj in $input) {
if ($obj.dltype -eq "http") {
# ...
}
}
}
如果你想把它变成一个高级函数(注意我已经改变了名字以符合PowerShell的动词-名词命名约定):
function Invoke-Download {
param(
# Declare a parameter explicitly and mark it as
# as pipeline-binding.
[Parameter(ValueFromPipeline, Mandatory)]
$InputObject # Not type-constraining the parameter implies [object]
)
# The `process` block is called for each pipeline input object
# with $InputObject referencing the object at hand.
process {
if ($InputObject.dltype -eq "http") {
# ...
}
}
}
$input
并不是真的要直接使用,你可能最好明确声明你的输入参数!
除了该答案中显示的 $InputObject
模式之外,您还可以按名称将输入对象 属性 值绑定到参数:
function Download
{
param(
[Parameter(ValueFromPipelineByPropertyName = $true)]
[Alias('dltype')]
[string]$Protocol = 'http'
)
process {
Write-Host "Choice of protocol: $Protocol"
}
}
注意虽然这个参数的名字是$Protocol
,但是[Alias('dltype')]
属性会保证输入对象上dltype
属性的值是绑定的.
这样的效果是:
PS ~> $WinSCP,$db |Download
Choice of protocol: http
Choice of protocol: sftp
对任何必需的输入参数重复此模式 - 声明一个映射到 属性 名称的命名参数(如有必要),您可能会得到如下结果:
function Download
{
[CmdletBinding()]
param(
[Parameter(ValueFromPipelineByPropertyName = $true)]
[ValidateSet('sftp', 'http')]
[Alias('dltype')]
[string]$Protocol,
[Parameter(ValueFromPipelineByPropertyName = $true)]
[Alias('dir')]
[string]$Path = $PWD,
[Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
[Alias('url','file')]
[string]$Uri
)
process {
Write-Host "Downloading $Uri to $Path over $Protocol"
}
}
现在你可以做:
PS ~> $WinSCP,$db |Download
Downloading https://cdn.winscp.net/files/WinSCP-5.17.8-Setup.exe to C:\Program Files(x86)\WinSCP over http
Downloading database_ to db over sftp
我们不再依赖直接访问 $input
、$InputObject
或 $_
,非常干净。
有关参数声明的详细信息,请参阅about_Functions_Advanced_Parameters
help file。