0

我是 Microsoft System Center Configuration Manager 管理员。我管理着大约 4,000 个 Windows 工作站,由 Win7 和 XP 组合而成。我负责在这些工作站上保持软件更新并定期进行软件部署。

不幸的是,这些客户端的配置没有真正的标准集,因此当出现阻止我将软件推送到客户端的问题时,它通常是单个实例。我厌倦了一直手动修复这些工作站,所以我决定创建一个怪物 Powershell 脚本来解决所有小问题。

目前,该脚本从一个中心位置运行并同步访问所有这些工作站(Powershell 作业即将到来)。这组功能和逻辑正在失控。每次我发现另一个使它变得无法管理的问题时,我都会不断地添加它。

首先,我提出一个问题,比如说“损坏的 WMI”。然后,我创建了一个 Test-BrokenWmi、Get-BrokenWmi 和 Fix-BrokenWmi 函数,例如。这些函数进入我拥有的模块之一,并从主脚本中调用。

然后,主脚本具有仅查找问题或根据传递给它的参数修复问题的选项。这是一个片段。有没有更好的方法来做到这一点,以便我可以轻松添加这些检查?为了使事情变得更加困难,一些检查具有依赖性,例如除非它实际工作,否则您无法从 WMI 获得任何东西。

param($ComputerName,[bool]$Remediate)

Write-Debug 'Starting script...'
$oPc = New-Object System.Object;
$oPc | Add-Member -Type NoteProperty -Name Name -Value $ComputerName;

try {
    if (!(Test-BrokenWmi $ComputerName)) {
        throw 'WMI is broken';
    } elseif (!(Test-ServiceNotStarted $ComputerName)) {
        throw 'Service not started';
    } elseif (............) {
      .....continue more elseifs
    ## Client looks to be OK since it didn't catch any health checks
    } else {
      $oPc | Add-Member -Type NoteProperty -Name TestResult -Value 'Healthy';
      $oPc | Add-Member -Type NoteProperty -Name RemediationAttempt -Value 'N/A';
  $oPc | Add-Member -Type NoteProperty -Name RemediationResult -Value 'N/A';
  return $oPc
    }
} catch [system.exception] {
    $problemfound = $_.Exception.Message;
    $oPc | Add-Member -type NoteProperty -Name TestResult -Value $problemfound;
    if (!$Remediate) {
        $oPc | Add-Member -Type NoteProperty -Name RemediationAttempt -Value 'TestOnlyMode';
    $oPc | Add-Member -Type NoteProperty -Name RemediationResult -Value 'TestOnlyMode';
    return $oPc;
     } else {
        try {
             switch ($problemfound) {
                  'WMI is broken' {
                      $oPc | Add-Member -Type NoteProperty -Name RemediationAttempt -Value 'Fix WMI';
                       throw Fix-Wmi $ComputerName
                  } 'Service is stopped' {
                      $oPc | Add-Member -Type NoteProperty -Name RemediationAttempt -Value 'Start service';
                      throw Fix-Service $ComputerName
                   }
              }
          } catch [system.exception] {
              if ($_.Exception.Message -eq $false) {
                   $oPc | Add-Member -Type NoteProperty -Name RemediationResult -Value 'Failed';
              } elseif ($_.Exception.Message -eq $true) {
           $oPc | Add-Member -Type NoteProperty -Name RemediationResult -Value 'Succeeded';
      } else {
        $oPc | Add-Member -Type NoteProperty -Name RemediationResult -Value $_.Exception.Message;
      }##endif
      return $oPc;
          }
     }
}

}

4

1 回答 1

1

这是我的看法,FWIW。首先,将该对象换成有序哈希表,直到结束。

function new-test {($computername)
$oPc = new-object collections.specialized.ordereddictionary
$oPc.computername = $computername
}

那是V2版本。在 V3 中,您将能够做到

$opc = [ordered]@{}
$oPc.computername = $computername

然后更改您的功能以从管道中获取它。在每次测试中,将其名称与结果一起添加到表中:

$oPc.TestBrokeWMI = "Fail"

这比对对象添加成员要容易得多。

然后将整个对象传递到管道中。

对于具有依赖关系的测试,请检查哈希表是否具有依赖关系的键和“通过”的值。

创建一个函数以在最后使用将哈希表转换为对象,这样您就可以使用一些友好的东西来格式化或导出。同样,在 V3 中,您将能够做到

new-object -property $oPc

它将与有序哈希表一起使用。您将需要使用有序哈希表,以便测试保持在结果对象中运行的顺序。

然后你的测试堆栈开始看起来像这样:

'Computer1' | New-Test | 
 Test-BrokenWmi | Get-BrokenWmi | Fix-BrokenWmi |
 Test-ServiceNotStarted | TestServiceStart |
 | New-TestResult
于 2012-03-21T23:39:04.203 回答