Reputation: 4198
I'm a Microsoft System Center Configuration Manager admin. I manage around 4,000 Windows workstations consisting of a combination of Win7 and XP. I'm responsible for keeping software updates on these workstations and doing periodic software deployments.
Unfortunately, there has been no real standard set for the configuration of these clients thus when a problem pops up that prevents me from pushing software to one, it's typically a single instance. I got tired of fixing these workstations manually all the time so I decided to create a monster Powershell script to fix all the little issues.
Currently, the script is run from a central location and hits all these workstations synchronously (Powershell jobs are coming). This set of functions and logic is getting out of control. I keep adding to it every time I find another problem which is making it become unmanageable.
First, I name a problem, let's say "broken WMI". I then create a Test-BrokenWmi, Get-BrokenWmi and Fix-BrokenWmi functions, for example. These functions go into one of the modules that I have and get called from the main script.
The main script then has options to only find problems or fix the problems depending on the params passed to it. Here's a snippet. Is there a better way to do this so I can easily add these checks? To make things more difficult, some checks have dependencies such as you can't get anything from WMI unless it's actually working.
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;
}
}
}
}
Upvotes: 0
Views: 414
Reputation: 68331
Here's my take, FWIW. First, trade that object for an ordered hash table until the end.
function new-test {($computername)
$oPc = new-object collections.specialized.ordereddictionary
$oPc.computername = $computername
}
That's the V2 version. In V3 you'll be able to do
$opc = [ordered]@{}
$oPc.computername = $computername
Then change your functions to take that from the pipeline. At each test, have it add it's name to the table along with the result:
$oPc.TestBrokeWMI = "Fail"
That's a lot easier than doing an add-member to an object.
Then pass the whole object on down the pipeline.
For tests that have dependencies, have the check to see if the hash table has key for the dependecy and a value of "Passed".
Create a function to use at the end to convert the hash table to an object so you've got something friendly to work with for formatting or exporting. Again, in V3 you'll be able to just do
new-object -property $oPc
and it will work with the ordered hash table. You'll want to use an ordered hash table so the tests stay in the order they were ran in the resulting object.
Then your test stack starts to look like this:
'Computer1' | New-Test |
Test-BrokenWmi | Get-BrokenWmi | Fix-BrokenWmi |
Test-ServiceNotStarted | TestServiceStart |
| New-TestResult
Upvotes: 1