PS script for blog: Enumeration of the files failed

Here’s the script for the Blog:  Reasons why the error “Enumeration of the files failed” may occur during System State backup

by Mike Rosado, posted June 18, 2010

 

Open Notepad.exe, copy & paste the script below and save it to a file named GetInvalidImagePathsV2.ps1 

###########################################################################
#
# NAME: GetInvalidImagePathsV2.ps1
#
# AUTHOR:      Suhas Rao
# REVISED BY:  Mark Stanfill
#
# COMMENT: This script was created to help minimize the time of parsing through the registry searching for invalid ImagePaths
#          under the HKEY_LOCAL_MACHINESYSTEMCurrentControlSetServices keys.
#
#          For more details, search for “Enumeration of the files failed” in a blog posted on:
#         
http://blogs.technet.com/b/askcore/
#
#    Disclaimer:
#   
#    The sample scripts are not supported under any Microsoft standard support program or service.
#    The sample scripts are provided AS IS without warranty of any kind. Microsoft further disclaims all implied warranties including,
#    without limitation, any implied warranties of merchantability or of fitness for a particular purpose.
#    The entire risk arising out of the use or performance of the sample scripts and documentation remains with you.
#    In no event shall Microsoft, its authors, or anyone else involved in the creation, production,
#    or delivery of the scripts be liable for any damages whatsoever (including, without limitation,
#    damages for loss of business profits, business interruption, loss of business information, or other pecuniary loss)
#    arising out of the use of or inability to use the sample scripts or documentation, even if Microsoft has been advised of the possibility of such damages.
#
#
# VERSION HISTORY:
# 1.0 – Initial release
# 2.0 – Included searching for spaces in the path
#
###########################################################################

$Verbose = $false;

if (($ARGS.Count -gt 0) -and ($ARGS[0] -ieq “-verbose”))
{
    $Verbose = $true;
}

#
# The list of possible reasons for failure
#
$FailureReasons = @{
                    “INVALID_CHARS”      = “The service path contains invalid characters. ” +
                                           “Characters < > : `” | ? cannot be used in a file path.”;
                    “INVALID_FORMAT”     = “The service path does not have a proper path format. ” +
                                           “Only paths beginning with [<Drive>]: format are supported.”;
                    “DOUBLE_SLASH”       = “The service path contains double inverted slashes. ” +
                                           “UNC Network paths or paths containing double inverted slashes are not supported.”;
                    “RELATIVE_PATH”      = “The service path is relative. ” +
                                           “Only absolute paths are supported.”;
                    “FOWARD_SLASH”       = “The service path contains a foward slash. ” +
                                           “Only paths containing an inverted slash are supported.”;
                    “REPARSE_POINT”      = “The service path contains a reparse point. ” +
                                           “Paths containing a reparse point are not supported.”;
                    “UNRECOGNIZED_PATH”  = “Unable to check the path. ” +
                                           “Expecting the ImagePath for the service to be a .dll or .exe”;
            “SPACE_IN_PATH”      = “The service path contains spaces, ” +
                       “the whole path needs to be enclosed using double quotes”;

                   }

#
# The failure INVALID_CHARS can occur due to the following type of characters
#
$InvalidChars   = @{
                    “*\*”   = “DOUBLE_SLASH”;
                    “*..*” = “RELATIVE_PATH”;
                    “*.*”  = “RELATIVE_PATH”;
                    “*/*”    = “FOWARD_SLASH”
           
                   }


#
# Display the service info
#
function PrintServiceInfo([System.Management.ManagementObject] $Service, [string] $Header,
                          [string] $Reason, [string] $Color)
{
    $Name    = $Service.Name
    $Caption = $Service.Caption
    $Path    = $Service.PathName
    $Info    = $FailureReasons.Item($Reason)

    if ($Color -eq “”)
    {
        $Color = “White”
    }

    Write-Host “$Header`n” `
               ”    Service Name    : $Name`n” `
               ”    Service Caption : $Caption`n” `
               ”    Registry key    : HKEY_LOCAL_MACHINESYSTEMCurrentControlSetservices$NameImagePath`n” `
               ”    Value           : $Path`n” `
               ”    Reason          : $Info`n” `
               “`n” `
               -ForeGroundColor “$Color”
}

#
# For verbose mode, print extra info for every path
#
function PrintStatus([Boolean] $IsBadPath)
{
    if ($Verbose -eq $true)
    {
        if ($IsBadPath -eq $true)
        {
            Write-Host “ERROR” -ForeGroundColor Red;
        }
        else
        {
            Write-Host “OK” -ForeGroundColor Green;
        }
    }
}

#
# This is a core function that fetches the service path given the input from registry
# It expects the service path to be a .dll or .exe
#
function GetActualPathFromServiceImagePath([string] $ServiceImagePath)
{
    $ActualPathName = $null
    $IndexForPath   = $null

    $ExeIndex = $ServiceImagePath.ToLower().IndexOf(“.exe”);
    $DllIndex = $ServiceImagePath.ToLower().IndexOf(“.dll”);

    ##
    ## NOTE: Assumption is that the Service Path Always ends in dll or exe
    ##
    if(($ExeIndex -eq -1) -and ($DllIndex -eq -1))
    {
        return $null
    }

    ##
    ## If the path contains both Dll And Exe then we should use the One that Comes First
    ##
    if(($ExeIndex -ne -1) -and ($DllIndex -ne -1))
    {
        if($ExeIndex -gt $DllIndex)
        {
            $IndexForPath = $DllIndex +4;
        }
        else
        {
            $IndexForPath = $ExeIndex +4;
        }
    }
    else
    {
        if($ExeIndex -eq -1)
        {
            $IndexForPath = $DllIndex +4;
        }
        else
        {
            $IndexForPath = $ExeIndex +4;
        }
    }


    $ActualPathName = $ServiceImagePath.Substring(0,$IndexForPath)

    $Quote = “`””
    if($ActualPathName.StartsWith($Quote))
    {
        $ActualPathName = $ActualPathName.Remove(0,1);
    }

    if ($ActualPathName.StartsWith(“\?”) -or $ActualPathName.StartsWith(“\.”))
    {
        $ActualPathName = $ActualPathName.Substring(4);
    }

    return $ActualPathName
}


##################################################################################
##                                  Main                                        ##
##################################################################################

$Services         = Get-WmiObject Win32_Service
$BadServices      = $null
$Reasons          = $null
$UnrecognizedPath = 0


for ($i = 0; $i -lt $Services.Count; $i++)
{
    ##
    ## Get the actual Exe Path
    ##
    $ActualPathName = GetActualPathFromServiceImagePath $Services[$i].PathName
    if($ActualPathName -eq $null)
    {
        $Path             = $Services[$i].PathName
        $Name             = $Services[$i].Name
        $UnrecognizedPath = 1;

        PrintServiceInfo $Services[$i] “WARNING:” “UNRECOGNIZED_PATH” “Yellow”
        continue;
    }


########new
#######make sure all paths with spaces have double quotes around them

if ( ($Services[$i].PathName -match “^[^x22].*s.*.exe.*” ) -eq $true)
   {
    $BadServices += ,$Services[$i];
    $Reasons += ,”SPACE_IN_PATH”;

    PrintStatus($true);
    continue;


   }

 

 

    if ($Verbose -eq $true)
    {
        Write-Host -nonewline “Analyzing path ‘$ActualPathName’ …”
    }

    ##
    ## Check for Attributes
    ##
    if((Test-Path -IsValid $ActualPathName) -eq $False)
    {
        $BadServices += ,$Services[$i] ;
        $Reasons     += ,”INVALID_CHARS”;

        PrintStatus($true);
        continue;
    }


    ##
    ## Check for invalid chars
    ##
    foreach ($Key in $InvalidChars.Keys)
    {
        $Value = $InvalidChars.Item($Key);

        if ($ActualPathName -like $Key)
        {
            $temp = $Key.Replace(“*”,””)

            $BadServices += ,$Services[$i]
            $Reasons     += ,$Value;
        }

    }

    ##
    ## The Start string must be in the below specified format
    ##
    if((($ActualPathName -match “^[a-z]:\”) -ne $true))
    {
        $BadServices += ,$Services[$i]
        $Reasons     += ,”INVALID_FORMAT”;

        PrintStatus($true);
        continue;
    }

    ##
    ## Check for Reparse points
    ##
    $RootPath = [System.IO.Path]::GetPathRoot($ActualPathName)

   
    $Path = $ActualPathName
    $DoesPathExist = Test-Path -Path $ActualPathName
    while(($DoesPathExist -eq $true) -and ($Path -ne $RootPath))
    {

         $h = [System.IO.File]::GetAttributes($Path);

         if ($h.CompareTo([System.IO.FileAttributes]::ReparsePoint) -ge 0)
         {
            $BadServices += ,$Services[$i]
            $Reasons     += ,”REPARSE_POINT”;

            PrintStatus($true);
            break;
         }

         if ($Path.Contains(“”) -ne $true)
         {
             break;
         }

         $strPath = $Path.Substring(0,$Path.LastIndexOf(“”));
         $Path    = $strPath
    }

    PrintStatus($false);
}


if ($BadServices.Count -gt 0)
{
    echo “”
    echo “Following are the service(s) found to be reporting invalid paths.”
    echo “”

    for ($i=0; $i-lt$BadServices.Count; $i++)
    {
        $Count   = $i + 1
        PrintServiceInfo $BadServices[$i] “$Count.” $Reasons[$i]
    }
}
elseif ($UnrecognizedPath -ne 1)
{
    echo “”
    Write-Host “No invalid service paths found.” -ForeGroundColor Green
    echo “”
}