Finding Invalid/Nonexistent Service Paths

This was prompted by someone’s comment on one of my other scripts.

This script accepts input from my .\Get-SVCPath script from the pipeline (get that script at the bottom of this post) and examines each valid imagepath to determine if the executable it’s calling actually exists. This can help you track down mangled path entries, as well as those that are left over and do not resolve to an executable anymore. (Maybe after an incomplete installation? or the installer simply didn’t remove it)

I reused some code from my .\Find-BADSVCPath (available here) script to put this together. You get the full objects back on the shell, so you can sort/filter on the new properties I’ve introduced to the object here using standard PowerShell syntax.

First thing, get input and start process loop

#Validate-SVCPath.ps1
[cmdletbinding()]
	Param ( #Define a Mandatory input
	[Parameter(
	 ValueFromPipeline=$true,
	 ValueFromPipelinebyPropertyName=$true,
	 Position=0)] $obj
	) #End Param
Process
{
}

Okay, now we add new object properties (so I can simply set them later) and create a string we can manipulate to test with.

$obj | Add-Member -MemberType NoteProperty -Name Invalid -value ""
$obj | Add-Member -MemberType NoteProperty -Name ExePath -value ""
$examine = $obj.Imagepath

With that done, we test the path. If it fails, we need to manipulate it to do things like remove quotes, arguments, flags, etc (basically everything we did in my .\Find-BADSVCPath but somewhat backwards)

if (!(Test-Path $examine 2>$nul)){ #If path not found
 
if ($examine.StartsWith('"')){
		$examine = $examine.TrimStart('"') #drop leading quotes so I can strip out path
		$examine = $examine -split '"', 0, "simplematch"
		$examine = $examine[0] }#Should be only the path
 
 
	if ($examine.contains("-") -or $examine.contains("/")) { #found arguments
		#split out arguments
		$split = $examine -split " -", 0, "simplematch"
		$split = $split[0] -split " /", 0, "simplematch"
		$examine = $split[0].Trim(" ") } #Path minus flagged args 
 
	if ($examine.contains(" ")){
		#check for unflagged argument
		$eval = $examine -Replace '".*"', '' #drop all quoted arguments
		$eval = $eval -split "\", 0, "simplematch" #split on foler delim
			if ($eval[-1].contains(" ")){ #last elem is executable and any unquoted args
				$eval= $eval[-1] -split " ", 0, "simplematch" #split out args
				$eval = $eval[0] #Get just the executable
				$examine = $examine -replace "$eval.*", "$eval" } } #path all else dropped 
 
	if ($examine.contains("\??\")){ #remove funky windows preceding tag
		$examine=$examine.replace("\??\", "")}

With all that out of the way, we also need to check that path for variable names. Things like %SystemRoot% are pretty common and PowerShell won’t interpret these directly, so I can exchange the names for actual paths using PowerShell’s environment variables

	#Test for and replace environmentals in paths
 
	if ($examine.startswith("system32")){
		$examine = $examine -replace "system32", "$ENV:SystemRoot\system32"}
 
	elseif ($examine.startswith("System32")){
	$examine = $examine -replace "System32", "$ENV:SystemRoot\system32"}
 
	elseif ($examine.startswith("\SystemRoot")){
		$examine = $examine.replace("\SystemRoot", "$ENV:systemroot")}
 
	elseif ($examine.startswith("%systemroot%")){
		$examine = $examine -replace "%systemroot%", "$ENV:SystemRoot\"}
 
	elseif ($examine.startswith("%SystemRoot%")){
		$examine = $examine -replace "%SystemRoot%", "$ENV:SystemRoot\"}
 
	elseif ($examine.startswith("%windir%")){
		$examine = $examine -replace "%windir%", "$ENV:windir\"}
 
	elseif ($examine.contains("%ProgramFiles%")){
		$examine = $examine -replace "%ProgramFiles%", "$ENV:ProgramFiles\"}
 
	elseif ($examine.contains("%PROGRAMFILES%")){
		$examine = $examine -replace "%PROGRAMFILES%", "$ENV:ProgramFiles\"}
 
	elseif ($examine.contains("SysWOW64")){
		$examine = $examine -replace "SysWOW64", "$ENV:SystemRoot\SysWOW64"}

And with that, we can test the path again. If it resolved, mark it good and write down the full exe path we found. If it’s still bad, mark it bad and write down the path we checked. We can also close out our top If statement so that if the path is good immediately, we can just mark it so and move on.

	if (!(Test-Path $examine)){#Try Corrected Path, if still fails
	$obj.exepath = "$examine"
	$obj.invalid = "Yes" 
	Write-Output $obj} #end if
	else {
	$obj.exepath = "$examine"
	$obj.invalid = "No"
	Write-Output $obj } }#end else, end if (first test)
 
else {
	$obj.exepath = "$examine"
	$obj.invalid = "No"
	Write-Output $obj }	} #end else, end process

And that’s it. I’ll get back every service obj on the shell, and I simply sort them out how I want to see them, or dump to file, whatever floats your boat really.

.\Get-BADSVCPath.ps1 | .\Validate-SVCPath.ps1 | Where {$_.invalid -eq "Yes"}

Here’s the whole thing:

#Validate-SVCPath.ps1
[cmdletbinding()]
	Param ( #Define a Mandatory input
	[Parameter(
	 ValueFromPipeline=$true,
	 ValueFromPipelinebyPropertyName=$true,
	 Position=0)] $obj
	) #End Param
Process
{
$obj | Add-Member -MemberType NoteProperty -Name Invalid -value ""
$obj | Add-Member -MemberType NoteProperty -Name ExePath -value ""
$examine = $obj.Imagepath
if (!(Test-Path $examine 2>$nul)){ #If path not found
 
	if ($examine.StartsWith('"')){
		$examine = $examine.TrimStart('"') #drop leading quotes so I can strip out path
		$examine = $examine -split '"', 0, "simplematch"
		$examine = $examine[0] }#Should be only the path
 
 
	if ($examine.contains("-") -or $examine.contains("/")) { #found arguments
		#split out arguments
		$split = $examine -split " -", 0, "simplematch"
		$split = $split[0] -split " /", 0, "simplematch"
		$examine = $split[0].Trim(" ") } #Path minus flagged args 
 
	if ($examine.contains(" ")){
		#check for unflagged argument
		$eval = $examine -Replace '".*"', '' #drop all quoted arguments
		$eval = $eval -split "\", 0, "simplematch" #split on foler delim
			if ($eval[-1].contains(" ")){ #last elem is executable and any unquoted args
				$eval= $eval[-1] -split " ", 0, "simplematch" #split out args
				$eval = $eval[0] #Get just the executable
				$examine = $examine -replace "$eval.*", "$eval" } } #path all else dropped 
 
	if ($examine.contains("\??\")){ #remove funky windows preceding tag
		$examine=$examine.replace("\??\", "")}
 
	#Test for and replace environmentals in paths
 
	if ($examine.startswith("system32")){
		$examine = $examine -replace "system32", "$ENV:SystemRoot\system32"}
 
	elseif ($examine.startswith("System32")){
	$examine = $examine -replace "System32", "$ENV:SystemRoot\system32"}
 
	elseif ($examine.startswith("\SystemRoot")){
		$examine = $examine.replace("\SystemRoot", "$ENV:systemroot")}
 
	elseif ($examine.startswith("%systemroot%")){
		$examine = $examine -replace "%systemroot%", "$ENV:SystemRoot\"}
 
	elseif ($examine.startswith("%SystemRoot%")){
		$examine = $examine -replace "%SystemRoot%", "$ENV:SystemRoot\"}
 
	elseif ($examine.startswith("%windir%")){
		$examine = $examine -replace "%windir%", "$ENV:windir\"}
 
	elseif ($examine.contains("%ProgramFiles%")){
		$examine = $examine -replace "%ProgramFiles%", "$ENV:ProgramFiles\"}
 
	elseif ($examine.contains("%PROGRAMFILES%")){
		$examine = $examine -replace "%PROGRAMFILES%", "$ENV:ProgramFiles\"}
 
	elseif ($examine.contains("SysWOW64")){
		$examine = $examine -replace "SysWOW64", "$ENV:SystemRoot\SysWOW64"}
 
	if (!(Test-Path $examine)){#Try Corrected Path, if still fails
	$obj.exepath = "$examine"
	$obj.invalid = "Yes" 
	Write-Output $obj} #end if
	else {
	$obj.exepath = "$examine"
	$obj.invalid = "No"
	Write-Output $obj } }#end else, end if (first test)
 
else {
	$obj.exepath = "$examine"
	$obj.invalid = "No"
	Write-Output $obj }	} #end else, end process

Jeff is a system administrator for an enterprise of over 4000 devices. He is comfortable on Windows and *nix and participates in everything from desktop to network support. In addition, he develops in PowerShell to aid in the automation of administrative tasks.

When not at work, Jeff is adjunct faculty at the University of Alaska Anchorage, where he teaches PC Architecture to first year students in the Computer and Networking Technology Program. He is also working on new curriculum in PowerShell and Virtualization as well as leading department technology deployments.


View Jeff Liford's profile on LinkedIn



Posted in Computer Security, PowerShell