0

我对通过管道或参数输入接受值时有什么区别有疑问。

我问是因为:

  • 在我的脚本中通过管道接受值是可行的。
  • 使用参数参数接受值,例如“ -ComputerName”类的作品。

我之所以这么说是因为,它确实从同一个变量中获取了我的输入,直到它无法连接到某个变量,然后它停止了脚本。是否有一个原因?

这是我的脚本给任何好奇的人:

Function Set-DWRCVersion {
<#
NAME
    Set-DWRCVersion
    
SYNTAX
    Set-DWRCVersion [[-ComputerName] <string[]>]  [<CommonParameters>]

EXAMPLES
    Set-DWRCVersion -ComputerName LocalHost,ComputerOne
    'LocalHost','ComputerOne' | Set-DWRCVersion
    $CritNames | Set-DWRCVersion
    
    $CritNames | Set-DWRCVersion |Export-Csv "$($env:USERPROFILE.Substring(0,20))\Desktop\NewCrit.CSV" -Force -NoTypeInformation 
#>

[cmdletbinding()]
    Param(
        [Parameter(Mandatory=$true,
                   ValueFromPipeline=$true,
                   ValueFromPipeLineByPropertyName=$true)]
                   [ValidateLength(1,15)]
                   [Alias('Comp','CN','name')]
                   [string[]]$ComputerName)
                   
Process{
        try{
        [string]$Path = "C:\Users\Abraham\Desktop\dwrcs"  #Dameware File Path (current)
            foreach($Computer in $ComputerName){
                $PSSession = New-PSSession -ComputerName $Computer -ErrorAction Stop
                $TestPath  = Invoke-Command -Session $PSSession -ScriptBlock { Test-Path -Path "C:\Windows\dwrcs" }
                    if($TestPath -eq $false){
                        Copy-Item -Path $Path -Destination "\\$Computer\C$\Windows" -Recurse -Force }
                        #Start-Sleep -Seconds 1

                $EXEVersion = Invoke-Command -Session $PSSession -ScriptBlock { [System.Diagnostics.FileVersionInfo]::GetVersionInfo("C:\Windows\dwrcs\DWRCS.EXE").FileVersion }
                $DLLVersion = Invoke-Command -Session $PSSession -ScriptBlock { [System.Diagnostics.FileVersionInfo]::GetVersionInfo("C:\Windows\dwrcs\DWRCRSS.dll").FileVersion }
                    if($EXEVersion -notmatch '12.1.2.584'){
                        [PSCustomObject] @{
                                "Computer Name"  = $Computer
                                "Status"         = "Online"
                                "DWRC Version"   = $EXEVersion
                                "DWRCRSS DLL"    = $DLLVersion
                                "DWRC Check"     = "Not up to date" }
                                ""
                        Write-Output -InputObject "Version not current"
                        Write-Output -InputObject "Stopping Service. . ."
                        Invoke-Command -Session $PSSession -ScriptBlock { 
                            Stop-Service -Name dwmrcs;
                            Get-Item -Path C:\windows\dwrcs | Rename-Item -NewName "dwrcs.old" }
                            Remove-Item -Path "\\$Computer\c$\Windows\dwrcs.old" -Recurse -Force -ErrorAction SilentlyContinue
                            #Start-Sleep 1

                        Write-Output -InputObject "Copying new files over. . ."
                        Copy-Item -Path $Path -Destination "\\$Computer\C$\Windows" -Recurse -Force

                        Write-Output -InputObject "Starting Service. . ."
                        Invoke-Command -Session $PSSession -ScriptBlock { Start-Service -Name dwmrcs }
                              } 
                    elseif($EXEVersion -match '12.1.2.584') {
                        [PSCustomObject] @{
                                "Computer Name"  = $Computer
                                "Status"         = "Online"
                                "DWRC Version"   = $EXEVersion
                                "DWRCRSS DLL"    = $DLLVersion
                                "Version Check"  = "Up to Date" }
                              }
                    else { Write-Output -InputObject "Error Occured"
                           Throw "$($Error[0].Exception.Message)"  }
                    }
            } Catch {
                        [PSCustomObject] @{
                                "Computer Name"  = $Computer
                                "Status"         = "Offline"
                                "DWRC Version"   = $null
                                "DWRCRSS DLL"    = $null
                                "Version Check"  = $null }
            } Finally {
                if ($PSSession) {
                Get-PSSession | Remove-PSSession }
        }
    }
}

总的来说,它是一个非常简单的脚本,它将为我获取一些远程文件版本。我只是不确定为什么从管道接受值不会停止脚本,但使用常规参数输入它们会。

我从 csv 导入以使用以下方法获取名称:

$Crit = Import-Csv -Path "$($env:USERPROFILE.Substring(0,20))\Desktop\med.csv"
$CritNames = $Crit.'NetBios Name' -replace "AREA51\\","" 

<# Names return like so:
COmputerOne
COmputerTwo
COmputerThr
Etc.. #>

并且在使用管道输入运行它时:$CritNames | Set-DWRCVersion有效但Set-DWRCVersion -ComputerName $CritNames无效;好吧,直到它遇到离线计算机然后停止脚本。

我有什么遗漏吗?比我聪明得多的人能教育我吗?(:

4

1 回答 1

2

您可以通过在循环移动 // 语句来解决try此问题catchfinallyforeach

process {
  foreach($Computer in $ComputerName){
    try {
      # ...
    }
    catch {
      # ...
    }
    finally {
      # ...
    }
  }
}

为什么这会有所作为?

当通过显式绑定一个值时-ComputerName,该process块仅被调用一次- 但是当您通过管道提供输入时,该process块被每个输入项调用一次

您可以使用如下简单的测试函数观察此行为:

function Test-ProcessInvocation {
  param(
    [Parameter(Mandatory,ValueFromPipeline)]
    [string[]]$ComputerName
  )

  process {
    "Running process block with $($ComputerName.Length) input arguments: [$ComputerName]"
  }
}

使用两种输入模式运行此命令将使此行为清晰可见:

PS ~> Test-ProcessInvocation -ComputerName 1,2,3
Running process block with 3 input arguments: [1 2 3]
PS ~> 1,2,3 |Test-ProcessInvocation
Running process block with 1 input arguments: [1]
Running process block with 1 input arguments: [2]
Running process block with 1 input arguments: [3]

这意味着运行Set-DWRCVersion -ComputerName Computer1,Computer2转换为以下语句序列:

# Single invocation of `process` block with $ComputerName = all input values at once
try {
  foreach($Computer in 'Computer1','Computer2'){

  }
}
catch {}
finally {}

'Computer1','Computer2' |Set-DWRCVersion另一方面运行:

# `process` block repeats per input item
try {
  foreach($Computer in 'Computer1'){

  }
}
catch {}
finally {}

try {
  foreach($Computer in 'Computer2'){

  }
}
catch {}
finally {}

因此,在foreach通过管道调用时在循环内抛出错误永远不会“跳过”任何项目,因为循环一次只对一个项目进行操作。

try通过反转循环和/语句之间的关系catch,任何错误现在都将在循环被捕获和处理,并且不再跳过$ComputerName.

于 2021-04-09T23:01:19.360 回答