Thanks Matt and Dave!
Matt, your approach would most likely work, and I had thought about doing something like that. But… Those “LowestLevel” functions are essentially utility functions that do one thing and return an object with the results. They’re designed for reuse in other scripts or just as tools at the command line, so I don’t want them writing to a log. To me, that makes them sort of dependent on the calling function and not really standalone.
Dave, your approach is more what I’m looking for, but I haven’t found the right information about using -ErrorVariable. If your method works, I think it will do what I want to do. I just need to figure out how to pass some info back through the error stream. And yes, I am seeing the exceptions written to my console, but I can’t figure out how to give the code access to them.
I’m going to look into using -ErrorVariable, but just because actual logic might make more sense, here are the functions I’m working with right now. Hopefully you can see the flow a little better with real world examples.
The whole script that I’m working on is looking for AV installs across our corporate AD. The main report script checks for a SCCM client, for a Symantec client, for a System Center Endpoint Protection client, etc. To accomplish that, it uses other tool functions that I’ve created. The code below deals with Symantec, but I’ve got several other similar scenarios.
This chunk of code is the part of that main report script that deals with SEP. It would be the “TopLevel” function in my example. You can see here that there is a lot of console and log writing going on based on the output of the Test-SEPInstall function. This is also where I’d like to log, (or modify the logic in some other way), the exceptions thrown at lower levels.
$SEPTest = $AVProcessList | Test-SEPInstall -DebugLevel $DebugLevel -ExpectedSEPVersion $ExpectedSEPVersion
foreach ($machine in $SEPTest) {
if ($machine.SEPInstalled) {
# If the version is returned, and it is at the expected level or higher, set it aside to check against SEP Manager and remove from further processing
if ($machine.SEPCurrent) {
$AVProcessList.Remove($machine.ComputerName)
if ($DebugLevel -ge 2) {
Write-Host "Machine removed from AVProcessList - $($machine.ComputerName)"
LogWrite -LogString "Machine removed from AVProcessList - $($machine.ComputerName)" -Severity 0
}
$SEPProcessList += $machine.ComputerName
if ($DebugLevel -ge 2) {
Write-Host "Machine added to SEPProcessList - $($machine.ComputerName)"
LogWrite -LogString "Machine added to SEPProcessList - $($machine.ComputerName)" -Severity 0
}
}
# If the version is returned, but it is lower than expected, write it to log as a warning
else {
if ($DebugLevel -ge 0) {
Write-Warning "Machine has old version of Symantec Endpoint Protection installed - ComputerName: $($machine.ComputerName), SEPVersion: $($machine.SEPVersion)"
LogWrite -LogString "Machine has old version of Symantec Endpoint Protection installed - ComputerName: $($machine.ComputerName), SEPVersion: $($machine.SEPVersion)" -Severity 1
}
}
}
# SEP is not installed
else {
if ($DebugLevel -ge 2) {
Write-Host "Machine does not have Symantec Endpoint Protection installed - $($machine.ComputerName)"
LogWrite -LogString "Machine does not have Symantec Endpoint Protection installed - $($machine.ComputerName)" -Severity 0
}
}
}
The Test-SEPInstall function does some simple logic based on the expected version of SEP and the version that is actually on the box and then creates a custom object with that information. This is the “MidLevel” function in my example.
function Test-SEPInstall {
[CmdletBinding()]
Param (
[Parameter(ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,Position=0,Mandatory=$true)][string[]]$ComputerName,
[Parameter(ValueFromPipeline=$false,Position=2,Mandatory=$false)][string]$ExpectedSEPVersion = "12"
)
BEGIN {
$SEPProcessList = @()
}
PROCESS {
foreach ($comp in $ComputerName) {
try {
$SEPInfo = $comp | Get-SymantecEndpointProtectionVersion
# If the version number isn't returned, SEP is not installed
if ($SEPInfo.SEPVersion -eq $null) {
$SEPInstalled = $false
$SEPVersion = $null
$SEPCurrent = $null
$SEPManaged = $null
}
else {
# If the version is returned, but it is lower than expected, write it to log as a warning
if ($SEPInfo.SEPVersion -lt $ExpectedSEPVersion) {
$SEPInstalled = $true
$SEPVersion = $SEPInfo.SEPVersion
$SEPCurrent = $false
$SEPManaged = $null
}
# If the version is returned, and it is at the expected level or higher, set it aside to check against SEP Manager and remove from further processing
else {
$SEPInstalled = $true
$SEPVersion = $SEPInfo.SEPVersion
$SEPCurrent = $true
# TODO: add code to verify SEP is managed by SEP Manager on JXUTILITY
$SEPManaged = $null
}
}
}
catch [Exception] {
throw $_.Exception
}
finally {
New-Object -TypeName PSObject -Property @{
ComputerName=$comp
SEPInstalled=$SEPInstalled
SEPVersion=$SEPVersion
SEPCurrent=$SEPCurrent
SEPManaged=$SEPManaged
} | Select-Object ComputerName,SEPInstalled,SEPVersion,SEPCurrent
}
}
}
END {
}
}
Get-SymantecEndpointProtectionVersion is the “LowestLevel” function. It queries the registry for the version info of Symantec Endpoint Protection, (big surprise!), and returns a custom object with that information.
function Get-SymantecEndpointProtectionVersion {
# ******************************************************************************
# http://www.symantec.com/connect/forums/powershell-script-which-determines-what-version-sep-machine
# ******************************************************************************
[CmdletBinding()]
Param(
[Parameter(ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,Position=0,Mandatory=$true)][string[]]$ComputerName
)
BEGIN {
}
PROCESS {
foreach ($comp in $ComputerName)
{
$SEPver = ""
$regkey = ""
try {
$reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey("LocalMachine",$comp)
$regkey = $reg.opensubkey("SOFTWARE\\Symantec\\Symantec Endpoint Protection\\SMC")
if ($regkey -ne $null) {
$SEPver = $regKey.GetValue('ProductVersion')
}
else
{
# Registry key not found, so no client installed
$SEPver = $null
}
}
catch [Exception] {
Write-Error "$comp : $_"
$SEPver = $null
}
finally {
$Results = New-Object -TypeName PSObject -Property @{
ComputerName=$comp
SEPVersion=$SEPver
}
$Results
}
}
}
END {
}
}