2012-03-21 91 views
0

我是Microsoft系统中心配置管理器管理员。我管理大约4,000个由Win7和XP组合组成的Windows工作站。我负责在这些工作站上保留软件更新并定期进行软件部署。Powershell脚本流程所需的建议

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

目前,脚本从中央位置运行并同步点击所有这些工作站(Powershell作业即将到来)。这套功能和逻辑正在失去控制。每当我发现另一个让它变得难以管理的问题时,我就不断加入它。

首先,我说出一个问题,让我们说“破碎的WMI”。然后,我创建一个Test-BrokenWmi,Get-BrokenWmi和Fix-BrokenWmi函数。这些函数进入我有的一个模块,并从主脚本中调用。

然后,主脚本可以选择仅查找问题或根据传递给它的参数来修复问题。这是一个片段。有没有更好的方法来做到这一点,所以我可以轻松地添加这些检查?为了使事情变得更加困难,一些检查具有依赖性,例如,除非WMI实际工作,否则无法从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; 
      } 
    } 
} 

}

回答

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 
+0

我很喜欢你使用管道这样的想法。我一定会看看我能不能做那样的事情。 – 2012-03-22 13:43:44

+0

很酷。让我知道它是如何运作的。 – mjolinor 2012-03-22 13:47:20

+0

它花了我一段时间,我做了一些其他的变化,但几个小时后,我能够改变所有的功能。我打算明天让它试运行。 – 2012-03-23 00:09:48