Batch script to configure Paths for Indexed Locations

Discussion in 'Scripting' started by AeonX, Apr 28, 2019.

  1. AeonX

    AeonX MDL Addicted

    Joined:
    May 24, 2013
    Messages:
    694
    Likes Received:
    542
    Trophy Points:
    30
    Is it possible to configure the paths indexed by Windows Search using a batch script? What commands do I need?

    I tried to monitor registry changes with the RegistryChangesView but it is not very simple to understand the logic of the changes. I tried some group policies too but they did not work out as I would like.

    I want the only indexed path after installing Windows to be:
    Code:
    C:\ProgramData\Microsoft\Windows\Start Menu
    Or (preferably):
    Code:
    %ProgramData%\Microsoft\Windows\Start Menu
     
  2. Thomas Dubreuil

    Thomas Dubreuil MDL Senior Member

    Joined:
    Aug 29, 2017
    Messages:
    357
    Likes Received:
    594
    Trophy Points:
    10
    You can use Group Policy to "include" some paths or "exlude" others from indexation, but you can't remove default paths and rules already set from Indexing Options.
    I think is possible with Powershell and calling Interop .dll but documentation is quite rare and obscure...
    deserves a look at it :)
     
  3. Thomas Dubreuil

    Thomas Dubreuil MDL Senior Member

    Joined:
    Aug 29, 2017
    Messages:
    357
    Likes Received:
    594
    Trophy Points:
    10
    #3 Thomas Dubreuil, May 6, 2019
    Last edited: May 13, 2019
    After a few tests, here you go... ;)
    Download Microsoft.Search.Interop.dll from here and place it next to the script.

    Code:
    @echo off
    
    setlocal
    set start=%time%
    set "scriptname=%TEMP%\SearchScopeTask.ps1"
    set "lock=%TEMP%\wait%random%.lock"
    cd /d "%~dp0"
    
    :: Get SID
       for /f "tokens=1,2 delims==" %%s IN ('wmic path win32_useraccount where name^='%username%' get sid /value ^| find /i "SID"') do set "SID=%%t"
    
    :: Make PS Script
       :: Call catalog
       @echo Add-Type -path "%~dp0Microsoft.Search.Interop.dll">>%scriptname%
       @echo $sm = New-Object Microsoft.Search.Interop.CSearchManagerClass>>%scriptname%
       @echo $catalog = $sm.GetCatalog^("SystemIndex"^)>>%scriptname%
       @echo $crawlman = $catalog.GetCrawlScopeManager^(^)>>%scriptname%
       :: Reset rules
       @echo $crawlman.RevertToDefaultScopes^(^)>>%scriptname%
       @echo $crawlman.SaveAll^(^)>>%scriptname%
       :: Remove rules
       @echo $crawlman.RemoveDefaultScopeRule^("file:///C:\Users\*"^)>>%scriptname%
       @echo $crawlman.SaveAll^(^)>>%scriptname%
       @echo $crawlman.RemoveDefaultScopeRule^("file:///C:\ProgramData\Microsoft\Windows\Start Menu\*"^)>>%scriptname%
       @echo $crawlman.SaveAll^(^)>>%scriptname%
       @echo $crawlman.RemoveDefaultScopeRule^("file:///C:\Users\*\AppData\Local\Microsoft\Windows\Temporary Internet Files\*"^)>>%scriptname%
       @echo $crawlman.SaveAll^(^)>>%scriptname%
       @echo $crawlman.RemoveDefaultScopeRule^("file:///C:\Users\*\AppData\Local\Temp\*"^)>>%scriptname%
       @echo $crawlman.SaveAll^(^)>>%scriptname%
       @echo $crawlman.RemoveDefaultScopeRule^("file:///C:\Users\*\AppData\*"^)>>%scriptname%
       @echo $crawlman.SaveAll^(^)>>%scriptname%
       @echo $crawlman.RemoveDefaultScopeRule^("iehistory://{%SID%}"^)>>%scriptname%
       @echo $crawlman.SaveAll^(^)>>%scriptname%
       :: Add start menu path
       @echo $crawlman.AddUserScopeRule^("file:///%ProgramData%\Microsoft\Windows\Start Menu\*",$true,$false,$null^)>>%scriptname%
       @echo $crawlman.SaveAll^(^)>>%scriptname%
       :: Remove automatically added favorites
       @echo $crawlman.RemoveDefaultScopeRule^("file:///%UserProfile%\Favorites\*"^)>>%scriptname%
       @echo $crawlman.SaveAll^(^)>>%scriptname%
       :: Reindex
       @echo $Catalog.Reindex^(^)>>%scriptname%
       :: Delete lock file
       @echo Remove-Item "%lock%">>%scriptname%
    
    :: Execute Task
       :: Create lock file
       @echo Locked>"%lock%"
       :: Launch ps script with admin and hidden
       PowerShell -NoProfile -ExecutionPolicy Bypass -c "& {Start-Process Powershell -ArgumentList '-ExecutionPolicy Unrestricted -File "%scriptname%" -force' -Verb RunAs -WindowStyle hidden}" >NUL 2>&1
       :: loop until lock file is deleted
       :Wait
       if exist "%lock%" goto :Wait
    
    :: Clean
       del "%scriptname%" /s /q >NUL 2>&1
    exit /b
    
    If you want to add more custom paths, here's an "interactive" (=not "post-install") hybrid script with a fancy browser :)

    Note: couldn't write the escape characters, so for the titles and colors to show/work,
    replace at lines 12, 15 and 145 ESC and BEL by "real" ESC and BEL signs (ANSI escape code 27 and 7: holding ALT key and type 027 or 07 in text editors).

    Edit: Added a little menu at start so user can choose to either set custom locations, add only windows start menus, reset to default, or remove everything from indexing options. :)

    Code:
    @if (@CodeSection == @Batch) @then
    
    
    @echo off
    setlocal
    set "Clean=OFF"
    set "Index=0"
    set "IndexedFolder="
    set "tmpfolder=%TEMP%\Indexing_Options_%random%.tmp"
    set "lock=%tmpfolder%\wait%random%.lock"
    set "scriptname=%tmpfolder%\SearchScopeTask.ps1"
    set "Shell_Title=ESC]0;Indexing OptionsBEL"
      
       mkdir "%tmpfolder%" >NUL 2>&1
       echo ESC[97m%Shell_Title%ESC[97m
       cls
       cd /d "%~dp0"
    
    :SmallMenu
       echo 1. Set custom locations& echo:
       echo 2. Add Windows start menus only& echo:
       echo 3. Remove all locations from indexing options& echo:
       echo 4. Default indexing options settings& echo: & echo:
       choice /c 12340 /n /m "Select your option, or 0 to exit: "
       if errorlevel 5 ( set "Clean=ON" & goto :Clean)
       if errorlevel 4 ( set "Style=default" & cls & goto :ScopeTask)
       if errorlevel 3 ( set "Style=reset" & cls & goto :ScopeTask)
       if errorlevel 2 ( set "Style=startmenus" & cls & goto :ScopeTask)
       if errorlevel 1 ( set "Style=custom" & goto :PathSelection)
       goto :eof
    
    :PathSelection
       setlocal EnableDelayedExpansion
       for /F "delims=" %%a in ('CScript //nologo //E:JScript "%~F0" "Select the folder or type the path you want to index, then click OK."') do (
           if %Index%==0 ( cls & set "IndexedFolder=%%a") else ( set "Index2_%Index%=%%a")
       )
       if "%IndexedFolder%" == "" ( cls & goto :SmallMenu)
       if %Index%==0 ( echo You selected "%IndexedFolder%") else ( echo You selected "!Index2_%Index%!")
       <nul set /p dummyName=Do you want to add another path to indexed locations? [Y/N]
       choice /C:YN /M "" >NUL 2>&1
       if errorlevel 2 ( echo No& goto :PathResult)
       set /a "Index+=1"
       echo Yes
       goto :PathSelection
    
    :PathResult
       echo:
       if %Index%==0 (
           echo Indexed location is "%IndexedFolder%"
           goto :SetCount
       )
       echo Indexed locations are
       echo "%IndexedFolder%"
    :SetCount
       set /a "Count=%Index%"
    
    :ResultLoop
       if "%Count%" == "0" ( echo: & goto :ScopeTask)
       set "Index2=!Index2_%Count%!"
       echo "%Index2%"
       set /a "Count-=1"
       goto :ResultLoop
    
    :ScopeTask
    :: Get SID
       <nul set /p dummyName=Setting Indexing Options...
       for /f "tokens=1,2 delims==" %%s IN ('wmic path win32_useraccount where name^='%username%' get sid /value ^| find /i "SID"') do set "SID=%%t"
    :: Make PS Script
       @echo Add-Type -path "%~dp0Microsoft.Search.Interop.dll">>%scriptname%
       @echo $sm = New-Object Microsoft.Search.Interop.CSearchManagerClass>>%scriptname%
       @echo $catalog = $sm.GetCatalog^("SystemIndex"^)>>%scriptname%
       @echo $crawlman = $catalog.GetCrawlScopeManager^(^)>>%scriptname%
       :: Reset rules
       @echo $crawlman.RevertToDefaultScopes^(^)>>%scriptname%
       @echo $crawlman.SaveAll^(^)>>%scriptname%
       :: Remove default rules
       if "%Style%" == "default" ( goto :MakeDefault)
       @echo $crawlman.RemoveDefaultScopeRule^("file:///C:\Users\*"^)>>%scriptname%
       @echo $crawlman.SaveAll^(^)>>%scriptname%
       @echo $crawlman.RemoveDefaultScopeRule^("file:///C:\ProgramData\Microsoft\Windows\Start Menu\*"^)>>%scriptname%
       @echo $crawlman.SaveAll^(^)>>%scriptname%
       @echo $crawlman.RemoveDefaultScopeRule^("file:///C:\Users\*\AppData\Local\Microsoft\Windows\Temporary Internet Files\*"^)>>%scriptname%
       @echo $crawlman.SaveAll^(^)>>%scriptname%
       @echo $crawlman.RemoveDefaultScopeRule^("file:///C:\Users\*\AppData\Local\Temp\*"^)>>%scriptname%
       @echo $crawlman.SaveAll^(^)>>%scriptname%
       @echo $crawlman.RemoveDefaultScopeRule^("file:///C:\Users\*\AppData\*"^)>>%scriptname%
       @echo $crawlman.SaveAll^(^)>>%scriptname%
       @echo $crawlman.RemoveDefaultScopeRule^("iehistory://{%SID%}"^)>>%scriptname%
       @echo $crawlman.SaveAll^(^)>>%scriptname%
       if "%Style%" == "default" ( goto :MakeDefault)
       if "%Style%" == "reset" ( goto :Finish_Ps)
       if "%Style%" == "startmenus" ( goto :AddStartMenus)
       if "%Style%" == "custom" ( goto :SetCustomPaths)
      
       :MakeDefault
       @echo $crawlman.AddUserScopeRule^("file:///C:\Users\*",$true,$false,$null^)>>%scriptname%
       @echo $crawlman.SaveAll^(^)>>%scriptname%
       @echo $crawlman.AddUserScopeRule^("file:///C:\ProgramData\Microsoft\Windows\Start Menu\*",$true,$false,$null^)>>%scriptname%
       @echo $crawlman.SaveAll^(^)>>%scriptname%
       @echo $crawlman.AddUserScopeRule^("iehistory://{%SID%}",$true,$false,$null^)>>%scriptname%
       @echo $crawlman.SaveAll^(^)>>%scriptname%  
       goto :Reindex
      
       :AddStartMenus
       :: Add start menu locations
       @echo $crawlman.AddUserScopeRule^("file:///%ProgramData%\Microsoft\Windows\Start Menu\Programs\*",$true,$false,$null^)>>%scriptname%
       @echo $crawlman.SaveAll^(^)>>%scriptname%
       @echo $crawlman.AddUserScopeRule^("file:///%AppData%\Microsoft\Windows\Start Menu\Programs\*",$true,$false,$null^)>>%scriptname%
       @echo $crawlman.SaveAll^(^)>>%scriptname%
       goto :Finish_Ps
      
       :SetCustomPaths
       :: Add custom path
       @echo $crawlman.AddUserScopeRule^("file:///%IndexedFolder%\*",$true,$false,$null^)>>%scriptname%
       @echo $crawlman.SaveAll^(^)>>%scriptname%
      
       :MorePathsLoop
       :: Loop until there is no more paths to add
       if %Index%==0 ( goto :Finish_Ps)
       set "Index2=!Index2_%Index%!"
       @echo $crawlman.AddUserScopeRule^("file:///%Index2%\*",$true,$false,$null^)>>%scriptname%
       @echo $crawlman.SaveAll^(^)>>%scriptname%
       set /a "Index-=1"
       goto :MorePathsLoop
      
       :Finish_Ps
       :: Remove automatically added favorites
       @echo $crawlman.RemoveDefaultScopeRule^("file:///%UserProfile%\Favorites\*"^)>>%scriptname%
       @echo $crawlman.SaveAll^(^)>>%scriptname%
       :Reindex
       @echo $Catalog.Reindex^(^)>>%scriptname%
       :: Delete lock file
       @echo Remove-Item "%lock%">>%scriptname%
    
    :: Execute Task
       :: Create lock file
       @echo Locked>"%lock%"
       :: Launch script
       PowerShell -NoProfile -ExecutionPolicy Bypass -c "& {Start-Process Powershell -ArgumentList '-ExecutionPolicy Unrestricted -File "%scriptname%" -force' -Verb RunAs -WindowStyle hidden}" >NUL 2>&1
       :: loop until lock file is deleted  
       :Wait
       if exist "%lock%" goto :Wait
    
    :Clean
       if "%Clean%" == "ON" ( cls & echo ESC[?25lNo indexing location has been set.) else ( echo ESC[?25lESC[92mDone.)
    :: loop to ensure temp files and folders are not anymore in use and can be deleted.
       :CleanCheck1  
       if not exist "%scriptname%" ( goto :CleanCheck2) else (
           del "%scriptname%" /f /s /q >NUL 2>&1
           goto :CleanCheck1
       )
       :CleanCheck2
       if not exist "%tmpfolder%" ( goto :End_Pause) else (
           rmdir "%tmpfolder%" /s /q >NUL 2>&1
           goto :CleanCheck2
       )
       :End_Pause
       timeout /t 2 /nobreak >NUL 2>&1
    goto :eof
    
    
    @end
    
    
    var shl = new ActiveXObject("Shell.Application");
    var folder = shl.BrowseForFolder(0, WScript.Arguments(0), 0x00000050,17);
    WScript.Stdout.WriteLine(folder ? folder.self.path : "");
    
    Sources:
    Powershell Bible page here and
    https://powertoe.wordpress.com/2010/05/17/powershell-tackles-windows-desktop-search/
     
  4. Thomas Dubreuil

    Thomas Dubreuil MDL Senior Member

    Joined:
    Aug 29, 2017
    Messages:
    357
    Likes Received:
    594
    Trophy Points:
    10
    #4 Thomas Dubreuil, May 9, 2019
    Last edited: May 13, 2019
  5. AeonX

    AeonX MDL Addicted

    Joined:
    May 24, 2013
    Messages:
    694
    Likes Received:
    542
    Trophy Points:
    30
    Thank you!! I will test as soon as I can and give feedback.
    I'm busy trying to finish a script for Windows 7 (searching, testing, refining the code ...).

    My goal is to create a script that works on both a live system and an offline image equally or as closely as possible.

    I would prefer to disable the windows search service but doing so will appear an unwanted message in windows explorer asking to activate the service or something like that every time I use the search. The reg tweak to disable this message only works if I remove the service (which I would not want to do without removing the rest of the component with NTLite or similar).

    I refer to this reg tweak:
    Code:
    reg add HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\InfoBarsDisabled /v ServerMSSNotInstalled /t REG_DWORD /d 1 /f
    Source: https://superuser.com/questions/102...n-non-indexed-locations-banner-from-appearing
     
  6. Thomas Dubreuil

    Thomas Dubreuil MDL Senior Member

    Joined:
    Aug 29, 2017
    Messages:
    357
    Likes Received:
    594
    Trophy Points:
    10
    I'm not sure you can set indexed locations on an offline image, but you can make a install/deployment script like first one.

    I also leave indexing enabled, only for start menu locations (both paths), so that I type few letters and can very quickly launch programs from search box.
    And that's why found your question interesting, never thought I could also automate that task...

    Just an idea (never tried) on your case, through gpo/gpedit you can set a "disk space limit" for Search Index so that it stop indexing when reached that size limit.
    I'd (script would) remove every indexed locations + set gpo to enabled and value like, I want to keep 480 go free on my (480go) drive.
    or for an "everyone" script, something like: remove all indexed loc/get system disk space/set disk space to leave (reg add or gpo editing with powershell)