Hklm software wow6432node microsoft windows currentversion explorer browser helper objects

Удалить InternetHelper Toolbar из Google Chrome, Mozilla Firefox, Internet Explorer

  • Что такое InternetHelper Toolbar
  • Скачать утилиту для удаления InternetHelper Toolbar
  • Удалить InternetHelper Toolbar вручную
  • Удалить InternetHelper Toolbar из Google Chrome
  • Удалить InternetHelper Toolbar из Mozilla Firefox
  • Удалить InternetHelper Toolbar из Internet Explorer
  • Удалить InternetHelper Toolbar из Windows 10
  • Удалить InternetHelper Toolbar из Windows 8/8.1
  • Удалить InternetHelper Toolbar из Windows 7
  • Сбросить настройки браузеров
  • Получить проффесиональную поддержку
  • Читать комментарии

Информация об угрозе

Название угрозы:InternetHelper Toolbar

Исполяемый файл:InternetHelperToolbarHelper.exe

Тип угрозы:Toolbars

Затронутые ОС:Win32/Win64 (Windows XP, Vista/7, 8/8.1, Windows 10)

Затронутые браузеры:Google Chrome, Mozilla Firefox, Internet Explorer, Safari

InternetHelper Toolbar

InternetHelper Toolbar устанавливается на ваш компьютер вместе с бесплатными программами. Этот способ можно назвать «пакетная установка». Бесплатные программы предлагают вам установить дополнительные модули (InternetHelper Toolbar). Если вы не отклоните предложение установка начнется в фоне. InternetHelper Toolbar копирует свои файлы на компьютер. Обычно это файл InternetHelperToolbarHelper.exe. Иногда создается ключ автозагрузки с именем InternetHelper Toolbar и значением InternetHelperToolbarHelper.exe. Вы также сможете найти угрозу в списке процессов с именем InternetHelperToolbarHelper.exe или InternetHelper Toolbar. также создается папка с названием InternetHelper Toolbar в папках C:\Program Files\ или C:\ProgramData. После установки InternetHelper Toolbar начинает показывать реламные баннеры и всплывающую рекламу в браузерах. рекомендуется немедленно удалить InternetHelper Toolbar. Если у вас есть дополнительные вопросы о InternetHelper Toolbar, пожалуйста, укажите ниже. Вы можете использовать программы для удаления InternetHelper Toolbar из ваших браузеров ниже.



Наша служба тех. поддержки удалит InternetHelper Toolbar прямо сейчас!

Обратитесь в нашу службу технической поддержки с проблемой связанной с InternetHelper Toolbar. Опишите все обстоятельства заражения InternetHelper Toolbar и его последствия. Команда предоставит вам варианты решения этой проблемы бесплатно в течении нескольких часов.

Подать запрос в тех. поддержку

Описание угрозы и инструкции по удалению предоставлены аналитическим отделом компании Security Stronghold.

Здесь вы можете перейти к:

  • Техническое описание угрозы InternetHelper Toolbar.
  • Инструкции по удалению InternetHelper Toolbar вручную.
  • Скачать утилиту для удаления InternetHelper Toolbar.

Как удалить InternetHelper Toolbar вручную

Проблема может быть решена вручную путем удаления файлов, папок и ключей реестра принадлежащих угрозе InternetHelper Toolbar. Поврежденные InternetHelper Toolbar системные файлы и компоненты могут быть восстановлены при наличии установочного пакета вашей операционной системы.

Чтобы избавиться от InternetHelper Toolbar, необходимо:

  • InternetHelperToolbarHelper.exe

Предупреждение: нужно удалить только файлы с именами и путями указанными здесь. В системе могут находится полезные файлы с такими же именами. Мы рекомендуем использовать утилиту для удаления InternetHelper Toolbar для безопасного решения проблемы.

  • %PROFILE%\Application Data\InternetHelper3.1
  • %PROFILE%\AppData\LocalLow\InternetHelper3.1
  • %PROGRAMFILES(X86)%\InternetHelper3.1
  • %PROGRAMFILES%\InternetHelper3.1
  • Key:
    HKCU\Software\Microsoft\Internet Explorer\Low Rights\ElevationPolicy\{0C85FBC2-F9CF-440E-B34F-CFB76AA51A71}
  • Key: HKLM\SOFTWARE\Wow6432Node\Microsoft\Internet Explorer\Low Rights\ElevationPolicy
    \{0C85FBC2-F9CF-440E-B34F-CFB76AA51A71}
  • Key:
    HKCU\Software\Microsoft\Internet Explorer\Low Rights\ElevationPolicy\{BB894EB2-4985-402C-BA01-BC68BC8D406F}
  • Key: HKLM\SOFTWARE\Wow6432Node\Microsoft\Internet Explorer\Low Rights\ElevationPolicy
    \{BB894EB2-4985-402C-BA01-BC68BC8D406F}
  • Key:
    HKCU\Software\Microsoft\Internet Explorer\SearchScopes\{928935C5-5A57-452D-82E5-BC069F467529}
  • Key:
    HKLM\SOFTWARE\Wow6432Node\Microsoft\Internet Explorer\SearchScopes\{928935C5-5A57-452D-82E5-BC069F467529}
  • Key: HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\explorer\Browser Helper Objects
    \{07cbf788-1359-421b-a4e3-5a8d041b90a3}
  • Key: HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\explorer\Browser Helper Objects
    \{07cbf788-1359-421b-a4e3-5a8d041b90a3}
  • Key: HKLM\SOFTWARE\Wow6432Node\InternetHelper3.1
  • Key: HKLM\SOFTWARE\InternetHelper3.1
  • Key: HKCU\Software\AppDataLow\Software\InternetHelper3.1
  • Key:
    HKCU\Software\Microsoft\Internet Explorer\Low Rights\ElevationPolicy\{0C85FBC2-F9CF-440E-B34F-CFB76AA51A71}
  • Key: HKLM\SOFTWARE\Wow6432Node\Microsoft\Internet Explorer\Low Rights\ElevationPolicy
    \{0C85FBC2-F9CF-440E-B34F-CFB76AA51A71}
  • Key:
    HKCU\Software\Microsoft\Internet Explorer\Low Rights\ElevationPolicy\{BB894EB2-4985-402C-BA01-BC68BC8D406F}
  • Key: HKLM\SOFTWARE\Wow6432Node\Microsoft\Internet Explorer\Low Rights\ElevationPolicy
    \{BB894EB2-4985-402C-BA01-BC68BC8D406F}
  • Key:
    HKCU\Software\Microsoft\Internet Explorer\SearchScopes\{928935C5-5A57-452D-82E5-BC069F467529}
  • Key:
    HKLM\SOFTWARE\Wow6432Node\Microsoft\Internet Explorer\SearchScopes\{928935C5-5A57-452D-82E5-BC069F467529}
  • Key: HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\explorer\Browser Helper Objects
    \{07cbf788-1359-421b-a4e3-5a8d041b90a3}
  • Key: HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\explorer\Browser Helper Objects
    \{07cbf788-1359-421b-a4e3-5a8d041b90a3}
  • Key: HKLM\SOFTWARE\Wow6432Node\InternetHelper3.1
  • Key: HKLM\SOFTWARE\InternetHelper3.1
  • Key: HKCU\Software\AppDataLow\Software\InternetHelper3.1

Предупреждение: если указано значение ключа реестра, значит необходимо удалить только значение и не трогать сам ключ. Мы рекомендуем использовать для этих целей утилиту для удаления InternetHelper Toolbar.

Удалить программу InternetHelper Toolbar и связанные с ней через Панель управления

Мы рекомендуем вам изучить список установленных программ и найти InternetHelper Toolbar а также любые другие подозрительные и незнакомы программы. Ниже приведены инструкции для различных версий Windows. В некоторых случаях InternetHelper Toolbar защищается с помощью вредоносного процесса или сервиса и не позволяет вам деинсталлировать себя. Если InternetHelper Toolbar не удаляется или выдает ошибку что у вас недостаточно прав для удаления, произведите нижеперечисленные действия в Безопасном режиме или Безопасном режиме с загрузкой сетевых драйверов или используйте утилиту для удаления InternetHelper Toolbar.

Windows 10

  • Кликните по меню Пуск и выберите Параметры.
  • Кликните на пункт Система и выберите Приложения и возможности в списке слева.
  • Найдите InternetHelper Toolbar в списке и нажмите на кнопку Удалить рядом.
  • Подтвердите нажатием кнопки Удалить в открывающемся окне, если необходимо.

Windows 8/8.1

  • Кликните правой кнопкой мыши в левом нижнем углу экрана (в режиме рабочего стола).
  • В открывшимся меню выберите Панель управления.
  • Нажмите на ссылку Удалить программу в разделе Программы и компоненты.
  • Найдите в списке InternetHelper Toolbar и другие подозрительные программы.
  • Кликните кнопку Удалить.
  • Дождитесь завершения процесса деинсталляции.

Windows 7/Vista

  • Кликните Пуск и выберите Панель управления.
  • Выберите Программы и компоненты и Удалить программу.
  • В списке установленных программ найдите InternetHelper Toolbar.
  • Кликните на кнопку Удалить.

Windows XP

  • Кликните Пуск.
  • В меню выберите Панель управления.
  • Выберите Установка/Удаление программ.
  • Найдите InternetHelper Toolbar и связанные программы.
  • Кликните на кнопку Удалить.

Удалите дополнения InternetHelper Toolbar из ваших браузеров

InternetHelper Toolbar в некоторых случаях устанавливает дополнения в браузеры. Мы рекомендуем использовать бесплатную функцию «Удалить тулбары» в разделе «Инструменты» в программе Spyhunter Remediation Tool для удаления InternetHelper Toolbar и свяанных дополнений. Мы также рекомендуем вам провести полное сканирование компьютера программами Wipersoft и Spyhunter Remediation Tool. Для того чтобы удалить дополнения из ваших браузеров вручную сделайте следующее:

  • Запустите Internet Explorer и кликните на иконку шестеренки в верхнем правом углу
  • В выпадающем меню выберите Настроить надстройки
  • Выберите вкладку Панели инструментов и расширения.
  • Выберите InternetHelper Toolbar или другой подозрительный BHO.
  • Нажмите кнопку Отключить.

Предупреждение: Эта инструкция лишь деактивирует дополнение. Для полного удаления InternetHelper Toolbar используйте утилиту для удаления InternetHelper Toolbar.

  • Запустите Google Chrome.
  • В адресной строке введите chrome://extensions/.
  • В списке установленных дополнений найдите InternetHelper Toolbar и кликните на иконку корзины рядом.
  • Подтвердите удаление InternetHelper Toolbar.
  • Запустите Firefox.
  • В адресной строке введите about:addons.
  • Кликните на вкладку Расширения.
  • В списке установленных расширений найдите InternetHelper Toolbar.
  • Кликните кнопку Удалить возле расширения.

Сбросить настройки поиска и домашней страницы в браузерах

InternetHelper Toolbar заражает ваши браузеры, а именно подменяет настройки поиска домашней страницы и новой вкладки в браузерах Google Chrome, Mozilla Firefox и Internet Explorer. Мы рекомендуем вам использовать бесплатную функцию Сбросить настройки браузеров в меню Инструменты в Spyhunter Remediation Tool, чтобы сбросить настройки всех установленных браузеров. Учтите, что перед этим необходимо деинсталлировать все программы связанные с InternetHelper Toolbar и удалить все файлы созданные этими программами. Для сброса настроек вручную и восстановления домашний страницы выполните следующие действия:

  • Если вы используете Windows XP, кликните Пуск, и кликните Выполнить. В окне Запуск введите «inetcpl.cpl» без кавычек, и нажмите Enter.
  • Если вы используете Windows 7 или Windows Vista, кликните Пуск. В окне поиска введите «inetcpl.cpl» без кавычек, и нажмите Enter.
  • Выберите вкладку Дополнительно.
  • Кликните кнопку Сброс…, которая расположена ниже.
  • Отметьте галочку Удалить личные настройки и кликните кнопку Сброс.
  • После завершения, кликните Закрыть в окне Сброс параметров настройки Internet Explorer.

Предупреждение: В случае если это не срабатывает, используйте бесплатную функцию Сбросить настройки браузеров в разделе Инструменты в Spyhunter Remediation Tool.

  • Зайдите в папку с установленным Google Chrome: C:\Users\»имя пользователя»\AppData\Local\Google\Chrome\Application\User Data.
  • В папке User Data, найдите файл Default и переименуйте его в DefaultBackup.
  • Запустите Google Chrome и будет создан новый файл Default.
  • Таким образом настройки будут сброшены.

Предупреждение: Эта опция может не сработать если ваш Google Chrome использует синхронизацию с другим компьютером. В этом случае используйте функцию Сбросить настройки браузеров в разделе Инструменты в Spyhunter Remediation Tool.

  • Откройте Mozilla Firefox.
  • Кликните на иконку с тремя горизонтальными линиями и затем на иконку вопросительного знака и выберите Информация для решения проблем.
  • Кликните на кнопку Сбросить Firefox.
  • После завершения процедуры Firefox создаст резервную папку на рабочем столе. Нажмите Завершить.

Предупреждение: Используя эту функцию вы также сбросите все запомненые пароли к сайтам. Если вы этого не хотите используйте функцию Сбросить настройки браузеров в разделе Инструменты в Spyhunter Remediation Tool.

Следующее описаниее: Top8844.com »

« Вернуться в каталог

Идея написания сводного руководства по самостоятельному обнаружению вирусов на станциях под управлением Windows зрела на протяжении достаточно длительного времени и обуславливалась, прежде всего необходимостью составить и время от времени дополнять справочник возможных расположений запуска вирусного кода. Лейтмотивом этой идеи является необходимость непосредственного, то есть самостоятельного (ручного) анализа системы в случаях, когда имеется подозрение, что автоматические методы (утилиты/антивирусы), не в состоянии обнаружить работающий в системе вредоносный код. Обнаружение вируса собственными силами — вот тот уровень, который не будет лишним для любого технического специалиста по операционным системам Windows. Хотелось бы сделать небольшое отступление и пару слов сказать на счет самих антивирусных продуктов. Надо заметить, что эти, самые надежные по мнению большинства, помощники в борьбе с вредоносным кодом, вообще-то не являются панацеей от заражения операционной системы. Повидавшая виды практика помнит случаи, когда грамотно написанный вредоносный код, учитывающий эвристические особенности определенных «региональных» антивирусов, долгое время оставался незамеченным на критически важных корпоративных системах. В этом то и заключается парадокс зараженной системы, в которой установлен авторитетный антивирус с актуальными антивирусными базами. Подобный курьез говорит о том, что если вирус использует хотя бы мало-мальски оригинальный код, методы маскировки, различные виды упаковок, алгоритмы противодействия, то антивирусу бывает сложно обнаружить его, либо он не может деактивировать и удалить уже находящийся и функционирующий в системе вредоносный код, и это не смотря на продвинутые методы контроля системы с перехватом различных системных вызовов и прочие виды глубокой системной интеграции. Подобных доводов можно привести множество, но все они сводятся к одному единственному выводу.

Невозможно обеспечить 100% антивирусную защиту автоматизированными средствами.

И именно в свете сего немаловажного обстоятельства, в критические моменты встает необходимость уметь собственноручно обнаруживать и удалять вредоносный код, и именно поэтому данная статья будет посвящена изложению методов обнаружения без использования каких-либо антивирусных средств, исключением у нас будут, разве что, небольшие сопутствующие утилиты.
«Все течет, все меняется» (© Гераклит), и операционные системы из этого постулата, конечно же, не исключение. На протяжении всей истории развития операционных систем Windows, идет их постоянное видоизменение, одни системные механизмы перестают эксплуатироваться, долгое время присутствуя в системе в виде рудиментов совместимости и в последствии исчезая, другие же появляются. Происходит бесконечное движение, вирусописатели подстраиваются под эволюционирующую среду, переписывая код, использующий устаревающие механизмы, начинают искать и эксплуатировать другие, обретающие актуальность. Учитывая меняющиеся от версии к версии особенности операционных систем и достаточно большое количество потенциальных точек активации вредоносного кода, статья эта никогда не будет завершена полностью и конечно же не будет претендовать на полное руководство по выбранной тематике. Однако, по мере получения новых знаний, будет время от времени мною дорабатываться в бесконечной попытке соответствовать современным реалиям.
Перед тем как мы начнем работать с довольно сложной темой под названием обнаружение вируса, хотелось бы отдельно сказать вот еще о чем.

Во избежание разночтения и неправильного трактования некоторых моих выражений, под понятием вирус в данной статье будет подразумеваться любой вид вредоносного кода.

Дело в том, что с момента зарождения эры компьютерных вирусов, специалистами по безопасности было введено в оборот такое великое многообразие терминов и определений, что классификация в рамках небольшой статьи выглядела бы, откровенно говоря, излишней, учитывая и тот факт, что в свете характера статьи для нас фактически не так уж и важно, как зовется та или иная разновидность вредоносного кода. В разнообразных материалах, посвященных теме компьютерных вирусов, встречаются оригинальные определения, специалисты по безопасности называют программное обеспечение, которое выполняет деструктивные действия различными именами. На заре операционной системы MS-DOS вирусами называли программы, которые реплицировали собственный код в обнаруживаемые исполняемые модули и загрузочный сектор. С появлением линейки операционных систем Windows, вредоносный код обрел истинное многообразие, на свет появилось большое количество всевозможных алгоритмических отклонений, таких как руткиты (rootkit), трояны (troyan), шпионы (spyware), рекламные программы (adware), вымогатели (ransomware), сетевые черви (worms) и прочее, прочее, прочее. И все эти вариации на вирусную тему имеют различное предназначение. Часто термины ассоциируются неправильно, и вещи называются не своими именами, в дополнение, ко всему этому многообразию применяются второстепенные термины, такие как вредоносный код, зловред, вредонос. Поэтому, дабы не вводить читателя в заблуждение, я буду использовать определение «вирус» применительно к любому вредоносному коду, поэтому встречая в тексте термин вирус, подразумеваем любой вид вредоносного кода.
По каким косвенным признакам пользователь может обнаружить вирус в операционной системе? Дело в том, что какого-то единого, вполне определенного и однозначного симптома заражения системы вирусом не существует, однако общими следствиями вирусной активности могут быть:

  • Низкая производительность операционной системы;
  • Низкая производительность отдельных приложений;
  • Часто возникающие ошибки в приложениях;
  • Отображение посторонних информационных окон;
  • Блокировка рабочего стола пользователя различными информационными окнами;
  • Блокировка страницы (вкладки) браузера различными информационными окнами;
  • Блокировка доступа к определенным ресурсам в сети Интернет (например, к сайтам антивирусных лабораторий);
  • Автоматический запуск разнообразных программ;
  • Отказ в изменении некоторых настроек операционной системы (даже под учетной записью локального администратора);
  • Загруженная сеть, наличие интенсивного трафика на интерфейсах в моменты бездействия;
  • Иная подозрительная (отклоненная от штатной) активность операционной системы;

Внимательно изучив описанные выше первичные признаки, можно сделать однозначный вывод что зачастую довольно сложно отличить вирусную активность от типовых сбоев, вызванных аппаратными и программными проблемами. Обычно в случае подозрения на аномальную активность, пользователь прибегает к помощи антивирусов, но что же делать ему в ситуации, когда работающий антивирус при сканировании не может детектировать в системе никакой вирусной активности, а «глюки» сохраняются и подозрение на вирус остается?! В этом случае можно попробовать переустановить операционную систему, выбор безусловно за вами, но в этом случае вы теряете уникальную возможность саморазвития, не получаете дополнительных знаний по компьютерным вирусам, исключаете возможность обнаружить новые виды вирусной активности. Может все же стоит попробовать «пройтись по системе» самостоятельно с целью обнаружения вируса, изучив возможные местоположения запуска и модификации? Хорошо, для начала требуется усвоить одно простое правильно:

Компьютерный вирус — код, способный (несанкционированно, без ведома пользователя) копировать самого себя в любом доступном виде, модифицируя требуемым образом различные системные области: регионы виртуальной памяти, системный реестр, загрузочный сектор диска/раздела, файловую систему. Может содержать деструктивную нагрузку.

Большинство вирусов рассчитаны на многократное исполнение, поэтому обычно оставляют свою копию в файловой системе в виде отдельного файла (группы файлов), с целью в дальнейшем иметь возможность запускаться многократно в автоматическом режиме. Применительно к операционной системе Windows, вирус представляется обычно в виде отдельного файла с расширением, идентифицирующим исполняемый различными подсистемами операционной системы код, вот некоторые из этих расширений: .exe, .dll, .sys, .ocx, .js, .ps1, .wht, .com, .bat, .vbs и прч. Некоторые вирусы, активизирующиеся в системе, не оставляют свои запускаемые копии, а просто проводят модификации определенных ключей реестра или ключевых конфигурационных файлов с целью решения собственных задач. Следуя этой логике, в целях обнаружения вируса, мы будем искать наличие подозрительных данных в физических секторах диска, файловой системе, реестре и оперативной памяти. Но ведь не придется же нам парсить полностью все эти компоненты в поисках вирусного кода? Хотя идея и неплоха :) но конечно же нет, мы будем пытаться обнаружить вирус в строго предопределенных местах: в тех расположениях в операционной системе, откуда, по задумке разработчиков, средствами самой системы могут запускаться различные исполняемые модули и где могут находиться важные для системы данные в виде файлов конфигурации различного назначения. Не лишним будет и умение отличать вирусный код от легального, знание о том, какие именно данные являются вполне безобидными, а какие из них подозрительны, то есть с большой вероятностью могут представлять вредоносный код.
Еще одним немаловажным аспектом является наличие сторонней среды, то есть операционной системы, заведомо чистой от различного рода вирусов. Делается это с тем расчетом, что некоторые особо продвинутые вирусы могут маскировать свою активность в системе, перехватывая вызовы различных функций Windows API. Поэтому, с целью получения чистой тестовой среды, мы можем:

  • Запуститься в обычном режиме загрузки под учетной записью с правами локального администратора.
  • Загрузиться в защищенный режим; Большинство вирусов в защищенном режиме не запускаются.
  • Загрузиться с внешнего диска LiveCD, содержащего среду Windows PE (Portable Executable), в состав которой входят средства работы с физическими секторами диска, файловой системой и системным реестром.

Сокращения, используемые далее в данной статье:

Сокращение Полное наименование
HKCR HKEY_CLASSES_ROOT
HKCU HKEY_CURRENT_USER
HKLM HKEY_LOCAL_MACHINE
HCU HKEY_USERS

В статье я постарался свести максимальное количество известных мне методов загрузки вирусов в операционной системе Windows.

Автозагрузка

Конечно же, первое по популярности расположение в операционной системе это автозагрузка. Автозагрузка — специализированное расположение в операционной системе, описываемое соответствующими ключами реестра а так же определенными каталогами в файловой системе, которое предназначается для автоматической загрузки исполняемых модулей на этапе загрузки операционной системы. Большой процент вирусов пытается прописать себя именно в автозагрузку методом модификации соответствующих ключей и расположений. Поэтому, для того, чтобы обнаружить вирус, достаточно пристально изучить списки программ, загружающихся с помощью данного системного механизма.

Автозагрузка в реестре

Windows 7:

  • HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
    Определяет общесистемную ветку реестра, содержащую записи о программам, запускаемых при входе в систему любого пользователя.
  • HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
    Определяет пользовательскую ветку реестра, содержащую записи о программах, запускаемых при входе в систему конкретного пользователя.
  • HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Run
    Определяет общесистемную ветку реестра, содержащую записи о 32-битных программах, загружаемых при входе в 64-битную систему любого пользователя.
  • HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce
    Определяет общесистемную ветку реестра, содержащие записи о программам, запускаемых при входе в систему разово, то есть единожды. После единственного запуска ключи программ автоматически удаляются операционной системой из данного раздела.
  • HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce
    Определяет ветку реестра конкретного пользователя, содержащую записи о программах, запускаемых при входе в систему конкретного пользователя разово, то есть единожды. После единственного запуска ключи программ автоматически удаляются операционной системой из данного раздела.
  • HKEY_USERS\SID_пользователя\Software\Microsoft\Windows\CurrentVersion\Run
    Содержит копию основной ветви автозагрузки для пользователя системы, определяемого конкретным SID-идентификатором. Например HKEY_USERS\S-1-5-21-792320725-696519568-570327587-7793\Software\Microsoft\Windows\CurrentVersion\Run. Если Вы проверяете систему из защищенного режима, либо с LiveCD, то не поленитесь проверить данный раздел для SID пользователя, который, предположительно, подхватил заразу.

Индивидуальные пути Windows 98/98SE/ME:

  • HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\RunServices
  • HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\RunServices
  • HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\RunServicesOnce
  • HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\RunServicesOnce
  • HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnceEx

Индивидуальные пути Windows XP:

  • HKCU\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows\Run

Автозагрузка групповой политики (в реестре)

В системе присутствуют ключи реестра, которые используются для загрузки программ как части групповой политики компьютера/пользователя. Если политики не заданы, что обычно имеет место быть в случае типовой домашней станции, то подраздел пуст. Записи в нем создаются только по определенным условиям, например при использовании локальной или доменной групповой политики для загрузки программ. Программы из списка автозагрузки с использованием групповой политики не отображаются во вкладке Автозагрузка в утилите msconfig.exe, могу предположить что и другие менеджеры автозагрузки могут не отображать эти записи, по этой то причине с целью обнаружения вируса, стоит заглянуть непосредственно в следующие ключи реестра:

  • HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer\Run
  • HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer\Run

Автозагрузка в файловой системе

Однако, автозагрузка вовсе не ограничивается ключами реестра. Как мы все прекрасно знаем, в Windows существует еще один (пожалуй основной) способ автоматически загрузить программу при старте операционной системы. В интерфейсе пользователя присутствует раздел Автозагрузка, который аккумулирует списки программ из специализированных расположений в файловой системе: каталогов с именем Startup в профиле конкретного пользователя и профиле пользователя по-умолчанию. Помещая в это расположение ярлык программы либо непосредственно саму программу, можно легко добиться автозагрузки программы на стадии запуска. Меня всегда вот удивляло, почему нельзя универсализировать механизмы реестровой автозагрузки и пользовательской и объединить их? Почему в Windows присутствует именно несколько различных методов загрузки, мало того, что представлены специальные ветви реестра, так еще и предоставили каталоги? Немного поразмыслив, понял, что механизм с реестром позиционируется как «системный», а механизм с автозагрузкой в качестве «пользовательского», чтобы пользователю можно было тривиально, в два клика обеспечить своему приложению автозапуск. Представляете ситуацию объединения этих механизмов.. неподготовленный (рядовой) пользователь получал бы возможность видеть все специализированные утилиты, которые загружаются через реестр и мог бы (не)преднамеренно просто их поудалять. К тому же, не каждая программа способна загрузиться посредством записи в ключах реестра.
Конечно же, и этот механизм не смог обойтись без внимания вирусописателей, и некоторые вирусы используют механизм автозагрузки из каталога для добавления исполняемых модулей при первичном получении управления собственным кодом. Поэтому специалисту не лишним будет проверить следующие местоположения:

Версия Размещение
Windows Vista/7 Для текущего пользователя: %APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup
Для всех пользователей системы: %ProgramData%\Microsoft\Windows\Start Menu\Programs\Startup
Windows 2000/XP Для текущего пользователя: %UserProfile%\Start Menu\Programs\Startup
Для всех пользователей системы: %AllUsersProfile%\Start Menu\Programs\Startup

Однако описанные местоположения могут быть изменены через ключи реестра.
Для всех пользователей системы:

  • ключ HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders,
    параметр Common Startup = %ProgramData%\Microsoft\Windows\Start Menu\Programs\Startup

Для текущего пользователя системы:

  • ключ HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders,
    параметр Startup = %USERPROFILE%\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup

Поэтому стоит иногда заглядывать в упомянутые ключи с целью проверки корректных значений установленных путей как составляющей общей стратегии по обнаружению вируса.

Загрузка на ранних стадиях

По задумке разработчиков некоторые сервисные утилиты, к примеру дефрагментаторы, программы проверки дисков, антивирусные сканеры, должны запускаться на раннем этапе процесса загрузки Windows, когда стартовали драйвера этапа загрузки (тип BOOT_START) и этапа системы (тип SYSTEM_START), но еще не инициализирован файл подкачки, переменные среды и не запущены некоторые подсистемы. В данной точке Диспетчер сеансов (Session Manager, smss.exe) только начинает разбирать переменные окружения пользовательского режима, поэтому никаких других процессов, понятное дело, еще не запущено. Однако, на данном этапе возможен запуск специально написанных образов, поддерживающих нативный (native) режим (использующих функции Native API).
Загрузка через Диспетчер сеансов настраивается в ключе реестра:

  • ключ HKLM\System\CurrentControlSet\Control\Session Manager,
    параметр BootExecute = autocheck autochk *

Если в данном параметре Вы обнаружили дополнительные образы загрузки, присмотритесь к ним внимательнее, а что если это вирус? Только не удаляйте значение по умолчанию (autocheck autochk *), оно указывает на запуск утилиты проверки диска autochk с модификатором autocheck, которая проверяет значение грязного бита (dirty bit), сообщающего о необходимости проверки раздела диска на наличие ошибок.

Hosts

Файл hosts — это системный конфигурационный (текстовый) файл, содержащий локальную базу доменных имен, используемую системой в процессе сопоставления имени хоста с IP-адресом и предназначающуюся для обеспечения возможности пользовательской настройки адресов отдельных узлов сети. Его еще можно назвать своеобразным локальным DNS-сервером. Предположим, у пользователя или какой-нибудь программы появится необходимость привязать имя домена example.com к IP-адресу 1.2.3.4, то он сможет это сделать именно благодаря внесению изменений в файл hosts. Запрос к записям из файла hosts имеет приоритет перед обращением к прописанным в системе DNS-серверам, что является немаловажным фактором. Надо ли объяснять, что для вирусов это достаточно интересная точка перенаправления трафика и модификация файла вирусом может привести к подмене адреса определенного доверенного узла. Существует категория вирусов, которая модифицирует файл hosts для маршрутизации запросов на фишинговые (поддельные) сайты, в точности эмитирующие страницы оригинальных сайтов [социальных сетей] с целью кражи паролей учетных записей, показа рекламных страниц, либо просто с целью блокировки доступа к определенным ресурсам. Поэтому, обнаружение в файле hosts сторонних записей может свидетельствовать о наличии в системе вредоносного кода, либо о разовой модификации записей вредоносным кодом, что может указывать на существование в системе серьезной уязвимости безопасности. Файл hosts по-умолчанию размещается в папке %SystemRoot%\System32\Drivers\etc\ и оригинальное его содержимое выглядит следующим образом:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

# Copyright (c) 19932009 Microsoft Corp.

#

# This is a sample HOSTS file used by Microsoft TCP/IP for Windows.

#

# This file contains the mappings of IP addresses to host names. Each

# entry should be kept on an individual line. The IP address should

# be placed in the first column followed by the corresponding host name.

# The IP address and the host name should be separated by at least one

# space.

#

# Additionally, comments (such as these) may be inserted on individual

# lines or following the machine name denoted by a ‘#’ symbol.

#

# For example:

#

#      102.54.94.97     rhino.acme.com          # source server

#       38.25.63.10     x.acme.com              # x client host

# localhost name resolution is handled within DNS itself.

# 127.0.0.1       localhost

# ::1             localhost

Видите, все закомментировано (лидирующий символ # в начале строки). В Windows 7 в файле hosts нет и одной реальной записи, только лишь примеры использования. В предыдущих версиях Windows правильный файл может содержать записи об интерфейсе локальной петли (localhost), но не более.
А вот как выглядит модифицированный вирусом тот же файл hosts:

...

1.2.3.4      my.mail.ru

1.2.3.4      m.my.mail.ru

1.2.3.4      vk.com

1.2.3.4      ok.ru

1.2.3.4      m.vk.com

1.2.3.4      odnoklassniki.ru

1.2.3.4      vk.com

1.2.3.4      www.odnoklassniki.ru

1.2.3.4      m.odnoklassniki.ru

1.2.3.4      ok.ru

1.2.3.4      m.ok.ru

1.2.3.4      www.odnoklassniki.ru

...

Можно увидеть, что доменные имена крупных российских социальных сетей перенаправлены на некий неизвестный хост 1.2.3.4. Поэтому, если Вы обнаружили в файле hosts подозрительные записи, которых Вы уж точно не добавляли, то можете их смело удалять. Однако, в случае, если они через некоторое время появляются вновь, можно с уверенностью говорить о наличии в системе активного вируса, одним из функциональных особенностей которого является периодическое обновление данных файла. Поскольку это не место загрузки вируса, а место модификации, то надо сперва обнаружить в системе сам активный код вируса и устранить причину, а затем уже следствие.
Ко всему прочему, само местоположение файла hosts в рамках системы может быть подвергнуто атаке и изменено. Задается оно соответствующим параметром в ветви реестра:

  • ключ HKLM\System\CurrentControlSet\Services\Tcpip\Parameters,
    параметр DatabasePath = %SystemRoot%\System32\drivers\etc

..но вредоносный код, получивший привилегии локального администратора, может изменить значение параметра на собственное, ссылающееся совершенно в другое местоположение файловой системы. Обязательно проверьте данный параметр, и если Вы обнаружите в параметре DatabasePath что-либо отличное от вышеуказанного значения, то стоит заменить значение на базовое.

DNS

DNS (Domain Name System) — распределенная система доменных имен, которая используется для сопоставления IP-адреса с именем хоста (фактически получения IP-адреса на основе заданного имени). Для большинства рабочих окружений на основе операционной системы Windows это основной метод разрешения внешних (по отношению к локальной сети) имен хостов. Конечно же, он имеет меньший приоритет по сравнению с вышеописанным файлом hosts, тем не менее используется очень часто. С помощью (локального|внешнего) сервера DNS разрешаются символические имена узлов (например datadump.ru), к которым Вы обращаетесь в локальной|внешней сети, и которые не были разрешены другими, более приоритетными, методами. Существует категория вирусов, которые преднамеренно модифицируют параметры реестра, относящиеся к настройкам DNS-серверов с целью перенаправления сетевого трафика скомпрометированной машины на собственные сервера имен. В операционной системе Windows настройки DNS-серверов, к которым обращается модуль разрешения имен, хранятся в специальном ключе реестра:

  • HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters

параметры DhcpNameServer и NameServer которого должны содержать исключительно DNS-сервера, предоставляемые вашим локальным сетевым подключенным сетевым оборудованием (роутером/маршрутизатором), контроллером домена либо провайдером-поставщиком услуг доступа к сети Интернет.
Дополнительно, я бы проверил одноименные параметры для адаптеров и интерфейсов в следующих ключах реестра:

  • HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Adapters\{GUID}
  • HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\{GUID}

Для того, чтобы проверить корректность адресов DNS-серверов, Вы должны просто-напросто знать адреса «своих» серверов, обычно это адреса из частных диапазонов подсетей: 192.168.0.0/16, 172.16.0.0/12 и 10.0.0.0/8, но не во всех случаях.
Для того, чтобы можно было посмотреть адреса DNS-серверов, можно выполнить из консоли (cmd) следующую команду:

ipconfig /all

которая сгенерирует вывод информации обо всех сетевых интерфейсах, сконфигурированных в вашей операционной системе:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

. . .

Ethernet adapter Подключение по локальной сети:

   DNS-суффикс подключения . . . . . : domain.com

   Описание. . . . . . . . . . . . . : Intel(R) 82579LM Gigabit Network Connection

   Физический адрес. . . . . . . . . : 24-BE-05-17-5D-79

   DHCP включен. . . . . . . . . . . : Да

   Автонастройка включена. . . . . . : Да

   IPv4-адрес. . . . . . . . . . . . : 172.16.5.16(Основной)

   Маска подсети . . . . . . . . . . : 255.255.255.128

   Аренда получена. . . . . . . . . . : 24 февраля 2016 г. 9:15:55

   Срок аренды истекает. . . . . . . . . . : 4 марта 2016 г. 9:16:02

   Основной шлюз. . . . . . . . . : 172.16.5.126

   DHCP-сервер. . . . . . . . . . . : 172.16.2.197

   DNS-серверы. . . . . . . . . . . : 172.16.0.23

                                       172.16.1.23

   NetBios через TCP/IP. . . . . . . . : Включен

. . .

Для того, чтобы найти в этом огромном потоке информации интересующие нас DNS-сервера, Вы можете найти в выводе тот интерфейс, который «смотрит» у вас в сеть Интернет, и изучить сопоставленные с ним параметры конфигурации. Стоит обратить внимание на значение параметра «DNS-серверы». Если Вы вдруг обнаружили «левые» адреса серверов, принадлежность которых сложно установить, то можете смело их удалять, либо менять на корректные.

Оболочка (Проводник)

С тех давних пор, как мир обленился и основная масса пользователей отказалась от текстового интерфейса в пользу графического, классическое понимание оболочки (shell) определенным образом трансформировалось и в дополнение к своим типичным консольным характеристикам текстового режима приобрело дополнительные особенности в виде графической среды взаимодействия с операционной системой. Графическая оболочка пользовательского интерфейса операционной системы Windows, иначе называемая Проводником и представленная в системе файлом explorer.exe, включает в себя функционал различных элементов интерфейса пользователя, как то: рабочий стол, меню пуск, проводник (файловый менеджер), панель инструментов и некоторые другие элементы взаимодействия. Однако в Windows с целью расширения целевого применения операционной системы в качестве различных однооконных киосков, не стали жестко закреплять «родную» пользовательскую оболочку explorer.exe и дали пользователю свободу конфигурировать альтернативную оболочку посредством ключей реестра, чем и не преминули воспользоваться вирусописатели.
В реестре за настройку пользовательской оболочки отвечает ключ:

  • ключ HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon,
    параметр Shell = explorer.exe

Помимо оболочки есть еще параметр userinit, который описывает программы, загружаемые процессом Winlogon на этапе входа пользователя в систему. По умолчанию, Winlogon запускает модуль под названием Userinit.exe, который запускает скрипты стадии загрузки, а уже только затем вызывает оболочку пользовательского интерфейса explorer.exe. Настройка хранится в том же ключе в параметре Userinit:

  • ключ HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon,
    параметр Userinit = C:\Windows\system32\userinit.exe,

Обнаружение вируса в данном случае сводится к проверке наличия сторонних записей в данных ключах реестра.

Конфигурационные ini-файлы

Вплоть до современных версий в системе Windows все еще присутствует такой рудимент из прошлого, как конфигурационные ini-файлы. Речь у нас идет о следующих файлах:

  • %SystemRoot%\system.ini
  • %SystemRoot%\win.ini

В старых версиях Windows ini-файлы активно использовались в качестве основного механизма конфигурации системы, в том числе и для автозагрузки. В современных же версиях Windows система загружает некоторые параметры из указанных ini-файлов в реестр, используя так называемое отображение (сопоставление), задаваемое в следующем ключе реестра:
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\IniFileMapping
Отображение (маппинг) осуществляется следующим образом:

  • Переменные Run и Load из секций [boot], [windows] файла win.ini, проецируются в ключ реестра HKCU\Software\Microsoft\Windows NT\CurrentVersion\Windows. Таким образом, данные параметры операционная система обрабатывает как элементы автозагрузки, то есть как если бы они находились в секции [windows] файла win.ini.
  • Переменная Shell из файла system.ini проецируется в HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon.

Отображение используется в целях совместимости с устаревшим программным обеспечением, которое знает про существование ini-файлов, однако не имеет никакого представления о том, что такое реестр. В случае подобного кода, который работает через совместимые функции Win16/Win32 API, функции эти получают информацию не из описанных файлов напрямую, а уже из соответствующих сопоставленных ключей реестра. Как мы можем догадаться, механизм этот оставлен разработчиками исключительно в целях совместимости с устаревшим интерфейсом Win16, который не рекомендуется к использованию в современных реалиях Win32. Но, как говорится, что работает, то может быть использовано, поэтому вирусы иногда задействуют данный механизм.

Фильтры выполнения оболочки

Так называемые фильтры выполнения оболочки (Shell Execute Hooks) предоставляют программный метод, который расширяет функционал системных функций ShellExecute и ShellExecuteEx. Конфигурацию фильтров в реестре можно найти в разделах:

  • HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\ShellExecuteHooks
  • HKLM\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Explorer\ShellExecuteHooks

Записи зачастую содержат идентификаторы CLSID, ссылающиеся на ключи HKLM\SOFTWARE\Classes\CLSID\{CLSID}, в которых в параметрах InprocServer32 содержится информация о конкретном исполняемом модуле фильтра.

Фильтры выполнения оболочки не рекомендованы к использованию начиная с Windows Vista.

Объекты загрузки оболочки

Объекты загрузки оболочки (SSO/Shell Service Object) — это библиотеки, которые в процессе загрузки пользовательского окружения загружаются системной программой оболочки explorer.exe в качестве так называемых собственных расширений проводника. Функционируют в контексте родительского процесса проводника (explorer.exe) и загружаются до авторизации пользователя в системе.
В реестре представлены ключами:

  • HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\ShellServiceObjects
  • HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Explorer\ShellServiceObjects

В дополнение к вышеописанным, имеются еще так называемые объекты отложенной загрузки оболочки (SSODL/Shell Service Object Delay Load), обычно представляющие из себя типичные библиотеки DLL. Описываются ключом реестра:

  • HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\ShellServiceObjectDelayLoad

параметры данного раздела — это имена объектов оболочки, которые записываются в форме:
Имя_объекта = CLSID (например: WebCheck = {E6FB5E20-DE35-11CF-9C87-00AA005127ED})
Как мы видим, имена ссылаются на идентификаторы CLSID, которые можно найти в разделе HKLM\SOFTWARE\Classes\CLSID\{CLSID}, где информация о местоположении исполняемого файла оболочки содержится в параметре InprocServer32.

Уведомления оболочки

В Windows имеется механизм под названием Winlogon Notification Packages или Уведомления оболочки. Механизм уведомлений используются для запуска программ при возникновении предопределенных системных событий. События подразделяются на: вход (logon), выход (logoff), запуск (startup), завершение (shutdown), запуск хранителя экрана (startscreensaver) и останов хранителя экрана (stopscreensaver). Когда модуль Winlogon стартует, он проверяет реестр и загружает зарегистрированные пакеты уведомления оболочки (представленные в виде .dll-библиотек). Приведенные события генерируются самим процессом Winlogon.exe на разных стадиях своего функционирования. Когда событие возникает, Winlogon в параметрах ключа Notify ищет функцию обработчика того или иного события. Вирусы обычно загружают себя по событию входа пользователя (logon) в операционную систему.
Ответственный ключ реестра:

  • HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\Notify

Модули (библиотеки) инициализации приложений

App Init DLLs — это системный механизм, который позволяет загружать произвольный список библиотек в адресное пространство каждого пользовательского процесса, использующего библиотеку user32.dll (а её функции используют практически все программы). Все начинается с загрузки user32.dll. Поскольку это типовая библиотека, входящая в состав базового набора поддержки подсистемы Win32 API, она загружается стандартным механизмом LoadLibrary. Загрузчик образа вызывает функцию DllEntryPoint библиотеки user32.dll, которая в недрах своего алгоритма содержит процедуру сканирования ключа реестра AppInit_Dll, которая загружает все перечисленные в ключе библиотеки в виртуальное адресное пространство процесса, а затем поочередно вызывает для каждой из них процедуру инициализации. Именно таким образом перечисленные библиотеки получают управление. Этот механизм так же носит название DLL injection, или внедрение динамической библиотеки. Естественно, если какое-либо приложение не использует стандартную библиотеку user32.dll, то никакие библиотеки, описанные в ключе AppInit_Dll в его адресное пространство загружены не будут. Согласитесь, что подобный функционал очень интересен для разнообразного злонамеренного кода. Поэтому, после всех проблем, которые доставил данный механизм в плане безопасности операционной системы, начиная с Windows 7 разработчики решили добавить необходимость подписания кода загружаемых библиотек. А в последствии грозятся и вовсе перейти на загрузку только лишь подписанных библиотек.

Later versions of Windows will load only code-signed AppInit DLLs and will not include a registry key to disable this requirement.

Информация об активном механизме, а так же списках загружаемых библиотек хранится в следующих ключах.

  • для 32-битных DLL, функционирующих в 32-битной системе:
    HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows
    параметр AppInit_DLLs
  • Для 64-битных DLL, функционирующих в 64-битной системе:
    HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows
    параметр AppInit_DLLs
  • Для 32-битных DLL, функционирующих в 64-битной системе:
    HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\Windows
    параметр AppInit_DLLs

Параметр содержит множество значений, разделенных пробелом либо запятой, каждое из которых описывает отдельную библиотеку.
Работать с данным ключам надо предельно внимательно, и хорошо себе представлять происходящее. Дело в том, что параметр может содержать модули вполне легальных приложений (антивирусы, клиенты виртуализации и прочее). Поэтому, не стоит спешить с массовым удалением всех присутствующих программ, и следует быть предельно аккуратным с очисткой данного параметра. Я думаю, в самом общем случае, алгоритм обнаружения вируса и очистки должен быть следующим: находим первую запись, определяем [гуглим] принадлежность модуля, если вирус — удаляем, если легальный — оставляем, и так по всем записям списка.

Известные библиотеки

В операционных системах Windows (начиная с Windows 95/NT) присутствует механизм под названием KnownDLL (известные библиотеки), в основном предназначающийся для кеширования часто используемых системных DLL с целью сокращения общего времени загрузки приложений (увеличения производительности). Помимо основного применения, механизм обеспечивает довольно интересный дополнительный функционал, который позиционируется как средство обеспечения безопасности. Оно позволяет предотвращать такой хитрый трюк, как загрузка дубликатов известных системных библиотек непосредственно из директории самого приложения. Поместил злоумышленник, к примеру, свою копию библиотеки wininet.dll в директорию приложения, которое данную библиотеку использует, и по идее данная библиотека должна загрузиться приоритетно, поскольку находится в директории загружаемого приложения, ан нет, механизм KnownDLL загрузит её из %SystemRoot%\System32\wininet.dll. Когда загрузчик образов подготавливает бинарный файл к выполнению, он смотрит в таблицу импорта и перечисляет библиотеки, которые используются загружаемым приложением. Для каждой библиотеки, которую загрузчик находит в таблице импорта, он пытается спроецировать библиотеку в адресное пространство процесса, для того, чтобы сделать функции библиотеки доступными основному приложению. Однако на этом же этапе загрузчик просматривает контейнер системных объектов KnownDLL и ищет в нем объект с именем \KnownDlls\<имя_библиотеки>, в случае существования которого, вместо подгрузки DLL непосредственно из текущего местоположения, загрузчик использует информацию объекта.
Описание секций присутствует в ключе реестра:

  • HKLM\System\CurrentControlSet\Control\Session Manager\KnownDLLs

Если Вы внимательно изучите содержимое ключа, то заметите, что все перечисленные в нем DLL не имеют полного пути, поскольку по задумке разработчиков располагаются в директории %SystemRoot%\System32 (задается ключом DllDirectory). Это поднимает уровень безопасности, поскольку теперь чтобы вирусу прикинуться известной библиотекой и использовать механизм KnownDLL, ему потребуются еще и права записи на системную папку. Создание секций \KnownDlls\<имя_библиотеки> для каждой DLL происходит на этапе загрузки операционной системы специализированным кодом, который просматривает описанный выше ключ и создает соответствующие секции. Поэтому, обнаружение вируса, использующего механизм KnownDLL, сводится к просмотру записей о библиотеках в описанном выше ключе и удалении модулей, вызывающих подозрение.

Параметры загрузки образов

Среди множества прочих, в системе реализован механизм под названием параметры загрузки образов (IFEO, Image File Execution Options), позволяющий контролировать некоторые аспекты запуска исполняемых образов (исполняемых файлов). Фактически он предоставлен разработчиками в целях отладки собственных программ. Одной из особенностей данного механизма является возможность перехватывать вызовы к исполняемому образу (программе), что дает неограниченные возможности по полному контролю запускаемого приложения, в том числе подмене его собственным кодом.
Настройки параметров загрузки хранятся в ключах реестра:

  • HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options;
  • HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\Image File Execution Options;

Данные разделы реестра содержат подключи, указывающие на имена загружаемых образов, которые, в свою очередь, содержат параметры, описывающие разнообразные опции для запуска той или иной программы. В контексте текущей статьи все параметры описывать нет никакого резона, скажу только, что со стороны вредоносного кода интересным будет использование параметра Debugger, который должен указывать, по версии разработчиков, на отладчик, запускаемый каждый раз, когда описанное приложение будет стартовать. Иными словами, например, если в ключе explorer.exe создать параметр Debugger (типа REG_SZ) и присвоить ему значение myapp.exe, то каждый раз при загрузке системой проводника будет запускаться указанное приложение с параметрами командной строки, указывающими на исходную программы и переданные уже ей параметры. Таким вот незатейливым способом вирусы могут подменять различные ключевые системные модули собственными. В этом случае, подозрительным с точки зрения безопасности будет факт присутствия в каком-либо модуле параметра Debugger, указывающего на подозрительное приложение.

Зачастую таким образом вирусами перехватывается запуск проводника (explorer.exe), поэтому при нахождении в описанных выше ключах реестра подключа explorer.exe можете смело его удалять.

Предзагрузка командного интерпретатора

Если командный интерпретатор (cmd.exe) запускается без параметра командной строки /D, то код интерпретатора вначале проверяет следующие ключи реестра:

  • ключ HKLM\Software\Microsoft\Command Processor,
    параметр AutoRun
  • ключ HKCU\Software\Microsoft\Command Processor,
    параметр AutoRun

..и если параметр AutoRun присутствует хотя бы в одном из описанных ключей, то указанный в параметре исполняемый образ загружается непосредственно перед загрузкой самого cmd.exe. Параметры пользователя имеют приоритет перед параметрами компьютера. Данную особенность активно эксплуатируют разного рода вирусы, поэтому стоит проверять вышеуказанные ключи реестра в обязательном порядке.

Планировщик заданий Windows

Планировщик заданий (Shared Task Scheduler) — системный компонент, предоставляющий возможность планирования выполнения заданий (программ или скриптов) в системе на основе большого количества всевозможных критериев. Другими словами, планировщик заданий отвечает за автоматический запуск пользовательских и системных задач, запланированных по определенным условиям. Подобные задания зачастую связаны с запуском внешних приложений, поэтому не сложно догадаться, что это достаточно интересный механизм для некоторых категорий вирусов. К примеру, код вируса может создать собственную задачу, которая будет с определенной периодичностью подменять системные DNS-сервера (кстати воочию подобное наблюдал).
Для контроля заданий нам потребуется запустить планировщик. Запускается планировщик заданий разными способами, но один из самых универсальных это запуск через цепочку Панель управленияАдминистрированиеПланировщик заданий. При запуске планировщика в Windows 7 открывается стандартный интерфейс апплета:

планировщик задание вируса

Для просмотра сторонних запланированных задач, выделяем пункт Библиотека планировщика заданий 1, затем ставим курсор (выделяем) на пункт задания в области списка заданий 2, смотрим вкладку действия 3 для каждого заинтересовавшего нас задания, с целью выяснить, какие же действия оно выполняет. Откровенно подозрительными обычно являются задания, которые производят запуск исполняемых модулей неизвестного назначения (с невнятными именами) из таких местоположений, как %LOCALAPPDATA% и вложенных подкаталогов (например: C:\Users\<имя_пользователя>\Appdata\Local\wupdate\wupdate.exe). При обнаружении подобного подозрительного или откровенно вредоносного задания, просто удаляем его из списка задач.

Windows Vista+:
Начиная с версии Windows Vista, задачи создаются в виде отдельных файлов формата XML (с расширением .xml). Размещаются планируемые задачи в нескольких местоположениях операционной системы:

  • Каталог C:\Windows\System32\Tasks;
  • Каталог C:\Windows\Tasks;
  • Ключ реестра HKLM\Software\Microsoft\Windows NT\CurrentVersion\Schedule\Taskcache\Tasks;
  • Ключ реестра HKLM\Software\Microsoft\Windows NT\CurrentVersion\Schedule\Taskcache\Tree;

Windows 2000/XP:
В данных версиях операционных систем задачи можно было найти в реестре, в следующей ветви:
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\SharedTaskScheduler

Службы [Сервисы] и драйверы

Службы (Сервисы) — это приложения, автоматически или по возникновению определенных событий, запускаемые в фоновом режиме на различных стадиях загрузки операционной системы, обеспечивающие основные функциональные возможности ОС. Как правило, службы (сервисы) не взаимодействуют с графическим интерфейсом пользователя, поэтому говорится, что они не имеют графического интерфейса, и работа их в большинстве случаев не заметна для пользователя. Служба, в зависимости от настроек, может быть запущена автоматически при загрузке операционной системы, поэтому начать функционирование она может до того момента, как пользователем будет произведен вход в Windows. Основная задача по обнаружению вируса, который установил в систему собственную службу, состоит в том, чтобы просмотреть весь список запускаемых служб и детально изучить его на предмет наличия подозрительных сервисов. С этой целью можно использовать знакомую уже многим оснастку Службы, вызвав её следующим образом:
Нажать комбинацию Win + R и вписать в строку services.msc, затем нажать ОК. После этого мы видим примерно следующее:

обнаружение вредоносного сервиса

Для полноты восприятия переключаемся в стандартный вид (1), далее сортируем службы по столбцу «Состояние», просто щелкнув на нём (2), тем самым выстроив сначала службы, которые в данный момент работают. И среди работающих служб начинаем искать те, которые могут показаться нам подозрительными. В случае нахождения подозрительной службы можно попробовать её выделить (3), нажать правую кнопку и попытаться остановить (4), выбрав одноименный пункт меню. После остановки службы можно зайти в «Свойства» и изменить Типа запуска (StartUp Type) на Отключено (Disabled), перезагрузив затем операционную систему.
На самом деле, можно смело утверждать, что практически с нулевой вероятностью «родные» системные сервисы от Microsoft вызовут у нас подозрение, поэтому хорошая практика, в данном случае, состоит в том, чтобы отфильтровать как-либо образом сторонние службы, написанные третьими лицами и вот уже среди них провести проверку. Визуально отличить стороннюю службу (коей обычно и является вирус) от системной можно при наличии определенных знаний, но не у всех они имеются, поэтому существует более надежный и простой способ с участием утилиты msconfig (Конфигурация системы). Из командной строки с правами локального администратора запускаем команду:

msconfig

открывается окно утилиты конфигурирования системы. Переходим во вкладку «Службы» — выделяем чекбокс Не отображать службы Microsoft, затем щелкаем по столбцу «Состояние», дабы отсортировать работающие службы в начало списка. В итоге у нас получится список из служб сторонних разработчиков такого вот примерно вида:

обнаружение сервиса вируса

А вот уже среди отфильтрованных (оставшихся) служб можно проводить детальный анализ.

Скрытые службы

На самом деле иногда все бывает гораздо сложнее, поскольку при определенных настройках безопасности службы и применении некоторых других методов, сервисы могут быть «скрыты». Подобные скрытые службы Вы не обнаружите при помощи традиционного инструментария (например: оснастка «Службы»). Исходя из этого более надежным, на мой взгляд, решением видится самостоятельный анализ ветви реестра текущей конфигурации:

  • HKLM\SYSTEM\CurrentControlSet\Services

В данном разделе реестра определены и службы и драйвера, инсталлированные в данный момент в операционной системе

Каждый ключ реестра в данной ветви — это запись о драйвере либо сервисе, который определен в операционной системе. В каждом ключе может содержать вложенные ключи, которые описывают дополнительные параметры конфигурации драйвера/службы.
На что стоит обращать внимание:

  • параметр Description — содержит либо осмысленное имя службы/драйвера, либо указание на библиотеку вида @%SystemRoot%\system32\AxInstSV.dll,-104.
  • параметр DisplayName — содержит либо осмысленное отображаемое имя службы/драйвера, либо указание на библиотеку.
  • параметр DriverPackageId — содержит указание на .inf-файл драйвера.
  • параметр ImagePath — содержит полный путь и имя файла образа загрузки для службы/драйвера. Многие службы группируются в рамках единого процесса svchost.exe, в этом случае содержат что-то вроде: %SystemRoot%\system32\svchost.exe -k AxInstSVGroup. Зачастую у драйверов имя файла образа имеет расширение .sys, у служб обычно .exe, но это не обязательное правило.

Алгоритм нахождения сторонних записей состоит в прохождении каждого ключа и беглого анализа содержимого. В случае, если Вам показалась странной какой-либо ключ, не спешите удалять его, поскольку он может оказаться важным системным драйвером/службой. В случае неясности, перво-наперво, было бы логичным проконсультироваться у поисковиков на предмет получения дополнительных знаний :)
Если уж быть совсем скрупулезным, не лишним будет просмотр и сопутствующих ветви реестра различных вариантов конфигурации (хотя это не обязательно):

  • HKLM\SYSTEM\ControlSet001\Services
  • HKLM\SYSTEM\ControlSet002\Services
  • HKLM\SYSTEM\ControlSet003\Services

С появлением 64-битных сборок Windows, процедура запуска не подписанного драйвера крайне осложнилась, а затем эту возможность перевели в предзагрузку. Теперь, чтобы запустить драйвера в 64-битной системе, необходимо наличие у него цифровой подписи. В связи со всеми этими нововведениями, протащить в систему сторонний драйвер стало достаточно проблематично. Конечно же, возможно имеются доступные открытые ключи, которыми можно подписывать собственные драйвера, однако непонятна их дальнейшая судьба в случае их активной эксплуатации. Основываясь на данных фактах, можно предположить, что в будущем использование драйверов с вредоносным кодом и вовсе сойдет на нет.

В случае обнаружения службы/драйвера вируса полностью удалить её из системы можно либо удалением соответствующего ключа реестра, либо командой:
sc delete имя_службы

Internet Explorer

Безо всякого сарказма это браузер с мировым именем :) На этой содержательной фразе можно было бы и остановиться, однако даже столь емкий термин не может в полной мере отразить весь тот огромный узел разнородных проблем, которых породили разработчики браузера самим фактом его создания. Пожалуй, можно смело утверждать, что браузер корпорации Microsoft является самой большой дырой в безопасности системы (на 2016 год почти восемь сотен обнаруженных уязвимостей). Восхождение звездного продукта началось с вытеснения в 1997 году конкурента под названием Netscape Navigator. Стратегическое решение было принято в связи со всё возрастающей ролью сети Интернет, и необходимостью более глубокой внутренней интеграцией обозревателя в систему. Вероятно, сама идея была действительно хорошая, поскольку продукт получился весьма функциональным, но как в последствии стало ясно, с очень непродуманной архитектурой. Практически постоянно можно наблюдать обход настроек безопасности, неправильную обработку внешних файлов, спуфинг, неавторизованную установку расширений. Зачастую уязвимости связаны с внешними плагинами типа Flash Player и Java, однако отсутствие изоляции процессов и собственной (встроенной) обработки флеш и явы делает сам браузер беспомощным. Последнее время Microsoft работают над новым браузером, который будет носить название Edge, вот только будет ли он сохранять совместимость?

Подключаемые протоколы

В браузере Internet Explorer есть возможность добавлять так называемые подключаемые протоколы, которые могут быть сконфигурированы пользователем в дополнение к стандартным. Протоколы предназначены для расширения функционала браузера и фактически позволяют определить метод доступа к внешним ресурсам исходя из пользовательских критериев, то есть по вашему собственному протоколу, задавая специфический префикс URL. Протокол сопоставляет поведение браузера и логики работы с символической короткой строкой вида mailto: или http:.

  • ветвь HKLM\SOFTWARE\Classes\PROTOCOLS содержит описание специализированных фильтров и обработчиков.
  • подветвь HKLM\SOFTWARE\Classes\PROTOCOLS\Handler содержит подключи, описывающие обработчики протоколов. подключи представляют собой имена обработчиков, в которых имеется параметр CLSID, указывающий на соответствующий CLSID обработчика.
  • подветвь HKLM\SOFTWARE\Classes\PROTOCOLS\Filter содержит подключи, описывающие фильтры протоколов. подключи представляют собой имена фильтров, в которых содержится параметр CLSID, указываются на соответствующий CLSID фильтра.

Как мы видим, классически все эти указанные в подразделах CLSID указывают на тот же CLSID в ключе HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{CLSID}, а вот уже внутри информация о местоположении самого исполняемого модуля содержится в параметре InprocServer32. Обнаружение вируса сводится к просмотру и нахождению подозрительных обработчиков и фильтров.

Элементы управления ActiveX для Internet Explorer

ActiveX — это механизм (дополнение), благодаря которому Internet Explorer может использовать другие системные приложения. При помощи него обеспечивается расширение функциональных возможностей браузера и, тем самым, достигается «лучшее взаимодействие» с веб-ресурсом. Например, через IE онлайновый антивирус посредством собственного ActiveX-компонента сканирует локальные файлы [на машине], сайт Microsoft Update устанавливает через свой ActiveX-компонент обновления безопасности в систему, ресурс может вызывать Windows Media Player для проигрывания звуковых форматов, вызывать QuickTime для воспроизведения анимации и так далее. Конечно же, данной технологией не могли не заинтересоваться вирусописатели, разрабатывающие вредоносные ActiveX-компоненты, которые обычно устанавливаются для последующей загрузки дополнительного программного обеспечения без вашего ведома. Все элементы ActiveX, которые инсталлируются через Internet Explorer, попадают сперва в директорию %Windir%\Downloaded Program Files. Обычно это модули типов .exe, .dll, .ocx, .cab и сопутствующие .inf. Кроме самого исполняемого модуля (или архива), сюда же попадает и .inf-файл, описывающий процесс инсталляции, при участии которого и выполняется установка ActiveX-компонента в систему. Устанавливаемые таким образом элементы могут регистрировать себя в системе в качестве полноценных приложений. Для самостоятельного поиска вируса нам потребуется простой механизм по изучению списка ActiveX-элементов, установленных в системе. Существует ключ реестра, который содержит списки идентификаторов ActiveX, установленных для IE:

  • HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Ext\PreApproved

Однако ключ (как всегда) содержит одни лишь голые идентификаторы, поэтому для установления ассоциации с исполняемыми модулями нам (опять) предстоит вручную проверять каждое значение CLSID в другом ключе реестра HKEY_CLASSES_ROOT\CLSID и изучать для каждого CLSID подключ InprocServer32.

Общие параметры сети в Internet Explorer

Разнообразные настройки для сети Интернет можно обнаружить в следующем ключе:

  • HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings

В ключе содержится большое количество параметров, и ниже посмотрим на какие же подключи стоит обратить особое внимание.

Сайты и протоколы Internet Explorer

Сайты и протоколы, добавленные в зону «Надежные узлы» (Trusted Zone). Обычно добавление в данную зону позволяет перечисленным в списке сайтам обходить некоторые виды проверок безопасности, то есть считаться более доверенными.
Используемые ключи реестра:

  • HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\Domains
  • HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\Domains
  • HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\ProtocolDefaults
  • HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\ProtocolDefaults

Об обнаружении вируса в системе может говорить наличие в описанных выше ключах записей о сторонних (неизвестных вам) ресурсах, назначение которых пользователю сложно определить.

Настройки прокси сервера

В ключе:

  • HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings

..параметр ProxyServer обычно отсутствует. В случае же наличия параметра следует понять, легальный ли это прокси и нужен ли он вам в работе?

Browser Helper Objects (BHO)

Browser Helper Object (Объект помощи браузеру, помощник браузера) — исполняемый модуль DLL, написанный в виде плагина для браузера Internet Explorer, предназначающийся для обеспечения дополнительного функционала, стандартно не поддерживаемого браузером. Вне зависимости от расширения практически всегда представляют собой обычные DLL библиотеки, которые загружаются вместе с браузером и работают в контексте основного процесса браузера. По этой причине разнообразная подозрительная активность зачастую остается незамеченной некоторыми персональными фаерволами. Вирусы могут инсталлировать BHO, отслеживающие защищенные соединения и мониторящие пароли, либо записывающие активность пользователя при посещении определенных интернет-ресурсов. С точки зрения вируса подключить BHO к браузеру Internet Explorer достаточно просто, для этого достаточно стандартными средствами зарегистрировать класс BHO и прописать ссылку на него в специальном ключе реестра:

  • HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Browser Helper Objects
  • HKLM\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Explorer\Browser Helper Objects

подразделы ключа имеют имя-значение GUID и ссылаются на одноименный компонент.

Плагины Internet Explorer

Плагины Internet Explorer — это небольшие программные модули, загружаемые при старте браузера с целью добавления браузеру определенных функциональных возможностей. Обычно используются для визуализации различного нестандартного контента: проигрывания специфических форматов видео, аудио и прочих.
Используемый ключ реестра:

  • HKLM\SOFTWARE\Microsoft\Internet Explorer\Plugins

подразделы описывают различные разделы плагинов.

Панели инструментов Internet Explorer

Панели инструментов Internet Explorer — это дополнения для браузера, которые позволяют создавать и добавлять отдельные пользовательские панели, наборы инструментов или даже отдельностоящие панели рабочего стола в различные местоположения окна браузера: командную строку, строку закладок, меню, системную панель задач, а так же в прочие управляющие элементы. Распространены ситуации, когда панели инструментов создаются установленными в браузер BHO.
Ответственные ключи реестра:

  • HKLM\SOFTWARE\Microsoft\Internet Explorer\Toolbar
  • HKCU\SOFTWARE\Microsoft\Internet Explorer\Toolbar
  • HKLM\SOFTWARE\Wow6432Node\Microsoft\Internet Explorer\Toolbar

содержит подразделы в виде GUID, которые ссылаются непосредственно на компоненты.

Расширения Internet Explorer

Расширения для Internet Explorer (Addons, Аддоны) — это специальная категория дополнений, которые используются для добавления элементов к пользовательскому интерфейсу браузера. Возможна модификация главной панели инструментов с целью реализации на этой панели разнообразных отдельностоящих кнопок и полноценных меню. Кнопки панели инструментов могут запускать приложение, скрипт или открывать новую панель. Меню (иногда называемые сервисами), могут создавать пользовательское подменю в меню «Сервис» или «Справка» на панели инструментов браузера. Очевидно, что меню (сервисы) и кнопки сами по себе опасности не представляют ровно до того момента, пока не будет задействован их (возможный) деструктивный функционал, например непосредственным нажатием на компонент. Ведь это всего лишь ссылки, но вот после нажатия (активации) ссылка вызывает закрепленную функциональную процедуру, которая не всегда может выполнять легитимные действия.
С определенной версии IE все расширения браузера можно увидеть в подразделе «Панели инструментов и расширения» специализированного апплета Надстройки, до которого можно добраться через «Свойства обозревателя» — «Программы»- «Настроить надстройки»:

Internet Explorer Add-ons

Другой способ предусматривает запуск браузера Internet Explorer из командной строки с параметром -extoff:

iexplore.exe -extoff

Поскольку при подобном типе запуска браузер позволяет увидеть все без исключения (и нормальные и скрытые) расширения.

Используемые ключи реестра:

  • HKLM\SOFTWARE\Microsoft\Internet Explorer\Extensions
  • HKCU\SOFTWARE\Microsoft\Internet Explorer\Extensions
  • HKLM\SOFTWARE\Wow6432Node\Microsoft\Internet Explorer\Extensions

Подразделы представляют из себя (традиционно) идентификаторы CLSID, в которых вложенными ключами описываются расширения.

Пункты меню Internet Explorer

Возможно добавить дополнительные пункты в контекстное меню браузера Internet Explorer. Обычно этот тип меню можно увидеть, нажав правую кнопку мыши на какой-либо активной ссылке, расположенной на странице, отображаемой в данный момент в окне браузера.
В реестре настройка меню представлена по следующему пути:

  • HKCU\SOFTWARE\Microsoft\Internet Explorer\MenuExt
  • HKLM\SOFTWARE\Microsoft\Internet Explorer\MenuExt

Подразделы имеют наименование пунктов меню. Параметр «по умолчанию» каждого подраздела указывает на функциональный модуль, ответственный за конкретный пункт меню.

Дополнительные параметры Internet Explorer

С определенной версии IE существует возможность модифицировать содержимое вкладки Дополнительно в свойствах обозревателя (Свойства обозревателя — Дополнительно), добавив туда новую группу настроек.
Ответственный ключ реестра:

  • HKLM\SOFTWARE\Microsoft\Internet Explorer\AdvancedOptions

подключи описывают группы параметров во вкладке Дополнительно.

Стартовая страница

Стартовая (начальная) страница отображается в первой (самой левой) стартовой вкладке окна браузера непосредственно после запуска.
Используемые ключи и параметры реестра:

  • ключ HKLM\SOFTWARE\Microsoft\Internet Explorer\Main,
    параметр Start Page
  • ключ HKCU\SOFTWARE\Microsoft\Internet Explorer\Main,
    параметр Start Page
  • ключ HKEY_USERS\SID_пользователя\SOFTWARE\Microsoft\Internet Explorer\Main,
    параметр StartPage

Страница поиска

  • HKLM\SOFTWARE\Microsoft\Internet Explorer\Main,
    параметр Search Page
  • HKCU\SOFTWARE\Microsoft\Internet Explorer\Main,
    параметр Search Page

Страница по умолчанию

Страница по умолчанию — страница, открываемая при нажатии на пиктограмму с изображением «домика» (располагающуюся справа от строки адреса).
Используемые ключи и параметры реестра:

  • HKLM\SOFTWARE\Microsoft\Internet Explorer\Main,
    параметр Default_Page_URL
  • HKCU\SOFTWARE\Microsoft\Internet Explorer\Main,
    параметр Default_Page_URL = что-то вроде http://go.microsoft.com/fwlink/p/?LinkId=255141

Префикс по умолчанию

Описывает префикс, который добавляется к адресу при отсутствии явного указания префикса URL пользователем в строке адреса. Обычно в IE используется приставка http://.
Используемый ключ и параметр реестра:

  • HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\URL\DefaultPrefix,
    параметр @=http://
  • HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\URL\Prefixes,
    параметры ftp, home, mosaic, www

Трансляция неизвестных адресов

Интерфейс IURLSearchHook раскрывает метод, используемый браузером для трансляции адресов, содержащих неизвестный или не указанный (не конкретизированный) непосредственно протокол. Примером может служить ситуация, когда в адресной строке браузера вводится адрес, не содержащий префикса http://. Для начала Internet Explorer пытается самостоятельно определить протокол используя оригинальный адрес. В ситуации, когда браузер не имеет возможности определить протокол адреса в адресной строке, он вызывает URLSearchHook, создает объекты URL Search Hook (которые зарегистрированы в системе) и вызывает для каждого объекта метод трансляции до тех пор, пока URL не будет оттранслирован или все фильтры не будут обработаны.
Настройка трансляции производится в ключе реестра:

  • HKCU\SOFTWARE\Microsoft\Internet Explorer\URLSearchHooks

Параметры имеют имена CLSID, ссылающиеся на ключи HKLM\SOFTWARE\Classes\CLSID\{CLSID}, в которых в параметрах InprocServer32 содержится информация о трансляторе. По-умолчанию это C:\Windows\System32\ieframe.dll.

Устаревшие (необрабатываемые, исключенные) настройки Internet Explorer

Данная группа параметров активно использовалась в устаревших ныне версиях браузера (5/6/7/8) и в современных либо не используется, либо заменена другими механизмами конфигурирования:

  • HKLM\SOFTWARE\Microsoft\Internet Explorer\Search,
    параметр SearchAssistant
  • HKLM\SOFTWARE\Microsoft\Internet Explorer\Search,
    параметр CustomizeSearch
  • HKCU\SOFTWARE\Microsoft\Internet Explorer\Search,
    параметр CustomizeSearch

Передача запроса поисковой системе. Когда в адресной строке браузера IE вводится что-либо, не соответствующее формату типового URL-адреса, то браузер передает строку заданной по умолчанию поисковой системе. Для подобных целей используется ключ реестра:

  • HKCU\SOFTWARE\Microsoft\Internet Explorer\SearchURL,
    параметр Default или ((По умолчанию))

Собственный заголовок окна. В старых версиях IE у окна браузера постоянно выводился заголовок, так вот для того, что бы иметь возможность задавать собственный заголовок окна браузера, был введен специализированный параметр реестра:

  • HKCU\SOFTWARE\Microsoft\Internet Explorer\Main,
    параметр Window Title

Отображение результатов поиска в главном окне/окне поиска браузера. Еще один устаревший параметр, который позволял изменить стиль отображения результатов поиска:

  • HKCU\SOFTWARE\Microsoft\Internet Explorer\Main,
    параметр Search Bar

Ориентировочно до версии IE6 в коде обозревателя присутствовал Мастер подключения к Интернету:

  • HKCU\SOFTWARE\Microsoft\Internet Connection Wizard,
    параметр ShellNext

где он теперь?

Локальная групповая политика

Время от времени модификации вредоносным кодом подвергаются файлы локальной групповой политики. В принципе, это достаточно привлекательный системный механизм для вирусописателей, поскольку модифицировав каким-либо образом локальную групповую политику, можно добиться автоматического внесения изменений в реестр. Например, на практике попадались методы заражения, которые подразумевали модификацию локальной групповой политики (а именно файла registry.pol) с целью последующего внесения изменений в те или иные ключи реестра. Например, часть конфигурации локальной групповой политики под названием «локальный компьютер» располагается по пути:

  • %SystemRoot%\System32\GroupPolicy\Machine\registry.pol

.. и если вредоносный код добавит туда, скажем, исключения для того же Защитника Windows или брендмауэра, то данные исключения каждый раз при применении групповой политики будут добавляться в соответствующие ключи реестра. Поэтому, лишний раз не поленитесь проверить содержимое файла registry.pol на предмет наличия подозрительных записей, и при обнаружении таковых, можно смело удалять последний.

Многоуровневый поставщик услуг

Winsock LSP (Layered Service Provider) — многоуровневый поставщик услуг, Windows Sockets версии 2.0, предоставляющий возможность пользователю подключать собственные библиотеки DLL для обработки вызовов Windows Sockets API. Обычно поставщик занимается обработкой низкоуровневых задач, связанных с сетевым трафиком. Поставщик обрабатывает данные, передаваемые по протоколу TCP/IP, который используется для связи с локальной сетью и сетью Интернет. В процессе приема/передачи данных по протоколу TCP/IP, информация последовательно проходит по цепочке через все зарегистрированные в стеке TCP/IP поставщики (по структуре обычные DLL-библиотеки, которые используют Winsock API). Каждый поставщик может как угодно модифицировать проходящие данные и адреса. Таким образом, механизм LSP используется для вполне легитимных действий над трафиком и пространством имен, таких как подсчет трафика, антивирусная проверка, фильтрация контента, поэтому, например, многие антивирусы и фаерволы могут на вполне легальных основаниях находиться в стеке TCP/IP в качестве поставщиков услуг. Однако, некоторые вирусы могут добавлять свои модули в цепочку обработки.
Список поставщиков услуг хранится в специальной базе, которую можно найти в реестре в следующем разделе:
HKLM\System\CurrentControlSet\Services\Winsock2\Parameters
Не редка ситуация, когда Вы каким-либо образом нашли и удалили из цепочки модуль вируса, который находился в стеке поставщиков, однако не произвели коррекцию самой цепочки, в этом случае цепочка обработки рвется, и работа по протоколу TCP/IP с локальной сетью и сетью Интернет становится невозможной. Бывают и случаи удаления вредоносной DLL из файловой системы без должной коррекции (отмены регистрации провайдера) базы провайдеров, которые тоже не приводят ни к чему хорошему. Для восстановления (корректировки) цепочки провайдеров существуют утилиты LSP-Fix и AVZ (является полноценным сканером), которые проходят по цепочке разделов реестра Winsock2 и восстанавливают корректные связи.
Конечно, в случае с Windows Sockets 2.0 все далеко не так радужно. Чаще всего, в случае проблем с работоспособностью локальной сети и интернет, выполняют восстановление по заданному системному шаблону, однако этот шаблон надо знать, поскольку неправильные действия с базой поставщиков могут привести к полной неработоспособности сетевого интерфейса.

В Windows 7/8 технология LSP всё еще функционирует, однако не рекомендуется к использованию! Это объясняется тем, что начиная с Windows Vista разработчики активно продвигают новую технологию под названием «Платформа фильтрации Windows» (Windows Filtering Platform, WFP), которая предназначена для обработки, отслеживания и перехвата сетевого трафика на всех уровнях сетевого стека, а так же призвана заменить все существующие технологии фильтрации в стеке TCP/IP. Существующие и разрабатываемые драйвера и приложения обработки пакетов предлагается портировать под новую технологию.

Компоненты Active Setup

Active Setup (Активная настройка/Набор активирования/Активный набор) — системный механизм, предназначенный для разового выполнения команд на этапе первичного входа пользователя в систему. Команды выполняются единожды, то есть при всех последующих входах пользователя команда исполняться уже не будет. Конфигурация каждого компонента Active Setup делится на машинную и пользовательскую части, которые расположены в разных ветвях реестра. Поэтому, когда пользователь входит в систему, Active Setup проверяет наличие идентификатора GUID каждого [заданного для установки] компонента в пользовательской части соответствующего ключа реестра и если GUID отсутствует, то выполняется команда, ассоциированная с компонентом, а по завершении процесса GUID компонента добавляется в пользовательскую часть реестра. Механизм может производить установку пакетов .msi. Работу механизма Active Setup мы можем, к примеру, лицезреть когда впервые авторизуемся в операционной системе: наблюдаем первичную настройку обозревателя Internet Explorer, проявляющую себя в появлении небольших окон установки в левом верхнем углу рабочего стола пользователя. Механизм может эксплуатироваться вирусами, поэтому поиск вируса в данном случае сводится к проверке машинной части ключей реестра Active Setup. Информация о машинной части размещается в реестре в ключе:

  • HKLM\SOFTWARE\Microsoft\Active Setup\Installed Components
  • HKLM\SOFTWARE\Wow6432Node\Microsoft\Active Setup\Installed Components

Содержит подключи в виде идентификаторов GUID, которые и описывают (содержат параметры) установленные в системе компоненты. Лечение сводится к обходу всех представленных в ключе идентификаторов и проверке вложенных параметров (таких как stubpath), содержащих полные пути к исполняемым образам компонентов.

Environment: 

Windows 7 x64 bit + Internet Explorer 11

Requirement:

You want to programmatically determine what all add-ons installed on your Windows 7 systems.  To do this you need to know where IE saves all of its Add-ons configuration/details.

Solution:

Here is a quick list of various locations that IE look for all of its add-ons on the system.  This list is obtained by profiling the IE browser while doing operation of: Internet Options > Manage Add-ons > In Show: drop down list > Select “All Add-ons” as shown below:

image

Resultant list of Internet Explorer browser add-on registry paths:

Sl.No Operation Registry Path
1 RegEnumValue HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Internet Settings\ActiveX Cache
2 RegEnumKey HKLM\SOFTWARE\Wow6432Node\Microsoft\Code Store Database\Distribution Units
3 RegEnumValue HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings\ActiveX Cache
4 RegEnumKey HKLM\SOFTWARE\Microsoft\Code Store Database\Distribution Units
5 RegEnumKey HKCU\Software\Microsoft\Windows\CurrentVersion\Ext\Stats
6 RegEnumKey HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\explorer\Browser Helper Objects
7 RegEnumKey HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Browser Helper Objects
8 RegEnumKey HKLM\SOFTWARE\Wow6432Node\Microsoft\Internet Explorer\Extensions
9 RegEnumKey HKLM\SOFTWARE\Microsoft\Internet Explorer\Extensions
10 RegEnumKey HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Ext\PreApproved
11 RegEnumKey HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Ext\PreApproved
     

<

p>

image

image

Other references on this topic:

  • Performing an Inventory of ActiveX Controls in Windows 7
  • Removing ActiveX/OLE controls

Содержание

  1. Браузерные помощники — HKLM SOFTWARE WOW6432NODE Microsoft Windows CurrentVersion Explorer Browser Helper Objects
  2. Что такое HKLM Software WOW6432Node Microsoft Windows CurrentVersion Explorer Browser Helper Objects?
  3. Какие функции выполняют Browser Helper Objects?
  4. Описание BHO
  5. Примеры Browser Helper Objects
  6. Что такое BHO и как они работают?
  7. Примеры популярных Browser Helper Objects:
  8. Как найти и удалить нежелательные BHO?
  9. Роль HKLM Software WOW6432Node Microsoft Windows CurrentVersion Explorer Browser Helper Objects
  10. Влияние на производительность и безопасность компьютера
  11. Как изменить настройки BHO для оптимизации работы браузера

Браузерные помощники — HKLM SOFTWARE WOW6432NODE Microsoft Windows CurrentVersion Explorer Browser Helper Objects

Если вы знакомы с разработкой программного обеспечения или использованием операционных систем Windows, вы наверняка слышали о реестре. Реестр Windows — это база данных, где хранятся настройки, параметры и другая информация о системе и установленном программном обеспечении.

Одной из важных составляющих реестра является «Hklm software wow6432node microsoft windows currentversion explorer browser helper objects». Это раздел реестра, который содержит информацию о помощниках браузера — программных объектах, которые могут расширить функциональность веб-браузеров, таких как Internet Explorer.

Помощники браузера — это небольшие программы или дополнения, которые интегрируются в браузер и обеспечивают дополнительные функции, такие как блокировка рекламы, защита от вредоносных программ или улучшенная навигация.

«Hklm software wow6432node microsoft windows currentversion explorer browser helper objects» содержит информацию о таких помощниках браузера, их идентификаторах, путях к файлам и других параметрах. Доступ к этому разделу реестра позволяет управлять и настраивать помощников браузера, а также добавлять или удалять их в системе.

В данной статье мы рассмотрим более подробно «Hklm software wow6432node microsoft windows currentversion explorer browser helper objects» и роль, которую они играют в контексте использования браузеров Windows.

Что такое HKLM Software WOW6432Node Microsoft Windows CurrentVersion Explorer Browser Helper Objects?

WOW6432Node — это подключение, которое содержит информацию об установленном программном обеспечении, специфичном для 32-битной версии операционной системы Windows на компьютере с 64-битной архитектурой. Внутри WOW6432Node существует подключение по имени «Microsoft», а внутри него — «Windows».

CurrentVersion — это подключение, которое содержит информацию о текущей установленной версии операционной системы Windows. Внутри CurrentVersion существует подключение «Explorer», а внутри него — «Browser Helper Objects».

Browser Helper Objects (BHO) — это объекты, расширения или плагины, которые интегрируются в веб-браузер и обеспечивают дополнительные функции и возможности. BHO могут быть установлены приложениями и расширениями, их задача состоит в том, чтобы помочь в работе с браузером путем предоставления дополнительных функций, таких как блокировка рекламы, защита от вредоносного кода или улучшение пользовательского опыта.

Использование HKLM Software WOW6432Node Microsoft Windows CurrentVersion Explorer Browser Helper Objects в реестре Windows может быть полезным для контроля и настройки Browser Helper Objects, установленных на компьютере. Это позволяет пользователям управлять функциональностью и поведением расширений браузера, а также обеспечить безопасность и защиту от потенциально вредоносных плагинов.

Какие функции выполняют Browser Helper Objects?

Основные функции BHO включают:

  • Расширение функциональности браузера: BHO позволяют добавлять новые кнопки, панели инструментов и меню в браузер, что может улучшить удобство использования и облегчить доступ к определенным функциям и сервисам.

  • Блокировка рекламы и вредоносного ПО: BHO могут использоваться для блокировки рекламных баннеров, всплывающих окон и другой нежелательной рекламы, а также для обнаружения и предотвращения угроз безопасности, таких как вредоносные программы и фишинговые сайты.

  • Интеграция с другими сервисами: BHO могут быть участниками системы распознавания речи, социальных сетей или других приложений, предоставляя удобный доступ и интеграцию с этими сервисами непосредственно через браузер.

В целом, Browser Helper Objects играют важную роль в расширении возможностей браузера и улучшения пользовательского опыта. Однако, следует помнить, что BHO являются сторонними компонентами и могут иметь доступ к вашей персональной информации. Поэтому важно устанавливать и использовать только надежные BHO, полученные из официальных источников.

Описание BHO

Основная цель BHO состоит в поддержке взаимодействия браузера с различными веб-сервисами и веб-приложениями. BHO может предоставлять функции, такие как блокировка рекламы, автозаполнение форм, проверка правописания, перевод текста, улучшенная навигация и многое другое. Они могут быть бесплатными или платными и обычно доступны для скачивания и установки из магазинов расширений браузера или от сторонних разработчиков.

Установка BHO обычно происходит путем загрузки соответствующего файла с расширением .dll или .exe и его последующей регистрации в системном реестре. После установки BHO может взаимодействовать с браузером, а также модифицировать отображение и поведение веб-страниц. Для пользователя BHO может быть полезным инструментом, который помогает улучшить его веб-переживания, но иногда они также могут быть использованы вредоносными программами для сбора информации о пользователе или нанесения вреда компьютеру.

Примеры Browser Helper Objects

  • Adobe Acrobat BHO — это BHO, предоставляемый Adobe Acrobat, который позволяет пользователю открывать и просматривать файлы PDF непосредственно в браузере.
  • Google Toolbar BHO — это BHO, предоставляемый Google Toolbar, который предоставляет доступ к различным сервисам Google, таким как поиск, переводчик, карты и другие, непосредственно из панели инструментов браузера.
  • Avast Online Security BHO — это BHO, предоставляемый антивирусной программой Avast, который обеспечивает безопасность пользователей во время просмотра веб-страниц, предупреждая о потенциально опасных или вредоносных сайтах.

BHO являются полезными инструментами для пользователей, поскольку они могут значительно улучшить их веб-серфинг и облегчить выполнение определенных задач. Они предоставляют дополнительные функции и возможности, которые иначе могли бы быть недоступными. Однако пользователи должны быть осторожны и установить BHO только от доверенных и проверенных источников, чтобы избежать установки вредоносного программного обеспечения или нарушения конфиденциальности данных.

Что такое BHO и как они работают?

Одним из примеров BHO-плагинов является плагин Adobe Acrobat, который добавляет возможность просмотра PDF-файлов внутри браузера. Другой пример — плагин блокировки рекламы, который блокирует отображение рекламных баннеров на веб-страницах.

Как работают BHO-плагины? Они интегрируются в браузер и могут мониторить действия пользователя, обрабатывать веб-страницы, добавлять дополнительные кнопки или панели инструментов, фильтровать или изменять содержимое страницы. BHO-плагины могут использоваться для различных целей — от улучшения пользовательского опыта до сбора информации о пользователях.

  • Улучшение пользовательского опыта: BHO-плагины могут добавлять дополнительные функции и возможности в браузер, такие как блокировка рекламы, управление закладками, перевод страниц на другие языки и другое.
  • Мониторинг действий пользователя: Некоторые BHO-плагины могут отслеживать действия пользователя, такие как посещенные веб-страницы, поисковые запросы и т. д. Эти данные могут быть использованы разработчиками для анализа поведения пользователей или направления целевой рекламы.
  • Фильтрация и изменение содержимого страниц: BHO-плагины могут фильтровать или изменять содержимое веб-страниц, например, для блокировки определенных элементов или замены текста.

Важно отметить, что не все BHO-плагины полезны или надежны. Некоторые плагины могут быть вредоносными и использоваться для сбора личных данных или распространения вредоносных программ. Поэтому важно быть осторожным при установке и использовании BHO-плагинов, проверять их надежность и соблюдать меры безопасности.

Примеры популярных Browser Helper Objects:

  • Adobe Acrobat BHO: Этот BHO разработан для совместной работы с Adobe Acrobat Reader. Он автоматически обнаруживает PDF-файлы и предоставляет возможность просмотра их в браузере. Таким образом, пользователи могут легко просматривать содержимое PDF-файлов без необходимости открывать их в отдельной программе.
  • Google Toolbar BHO: Инструментальная панель Google является одним из самых популярных и полезных BHO. Она предлагает широкий спектр функций, включая поиск в Интернете, переводчик, проверку орфографии и доступ к различным сервисам Google. Благодаря этому, пользователи могут получать доступ ко множеству функций Google прямо из своего браузера.
  • Amazon Assistant BHO: Этот BHO разработан Amazon для улучшения опыта покупок. Он предоставляет быстрый доступ к функциям Amazon, таким как поиск товаров, сравнение цен, добавление товаров в список желаний и получение рекомендаций. Благодаря этому, пользователи могут легко находить и покупать товары на Amazon, не покидая страницу, которую они просматривают.

Приведенные примеры популярных Browser Helper Objects представляют лишь небольшую часть множества инструментов, доступных для расширения функциональности браузеров. Они позволяют пользователям получить дополнительные возможности при просмотре веб-контента и облегчают выполнение различных задач. Важно отметить, что все BHO должны быть установлены и использоваться с осторожностью, чтобы не нарушать безопасность и конфиденциальность данных пользователей.

Как найти и удалить нежелательные BHO?

Первым шагом в поиске и удалении нежелательных BHO является открытие реестра Windows. Для этого нажмите клавиши «Win» + «R», введите «regedit» и нажмите «ОК». После открытия редактора реестра, найдите ветку «HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Explorer\Browser Helper Objects». Здесь вы найдете список всех установленных BHO.

Чтобы удалить нежелательные BHO, просто щелкните правой кнопкой мыши на нужном объекте BHO и выберите «Удалить». При этом будьте осторожны и не удаляйте BHO, о которых вы не уверены, так как это может повредить работу вашего браузера. Лучше всего перед удалением нежелательных BHO создать резервную копию реестра или точку восстановления системы, чтобы вы могли вернуть все настройки в случае проблем.

Роль HKLM Software WOW6432Node Microsoft Windows CurrentVersion Explorer Browser Helper Objects

Когда вы устанавливаете новое расширение браузера или плагин, связанный BHO-ключ добавляется в реестр вашего компьютера. Затем при каждом запуске вашего браузера Windows проверяет этот ключ и загружает соответствующие дополнения. BHO также может быть задействован для улучшения производительности вашего браузера, блокирования нежелательного контента или обеспечения дополнительных функций безопасности.

Поэтому важно регулярно проверять и управлять установленными BHO на вашем компьютере. Вы можете использовать специализированные программы или инструменты, предоставленные вашим браузером или вариантом Windows, чтобы управлять и контролировать эти дополнения. Убедитесь, что у вас установлена надежная система безопасности и обновляйте ее регулярно, чтобы минимизировать риск использования вредоносных BHO.

Влияние на производительность и безопасность компьютера

BHO — это небольшие программы, которые расширяют функциональность веб-браузера, добавляя новые возможности и функции. Некоторые BHO могут быть полезными, например, предоставлять дополнительные возможности поиска или блокировать рекламные баннеры. Однако, существуют и вредоносные BHO, которые могут подвергать компьютер риску безопасности или замедлять его работу.

При установке нового программного обеспечения или расширения для браузера, важно быть внимательным и изучить, какие BHO будут установлены вместе с ними. Некоторые BHO могут перехватывать ваши данные, отслеживать ваши привычки в интернете или открывать дверь для других вредоносных программ. Поэтому, стоит быть осмотрительным и устанавливать только те BHO, которые доверяете.

Если вы заметили, что ваш компьютер работает медленнее или стало появляться больше рекламы в браузере, возможно, это связано с нежелательными BHO. Вы можете проверить и управлять установленными BHO в разделе «Hklm software wow6432node microsoft windows currentversion explorer browser helper objects» в реестре операционной системы Windows. Удаление или отключение нежелательных BHO может улучшить производительность и безопасность вашего компьютера.

Как изменить настройки BHO для оптимизации работы браузера

Прежде чем приступить к изменению настроек BHO, вам необходимо открыть реестр и найти раздел «HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Explorer\Browser Helper Objects». Этот раздел содержит информацию о всех установленных дополнениях браузера.

Приступая к изменению настроек BHO, важно помнить о безопасности. Удаление некоторых дополнений может повлиять на функциональность браузера, поэтому рекомендуется создать резервную копию реестра перед внесением каких-либо изменений.

Для оптимизации работы браузера вы можете отключить ненужные BHO. Для этого найдите ключ соответствующего дополнения в разделе «Browser Helper Objects» и измените значение ключа на «0» или удалите его полностью. Это действие поможет избавиться от нежелательных дополнений, которые могут замедлить работу браузера или вызывать ошибки.

Кроме того, вы можете изменить порядок загрузки BHO в браузере. Некоторые дополнения могут быть более важными для вас, поэтому вы можете изменить их приоритет так, чтобы они загружались раньше или позже других дополнений. Для этого измените значение ключа «LoadOrder» соответствующего дополнения. Более низкое значение означает более высокий приоритет загрузки.

Не забывайте, что настройки BHO могут различаться в зависимости от используемого браузера. Рекомендуется ознакомиться с документацией вашего браузера или обратиться к разработчику, чтобы получить более точную информацию о настройках BHO и их влиянии на работу браузера.

Внесение изменений в настройки BHO может значительно повысить производительность вашего браузера и улучшить ваш опыт в интернете. Не бойтесь экспериментировать, но помните о безопасности и создавайте резервные копии данных перед внесением изменений в реестр.

This article will serve as an informative guide and give you a clear understanding of how to perform silent uninstalls of Microsoft Office 2019 Click To Run (C2R) using the OffScrub VBS Script created by Microsoft Customer Support Services. The OffScrub VBS Script will completely remove any previously installed Microsoft Office components.

How to Uninstall Microsoft Office 2019 Click To Run (C2R) Using the OffScrub VBS Script

Microsoft Office 2019 Click To Run (C2R) Silent Uninstall (VBS Script)

  • Copy the VBS Script below to “C:\Downloads” & name it OffScrubC2R.vbs
  • Open an Elevated Command Prompt by Right-Clicking on Command Prompt and select Run as Administrator
  • Navigate to the C:\Downloads folder
  • Enter the following command: Cscript.exe //nologo .\OffScrubC2R.vbs /ByPass 1 /Q /NoCancel
  • Press Enter
'*******************************************************************************
' Name: OffScrubC2R.vbs
' Author: Microsoft Customer Support Services
' Copyright (c) 2014 - 2016 Microsoft Corporation
' Script to remove Office Click To Run (C2R) products
' when a regular uninstall is no longer possible
'
' Scope: Office 2013, 2016 and O365 C2R products
'*******************************************************************************

Option Explicit

'-------------------------------------------------------------------------------
'
'   Declaration of constants
'-------------------------------------------------------------------------------


Const SCRIPTVERSION   = "2.12"
Const SCRIPTFILE      = "OffScrubC2R.vbs"
Const SCRIPTNAME      = "OffScrubC2R"
Const RETVALFILE      = "ScrubRetValFile.txt"
Const ONAME           = "Office C2R / O365"
Const HKCR            = &H80000000
Const HKCU            = &H80000001
Const HKLM            = &H80000002
Const HKU             = &H80000003
Const PRODLEN         = 13
Const SQUISHED        = 20
Const COMPRESSED      = 32
Const REG_ARP         = "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\"
Const VB_YES          = 6
Const VB_NO           = 7

Const ERROR_SUCCESS                 = 0   'Bit #1.  0 indicates Success. Script completed successfully
Const ERROR_FAIL                    = 1   'Bit #1.  Failure bit. Indicates an overall script failure.
                                          'RESERVED bit! Returned when process is killed from task manager
Const ERROR_REBOOT_REQUIRED         = 2   'Bit #2.  Reboot bit. If set a reboot is required
Const ERROR_USERCANCEL              = 4   'Bit #3.  User Cancel bit. Controlled cancel from script UI
Const ERROR_STAGE1                  = 8   'Bit #4.  Informational. Msiexec based install was not possible
Const ERROR_STAGE2                  = 16  'Bit #5.  Critical. Not all of the intended cleanup operations could be applied
Const ERROR_INCOMPLETE              = 32  'Bit #6.  Pending file renames (del on reboot) - OR - Removal needs to run again after a system reboot.
Const ERROR_DCAF_FAILURE            = 64  'Bit #7.  Critical. Da capo al fine (second attempt) still failed.
Const ERROR_ELEVATION_USERDECLINED  = 128 'Bit #8.  Critical script error. User declined to allow mandatory script elevation
Const ERROR_ELEVATION               = 256 'Bit #9.  Critical script error. The attempt to elevate the process did not succeed
Const ERROR_SCRIPTINIT              = 512 'Bit #10. Critical script error. Initialization failed
Const ERROR_RELAUNCH                = 1024'Bit #11. Critical script error. This is a temporary value and must not be the final return code
Const ERROR_UNKNOWN                 = 2048'Bit #12 Critical script error. Script did not complete in a well defined state
Const ERROR_ALL                     = 4095'Full BitMask
Const ERROR_USER_ABORT              = &HC000013A 'RESERVED. Dec -1073741510. Critical error. Returned when user aborts with <Ctrl>+<Break> or closes the cmd window
Const ERROR_SUCCESS_CONFIG_COMPLETE = 1728
Const ERROR_SUCCESS_REBOOT_REQUIRED = 3010

'-------------------------------------------------------------------------------
'
'   Declaration of variables
'-------------------------------------------------------------------------------

Dim oFso, oMsi, oReg, oWShell, oWmiLocal, oShellApp
Dim ComputerItem, Key, Item, LogStream, TmpKey
Dim arrVersion
Dim dicKeepLis, dicApps, dicKeepFolder, dicDelRegKey, dicKeepReg
Dim dicInstalledSku, dicRemoveSku, dicKeepSku, dicC2RSuite, dicDelInUse
Dim dicDelFolder
Dim sAppData, sScrubDir, sProgramFiles, sProgramFilesX86, sCommonProgramFiles
Dim sAllusersProfile, sOSVersion, sWinDir, sWICacheDir, sCommonProgramFilesX86
Dim sProgramData, sPackageFolder, sLocalAppData, sOInstallRoot, sSkuRemoveList
Dim sOSinfo, sDefault, sTemp, sTmp, sCmd, sLogDir, sProfilesDirectory
Dim sRetVal, sScriptDir, sPackageGuid, sValue, sActiveConfiguration, sNotepad
Dim iVersionNT, iError, iProcCloseCnt
Dim f64, fLogInitialized, fNoCancel, fRemoveOse, fDetectOnly, fQuiet, fForce
Dim fC2R, fRemoveAll, fRebootRequired, fRerun, fSetRunOnce, fTestRerun
Dim fIsElevated, fNoElevate, fUserConsent, fCScript, fReturnErrorOrSuccess
Dim fClearTaskBand, fSkipSD 

'-------------------------------------------------------------------------------
'                                   Main
'
'                           Main section of script
'-------------------------------------------------------------------------------


' initialize required settings and objects
' ----------------------------------------
Initialize

' call the command line parser
'-----------------------------
ParseCmdLine

                                '-----------------------------
                                ' Stage # 0 - Basic detection |
                                '-----------------------------

LogH "Stage # 0 " & chr(34) & "Basic detection" & chr(34) 

' ensure integrity of WI metadata which could fail used APIs otherwise
'---------------------------------------------------------------------
LogH1 "Ensure Windows Installer metadata integrity " & " (" & Time & ")"
EnsureValidWIMetadata HKCU,"Software\Classes\Installer\Products", COMPRESSED
EnsureValidWIMetadata HKCR,"Installer\Products", COMPRESSED
EnsureValidWIMetadata HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Products", COMPRESSED
EnsureValidWIMetadata HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Components", COMPRESSED
EnsureValidWIMetadata HKCR,"Installer\Components", COMPRESSED

' build a list with installed/registered Office products
'-------------------------------------------------------
FindInstalledOProducts
If dicC2RSuite.Count > 0 Then 
    Log "Registered ARP product(s) found:"
    For Each Key In dicC2RSuite.Keys
    	Log " - " & Key & " - " & dicC2RSuite.Item(Key)
    Next 'Key
'    For Each Item in dicC2RSuite.Items
'        Log " - " & Item
'    Next 'Item
Else
    Log "No registered product(s) found"
End If

' locate the C2R %PackageFolder% and the PackageGuid
'---------------------------------------------------
sPackageFolder = ""
If RegReadValue(HKLM, "SOFTWARE\Microsoft\Office\15.0\ClickToRun", "PackageFolder", sValue, "REG_SZ") Then
	sPackageFolder = sValue
ElseIf RegReadValue(HKLM, "SOFTWARE\Microsoft\Office\16.0\ClickToRun", "PackageFolder", sPackageFolder, "REG_SZ") Then
	sPackageFolder = sValue
ElseIf RegReadValue(HKLM, "SOFTWARE\Microsoft\Office\ClickToRun", "PackageFolder", sPackageFolder, "REG_SZ") Then
	sPackageFolder = sValue
End If
' if sPackageFolder is invalid set it to the c2r registry reference string
If NOT Len(sPackageFolder) > 0 OR IsNull(sPackageFolder) Then 
	If oFso.FolderExists(oWShell.ExpandEnvironmentStrings("%programfiles%") & "\Microsoft Office 15") Then
		sPackageFolder = oWShell.ExpandEnvironmentStrings("%programfiles%") & "\Microsoft Office 15"
	ElseIf oFso.FolderExists(oWShell.ExpandEnvironmentStrings("%programfiles%") & "\Microsoft Office 16") Then
		sPackageFolder = oWShell.ExpandEnvironmentStrings("%programfiles%") & "\Microsoft Office 16"
	ElseIf oFso.FolderExists(oWShell.ExpandEnvironmentStrings("%programfiles%") & "\Microsoft Office\PackageManifests") Then
		sPackageFolder = oWShell.ExpandEnvironmentStrings("%programfiles%") & "\Microsoft Office"
	ElseIf oFso.FolderExists(oWShell.ExpandEnvironmentStrings("%programfiles(x86)%") & "\Microsoft Office\PackageManifests") Then
		sPackageFolder = oWShell.ExpandEnvironmentStrings("%programfiles(x86)%") & "\Microsoft Office"
	End If
End If

sPackageGuid = ""
If RegReadValue(HKLM, "SOFTWARE\Microsoft\Office\15.0\ClickToRun", "PackageGUID", sValue, "REG_SZ") Then
	sPackageGuid = sValue
ElseIf RegReadValue(HKLM, "SOFTWARE\Microsoft\Office\16.0\ClickToRun", "PackageGUID", sValue, "REG_SZ") Then
	sPackageGuid = sValue
ElseIf RegReadValue(HKLM, "SOFTWARE\Microsoft\Office\ClickToRun", "PackageGUID", sValue, "REG_SZ") Then
	sPackageGuid = sValue
End If

' Init complete. Reset the return value
'--------------------------------------
ClearError ERROR_SCRIPTINIT


                                '-----------------------
                                ' Stage # 1 - Uninstall |
                                '-----------------------

LogH "Stage # 1 " & chr(34) & "Uninstall" & chr(34)

' clean O15 SPP
'--------------
LogH1 "Clean OSPP" 
CleanOSPP

' end all running Office applications
'------------------------------------
LogH1 "End running processes" 
If NOT dicKeepSku.Count > 0 Then ClearShellIntegrationReg
CloseOfficeApps

' remove scheduled tasks which might interfere with uninstall
'------------------------------------------------------------
DelSchtasks

' unpin shortcuts
'----------------
' need to unpin as long as the shortcuts are still valid!
LogH1 "Clean shortcuts" 
CleanShortcuts sAllusersProfile, True, True
CleanShortcuts sProfilesDirectory, True, True

' uninstall
'----------
LogH1 "Remove " & ONAME  
Uninstall

                                '---------------------
                                ' Stage # 2 - CleanUp |
                                '---------------------
LogH "Stage # 2 " & chr(34) & "CleanUp" & chr(34)

' Cleanup registry data
'----------------------
RegWipe

' Cleanup files
'--------------
FileWipe

' for test purposes only!
If fTestRerun Then
    LogH2 "Enforcing 'Rerun' mode for test purposes"
    fRebootRequired = True
    SetError ERROR_REBOOT_REQUIRED
    Rerun
End If

' Ensure Explorer runs
RestoreExplorer

' Exit
ExitScript

                                    '------------------
                                    ' Stage # 3 - Exit |
                                    '------------------

'-------------------------------------------------------------------------------
'   ExitScript
'
'   Returncode and reboot handler 
'-------------------------------------------------------------------------------
Sub ExitScript
    Dim sPrompt

    ' Update cached error and quit
    '-----------------------------
    If NOT CBool(iError AND (ERROR_FAIL + ERROR_INCOMPLETE)) Then RegDeleteValue HKCU, "SOFTWARE\Microsoft\Office\15.0\CleanC2R", "Rerun", False
    SetRetVal iError

    ' log result
    If CBool(iError AND ERROR_INCOMPLETE) Then 
        LogH2 "Removal result: " & iError & " - INCOMPLETE. Uninstall requires a system reboot to complete."
    Else
        sTmp = " - SUCCESS"
        If CBool(iError AND ERROR_USERCANCEL) Then sTmp = " - USER CANCELED"
        If CBool(iError AND ERROR_FAIL) Then sTmp = " - FAIL"
        LogH2 "Removal result: " & iError & sTmp
    End If
    If CBool(iError AND ERROR_FAIL) Then
        If CBool(iError AND ERROR_REBOOT_REQUIRED) Then Log " - Reboot required"
        If CBool(iError AND ERROR_USERCANCEL) Then Log " - User cancel"
        If CBool(iError AND ERROR_STAGE1) Then Log " - Msiexec failed"
        If CBool(iError AND ERROR_STAGE2) Then Log " - Cleanup failed"
        If CBool(iError AND ERROR_INCOMPLETE) Then Log " - Removal incomplete. Rerun after reboot needed"
        If CBool(iError AND ERROR_DCAF_FAILURE) Then Log " - Second attempt cleanup still incomplete"
        If CBool(iError AND ERROR_ELEVATION_USERDECLINED) Then Log " - User declined elevation"
        If CBool(iError AND ERROR_ELEVATION) Then Log " - Elevation failed"
        If CBool(iError AND ERROR_SCRIPTINIT) Then Log " - Initialization error"
        If CBool(iError AND ERROR_RELAUNCH) Then Log " - Unhandled error during relaunch attempt"
        If CBool(iError AND ERROR_UNKNOWN) Then Log " - Unknown error"
        ' ERROR_USER_ABORT is only valid for the temporary cached error file
        'If CBool(iError AND ERROR_USER_ABORT) Then Log " - Process terminated by user"
    End If

    LogH2 "Removal end." 

    ' Check if we need to show a simplified return code
    ' 0 = Success
    ' Non Zero = Error
     If CBool(iError AND ERROR_FAIL) AND fReturnErrorOrSuccess Then
        Dim fOverallSuccess
        fOverallSuccess = True
        If CBool(iError AND ERROR_USERCANCEL) Then fOverallSuccess = False
        If CBool(iError AND ERROR_STAGE2) Then fOverallSuccess = False
        If CBool(iError AND ERROR_DCAF_FAILURE) Then fOverallSuccess = False
        If CBool(iError AND ERROR_ELEVATION_USERDECLINED) Then fOverallSuccess = False
        If CBool(iError AND ERROR_ELEVATION) Then fOverallSuccess = False
        If CBool(iError AND ERROR_SCRIPTINIT) Then fOverallSuccess = False
        If CBool(iError AND ERROR_RELAUNCH) Then fOverallSuccess = False
        If CBool(iError AND ERROR_UNKNOWN) Then fOverallSuccess = False

        If fOverallSuccess Then iError = ERROR_SUCCESS

        sTmp = "ReturnErrorOrSuccess switch has been set. The current value return code translates to: "
        If fOverallSuccess Then 
            iError = ERROR_SUCCESS
            Log sTmp & "SUCCESS"
        Else
            Log sTmp & "ERROR"
        End If

    End If
   
    ' Reboot handling
    If fRebootRequired Then
        sPrompt = "In order to complete uninstall, a system reboot is necessary. Would you like to reboot now?"
        If NOT fQuiet Then
            If MsgBox(sPrompt, vbYesNo, SCRIPTNAME & " - Reboot Required") = VB_YES Then
                Dim colOS, oOS
                Dim oWmiReboot
                Set oWmiReboot = GetObject("winmgmts:{impersonationLevel=impersonate,(Shutdown)}!\\.\root\cimv2")
                Set colOS = oWmiReboot.ExecQuery ("Select * from Win32_OperatingSystem")
                For Each oOS in colOS
                    oOS.Reboot()
                Next
            End If
        End If
    End If

    wscript.quit iError
End Sub 'ExitScript

'-------------------------------------------------------------------------------
'                                  End  Main
'
'                           End of Main section
'-------------------------------------------------------------------------------

'-------------------------------------------------------------------------------
'   Initialize
'
'   Configure defaults and initialize all required objects
'-------------------------------------------------------------------------------
Sub Initialize ()
    Dim iCnt

    ' set defaults
    '-------------
    iError = ERROR_SUCCESS
    iProcCloseCnt = 0
    sLogDir = ""
    sPackageFolder = ""
    f64 = False
    fCScript = False
    fLogInitialized = False
    fNoCancel = False
    fRemoveOse = False
    fDetectOnly = False
    fQuiet = False
    fForce = False
    fC2R = True
    fRebootRequired = False
    fRerun = False
    fTestRerun = False
    fIsElevated = False
    fNoElevate = False
    fSetRunOnce = False
    fUserConsent = False
    fReturnErrorOrSuccess = False
    fSkipSD = False
    fClearTaskBand = False

    ' create required objects
    '------------------------
    Set oWmiLocal   = GetObject("winmgmts:\\.\root\cimv2")
    Set oWShell     = CreateObject("Wscript.Shell")
    Set oShellApp   = CreateObject("Shell.Application")
    Set oFso        = CreateObject("Scripting.FileSystemObject")
    Set oMsi        = CreateObject("WindowsInstaller.Installer")
    Set oReg        = GetObject("winmgmts:\\.\root\default:StdRegProv")

    ' get environment path values
    '----------------------------
    sAppData            = oWShell.ExpandEnvironmentStrings("%appdata%")
    sLocalAppData       = oWShell.ExpandEnvironmentStrings("%localappdata%")
    sTemp               = oWShell.ExpandEnvironmentStrings("%temp%")
    sAllUsersProfile    = oWShell.ExpandEnvironmentStrings("%allusersprofile%")
    RegReadValue HKLM, "SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList", "ProfilesDirectory", sProfilesDirectory, "REG_EXPAND_SZ"
    If NOT oFso.FolderExists(sProfilesDirectory) Then 
        sProfilesDirectory  = oFso.GetParentFolderName(oWShell.ExpandEnvironmentStrings("%userprofile%"))
    End If
    sProgramFiles       = oWShell.ExpandEnvironmentStrings("%programfiles%")
    'sProgramFilesX86   = deferred. Depends on operating system architecture check
    sCommonProgramFiles = oWShell.ExpandEnvironmentStrings("%commonprogramfiles%")
    'sCommonProgramFilesX86 = deferred. Depends on operating system architecture check
    sProgramData        = oWSHell.ExpandEnvironmentStrings("%programdata%")
    sWinDir             = oWShell.ExpandEnvironmentStrings("%windir%")
    'sPackageFolder      = deferred
    sWICacheDir         = sWinDir & "\" & "Installer"
    sScrubDir           = sTemp & "\" & SCRIPTNAME
    sScriptDir          = wscript.ScriptFullName
    sScriptDir          = Left(sScriptDir, InStrRev(sScriptDir, "\"))
    sNotepad            = sWinDir & "\notepad.exe"

    ' ensure 64 bit host if needed
    If InStr(LCase(wscript.path), "syswow64") > 0 Then RelaunchAs64Host

    ' create the temp folder
    '-----------------------
    If Not oFso.FolderExists(sScrubDir) Then oFso.CreateFolder sScrubDir

    ' set the default logging directory
    '----------------------------------
    sLogDir = sScrubDir

    ' detect bitness of the operating system
    '----------------------------------------
    Set ComputerItem = oWmiLocal.ExecQuery("Select * from Win32_ComputerSystem")
    For Each Item In ComputerItem
        f64 = Instr(Left(Item.SystemType, 3), "64") > 0
    Next
    If f64 Then sProgramFilesX86 = oWShell.ExpandEnvironmentStrings("%programfiles(x86)%")
    If f64 Then sCommonProgramFilesX86 = oWShell.ExpandEnvironmentStrings("%CommonProgramFiles(x86)%")

    ' update error flag
    '------------------
    SetError ERROR_SCRIPTINIT

    ' get Win32_OperatingSystem details
    '----------------------------------
    Set ComputerItem = oWmiLocal.ExecQuery("Select * from Win32_OperatingSystem")
    For Each Item in ComputerItem 
        sOSinfo = sOSinfo & Item.Caption 
        sOSinfo = sOSinfo & Item.OtherTypeDescription
        sOSinfo = sOSinfo & ", " & "SP " & Item.ServicePackMajorVersion
        sOSinfo = sOSinfo & ", " & "Version: " & Item.Version
        sOsVersion = Item.Version
        sOSinfo = sOSinfo & ", " & "Codepage: " & Item.CodeSet
        sOSinfo = sOSinfo & ", " & "Country Code: " & Item.CountryCode
        sOSinfo = sOSinfo & ", " & "Language: " & Item.OSLanguage
    Next

    ' get VersionNT number
    '---------------------
    arrVersion = Split(sOsVersion, Delimiter(sOsVersion))
    iVersionNt = CInt(arrVersion(0)) * 100 + CInt(arrVersion(1))

    ' ensure sufficient registry permisions
    '--------------------------------------
    fIsElevated = CheckRegPermissions
    If NOT fIsElevated AND NOT fNoElevate Then
        ' try to relaunch elevated
        RelaunchElevated

        ' can't relaunch. Exit out
        SetError ERROR_ELEVATION
        If UCase(Mid(Wscript.FullName, Len(Wscript.Path) + 2, 1)) = "C" Then
            If Not fLogInitialized Then CreateLog
            Log "Error: Insufficient registry access permissions - exiting"
        End If
        SetRetVal iError
        'wscript.quit iError
        ExitScript
    End If

    ' clear error flags
    '------------------
    ClearError ERROR_ELEVATION
    ClearError ERROR_SCRIPTINIT

    ' ensure CScript as engine
    '------------------------
    fCScript = UCase(Mid(Wscript.FullName, Len(Wscript.Path) + 2, 1)) = "C"
    If NOT fCScript AND NOT fQuiet Then RelaunchAsCScript

    ' set retval for file based logic
    '--------------------------------
    ' value needs to be kept on 'user abort'
    SetRetVal ERROR_USER_ABORT

    ' create dictionary objects
    '--------------------------
    Set dicInstalledSku = CreateObject("Scripting.Dictionary")
    Set dicRemoveSku = CreateObject("Scripting.Dictionary")
    Set dicKeepSku = CreateObject("Scripting.Dictionary")
    Set dicKeepLis = CreateObject("Scripting.Dictionary")
    Set dicKeepFolder = CreateObject("Scripting.Dictionary")
    Set dicApps = CreateObject("Scripting.Dictionary")
    Set dicDelRegKey = CreateObject("Scripting.Dictionary")
    Set dicKeepReg = CreateObject("Scripting.Dictionary")
    Set dicC2RSuite = CreateObject("Scripting.Dictionary")
    Set dicDelInUse = CreateObject("Scripting.Dictionary")
    Set dicDelFolder = CreateObject("Scripting.Dictionary")

    ' add initial known .exe files that need to be closed
    '----------------------------------------------------
    dicApps.Add "appvshnotify.exe", "appvshnotify.exe"
    dicApps.Add "integratedoffice.exe", "integratedoffice.exe"
    dicApps.Add "integrator.exe", "integrator.exe"
    dicApps.Add "firstrun.exe", "firstrun.exe"
    'Adding setup.exe to the hard list of processes that are shut down will potentially break wrappers that invoke OffScrub
    'dicApps.Add "setup.exe", "setup.exe"
    dicApps.Add "communicator.exe", "communicator.exe"
    dicApps.Add "msosync.exe", "msosync.exe"
    dicApps.Add "OneNoteM.exe", "OneNoteM.exe"
    dicApps.Add "iexplore.exe", "iexplore.exe"
    dicApps.Add "mavinject32.exe", "mavinject32.exe"
    dicApps.Add "werfault.exe", "werfault.exe"
    dicApps.Add "perfboost.exe", "perfboost.exe"
    dicApps.Add "roamingoffice.exe", "roamingoffice.exe"
    ' SP1 additions / changes
    dicApps.Add "officeclicktorun.exe", "officeclicktorun.exe"
    dicApps.Add "officeondemand.exe", "officeondemand.exe"
    dicApps.Add "OfficeC2RClient.exe", "OfficeC2RClient.exe"

End Sub 'Initialize

'-------------------------------------------------------------------------------
'   ParseCmdLine
'
'   Command line parser
'-------------------------------------------------------------------------------
Sub ParseCmdLine

    Dim iCnt, iArgCnt
    Dim arrArguments, sArguments
    Dim sArg0
    
    iArgCnt = Wscript.Arguments.Count
    If iArgCnt > 0 Then
        If wscript.Arguments(0) = "UAC" Then
            If wscript.arguments.count = 1 Then iArgCnt = 0
        End If
    End If
    If iArgCnt = 0 Then
        Select Case UCase(wscript.ScriptName)
        Case Else
            'Create the log
            CreateLog
            FindInstalledOProducts
            sDefault = "ALL"
            arrArguments = Split(Trim(sDefault), " ")
            If UBound(arrArguments) = -1 Then ReDim arrArguments(0)
        End Select
    Else
        ReDim arrArguments(iArgCnt-1)
        For iCnt = 0 To (iArgCnt-1)
            arrArguments(iCnt) = UCase(Wscript.Arguments(iCnt))
            sArguments = sArguments & arrArguments(iCnt) & " "
        Next 'iCnt
    End If 'iArgCnt = 0

    ' hardcode to full removal
    sArg0 = "ALL"

    Select Case UCase(sArg0)
    Case "?"
        ShowSyntax
    Case "ALL"
        fRemoveAll = True
        fRemoveOse = False
    Case "C2R"
        fC2R = True
        fRemoveAll = False
        fRemoveOse = False
    Case Else
        fRemoveAll = False
        fRemoveOse = False
        sSkuRemoveList = sArg0
    End Select
    
    For iCnt = 0 To UBound(arrArguments)
        Select Case arrArguments(iCnt)
        Case "?", "/?", "-?"
            ShowSyntax
        
        Case "/L", "/LOG"
            fLogInitialized = False
            If UBound(arrArguments) > iCnt Then
                If oFso.FolderExists(arrArguments(iCnt + 1)) Then 
                    sLogDir = arrArguments(iCnt + 1)
                Else
                    On Error Resume Next
                    oFso.CreateFolder(arrArguments(iCnt + 1))
                    If Err <> 0 Then sLogDir = sScrubDir Else sLogDir = arrArguments(iCnt + 1)
                End If
            End If
        
        Case "/N", "/NOCANCEL"
            fNoCancel = True
        
        Case "/NE", "/NOELEVATE"
            fNoElevate = True

        Case "/O", "/OSE"
            fRemoveOse = True
        
        Case "/Q", "/QUIET"
            fQuiet = True
        
        Case "/RETERRORSUCCESS", "/RETURNERRORORSUCCESS", "/REOS"
            fReturnErrorOrSuccess = True

        Case "/S", "/SKIPSD", "/SKIPSHORTCUTDETECTION"
            fSkipSD = True
        
        ' for test purposes only!
        Case "/TR", "/TESTRERUN"
            fTestRerun = True
        Case Else
        End Select
    Next 'iCnt
    If Not fLogInitialized Then CreateLog
    LogH2 "Arguments: " & sArguments & vbCrLf
    
End Sub 'ParseCmdLine

'-------------------------------------------------------------------------------
'   ShowSyntax
'
'   Show the expected syntax for the script usage
'-------------------------------------------------------------------------------
Sub ShowSyntax
    Wscript.Echo vbCrLf & _
             SCRIPTFILE & " V " & SCRIPTVERSION & vbCrLf & _
             "Copyright (c) Microsoft Corporation. All Rights Reserved" & vbCrLf & vbCrLf & _
             SCRIPTFILE & " - Remove " & ONAME & vbCrLf & _
             "when a regular uninstall is no longer possible" & vbCrLf & vbCrLf & _
             "Usage:" & vbTab & SCRIPTFILE & vbCrLf & vbCrLf & _
             vbTab & "/?                          ' Displays this help"& vbCrLf & _
             vbTab & "/Log [LogfolderPath]        ' Custom folder for log files" & vbCrLf & _
             vbTab & "/SkipSD                     ' Skips the ShortcutDetection in local profiles" & vbCrLf & _
             vbTab & "/NoCancel                   ' Setup.exe and Msiexec.exe have no Cancel button" & vbCrLf &_
             vbTab & "/Quiet                      ' Script, Setup.exe and Msiexec.exe run quiet with no UI" & vbCrLf &_
             vbTab & "/ReturnErorOrSuccess        ' Returns 0 for a successful removal. Non-Zero if not." & vbCrLf
    Wscript.Quit
End Sub 'ShowSyntax

'-------------------------------------------------------------------------------
'   FindInstalledOProducts
'
'   Office configuration products are listed with their configuration product
'   name in the "Uninstall" key.
'-------------------------------------------------------------------------------
Sub FindInstalledOProducts
    Dim ArpItem, prod, cult
    Dim sCurKey, sValue, sConfigName, sCulture, sDisplayVersion, sVersionFallback
    Dim sUninstallString, sProd
    Dim iLeft, iRight
    Dim arrKeys, arrProducts, arrCultures
    Dim fSystemComponent0, fDisplayVersion, fUninstallString

	Const REG_ARP                 = "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\"
	Const REG_O15RPROPERTYBAG     = "SOFTWARE\Microsoft\Office\15.0\ClickToRun\propertyBag\"
	Const REG_O15C2RCONFIGURATION = "SOFTWARE\Microsoft\Office\15.0\ClickToRun\Configuration\"
	Const REG_O15C2RPRODUCTIDS    = "SOFTWARE\Microsoft\Office\15.0\ClickToRun\ProductReleaseIDs\Active\"
	Const REG_O16C2RCONFIGURATION = "SOFTWARE\Microsoft\Office\16.0\ClickToRun\Configuration\"
	Const REG_O16C2RPRODUCTIDS    = "SOFTWARE\Microsoft\Office\16.0\ClickToRun\ProductReleaseIDs\Active\"
	Const REG_C2RCONFIGURATION    = "SOFTWARE\Microsoft\Office\ClickToRun\Configuration\"
	Const REG_C2RPRODUCTIDS       = "SOFTWARE\Microsoft\Office\ClickToRun\ProductReleaseIDs\"


    If dicInstalledSku.Count > 0 Then Exit Sub 'Already done from command line parser
    
    fDisplayVersion = False

    ' identify C2R products
    LogH1 "Detect installed products "
    
	LogOnly "Check for O15 C2R products"
	' Check O15 Configuration key
    If RegReadValue(HKLM, REG_O15C2RCONFIGURATION, "ProductReleaseIds", sValue, "REG_SZ") Then
        arrProducts = Split(sValue, ",")
        fDisplayVersion = RegReadValue(HKLM, REG_O15C2RPRODUCTIDS & "culture", "x-none", sVersionFallback, "REG_SZ")
        If NOT Err = 0 Then
            Err.Clear
        Else
            ' get version from active with fallback on configuration
            For Each prod in arrProducts
                LogOnly "Found O15 C2R product in Configuration: " & prod
                ' update product dictionary
                If NOT dicInstalledSku.Exists(LCase(prod)) Then
                	LogOnly "add new product to dictionary: " & LCase(prod)
                	dicInstalledSku.Add LCase(prod), sVersionFallback
                End If
            Next 'prod
        End If
    End If
    
    ' Check O15 PropertyBag key
    If RegReadValue(HKLM, REG_O15RPROPERTYBAG, "productreleaseid", sValue, "REG_SZ") Then
        arrProducts = Split(sValue, ",")
        fDisplayVersion = RegReadValue(HKLM, REG_O15C2RPRODUCTIDS & "culture", "x-none", sVersionFallback, "REG_SZ")
        If NOT Err = 0 Then
            Err.Clear
        Else
            For Each prod in arrProducts
                LogOnly "Found O15 C2R product in PropertyBag: " & prod
                ' update product dictionary
                If NOT dicInstalledSku.Exists(LCase(prod)) Then
                	LogOnly "add new product to dictionary: " & LCase(prod)
                	dicInstalledSku.Add LCase(prod), sVersionFallback
                End If
            Next 'prod
        End If
    End If
    
	'O16 section
	LogOnly "Check for Office C2R products (>=QR8)"
	' Check Office Configuration key
    If RegReadValue(HKLM, REG_C2RPRODUCTIDS, "ActiveConfiguration", sActiveConfiguration, "REG_SZ") Then
    	' Get DisplayVersion
    	'Try QR8 logic first
		fDisplayVersion = RegReadValue(HKLM, REG_C2RPRODUCTIDS & sActiveConfiguration & "\culture", "x-none", sVersionFallback, "REG_SZ")
    	If RegEnumKey(HKLM, REG_C2RPRODUCTIDS & sActiveConfiguration & "\culture", arrCultures) Then
    		For Each cult In arrCultures
    			If InStr(LCase(cult), "x-none") > 0 Then
    				fDisplayVersion = RegReadValue(HKLM, REG_C2RPRODUCTIDS & sActiveConfiguration & "\culture\" & cult, "Version", sVersionFallback, "REG_SZ")
    			End If
    		Next 'cult
    	End If 
    	' Update product dic
    	If RegEnumKey(HKLM, REG_C2RPRODUCTIDS & sActiveConfiguration, arrProducts) Then
    		For Each prod In arrProducts
    			sProd = LCase(prod)
    			If InStr(sProd, ".") > 0 Then sProd = Left(sProd, InStr(sProd, ".") - 1)
    			Select Case LCase(sProd)
    			Case "culture", "stream"
    			Case Else
	                LogOnly "Found Office C2R product in Configuration: " & prod
	                ' update product dictionary
	                If NOT dicInstalledSku.Exists(sProd) Then
		                LogOnly "add new product to dictionary: " & sProd
		                If RegReadValue(HKLM, REG_C2RPRODUCTIDS & sActiveConfiguration & "\" & prod & "\x-none", "Version", sDisplayVersion, "REG_SZ") Then
		                	dicInstalledSku.Add sProd, sDisplayVersion
		                Else
	                		dicInstalledSku.Add sProd, sVersionFallback
	                	End If
	                End If
    			End Select
    		Next 'prod
    	End If 'arrProducts
    End If 'ActiveConfiguration

	LogOnly "Check for Office C2R products (QR7)"
	' Check Office Configuration key
	If RegReadValue(HKLM, REG_C2RCONFIGURATION, "ProductReleaseIds", sValue, "REG_SZ") Then
	    arrProducts = Split(sValue, ",")
	    If Not fDisplayVersion Then fDisplayVersion = RegReadValue(HKLM, REG_C2RPRODUCTIDS & "Active\culture", "x-none", sVersionFallback, "REG_SZ")
	    If NOT Err = 0 Then
	        Err.Clear
	    Else
	        For Each prod in arrProducts
	            LogOnly "Found Office C2R product in Configuration: " & prod
	            ' update version tracking
	            If NOT dicInstalledSku.Exists(LCase(prod)) Then
	            	LogOnly "add new product to dictionary: " & LCase(prod)
	            	dicInstalledSku.Add LCase(prod), sVersionFallback
	            End If
	        Next 'prod
	    End If
	End If

	LogOnly "Check for O16 C2R products (QR6)"
	' Check O16 Configuration key
    If RegReadValue(HKLM, REG_O16C2RCONFIGURATION, "ProductReleaseIds", sValue, "REG_SZ") Then
        arrProducts = Split(sValue, ",")
        If Not fDisplayVersion Then fDisplayVersion = RegReadValue(HKLM, REG_O16C2RPRODUCTIDS & "culture", "x-none", sVersionFallback, "REG_SZ")
        If NOT Err = 0 Then
            Err.Clear
        Else
            For Each prod in arrProducts
                LogOnly "Found O16 (QR6) C2R product in Configuration: " & prod
                ' update product dictionary
                If NOT dicInstalledSku.Exists(LCase(prod)) Then
                	LogOnly "add new product to dictionary: " & prod
                	dicInstalledSku.Add LCase(prod), sVersionFallback
                End If
            Next 'prod
        End If
    End If

    LogOnly "Check ARP for Office C2R products"
    ' ARP
    RegEnumKey HKLM, REG_ARP, arrKeys
    If IsArray(arrKeys) Then
        For Each ArpItem in arrKeys
            ' filter on Office C2R products
            sCurKey = REG_ARP & ArpItem & "\"
            fUninstallString = RegReadValue(HKLM, sCurKey, "UninstallString", sValue, "REG_SZ")
            If (fUninstallString And( (InStr(UCase(sValue), UCase("Microsoft Office 1")) > 0) Or (InStr(UCase(sValue), UCase("OfficeClickToRun.exe")) > 0) )) Then
                'get Version
                fDisplayVersion = RegReadValue(HKLM, sCurKey, "DisplayVersion", sDisplayVersion, "REG_SZ")
                'extract the productreleaseid
                sValue = Trim(sValue)
                prod = Trim(Mid(sValue, InStrRev(sValue, " ")))
                prod = Replace(prod, "productstoremove=", "")
                If InStr(prod, "_") > 0 Then
                    prod = Left(prod, InStr(prod, "_") - 1)
                End If
                If InStr(prod, ".1") > 0 Then
                    prod = Left(prod, InStr(prod, ".1") - 1)
                End If
                LogOnly "Found C2R product in ARP: " & prod
                If NOT dicInstalledSku.Exists(LCase(prod)) Then
                	LogOnly "add new product to dictionary: " & prod
                	dicInstalledSku.Add LCase(prod), sDisplayVersion
                End If
                ' categorize the SKU as C2R
                If NOT dicC2RSuite.Exists(ArpItem) Then dicC2RSuite.Add ArpItem, prod & " - " & sDisplayVersion 
            Else
            
	            'Legacy logic keep for compat reasons
	            sValue = ""
	            sDisplayVersion = ""
	            fSystemComponent0 = NOT (RegReadValue(HKLM, sCurKey, "SystemComponent", sValue, "REG_DWORD") AND (sValue = "1"))
	            fDisplayVersion = RegReadValue(HKLM, sCurKey, "DisplayVersion", sValue, "REG_SZ")
	            If fDisplayVersion Then
	                sDisplayVersion = sValue
	                If Len(sValue) > 1 Then
	                	On Error Resume Next
	                    fDisplayVersion = (CInt(Left(sValue, 2)) > 14)
	                    If Not Err <> 0 Then Err.Clear
	                Else
	                    fDisplayVersion = False
	                End If
	            End If
	            fUninstallString = RegReadValue(HKLM, sCurKey, "UninstallString", sUninstallString, "REG_SZ")
	            
	            ' filter on C2R configuration SKU
	            If (fUninstallString And( (InStr(UCase(sUninstallString), UCase("Microsoft Office 1")) > 0) Or (InStr(UCase(sUninstallString), UCase("OfficeClickToRun.exe")) > 0) )) Then
	                ' Extract the ProductReleaseID
	                If InStr(sUninstallString, "productstoremove=") > 0 Then
		                sConfigName = Trim(Mid(sValue, InStrRev(sUninstallString, " ")))
		                sConfigName = Replace(sConfigName, "productstoremove=", "")
		                If InStr(prod, "_") > 0 Then
		                    sConfigName = Left(sConfigName, InStr(sConfigName, "_") - 1)
		                End If
	                Else
		                iLeft = InStr(ArpItem, " - ") + 2
		                iRight = InStr(iLeft, ArpItem, " - ") - 1
		                If iRight > 0 Then
		                    sConfigName = Trim(Mid(ArpItem, iLeft, (iRight - iLeft)))
		                    sCulture = Mid(ArpItem, iRight + 3)
		                Else
		                    sConfigName = Trim(Left(ArpItem, iLeft - 3))
		                    sCulture = Mid(ArpItem, iLeft)
		                End If
		                sConfigName = Replace(sConfigName, "Microsoft", "")
		                sConfigName = Replace(sConfigName, "Office", "")
		                sConfigName = Replace(sConfigName, "Professional", "Pro")
		                sConfigName = Replace(sConfigName, "Standard", "Std")
		                sConfigName = Replace(sConfigName, "(Technical Preview)", "")
		                sConfigName = Replace(sConfigName, "15", "")
		                sConfigName = Replace(sConfigName, "16", "")
		                sConfigName = Replace(sConfigName, "2013", "")
		                sConfigName = Replace(sConfigName, "2016", "")
		                sConfigName = Replace(sConfigName, " ", "")
		                sConfigName = Replace(sConfigName, "Project", "Prj")
		                sConfigName = Replace(sConfigName, "Visio", "Vis")
	                End If
	                If NOT dicInstalledSku.Exists(LCase(sConfigName)) Then
	                	LogOnly "add new product to dictionary (ARP Legacy): " & sConfigName
	                	dicInstalledSku.Add LCase(sConfigName), sDisplayVersion
	                End If
	                ' categorize the SKU as C2R
	                If NOT dicC2RSuite.Exists(ArpItem) Then dicC2RSuite.Add ArpItem, sConfigName & " - " & sDisplayVersion 
	            ElseIf (fDisplayVersion AND (InStr(UCase(ArpItem), UCase("OFFICE15.")) > 0 Or InStr(UCase(ArpItem), UCase("OFFICE16.")) > 0)) Then
	                ' classic .msi install SKU
	                iLeft = InStr(ArpItem, ".") + 1
	                iRight = InStr(iLeft, ArpItem, "-") - 1
	                sConfigName = Mid(ArpItem, iLeft)
	                sCulture = ""
	                If NOT dicKeepSku.Exists(ArpItem) Then dicKeepSku.Add ArpItem, sConfigName & " - " & sDisplayVersion
	            End If
	            
	            ' Other products
	            If InScope(ArpItem) Then
	                Select Case Mid(ArpItem,11,4)
	                ' 007E = Licensing
	                ' 008F = Licensing
	                ' 008C = Extensibility Components
	                ' 00DD = Extensibility Components 64 bit
	                Case "007E", "008F", "008C", "00DD"
	                    sConfigName = "Habanero"
	                    RegReadValue HKLM, sCurKey, "DisplayName", sConfigName, "REG_SZ"
	                    If NOT dicInstalledSku.Exists(LCase(ArpItem)) Then
	                    	LogOnly "add new product to dictionary (ARP Integraton Components): " & ArpItem
	                    	dicInstalledSku.Add LCase(ArpItem), sDisplayVersion
	                    End If
	                    If NOT dicC2RSuite.Exists(ArpItem) Then dicC2RSuite.Add ArpItem, sConfigName & " - " & sDisplayVersion
	                Case "24E1", "237A"
	                    sConfigName = "MSOIDLOGIN"
	                    If NOT dicInstalledSku.Exists(LCase(ArpItem)) Then
	                    	LogOnly "add new product to dictionary (ARP MSOIDLogin): " & ArpItem
	                    	dicInstalledSku.Add LCase(ArpItem), sDisplayVersion
	                    End If
	                    If NOT dicC2RSuite.Exists(ArpItem) Then dicC2RSuite.Add ArpItem, sConfigName & " - " & sDisplayVersion
	                Case Else
	                    If NOT dicInstalledSku.Exists(LCase(ArpItem)) Then
	                    	LogOnly "add new product to dictionary (ARP other): " & ArpItem
	                    	dicInstalledSku.Add LCase(ArpItem), sDisplayVersion
	                    End If
	                End Select
	            Else
                    ' not in scope for c2r removal!
	            End If 'InScope  
	            ' End legacy logic
	            
            End If
        Next 'ArpItem
    End If
    
End Sub 'FindInstalledOProducts

'-------------------------------------------------------------------------------
'   EnsureValidWIMetadata
'
'   Ensures that only valid metadata entries exist to avoid API failures.
'   Invalid entries will be removed
'-------------------------------------------------------------------------------
Sub EnsureValidWIMetadata(hDefKey, sKey, iValidLength)
    Dim arrKeys
    Dim SubKey

    If Len(sKey) > 1 Then
        If Right(sKey, 1) = "\" Then sKey = Left(sKey, Len(sKey) - 1)
    End If

    If RegEnumKey(hDefKey, sKey, arrKeys) Then
        For Each SubKey in arrKeys
            If NOT Len(SubKey) = iValidLength Then
                RegDeleteKey hDefKey, sKey & "\" & SubKey & "\"
            End If
        Next 'SubKey
    End If
End Sub 'EnsureValidWIMetadata

'-------------------------------------------------------------------------------
'   CleanOSPP
'
'   Clean out licenses from the Office Software Protection Platform 
'-------------------------------------------------------------------------------
Sub CleanOSPP
    Dim oProductInstances, pi
    Dim sCleanOSPP, sCmd, sRetVal

    CONST OfficeAppId = "0ff1ce15-a989-479d-af46-f275c6370663"  'Office 2013

    sCleanOSPP = "x64\CleanOSPP.exe"
    If Not f64 Then sCleanOSPP = "x86\CleanOSPP.exe"
    If oFso.FileExists(sScriptDir & sCleanOSPP) Then
        sCmd = sScriptDir & sCleanOSPP
        Log "   Running: " & sCmd
        On Error Resume Next
        sRetVal = oWShell.Run(sCmd, 0, True)
        Log "   Return value: " & sRetVal
        On Error Goto 0
        Exit Sub
    End If
    
    On Error Resume Next
    If NOT (dicC2RSuite.Count > 0 OR dicKeepSku.Count > 0) Then
        Log "Skip CleanOSPP"
        Exit Sub
    End If
    
    ' Initialize the software protection platform object with a filter on Office 2013 products
    If iVersionNT > 601 Then
        Set oProductInstances = oWmiLocal.ExecQuery("SELECT ID, ApplicationId, PartialProductKey, Name, ProductKeyID FROM SoftwareLicensingProduct WHERE ApplicationId = '" & OfficeAppId & "' " & "AND PartialProductKey <> NULL")
    Else
        Set oProductInstances = oWmiLocal.ExecQuery("SELECT ID, ApplicationId, PartialProductKey, Name, ProductKeyID FROM OfficeSoftwareProtectionProduct WHERE ApplicationId = '" & OfficeAppId & "' " & "AND PartialProductKey <> NULL")
    End If

    ' Remove all licenses
    For Each pi in oProductInstances
        If NOT IsNull(pi) Then
            pi.UninstallProductKey( pi.ProductKeyID)
        End If
    Next 'pi


End Sub 'CleanOSPP

'-------------------------------------------------------------------------------
'   DelSchtasks
'
'   Delete know scheduled tasks.
'-------------------------------------------------------------------------------
Sub DelSchtasks ()
    Dim sCmd

    If CBool(iError AND ERROR_USERCANCEL) Then Exit Sub

    LogH1 "Remove scheduled tasks" 

    LogOnly "FF_INTEGRATEDstreamSchedule"
    oWShell.Run "SCHTASKS /Delete /TN FF_INTEGRATEDstreamSchedule /F", 0, False
    wscript.sleep 500

    LogOnly "FF_INTEGRATEDUPDATEDETECTION"
    oWShell.Run "SCHTASKS /Delete /TN FF_INTEGRATEDUPDATEDETECTION /F", 0, False
    wscript.sleep 500

    LogOnly "C2RAppVLoggingStart"
    oWShell.Run "SCHTASKS /Delete /TN C2RAppVLoggingStart /F", 0, False
    wscript.sleep 500

    LogOnly "Office 15 Subscription Heartbeat"
    sCmd = "SCHTASKS /Delete /TN " & Chr(34) & "Office 15 Subscription Heartbeat" & Chr(34) & " /F"
    oWShell.Run sCmd, 0, False
    wscript.sleep 500

    LogOnly "Microsoft Office 15 Sync Maintenance"
    sCmd = "SCHTASKS /Delete /TN " & Chr(34) & "Microsoft Office 15 Sync Maintenance for {d068b555-9700-40b8-992c-f866287b06c1}" & Chr(34) & " /F"
    oWShell.Run sCmd, 0, False
    wscript.sleep 500

    LogOnly "OfficeInventoryAgentFallBack"
    sCmd = "SCHTASKS /Delete /TN " & Chr(34) & "\Microsoft\Office\OfficeInventoryAgentFallBack" & Chr(34) & " /F"
    oWShell.Run sCmd, 0, False
    wscript.sleep 500

    LogOnly "OfficeTelemetryAgentFallBack"
    sCmd = "SCHTASKS /Delete /TN " & Chr(34) & "\Microsoft\Office\OfficeTelemetryAgentFallBack" & Chr(34) & " /F"
    oWShell.Run sCmd, 0, False
    wscript.sleep 500

    LogOnly "OfficeInventoryAgentLogOn"
    sCmd = "SCHTASKS /Delete /TN " & Chr(34) & "\Microsoft\Office\OfficeInventoryAgentLogOn" & Chr(34) & " /F"
    oWShell.Run sCmd, 0, False

    LogOnly "OfficeTelemetryAgentLogOn"
    sCmd = "SCHTASKS /Delete /TN " & Chr(34) & "\Microsoft\Office\OfficeTelemetryAgentLogOn" & Chr(34) & " /F"
    oWShell.Run sCmd, 0, False

    LogOnly "Office Background Streaming"
    sCmd = "SCHTASKS /Delete /TN " & Chr(34) & "Office Background Streaming" & Chr(34) & " /F"
    oWShell.Run sCmd, 0, False
    wscript.sleep 500

    LogOnly "Office Automatic Updates"
    sCmd = "SCHTASKS /Delete /TN " & Chr(34) & "\Microsoft\Office\Office Automatic Updates" & Chr(34) & " /F"
    oWShell.Run sCmd, 0, False
    wscript.sleep 500

    LogOnly "Office ClickToRun Service Monitor"
    sCmd = "SCHTASKS /Delete /TN " & Chr(34) & "\Microsoft\Office\Office ClickToRun Service Monitor" & Chr(34) & " /F"
    oWShell.Run sCmd, 0, False
    wscript.sleep 500

    LogOnly "Office Subscription Maintenance"
    sCmd = "SCHTASKS /Delete /TN " & Chr(34) & "Office Subscription Maintenance" & Chr(34) & " /F"
    oWShell.Run sCmd, 0, False
    wscript.sleep 500

End Sub

'-------------------------------------------------------------------------------
'   CloseOfficeApps
'
'   End all running instances of applications that will be removed.
'-------------------------------------------------------------------------------
Sub CloseOfficeApps
    Dim Processes, Process, app, prop
    Dim sAppName, sOut, sUserWarn
    Dim fWait
    Dim iRet
    
    On Error Resume Next
    fWait = False
    iProcCloseCnt = iProcCloseCnt + 1
    If fRerun Then Exit Sub

    If NOT fUserConsent Then
        ' detect processes to allow a user warning
        sUserWarn =  "Please save all open documents and close all Office, IE and Windows Explorer applications before proceeding." & vbCrLf & _
                    "When you click OK this removal process will terminate all running Office, IE and Windows Explorer processes and applications." & vbCrLf & vbCrLf & _
                    "Click ‘Cancel’ to to end this removal now."
        For Each app in dicApps.Keys
            sAppName = Replace(app, ".", "%.")
            Set Processes = oWmiLocal.ExecQuery("Select * From Win32_Process Where Name like '" & sAppName & "'")
            For Each Process in Processes
                If NOT InStr(sUserWarn, Process.Name) > 0 Then sUserWarn = sUserWarn & vbCrLf & " - " & Process.Name
            Next 'Process
        Next 'app
        Set Processes = oWmiLocal.ExecQuery("Select * From Win32_Process")
        For Each Process in Processes
            For Each prop in Process.Properties_
                If prop.Name = "ExecutablePath" Then 
                    If IsC2R(prop.Value) Then sUserWarn = sUserWarn & vbCrLf & " - " & Process.Name
                End If 'ExcecutablePath
            Next 'prop
        Next 'Process
        If (InStr(sUserWarn, " - ") > 0 AND NOT fQuiet) Then
            iRet = MsgBox(sUserWarn, 49, "Save your unsaved work now!")
            If iRet = 2 Then 
                SetError ERROR_USERCANCEL
                ExitScript
            Else
                fUserConsent = True
            End If
        End If
    End If 'fUserConsent

    ' end known processes first
    For Each app in dicApps.Keys
        sAppName = Replace(app, ".", "%.")
        Set Processes = oWmiLocal.ExecQuery("Select * From Win32_Process Where Name like '" & sAppName & "'")
        For Each Process in Processes
            sOut = "End process '" & Process.Name
            iRet = Process.Terminate()
            CheckError "CloseOfficeApps: " & Process.Name
            Log sOut & "' returned: " & iRet
            fWait = True
        Next 'Process
    Next 'app

    ' end running applications
    Set Processes = oWmiLocal.ExecQuery("Select * From Win32_Process")
    For Each Process in Processes
        For Each prop in Process.Properties_
            If prop.Name = "ExecutablePath" Then 
                If IsC2R(prop.Value) Then
                    sOut = "End process '" & Process.Name
                    iRet = Process.Terminate()
                    CheckError "CloseOfficeApps: " & Process.Name
                    Log sOut & "' returned: " & iRet
                    fWait = True
                End If 
            End If 'ExcecutablePath
        Next 'prop
    Next 'Process
    If fWait Then wscript.sleep 5000
End Sub 'CloseOfficeApps

'-------------------------------------------------------------------------------
'   Uninstall
'
'   Identify and invoke default uninstall command for a regular uninstall.
'-------------------------------------------------------------------------------
Sub Uninstall
    Dim OseService, srvc
    Dim hDefKey, sSubKeyName, sValue, Name, arrNames, arrTypes
    Dim sku, prod, sUninstallCmd, sReturn, sMsiProp, sCmd
    Dim sPkgFld, sPkgGuid
    Dim i

    If CBool(iError AND ERROR_USERCANCEL) Then Exit Sub

    ' check if OSE service is *installed, *not disabled, *running under System context.
    LogH2 "Check state of OSE service"
    Set OseService = oWmiLocal.Execquery("Select * From Win32_Service Where Name like 'ose%'")
    For Each srvc in OseService
        If (srvc.StartMode = "Disabled") AND (Not srvc.ChangeStartMode("Manual") = 0) Then _
            Log "Conflict detected: OSE service is disabled"
        If (Not srvc.StartName = "LocalSystem") AND (srvc.Change( , , , , , , "LocalSystem", "")) Then _
            Log "Conflict detected: OSE service not running as LocalSystem"
    Next 'srvc

    If NOT dicC2RSuite.Count > 0 Then
        Log "No uninstallable C2R items registered in Uninstall"
    End If

    ' remove the published component registration for C2R packages
    LogH2 "Remove published component registration for C2R packages"
    ' delete the manifest files
    For i = 1 To 4
    	Select Case i
    	Case 1
	    	RegReadValue HKLM, "SOFTWARE\Microsoft\Office\15.0\ClickToRun", "PackageFolder", sPkgFld, "REG_SZ" 
	    	RegReadValue HKLM, "SOFTWARE\Microsoft\Office\15.0\ClickToRun", "PackageGUID", sPkgGuid, "REG_SZ"
	    Case 2
	    	RegReadValue HKLM, "SOFTWARE\Microsoft\Office\16.0\ClickToRun", "PackageFolder", sPkgFld, "REG_SZ" 
	    	RegReadValue HKLM, "SOFTWARE\Microsoft\Office\16.0\ClickToRun", "PackageGUID", sPkgGuid, "REG_SZ"
	    Case 3
	    	RegReadValue HKLM, "SOFTWARE\Microsoft\Office\ClickToRun", "PackageFolder", sPkgFld, "REG_SZ" 
	    	RegReadValue HKLM, "SOFTWARE\Microsoft\Office\ClickToRun", "PackageGUID", sPkgGuid, "REG_SZ"
	    Case 4
	    	sPkgFld = sPackageFolder
	    	sPkgGuid = sPackageGuid
	    End Select
	    If oFso.FolderExists(sValue & "\root\Integration") Then
	        sCmd = "cmd.exe /c del " & chr(34) & sPkgFld & "\root\Integration\C2RManifest*.xml" & chr(34)
	        Log "   Run: " & sCmd
	        sReturn = oWShell.Run (sCmd, 0, True)
	        Log "   Return value: " & sReturn
	        If oFso.FileExists(sPkgFld & "\root\Integration\integrator.exe") Then
	            sCmd = chr(34) & sPkgFld & "\root\Integration\integrator.exe" & chr(34) & " /U  /Extension PackageRoot=" & chr(34) & sPkgFld & "\root" & chr(34) & " PackageGUID=" & sPkgGuid
	            Log "   Run: " & sCmd
	            sReturn = oWShell.Run (sCmd, 0, True)
	            Log "   Return value: " & sReturn
	            sCmd = chr(34) & sPkgFld & "\root\Integration\integrator.exe" & chr(34) & " /U"
	            Log "   Run: " & sCmd
	            sReturn = oWShell.Run (sCmd, 0, True)
	            Log "   Return value: " & sReturn
	        End If
	        If oFso.FileExists(sProgramData & "\Microsoft\ClickToRun\{" & sPkgGuid & "}\integrator.exe") Then
	            sCmd = chr(34) & sProgramData & "\Microsoft\ClickToRun\{" & sPkgGuid & "}\integrator.exe" & chr(34) & " /U  /Extension PackageRoot=" & chr(34) & sPkgFld & "\root" & chr(34) & " PackageGUID=" & sPkgGuid
	            Log "   Run: " & sCmd
	            sReturn = oWShell.Run (sCmd, 0, True)
	            Log "   Return value: " & sReturn
	        End If
	    End If
    Next 'i

    ' delete potential blocking registry keys for msiexec based tasks
    LogH2 "Remove C2R and App-V registry data"
    For Each sku in dicC2RSuite.Keys
        ' remove the ARP entry
        RegDeleteKey HKLM, REG_ARP & sku
    Next 'sku
    RegDeleteKey HKCU, "SOFTWARE\Microsoft\Office\15.0\ClickToRun"
    RegDeleteKey HKLM, "SOFTWARE\Microsoft\Office\15.0\ClickToRun"
    RegDeleteKey HKCU, "SOFTWARE\Microsoft\Office\16.0\ClickToRun"
    RegDeleteKey HKLM, "SOFTWARE\Microsoft\Office\16.0\ClickToRun"
    RegDeleteKey HKCU, "SOFTWARE\Microsoft\Office\ClickToRun"
    RegDeleteKey HKLM, "SOFTWARE\Microsoft\Office\ClickToRun"
    
    ' AppV keys
    hDefKey = HKCU
    sSubKeyName = "SOFTWARE\Microsoft\AppV\ISV"
    Do
        If RegEnumValues(hDefKey, sSubKeyName, arrNames, arrTypes) Then
            For Each Name in arrNames
                If IsC2R(Name) Then RegDeleteValue hDefKey, sSubKeyName, Name, False
            Next 'Name
        End If 'RegEnumValues
        If hDefKey = HKLM Then Exit Do
        hDefKey = HKLM
    Loop

    ' msiexec based uninstall
    sMsiProp = " REBOOT=ReallySuppress NOREMOVESPAWN=True"
    LogH2 "Detect Msi based products"
    For Each prod in oMsi.Products
        If CheckDelete(prod) Then
            Log "Call msiexec.exe to remove " & prod 
            sUninstallCmd = "msiexec.exe /x" & prod & sMsiProp
            If fQuiet Then 
                sUninstallCmd = sUninstallCmd & " /q"
            Else
                sUninstallCmd = sUninstallCmd & " /qb-!"
            End If
            sUninstallCmd = sUninstallCmd & " /l*v " & chr(34) & sLogDir & "\Uninstall_" & prod & ".log" & chr(34)
            CloseOfficeApps
            LogOnly "Call msiexec with '" & sUninstallCmd & "'"
            sReturn = oWShell.Run(sUninstallCmd, 0, True)
            Log "msiexec returned: " & SetupRetVal(sReturn) & " (" & sReturn & ")" & vbCrLf
            fRebootRequired = fRebootRequired OR (sReturn = "3010")
            If fRebootRequired Then SetError ERROR_REBOOT_REQUIRED
            Select Case CInt(sReturn)
            Case ERROR_SUCCESS,ERROR_SUCCESS_CONFIG_COMPLETE,ERROR_SUCCESS_REBOOT_REQUIRED
                'success no action required
            Case Else
                SetError ERROR_STAGE1
            End Select
        Else
        	LogOnly "Skip out of scope product: " & prod
        End If 'CheckDelete
    Next 'Product
    oWShell.Run "cmd.exe /c net stop msiserver", 0, False
End Sub 'Uninstall

'-------------------------------------------------------------------------------
'   RegWipe
'
'   Removal of left behind registry data 
'-------------------------------------------------------------------------------
Sub Regwipe
    Dim hDefKey, item, name, value, RetVal
    Dim sGuid, sSubKeyName, sValue, sCmd
    Dim i, iLoopCnt
    Dim arrKeys, arrNames, arrTypes, arrTestNames, arrTestTypes
    Dim arrMultiSzValues, arrMultiSzNewValues
    Dim fDelReg

    If CBool(iError AND ERROR_USERCANCEL) Then Exit Sub

    LogH1 "Registry CleanUp"
    
    'Moved to earlier timing to avoid reboot needs
    'If NOT dicKeepSku.Count > 0 Then ClearShellIntegrationReg
    
    CloseOfficeApps

    ' Note: ARP entries have already been cleared in uninstall stage

    ' HKCU Registration
    RegDeleteKey HKCU, "Software\Microsoft\Office\15.0\Registration"
    RegDeleteKey HKCU, "Software\Microsoft\Office\16.0\Registration"
    RegDeleteKey HKCU, "Software\Microsoft\Office\Registration"

    
    ' C2R specifics
    ' AppV key "SOFTWARE\Microsoft\AppV" has already been cleared in uninstall stage

    ' Virtual InstallRoot
    RegDeleteKey HKLM, "SOFTWARE\Microsoft\Office\15.0\Common\InstallRoot\Virtual"
    RegDeleteKey HKLM, "SOFTWARE\Microsoft\Office\16.0\Common\InstallRoot\Virtual"
    RegDeleteKey HKLM, "SOFTWARE\Microsoft\Office\Common\InstallRoot\Virtual"

    ' Mapi Search reg
    'O15
    If NOT dicKeepSku.Count > 0 Then RegDeleteKey HKLM, "SOFTWARE\Classes\CLSID\{2027FC3B-CF9D-4ec7-A823-38BA308625CC}"
    'O16
    '{F8E61EDD-EA25-484e-AC8A-7447F2AAE2A9}

    
    ' C2R keys
    RegDeleteKey HKCU, "SOFTWARE\Microsoft\Office\15.0\ClickToRun"
    RegDeleteKey HKLM, "SOFTWARE\Microsoft\Office\15.0\ClickToRun"
    RegDeleteKey HKLM, "SOFTWARE\Microsoft\Office\15.0\ClickToRunStore"
    RegDeleteKey HKCU, "SOFTWARE\Microsoft\Office\16.0\ClickToRun"
    RegDeleteKey HKLM, "SOFTWARE\Microsoft\Office\16.0\ClickToRun"
    RegDeleteKey HKLM, "SOFTWARE\Microsoft\Office\16.0\ClickToRunStore"
    RegDeleteKey HKCU, "SOFTWARE\Microsoft\Office\ClickToRun"
    RegDeleteKey HKLM, "SOFTWARE\Microsoft\Office\ClickToRun"
    RegDeleteKey HKLM, "SOFTWARE\Microsoft\Office\ClickToRunStore"
    
    ' Office key in HKLM
    If Not dicKeepSku.Count > 0 Then
    	'double calls to ensure Wow6432 gets cleared out as well
    	RegDeleteKey HKLM, "Software\Microsoft\Office\15.0"
    	RegDeleteKey HKLM, "Software\Microsoft\Office\15.0"
    	RegDeleteKey HKLM, "Software\Microsoft\Office\16.0"
    	RegDeleteKey HKLM, "Software\Microsoft\Office\16.0"
    End If
    ClearOfficeHKLM "SOFTWARE\Microsoft\Office"

    ' Run key
    sSubKeyName = "SOFTWARE\Microsoft\Windows\CurrentVersion\Run"
    If RegEnumValues (HKLM, sSubKeyName, arrNames, arrTypes) Then
        For Each name in arrNames
            If RegReadValue(HKLM, sSubKeyName, name, sValue, "REG_SZ") Then
                If IsC2R(sValue) Then RegDeleteValue HKLM, sSubKeyName, name, False
            End If
        Next 'item
    End If
    RegDeleteValue HKLM, "SOFTWARE\Microsoft\Windows\CurrentVersion\Run", "Lync15", False
    RegDeleteValue HKLM, "SOFTWARE\Microsoft\Windows\CurrentVersion\Run", "Lync16", False
    
    ' ARP
    ' Note: configuration entries have already been removed 
    ' as part of the 'Uninstall' stage
    If RegEnumKey(HKLM, REG_ARP, arrKeys) Then
        For Each item in arrKeys
            If Len(item) > 37 Then
                sGuid = UCase(Left(item, 38))
                If CheckDelete(sGuid) Then RegDeleteKey HKLM, REG_ARP & item & "\"
            End If 'Len(Item)>37
        Next 'Item
    End If

    ' UpgradeCodes, WI config, WI global config
    LogH2 "Scan Windows Installer metadata for removeable UpgradeCodes"
    For iLoopCnt = 1 to 5
        Select Case iLoopCnt
        Case 1
            sSubKeyName = "SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UpgradeCodes\"
            hDefKey = HKLM
        Case 2 
            sSubKeyName = "Installer\UpgradeCodes\"
            hDefKey = HKCR
        Case 3
            sSubKeyName = "SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Products\"
            hDefKey = HKLM
        Case 4 
            sSubKeyName = "Installer\Features\"
            hDefKey = HKCR
        Case 5 
            sSubKeyName = "Installer\Products\"
            hDefKey = HKCR
        End Select
        If RegEnumKey(hDefKey, sSubKeyName, arrKeys) Then
            For Each item in arrKeys
                ' ensure the expected length for a compressed GUID
                If Len(item) = 32 Then
                    ' expand the GUID
                    sGuid = GetExpandedGuid(item) 
                    ' check if it's an Office key
                    If CheckDelete(sGuid) Then
                        If iLoopCnt < 3 Then
                            ' enum all entries
                            RegEnumValues hDefKey, sSubKeyName & item, arrNames, arrTypes
                            If IsArray(arrNames) Then
                                ' delete entries within removal scope
                                For Each name in arrNames
                                    If Len(name) = 32 Then
                                        sGuid = GetExpandedGuid(name)
                                        If CheckDelete(sGuid) Then RegDeleteValue hDefKey, sSubKeyName & item & "\", name, True
                                    Else
                                        ' invalid data -> delete the value
                                        RegDeleteValue hDefKey, sSubKeyName & item & "\", name, True
                                    End If
                                Next 'Name
                            End If 'IsArray(arrNames)
                            ' if all entries were removed - delete the key
                            If NOT RegEnumValues(hDefKey, sSubKeyName & item, arrNames, arrTypes) Then RegDeleteKey hDefKey, sSubKeyName & item & "\"
                        Else 'iLoopCnt >= 3
                            RegDeleteKey hDefKey, sSubKeyName & item & "\"
                        End If 'iLoopCnt < 3
                    End If 'InScope
                End If 'Len(Item)=32
            Next 'Item
        End If 'RegEnumKey
    Next 'iLoopCnt

    ' Components in Global
    LogH2 "Scan Windows Installer Global Components metadata"
    sSubKeyName = "SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Components\"
    hDefKey = HKLM
    If RegEnumKey(hDefKey, sSubKeyName, arrKeys) Then
        For Each item in arrKeys
            ' ensure the expected length for a compressed GUID
            If Len(Item) = 32 Then
                If RegEnumValues(hDefKey, sSubKeyName & item, arrNames, arrTypes) Then
                    For Each name in arrNames
                        If Len(Name) = 32 Then
                            sGuid = GetExpandedGuid(Name)
                            If CheckDelete(sGuid) Then
                                RegDeleteValue hDefKey, sSubKeyName & item & "\", name, False
                                ' if all entries were removed - delete the key
                                If NOT RegEnumValues(hDefKey, sSubKeyName & item, arrTestNames, arrTestTypes) Then RegDeleteKey hDefKey, sSubKeyName & item & "\"
                            End If
                        End If '32
                    Next 'Name
                End If 'RegEnumValues
            End If '32
        Next 'Item
    End If 'RegEnumKey

    ' Published Components
    LogH2 "Scanning Windows Installer Published Components metadata"
    sSubKeyName = "Installer\Components\"
    hDefKey = HKCR
    If RegEnumKey(hDefKey, sSubKeyName, arrKeys) Then
        For Each item in arrKeys
            ' ensure the expected length for a compressed GUID
            If Len(Item) = 32 Then
                If RegEnumValues(hDefKey, sSubKeyName & item, arrNames, arrTypes) Then
                    For Each name in arrNames
                        If RegReadValue (hDefKey, sSubKeyName & item, name, sValue, "REG_MULTI_SZ") Then
                            arrMultiSzValues = Split(sValue, chr(13))
                            If IsArray(arrMultiSzValues) Then
                                i = -1
                                ReDim arrMultiSzNewValues(-1)
                                fDelReg = False
                                For Each value in arrMultiSzValues
                                    If Len(value) > 19 Then
                                        sGuid = ""
                                        If GetDecodedGuid(Left(value, SQUISHED), sGuid) Then
                                            If CheckDelete(sGuid) Then
                                                fDelReg = True
                                            Else
                                                i = i + 1 
                                                ReDim Preserve arrMultiSzNewValues(i)
                                                arrMultiSzNewValues(i) = value
                                            End If 'CheckDelete
                                        End If 'decode
                                    End If '19
                                Next 'Value
                                If NOT (i = -1) Then
                                    If NOT UBound(arrMultiSzValues) = i Then oReg.SetMultiStringValue hDefKey, sSubKeyName & item, name,arrMultiSzNewValues
                                Else
                                    If fDelReg Then
                                        RegDeleteValue hDefKey, sSubKeyName & item & "\", name, True
                                        ' if all entries were removed - delete the key
                                        If NOT RegEnumValues(hDefKey, sSubKeyName & item, arrTestNames, arrTestTypes) Then RegDeleteKey hDefKey, sSubKeyName & item & "\"
                                    End If 'DelReg
                                End If
                            End If 'IsArray
                        End If
                    Next 'Name
                End If 'RegEnumValues
            End If '32
        Next 'Item
    End If 'RegEnumKey

End Sub 'Regwipe

'-------------------------------------------------------------------------------
'   ClearShellIntegrationReg
'
'   Delete registry items that may cause Explorer / Windows Shell to have a lock
'   on files 
'-------------------------------------------------------------------------------
Sub ClearShellIntegrationReg
    Dim Processes, Process
    Dim sOut
    Dim iRet
    
    Set Processes = oWmiLocal.ExecQuery("Select * From Win32_Process Where Name like 'explorer.exe'")
    For Each Process in Processes
        sOut = "End process '" & Process.Name
        iRet = Process.Terminate()
        CheckError "CloseOfficeApps: " & Process.Name
        Log sOut & "' returned: " & iRet
    Next 'Process
    wscript.sleep 500

    
    ' Protocol Handlers
    RegDeleteKey HKLM, "SOFTWARE\Classes\Protocols\Handler\osf"

    ' Groove ShellIconOverlayIdentifiers
    RegDeleteKey HKLM, "SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers\Microsoft SPFS Icon Overlay 1 (ErrorConflict)"
    RegDeleteKey HKLM, "SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers\Microsoft SPFS Icon Overlay 2 (SyncInProgress)"
    RegDeleteKey HKLM, "SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers\Microsoft SPFS Icon Overlay 3 (InSync)"
    RegDeleteKey HKLM, "SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers\Microsoft SPFS Icon Overlay 1 (ErrorConflict)"
    RegDeleteKey HKLM, "SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers\Microsoft SPFS Icon Overlay 2 (SyncInProgress)"
    RegDeleteKey HKLM, "SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers\Microsoft SPFS Icon Overlay 3 (InSync)"

    ' Shell extensions
    RegDeleteValue HKLM, "SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved\", "{B28AA736-876B-46DA-B3A8-84C5E30BA492}", False
    RegDeleteValue HKLM, "SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved\", "{8B02D659-EBBB-43D7-9BBA-52CF22C5B025}", False
    RegDeleteValue HKLM, "SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved\", "{0875DCB6-C686-4243-9432-ADCCF0B9F2D7}", False
    RegDeleteValue HKLM, "SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved\", "{42042206-2D85-11D3-8CFF-005004838597}", False
    RegDeleteValue HKLM, "SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved\", "{993BE281-6695-4BA5-8A2A-7AACBFAAB69E}", False
    RegDeleteValue HKLM, "SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved\", "{C41662BB-1FA0-4CE0-8DC5-9B7F8279FF97}", False
    RegDeleteValue HKLM, "SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved\", "{506F4668-F13E-4AA1-BB04-B43203AB3CC0}", False
    RegDeleteValue HKLM, "SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved\", "{D66DC78C-4F61-447F-942B-3FB6980118CF}", False
    RegDeleteValue HKLM, "SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved\", "{46137B78-0EC3-426D-8B89-FF7C3A458B5E}", False
    RegDeleteValue HKLM, "SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved\", "{8BA85C75-763B-4103-94EB-9470F12FE0F7}", False
    RegDeleteValue HKLM, "SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved\", "{CD55129A-B1A1-438E-A425-CEBC7DC684EE}", False
    RegDeleteValue HKLM, "SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved\", "{D0498E0A-45B7-42AE-A9AA-ABA463DBD3BF}", False
    RegDeleteValue HKLM, "SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved\", "{E768CD3B-BDDC-436D-9C13-E1B39CA257B1}", False

    ' BHO
    RegDeleteKey HKLM, "SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Browser Helper Objects\{31D09BA0-12F5-4CCE-BE8A-2923E76605DA}"
    RegDeleteKey HKLM, "SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Browser Helper Objects\{B4F3A835-0E21-4959-BA22-42B3008E02FF}"
    RegDeleteKey HKLM, "SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Browser Helper Objects\{D0498E0A-45B7-42AE-A9AA-ABA463DBD3BF}"
    RegDeleteKey HKLM, "SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Explorer\Browser Helper Objects\{31D09BA0-12F5-4CCE-BE8A-2923E76605DA}"
    RegDeleteKey HKLM, "SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Explorer\Browser Helper Objects\{B4F3A835-0E21-4959-BA22-42B3008E02FF}"
    RegDeleteKey HKLM, "SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Explorer\Browser Helper Objects\{D0498E0A-45B7-42AE-A9AA-ABA463DBD3BF}"

    ' OneNote Namespace Extension for Desktop
    RegDeleteKey HKLM, "SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Desktop\NameSpace\{0875DCB6-C686-4243-9432-ADCCF0B9F2D7}"

    ' Web Sites
    RegDeleteKey HKLM, "SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Desktop\Namespace\{B28AA736-876B-46DA-B3A8-84C5E30BA492}"
    RegDeleteKey HKLM, "SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\NetworkNeighborhood\Namespace\{46137B78-0EC3-426D-8B89-FF7C3A458B5E}"

    ' VolumeCaches
    RegDeleteKey HKLM, "SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Microsoft Office Temp Files"

    Set Processes = oWmiLocal.ExecQuery("Select * From Win32_Process Where Name like 'explorer.exe'")
    For Each Process in Processes
        sOut = "End process '" & Process.Name
        iRet = Process.Terminate()
        CheckError "CloseOfficeApps: " & Process.Name
        Log sOut & "' returned: " & iRet
    Next 'Process
    wscript.sleep 500
    RestoreExplorer

End Sub 'ClearShellIntegrationReg

'-------------------------------------------------------------------------------
'   FileWipe
'
'   Removal of left behind services, files and shortcuts 
'-------------------------------------------------------------------------------
Sub FileWipe
    Dim scRoot
    Dim fDelFolders
    
    If CBool(iError AND ERROR_USERCANCEL) Then Exit Sub

    LogH1 "File Cleanup" 

    fDelFolders = False
    CloseOfficeApps
    DelSchtasks

    LogH1 "Delete Services"
    ' remove the OfficeSvc service
    LogH2 "Delete OfficeSvc service"
    DeleteService "OfficeSvc"

    ' SP1 addition / change
    ' remove the ClickToRunSvc service
    LogH2 "Delete ClickToRunSvc service" 
    DeleteService "ClickToRunSvc"

    ' adding additional processes for termination
    'dicApps.Add "explorer.exe", "explorer.exe"
    dicApps.Add "msiexec.exe", "msiexec.exe"
    dicApps.Add "ose.exe", "ose.exe"
    
    If fC2R Then
	    LogH1 "Delete Files and Folders"
        ' delete C2R package files
        LogH2 "Delete C2R package files" 
        If oFso.FolderExists(sProgramFiles & "\Microsoft Office 15") _
        Or oFso.FolderExists(sProgramFiles & "\Microsoft Office 16") _
        Or oFso.FolderExists(oWShell.ExpandEnvironmentStrings("%programfiles%") & "\Microsoft Office\PackageManifests") _
        Or oFso.FolderExists(oWShell.ExpandEnvironmentStrings("%programfiles(x86)%") & "\Microsoft Office\PackageManifests") Then
            fDelFolders = True
            'Log "   Attention: Now closing Explorer.exe for file delete operations"
            'Log "   Explorer will automatically restart."
            wscript.sleep 2000
            CloseOfficeApps
        End If
        ' delete Office folders
        LogH2 "Delete Office folders"
        DeleteFolder sProgramFiles & "\Microsoft Office 15"
        DeleteFolder sProgramFiles & "\Microsoft Office 16"
        If f64 Then 
        	DeleteFolder sCommonProgramFilesX86 & "\Microsoft Office 15"
        	DeleteFolder sCommonProgramFilesX86 & "\Microsoft Office 16"
        End If
        If fDelFolders Then
        	DeleteFolder sProgramFiles & "\Microsoft Office\PackageManifests"
        	DeleteFolder sProgramFiles & "\Microsoft Office\PackageSunrisePolicies"
        	DeleteFolder sProgramFiles & "\Microsoft Office\root"
        	DeleteFile sProgramFiles & "\Microsoft Office\AppXManifest.xml"
         	DeleteFile sProgramFiles & "\Microsoft Office\FileSystemMetadata.xml"
        	If Not dicKeepSku.Count > 0 Then 
        		DeleteFolder sProgramFiles & "\Microsoft Office\Office16"
        		DeleteFolder sProgramFiles & "\Microsoft Office\Office15"
        	End If
        	If f64 Then
	        	DeleteFolder sProgramFilesX86 & "\Microsoft Office\PackageManifests"
	        	DeleteFolder sProgramFilesX86 & "\Microsoft Office\PackageSunrisePolicies"
	        	DeleteFolder sProgramFilesX86 & "\Microsoft Office\root"
	        	DeleteFile sProgramFilesX86 & "\Microsoft Office\AppXManifest.xml"
	         	DeleteFile sProgramFilesX86 & "\Microsoft Office\FileSystemMetadata.xml"
	        	If Not dicKeepSku.Count > 0 Then 
	        		DeleteFolder sProgramFilesX86 & "\Microsoft Office\Office16"
	        		DeleteFolder sProgramFilesX86 & "\Microsoft Office\Office15"
	        	End If
       		End If
		End If
        
        DeleteFolder sProgramData & "\Microsoft\ClickToRun"
        DeleteFolder sCommonProgramFiles & "\microsoft shared\ClickToRun"
        DeleteFolder sProgramData & "\Microsoft\office\FFPackageLocker"
        DeleteFolder sProgramData & "\Microsoft\office\ClickToRunPackageLocker"
        If oFso.FileExists(sProgramData & "\Microsoft\office\FFPackageLocker") Then DeleteFile sProgramData & "\Microsoft\office\FFPackageLocker"
        If oFso.FileExists(sProgramData & "\Microsoft\office\FFStatePBLocker") Then DeleteFile sProgramData & "\Microsoft\office\FFStatePBLocker"
        If NOT dicKeepSku.Count > 0 Then DeleteFolder sProgramData & "\Microsoft\office\Heartbeat"
        DeleteFolder oWShell.ExpandEnvironmentStrings("%userprofile%") & "\Microsoft Office"
        DeleteFolder oWShell.ExpandEnvironmentStrings("%userprofile%") & "\Microsoft Office 15"
        DeleteFolder oWShell.ExpandEnvironmentStrings("%userprofile%") & "\Microsoft Office 16"
    End If

    ' restore explorer.exe if needed
    RestoreExplorer

    ' delete shortcuts
    LogH2 "Search and delete shortcuts"
    CleanShortcuts sAllUsersProfile, True, False
    CleanShortcuts sProfilesDirectory, True, False

    ' delete empty folder structures
    If dicDelFolder.Count > 0 Then
        LogH2 "Remove empty folders"
        DeleteEmptyFolders
    End If

    ' add the collected files in use for delete on reboot
    If dicDelInUse.Count > 0 Then ScheduleDeleteEx

    LogH2 "File Cleanup complete"
End Sub ' FileWipe

'-------------------------------------------------------------------------------
'   CleanShortcuts
'
'   Recursively search all profile folders for Office shortcuts in scope 
'-------------------------------------------------------------------------------
Sub CleanShortcuts (sFolder, fDelete, fUnPin)
    Dim oFolder, fld, file, sc, item
    Dim fDeleteSC

	If fSkipSD Then Exit Sub
	
	Set oFolder = oFso.GetFolder(sFolder)
	' exclude system protected link folders
    If CBool(oFolder.Attributes AND 1024) Then Exit Sub

    On Error Resume Next
    For Each fld In oFolder.SubFolders
        If Err <> 0 Then
		    CheckError "CleanShortcuts: " & vbTab & sFolder
        Else
            CleanShortcuts fld.Path, fDelete, fUnPin
        End If
	Next
    For Each file In oFolder.Files
		If LCase(Right(file.Path, 4)) = ".lnk" Then
            fDeleteSC = False
            LogOnly " check file: " & file.Path
            set sc = oWShell.CreateShortcut(file.Path)
            If Err <> 0 Then
		        CheckError "CleanShortcutsSC: " & vbTab & sFolder
            Else
                'Compare if the shortcut target is in the list of executables that will be removed
                'LogOnly "  - SC.TargetPath: " & sc.TargetPath
                If Len(sc.TargetPath) > 0 Then
                    If InStr(sc.TargetPath,"{") > 0 Then
                        'Handle Windows Installer shortcuts
                        If Len(sc.TargetPath) >= InStr(sc.TargetPath,"{") + 37 Then
                            If CheckDelete(Mid(sc.TargetPath, InStr(sc.TargetPath,"{"), 38)) Then fDeleteSC = True
                        End If
                    Else
                        'Handle regular shortcuts
                        If IsC2R(sc.TargetPath) Then fDeleteSC = True
                        If NOT oFso.FileExists(sc.TargetPath) Then
                            ' Shortcut target does not exist
                            If IsC2R(sc.TargetPath) Then
                                LogOnly "remove Office shortcut with non-existent target: " & file.Path & " - " & sc.TargetPath
                                fDeleteSC = True
                            Else
                                'LogOnly "  - keep orphaned SC as target is not in scope: " & sc.TargetPath
                            End If
                        Else
                            'LogOnly "  - keep SC as shortcut target does still exist: " & sc.TargetPath
                        End If
                    End If
                End If
            End If
            If fDeleteSC Then 
                If NOT dicDelFolder.Exists(sFolder) Then dicDelFolder.Add sFolder, sFolder
                If fUnPin OR fDelete Then 
                    If oFso.FileExists(sc.TargetPath) Then
                        UnPin file
                    Else
                        sc.TargetPath = sNotepad
                        sc.Save
                        UnPin file
                    End If
                End If
                If fDelete Then DeleteFile file.Path
                fDeleteSC = False
                fClearTaskBand = True
            End If 'fDeleteSC
        End If
	Next
    On Error Goto 0
End Sub 'CleanShortcuts

'-------------------------------------------------------------------------------
'   UnPin
'
'   Unpins a shortcut from the taskbar or start menu 
'-------------------------------------------------------------------------------
Sub UnPin(file)
    Dim fldItem, verb

    On Error Resume Next
    Set fldItem = oShellApp.NameSpace(file.ParentFolder.Path).ParseName(file.Name)
    For Each verb in fldItem.Verbs
        Select Case LCase(Replace(verb, "&", ""))
        Case "unpin from taskbar", "von taskleiste lösen", "détacher du barre des tâches", "détacher de la barre des tâches", "desanclar de la barra de tareas", "ta bort från aktivitetsfältet", "frigør fra proceslinje", "frigør fra proceslinjen", "desanclar de la barra de tareas", "odepnout z hlavního panelu", "van de taakbalk losmaken", "poista kiinnitys tehtäväpalkista", "rimuovi dalla barra delle applicazioni"
            LogOnly "unpin Office shortcut from taskbar: " & file.Name 
            verb.DoIt
        Case "unpin from start menu", "vom startmenü lösen", "désépingler du menu démarrer", "supprimer du menu démarrer", "détacher du menu démarrer", "détacher de la menu démarrer", "odepnout z nabídky start", "frigør fra menuen start", "van het menu start losmaken", "losmaken van menu start", "poista kiinnitys käynnistä-valikosta", "irrota aloitusvalikosta"
            LogOnly "unpin Office shortcut from start menu: " & file.Name 
            If iVersionNT > 600 Then verb.DoIt
        End Select
        Select Case Replace(verb, "&", "")
        Case "从「开始」菜单解锁", "從 [開始] 功能表取消釘選", "タスク バーに表示しない(K)", "작업 표시줄에서 제거(K)", "Открепить от панели задач", "Ξεκαρφίτσωμα από το μενού Έναρξη", "‏‏בטל הצמדה לתפריט התחלה"
            LogOnly "unpin Office shortcut: " & file.Name 
            verb.DoIt
        End Select
    Next
    On Error Goto 0
End Sub

'-------------------------------------------------------------------------------
'   ClearTaskBand
'
'   Clears contents from the users taskband to get rid of pinned items
'-------------------------------------------------------------------------------
Sub ClearTaskBand ()
    Dim sid
    Dim sTaskBand, sHKUTaskBand
    Dim arrSid

    sTaskBand = "Software\Microsoft\Windows\CurrentVersion\Explorer\Taskband\"
    RegDeleteValue HKCU, sTaskBand, "Favorites", False
    RegDeleteValue HKCU, sTaskBand, "FavoritesRemovedChanges", False
    RegDeleteValue HKCU, sTaskBand, "FavoritesChanges", False
    RegDeleteValue HKCU, sTaskBand, "FavoritesResolve", False
    RegDeleteValue HKCU, sTaskBand, "FavoritesVersion", False

    ' enum all profiles in HKU
    LoadUsersReg
    If NOT RegEnumKey(HKU, "", arrSid) Then Exit Sub
    For Each sid in arrSid
        sHKUTaskBand = sid & "\" & sTaskBand
        RegDeleteValue HKCU, sHKUTaskBand, "Favorites", False
        RegDeleteValue HKCU, sHKUTaskBand, "FavoritesRemovedChanges", False
        RegDeleteValue HKCU, sHKUTaskBand, "FavoritesChanges", False
        RegDeleteValue HKCU, sHKUTaskBand, "FavoritesResolve", False
        RegDeleteValue HKCU, sHKUTaskBand, "FavoritesVersion", False
    Next 'sid
End Sub 'ClearTaskBand

'-------------------------------------------------------------------------------
'   LoadUsersReg
'
'   Loads the HKCU for all local users
'-------------------------------------------------------------------------------
Sub LoadUsersReg ()
    Dim profilefolder
    Dim sValue

    LogH1 "Load User Registry Profiles"
    On Error Resume Next

    oReg.GetExpandedStringValue HKLM, "SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList", "ProfilesDirectory", sValue
    For Each profilefolder in oFso.GetFolder(sValue).SubFolders
        If oFso.FileExists(profilefolder.path & "\ntuser.dat") Then
            LogOnly " load: " & profilefolder.path & "\ntuser.dat" & " as " & "HKU\" & profilefolder.name
            oWShell.Run "reg load " & _
                                    chr(34) & "HKU\" & profilefolder.name & chr(34) & " " & _
                                    chr(34) & profilefolder.path & "\ntuser.dat" & chr(34), 0, True
        End If
'        If oFso.FileExists(profilefolder.path & "\Local Settings\Application Data\Microsoft\Windows\UsrClass.dat") Then
'            LogOnly " load: " & profilefolder.path & "\..\UsrClass.dat" & " as " & "HKU\" & profilefolder.name & "_Classes"
'            oWShell.Run "reg load " & _
'                                    chr(34) & "HKU\" & profilefolder.name & "_Classes" & chr(34) & " " & _
'                                    chr(34) & profilefolder.path & "\Local Settings\Application Data\Microsoft\Windows\UsrClass.dat" & chr(34),0,True
'        End If
    Next
End Sub

'-------------------------------------------------------------------------------
'   ClearOfficeHKLM
'
'   Recursively search and clear the HKLM Office key from references in scope 
'-------------------------------------------------------------------------------
Sub ClearOfficeHKLM (sSubKeyName)
    Dim key, name
    Dim sValue
    Dim arrKeys, arrNames, arrTypes
    Dim arrTestNames, arrTestTypes, arrTestKeys

    ' recursion
    If RegEnumKey(HKLM, sSubKeyName, arrKeys) Then
        For Each key in arrKeys
            ClearOfficeHKLM sSubKeyName & "\" & key
        Next 'key
    End If
    
    ' identify & clear removable entries
    If RegEnumValues(HKLM, sSubKeyName, arrNames, arrTypes) Then
        For Each name in arrNames
            If RegReadValue(HKLM, sSubKeyName, name, sValue, "REG_SZ") Then
                If IsC2R(sValue) Then RegDeleteValue HKLM, sSubKeyName, name, False
            End If
        Next 'item
    End If
    
    ' clear out empty keys
    If (NOT RegEnumValues(HKLM, sSubKeyName, arrNames, arrTypes)) AND _
       (NOT RegEnumKey(HKLM, sSubKeyName, arrKeys)) AND _
       (NOT dicKeepSku.Count > 0) Then _
        RegDeleteKey HKLM, sSubKeyName
End Sub


'-------------------------------------------------------------------------------
'
'                                        Helper Functions
'
'-------------------------------------------------------------------------------

'-------------------------------------------------------------------------------
'   IsC2R
'
'   Check if the passed in string is related to C2R
'   Returns TRUE if in C2R scope
'-------------------------------------------------------------------------------
Function IsC2R (sValue)

	Const OREF            = "\ROOT\OFFICE1"
	Const OREFROOT        = "Microsoft Office\Root\"
	Const OREGREFC2R15    = "Microsoft Office 15"
	Const OREGREFC2R16    = "Microsoft Office 16"
	Const OCOMMON		  = "\microsoft shared\ClickToRun"
	Const OMANIFEST		  = "\Microsoft Office\PackageManifests"
	Const OSUNRISE		  = "\Microsoft Office\PackageSunrisePolicies"
	
	Dim fReturn
	
	fReturn = False
	
    If InStr(LCase(sValue), LCase(OREF)) > 0 _
    Or InStr(LCase(sValue), LCase(OREFROOT)) > 0 _
    Or InStr(LCase(sValue), LCase(OCOMMON)) > 0 _
    Or InStr(LCase(sValue), LCase(OMANIFEST)) > 0 _
    Or InStr(LCase(sValue), LCase(OSUNRISE)) > 0 _
    Or InStr(LCase(sValue), LCase(OREGREFC2R15)) > 0 _
    Or InStr(LCase(sValue), LCase(OREGREFC2R16)) > 0 Then fReturn = True
    
	IsC2R = fReturn
End Function

'-------------------------------------------------------------------------------
'   CheckRegPermissions
'
'   Test the permissions on some key registry locations to determine if 
'   sufficient permissions are given.
'-------------------------------------------------------------------------------
Function CheckRegPermissions
    Const KEY_QUERY_VALUE       = &H0001
    Const KEY_SET_VALUE         = &H0002
    Const KEY_CREATE_SUB_KEY    = &H0004
    Const DELETE                = &H00010000

    Dim sSubKeyName
    Dim fReturn

    CheckRegPermissions = True
    sSubKeyName = "Software\Microsoft\Windows\"
    oReg.CheckAccess HKLM, sSubKeyName, KEY_QUERY_VALUE, fReturn
    If Not fReturn Then CheckRegPermissions = False
    oReg.CheckAccess HKLM, sSubKeyName, KEY_SET_VALUE, fReturn
    If Not fReturn Then CheckRegPermissions = False
    oReg.CheckAccess HKLM, sSubKeyName, KEY_CREATE_SUB_KEY, fReturn
    If Not fReturn Then CheckRegPermissions = False
    oReg.CheckAccess HKLM, sSubKeyName, DELETE, fReturn
    If Not fReturn Then CheckRegPermissions = False

End Function 'CheckRegPermissions

'-------------------------------------------------------------------------------
'   GetMyProcessId
'
'   Returns the process id of the own process
'-------------------------------------------------------------------------------
Function GetMyProcessId()
    Dim iParentProcessId

    iParentProcessId = 0
    ' try to obtain from creating a new cscript instance
    On Error Resume Next
    iParentProcessId = GetObject("winmgmts:root\cimv2").Get("Win32_Process.Handle='" & oWShell.Exec("cscript.exe").ProcessId & "'").ParentProcessId
    On Error Goto 0
    If iParentProcessId > 0 Then
        ' succeeded to obtain the process id
        GetMyProcessId = iParentProcessId
        Exit Function
    End If

    ' failed to obtain the id from the creation of a new instance
    ' get it from enum of Win32_Process
    Dim Process, Processes
    Err.Clear
    Set Processes = oWmiLocal.ExecQuery("Select * From Win32_Process WHERE Name='cscript.exe' AND CommandLine like '%" & SCRIPTNAME & "%'")
    For Each Process in Processes
        iParentProcessId = Process.ProcessId
        Exit For
    Next
    GetMyProcessId = iParentProcessId
End Function 'GetMyProcessId

'-------------------------------------------------------------------------------
'   Delimiter
'
'   Returns the delimiter for a passed in string
'-------------------------------------------------------------------------------
Function Delimiter (sVersion)
    Dim iCnt, iAsc

    Delimiter = " "
    For iCnt = 1 To Len(sVersion)
        iAsc = Asc(Mid(sVersion, iCnt, 1))
        If Not (iASC >= 48 And iASC <= 57) Then 
            Delimiter = Mid(sVersion, iCnt, 1)
            Exit Function
        End If
    Next 'iCnt
End Function

'-------------------------------------------------------------------------------
'   GetExpandedGuid
'
'   Returns the expanded string from a compressed GUID
'-------------------------------------------------------------------------------
Function GetExpandedGuid (sGuid)
    Dim i

    'Ensure valid length
    If NOT Len(sGuid) = 32 Then Exit Function

    GetExpandedGuid = "{" & StrReverse(Mid(sGuid,1,8)) & "-" & _
                       StrReverse(Mid(sGuid,9,4)) & "-" & _
                       StrReverse(Mid(sGuid,13,4))& "-"
    For i = 17 To 20
	    If i Mod 2 Then
		    GetExpandedGuid = GetExpandedGuid & mid(sGuid,(i + 1),1)
	    Else
		    GetExpandedGuid = GetExpandedGuid & mid(sGuid,(i - 1),1)
	    End If
    Next
    GetExpandedGuid = GetExpandedGuid & "-"
    For i = 21 To 32
	    If i Mod 2 Then
		    GetExpandedGuid = GetExpandedGuid & mid(sGuid,(i + 1),1)
	    Else
		    GetExpandedGuid = GetExpandedGuid & mid(sGuid,(i - 1),1)
	    End If
    Next
    GetExpandedGuid = GetExpandedGuid & "}"
End Function 'GetExpandedGuid

'-------------------------------------------------------------------------------
'   GetCompressedGuid
'
'   Returns the compressed string for a GUID
'-------------------------------------------------------------------------------
Function GetCompressedGuid (sGuid)
    Dim sCompGUID
    Dim i
    
    'Ensure Valid Length
    If NOT Len(sGuid) = 38 Then Exit Function

    sCompGUID = StrReverse(Mid(sGuid,2,8))  & _
                StrReverse(Mid(sGuid,11,4)) & _
                StrReverse(Mid(sGuid,16,4)) 
    For i = 21 To 24
	    If i Mod 2 Then
		    sCompGUID = sCompGUID & Mid(sGuid, (i + 1), 1)
	    Else
		    sCompGUID = sCompGUID & Mid(sGuid, (i - 1), 1)
	    End If
    Next
    For i = 26 To 37
	    If i Mod 2 Then
		    sCompGUID = sCompGUID & Mid(sGuid, (i - 1), 1)
	    Else
		    sCompGUID = sCompGUID & Mid(sGuid, (i + 1), 1)
	    End If
    Next
    GetCompressedGuid = sCompGUID
End Function

'-------------------------------------------------------------------------------
'   GetDecodedGuid
'
'   Returns the GUID from a squished format
'-------------------------------------------------------------------------------
Function GetDecodedGuid(sEncGuid, sGuid)

Dim sDecode, sTable, sHex, iChr
Dim arrTable
Dim i, iAsc, pow85, decChar
Dim lTotal
Dim fFailed

    fFailed = False

    sTable =    "0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff," & _
                "0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff," & _
                "0xff,0x00,0xff,0xff,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0xff," & _
                "0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0xff,0xff,0xff,0x16,0xff,0x17," & _
                "0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27," & _
                "0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,0xff,0x34,0x35,0x36," & _
                "0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x40,0x41,0x42,0x43,0x44,0x45,0x46," & _
                "0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,0x50,0x51,0x52,0xff,0x53,0x54,0xff"
    arrTable = Split(sTable,",")
    lTotal = 0 : pow85 = 1
    For i = 0 To 19
        fFailed = True
        If i Mod 5 = 0 Then
            lTotal = 0 : pow85 = 1
        End If ' i Mod 5 = 0
        iAsc = Asc(Mid(sEncGuid,i+1,1))
        sHex = arrTable(iAsc)
        If iAsc >=128 Then Exit For
        If sHex = "0xff" Then Exit For
        iChr = CInt("&h"&Right(sHex,2))
        lTotal = lTotal + (iChr * pow85)
        If i Mod 5 = 4 Then sDecode = sDecode & DecToHex(lTotal)
        pow85 = pow85 * 85
        fFailed = False
    Next 'i
    If NOT fFailed Then sGuid = "{"&Mid(sDecode,1,8)&"-"& _
                                Mid(sDecode,13,4)&"-"& _
                                Mid(sDecode,9,4)&"-"& _
                                Mid(sDecode,23,2) & Mid(sDecode,21,2)&"-"& _
                                Mid(sDecode,19,2) & Mid(sDecode,17,2) & Mid(sDecode,31,2) & Mid(sDecode,29,2) & Mid(sDecode,27,2) & Mid(sDecode,25,2) &"}"

    GetDecodedGuid = NOT fFailed

End Function 'GetDecodedGuid

'-------------------------------------------------------------------------------
'   DecToHex
'
'   Convert a long decimal to hex
'-------------------------------------------------------------------------------
Function DecToHex(lDec)
    
    Dim sHex
    Dim iLen
    Dim lVal, lExp
    Dim arrChr
  
    arrChr = Array("0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F")
    sHex = ""
    lVal = lDec
    lExp = 16^10
    While lExp >= 1
        If lVal >= lExp Then
            sHex = sHex & arrChr(Int(lVal / lExp))
            lVal = lVal - lExp * Int(lVal / lExp)
        Else
            sHex = sHex & "0"
            If sHex = "0" Then sHex = ""
        End If
        lExp = lExp / 16
    Wend

    iLen = 8 - Len(sHex)
    If iLen > 0 Then sHex = String(iLen, "0") & sHex
    DecToHex = sHex
End Function

'-------------------------------------------------------------------------------
'   RelaunchAs64Host
'
'   Relaunch self with 64 bit CScript host
'-------------------------------------------------------------------------------
Sub RelaunchAs64Host
    Dim Argument, sCmd
    Dim fQuietRelaunch

    fQuietRelaunch = False
    sCmd = Replace(LCase(wscript.Path), "syswow64", "sysnative") & "\cscript.exe " & Chr(34) & WScript.scriptFullName & Chr(34)
    If fQuiet Then fQuietRelaunch = True
    If Wscript.Arguments.Count > 0 Then
        For Each Argument in Wscript.Arguments
            sCmd = sCmd  &  " " & chr(34) & Argument & chr(34)
            Select Case UCase(Argument)
            Case "/Q", "/QUIET"
                fQuietRelaunch = True
            End Select
        Next 'Argument
    End If
    sCmd = sCmd & " /ChangedHostBitness"
    If fQuietRelaunch Then
        sCmd = Replace (sCmd, "\cscript.exe", "\wscript.exe")
        Wscript.Quit CLng(oWShell.Run (sCmd, 0, True))
    Else
        Wscript.Quit CLng(oWShell.Run (sCmd, 1, True))
    End If

End Sub 'RelaunchAs64Host

'-------------------------------------------------------------------------------
'   RelaunchElevated
'
'   Relaunch the script with elevated permissions
'-------------------------------------------------------------------------------
Sub RelaunchElevated
    Dim Argument, Process, Processes
    Dim iParentProcessId, iSpawnedProcessId
    Dim sCmdLine, sRetValFile, sValue
    Dim oShell

    SetError ERROR_RELAUNCH
    ' Shell object for relaunch
    Set oShell = CreateObject("Shell.Application")
    ' Note: Command line has not been parsed at this point
    ' build command line for relaunch
    sCmdLine = Chr(34) & WScript.ScriptFullName & Chr(34)
    If Wscript.Arguments.Count > 0 Then
        For Each Argument in Wscript.Arguments
            Select Case UCase(Argument)
            Case "/Q","/QUIET"
                'Don't try to relaunch in quiet mode
                Exit Sub
                SetError ERROR_ELEVATION_FAILED
            Case "UAC"
                'Already tried elevated relaunch
                SetError ERROR_ELEVATION_FAILED
                Exit Sub
            Case Else
                sCmdLine = sCmdLine  &  " " & chr(34) & Argument & chr(34)
            End Select
        Next 'Argument
    End If
    ' prep work to get the return value from the elevated process
    iParentProcessId = GetMyProcessId 
    
'    ' make user aware of elevation attempt after reboot
'    If RegReadValue(HKCU, "SOFTWARE\Microsoft\Office\15.0\CleanC2R", "Rerun", sValue, "REG_DWORD") Then
'        oWShell.Popup "System reboot complete. OffScrub will now prompt for elevation!", 10, SCRIPTNAME & " - NOTE!"
'    End If
    
    ' launch the elevated instance
    oShell.ShellExecute "cscript.exe", sCmdLine & " /NoElevate UAC", "", "runas", 1
    ' get the process id of the spawned instance
    WScript.Sleep 500
    Set Processes = oWmiLocal.ExecQuery("Select * From Win32_Process WHERE ParentProcessId='" & iParentProcessId & "'")
    If Processes.Count > 0 Then
        For Each Process in Processes
		    iSpawnedProcessId = Process.ProcessId
		    Exit For
        Next 'Process
        ' monitor the tasklist to detect the end of the spawned process
        While oWmiLocal.ExecQuery("Select * From Win32_Process WHERE ProcessId='" & iSpawnedProcessId & "'").Count > 0
            WScript.Sleep 3000
        Wend
        ' get the return value from the file
        Wscript.Quit GetRetValFromFile
    End If
    ' elevation failed (user declined)
    SetError ERROR_ELEVATION_USERDECLINED
End Sub 'RelaunchElevated

'-------------------------------------------------------------------------------
'   RelaunchAsCScript
'
'   Relaunch self with Cscript as host
'-------------------------------------------------------------------------------
Sub RelaunchAsCScript
    Dim Argument
    Dim sCmdLine
    Dim fQuietNoCScript

    fQuietNoCScript = False
    SetError ERROR_RELAUNCH
    sCmdLine = "cmd.exe /c " & WScript.Path & "\cscript.exe //NOLOGO " & Chr(34) & WScript.scriptFullName & Chr(34)
    If Wscript.Arguments.Count > 0 Then
        For Each Argument in Wscript.Arguments
            sCmdLine = sCmdLine  &  " " & chr(34) & Argument & chr(34)
            Select Case UCase(Argument)
            Case "/Q","/QUIET"
                fQuietNoCScript = True
                ClearError ERROR_RELAUNCH
            End Select
        Next 'Argument
    End If
    sCmdLine = sCmdLine  &  " " & chr(34) & "/ChangedScriptHost" & chr(34)
    
    If NOT fQuietNoCScript Then Wscript.Quit CLng(oWShell.Run(sCmdLine, 1, True))
End Sub 'RelaunchAsCScript

'-------------------------------------------------------------------------------
'   SetError
'
'   Set error bit(s) 
'-------------------------------------------------------------------------------
Sub SetError(ErrorBit)
    iError = iError OR ErrorBit
    Select Case ErrorBit
    Case ERROR_DCAF_FAILURE, ERROR_STAGE2, ERROR_ELEVATION_USERDECLINED, ERROR_ELEVATION, ERROR_SCRIPTINIT
        iError = iError OR ERROR_FAIL
    End Select
End Sub

'-------------------------------------------------------------------------------
'   ClearError
'
'   Unset error bit(s) 
'-------------------------------------------------------------------------------
Sub ClearError(ErrorBit)
    iError = iError AND (ERROR_ALL - ErrorBit)
    Select Case ErrorBit
    Case ERROR_ELEVATION_USERDECLINED, ERROR_ELEVATION, ERROR_SCRIPTINIT
        iError = iError AND (ERROR_ALL - ERROR_FAIL)
    End Select
End Sub

'-------------------------------------------------------------------------------
'   SetRetVal
'
'   Write return value to file
'-------------------------------------------------------------------------------
Sub SetRetVal(iError)
    Dim RetValFileStream
    
    'don't fail script execution if writing the return value to file fails
    On Error Resume Next 

    Set RetValFileStream = oFso.createTextFile(sScrubDir & "\" & RETVALFILE, True, True)
    RetValFileStream.Write iError
    RetValFileStream.Close
    On Error Goto 0
End Sub 'SetRetVal

'-------------------------------------------------------------------------------
'   GetRetValFromFile
'
'   Read return value from file.
'   Used to ensure return value can get obtained from an elevated process
'-------------------------------------------------------------------------------
Function GetRetValFromFile ()
    Dim RetValFileStream
    Dim iRetValFromFile

    On Error Resume Next 'don't fail script execution when getting the return value from file fails

    If oFso.FileExists(sScrubDir & "\" & RETVALFILE) Then
        Set RetValFileStream = oFso.OpenTextFile(sScrubDir & "\" & RETVALFILE, 1, False, -2)
        GetRetValFromFile = RetValFileStream.ReadAll
        RetValFileStream.Close
        Exit Function
    End If
    Err.Clear
    On Error Goto 0
    GetRetValFromFile = ERROR_UNKNOWN
End Function 'GetRetValFromFile

'-------------------------------------------------------------------------------
'   CreateLog
'
'   Create the removal log file
'-------------------------------------------------------------------------------
Sub CreateLog
    Dim DateTime
    Dim sLogName
    
    On Error Resume Next
    ' create the log file
    Set DateTime = CreateObject("WbemScripting.SWbemDateTime")
    DateTime.SetVarDate Now, True
    sLogName = sLogDir & "\" & oWShell.ExpandEnvironmentStrings("%COMPUTERNAME%")
    sLogName = sLogName &  "_" & Left(DateTime.Value, 14)
    sLogName = sLogName & "_ScrubLog.txt"
    Err.Clear
    Set LogStream = oFso.CreateTextFile(sLogName, True, True)
    If Err <> 0 Then 
        Err.Clear
        sLogDir = sScrubDir
        sLogName = sLogDir & "\" & oWShell.ExpandEnvironmentStrings("%COMPUTERNAME%")
        sLogName = sLogName &  "_" & Left(DateTime.Value, 14)
        sLogName = sLogName & "_ScrubLog.txt"
        Set LogStream = oFso.CreateTextFile(sLogName, True, True)
    End If
    On Error Goto 0

    LogH2 "Microsoft Customer Support Services - " & ONAME & " Removal Utility" & vbCrLf & vbCrLf & _
        	"Version: " & vbTab & SCRIPTVERSION & vbCrLf & _
        	"64 bit OS: " & vbTab & f64 & vbCrLf & _
        	"Removal start: " & vbTab & Time 
    LogH2	"OS Details: " & sOSinfo & vbCrLf
    fLogInitialized = True
End Sub 'CreateLog

'-------------------------------------------------------------------------------
'   HiveString
'
'   Translates the numeric constant into the human readable registry hive string
'-------------------------------------------------------------------------------
Function HiveString(hDefKey)
    Select Case hDefKey
        Case HKCR : HiveString = "HKEY_CLASSES_ROOT"
        Case HKCU : HiveString = "HKEY_CURRENT_USER"
        Case HKLM : HiveString = "HKEY_LOCAL_MACHINE"
        Case HKU  : HiveString = "HKEY_USERS"
        Case Else : HiveString = hDefKey
    End Select
End Function

'-------------------------------------------------------------------------------
'   RegKeyExists
'
'   Returns a boolean for the test on existence of a given registry key
'-------------------------------------------------------------------------------
Function RegKeyExists(hDefKey, sSubKeyName)
    Dim arrKeys
    RegKeyExists = False
    If oReg.EnumKey(hDefKey, sSubKeyName, arrKeys) = 0 Then RegKeyExists = True
End Function

'-------------------------------------------------------------------------------
'   RegValExists
'
'   Returns a boolean for the test on existence of a given registry value
'-------------------------------------------------------------------------------
Function RegValExists(hDefKey,sSubKeyName,sName)
    Dim arrValueTypes, arrValueNames
    Dim i

    RegValExists = False
    If Not RegKeyExists(hDefKey,sSubKeyName) Then Exit Function
    If oReg.EnumValues(hDefKey,sSubKeyName,arrValueNames,arrValueTypes) = 0 AND IsArray(arrValueNames) Then
        For i = 0 To UBound(arrValueNames) 
            If LCase(arrValueNames(i)) = Trim(LCase(sName)) Then RegValExists = True
        Next 
    End If 'oReg.EnumValues
End Function

'-------------------------------------------------------------------------------
'   RegReadValue
'
'   Read the value of a given registry entry
'   The correct type has to be passed in as argument
'-------------------------------------------------------------------------------
Function RegReadValue(hDefKey, sSubKeyName, sName, sValue, sType)
    Dim RetVal
    Dim Item
    Dim arrValues
    
    Select Case UCase(sType)
        Case "1", "REG_SZ"
            RetVal = oReg.GetStringValue(hDefKey, sSubKeyName, sName, sValue)
            If Not RetVal = 0 AND f64 Then RetVal = oReg.GetStringValue(hDefKey, Wow64Key(hDefKey, sSubKeyName), sName, sValue)
        Case "2", "REG_EXPAND_SZ"
            RetVal = oReg.GetExpandedStringValue(hDefKey, sSubKeyName, sName, sValue)
            If NOT RetVal = 0 AND f64 Then RetVal = oReg.GetExpandedStringValue(hDefKey, Wow64Key(hDefKey, sSubKeyName), sName, sValue)
        Case "3", "REG_BINARY"
            RetVal = oReg.GetBinaryValue(hDefKey, sSubKeyName, sName, sValue)
            If NOT RetVal = 0 AND f64 Then RetVal = oReg.GetBinaryValue(hDefKey, Wow64Key(hDefKey, sSubKeyName), sName, sValue)
        Case "4", "REG_DWORD"
            RetVal = oReg.GetDWORDValue(hDefKey, sSubKeyName, sName, sValue)
            If NOT RetVal = 0 AND f64 Then RetVal = oReg.GetDWORDValue(hDefKey, Wow64Key(hDefKey, sSubKeyName), sName, sValue)
        Case "7", "REG_MULTI_SZ"
            RetVal = oReg.GetMultiStringValue(hDefKey, sSubKeyName, sName, arrValues)
            If NOT RetVal = 0 AND f64 Then RetVal = oReg.GetMultiStringValue(hDefKey, Wow64Key(hDefKey, sSubKeyName), sName, arrValues)
            If RetVal = 0 Then sValue = Join(arrValues, chr(13))
        Case Else
            RetVal = -1
    End Select 'sValue
    
    RegReadValue = (RetVal = 0)
End Function 'RegReadValue

'-------------------------------------------------------------------------------
'   RegEnumValues
'
'   Enumerate a registry key to return all values
'-------------------------------------------------------------------------------
Function RegEnumValues(hDefKey, sSubKeyName, arrNames, arrTypes)
    Dim RetVal, RetVal64
    Dim arrNames32, arrNames64, arrTypes32, arrTypes64
    
    If f64 Then
        RetVal = oReg.EnumValues(hDefKey, sSubKeyName, arrNames32, arrTypes32)
        RetVal64 = oReg.EnumValues(hDefKey, Wow64Key(hDefKey, sSubKeyName), arrNames64, arrTypes64)
        If (RetVal = 0) AND (NOT RetVal64 = 0) AND IsArray(arrNames32) AND IsArray(arrTypes32) Then 
            arrNames = arrNames32
            arrTypes = arrTypes32
        End If
        If (NOT RetVal = 0) AND (RetVal64 = 0) AND IsArray(arrNames64) AND IsArray(arrTypes64) Then 
            arrNames = arrNames64
            arrTypes = arrTypes64
        End If
        If (RetVal = 0) AND (RetVal64 = 0) AND IsArray(arrNames32) AND IsArray(arrNames64) AND IsArray(arrTypes32) AND IsArray(arrTypes64) Then 
            arrNames = RemoveDuplicates(Split((Join(arrNames32, "\") & "\" & Join(arrNames64, "\")), "\"))
            arrTypes = RemoveDuplicates(Split((Join(arrTypes32, "\") & "\" & Join(arrTypes64, "\")), "\"))
        End If
    Else
        RetVal = oReg.EnumValues(hDefKey, sSubKeyName, arrNames, arrTypes)
    End If 'f64
    RegEnumValues = ((RetVal = 0) OR (RetVal64 = 0)) AND IsArray(arrNames) AND IsArray(arrTypes)
End Function 'RegEnumValues

'-------------------------------------------------------------------------------
'   RegEnumKey
'
'   Enumerate a registry key to return all subkeys
'-------------------------------------------------------------------------------
Function RegEnumKey(hDefKey, sSubKeyName, arrKeys)
    Dim RetVal, RetVal64
    Dim arrKeys32, arrKeys64
    
    If f64 Then
        RetVal = oReg.EnumKey(hDefKey, sSubKeyName, arrKeys32)
        RetVal64 = oReg.EnumKey(hDefKey, Wow64Key(hDefKey, sSubKeyName), arrKeys64)
        If (RetVal = 0) AND (NOT RetVal64 = 0) AND IsArray(arrKeys32) Then arrKeys = arrKeys32
        If (Not RetVal = 0) AND (RetVal64 = 0) AND IsArray(arrKeys64) Then arrKeys = arrKeys64
        If (RetVal = 0) AND (RetVal64 = 0) Then 
            If IsArray(arrKeys32) AND IsArray (arrKeys64) Then 
                arrKeys = RemoveDuplicates(Split((Join(arrKeys32, "\") & "\" & Join(arrKeys64, "\")), "\"))
            ElseIf IsArray(arrKeys64) Then
                arrKeys = arrKeys64
            Else
                arrKeys = arrKeys32
            End If
        End If
    Else
        RetVal = oReg.EnumKey(hDefKey, sSubKeyName, arrKeys)
    End If 'f64
    RegEnumKey = ((RetVal = 0) OR (RetVal64 = 0)) AND IsArray(arrKeys)
End Function 'RegEnumKey

'-------------------------------------------------------------------------------
'   RegDeleteValue
'
'   Wrapper around oReg.DeleteValue to handle 64 bit
'-------------------------------------------------------------------------------
Sub RegDeleteValue(hDefKey, sSubKeyName, sName, fRegMultiSZ)
    Dim sDelKeyName, sValue
    Dim iRetVal
    Dim fKeep
    
    ' ensure trailing "\"
    sSubKeyName = sSubKeyName & "\"
    While InStr(sSubKeyName, "\\") > 0
        sSubKeyName = Replace(sSubKeyName, "\\", "\")
    Wend

    fKeep = dicKeepReg.Exists(LCase(sSubKeyName & sName))
    If (NOT fKeep AND f64) Then fKeep = dicKeepReg.Exists(LCase(Wow64Key(hDefKey, sSubKeyName) & sName))
    If fKeep Then
        LogOnly "Disallowing the delete of still required keypath element: " & HiveString(hDefKey) & "\" & sSubKeyName & sName
        If NOT fForce Then Exit Sub
    End If
    
    ' check on forced delete
    If fKeep Then
        LogOnly "Enforced delete of still required keypath element: " & HiveString(hDefKey) & "\" & sSubKeyName & sName
        LogOnly "   Remaining applications will need a repair!"
    End If
    
    ' ensure value exists
    If RegValExists(hDefKey, sSubKeyName, sName) Then
        sDelKeyName = sSubKeyName
    ElseIf RegValExists(hDefKey, Wow64Key(hDefKey, sSubKeyName), sName) Then
        sDelKeyName =  Wow64Key(hDefKey, sSubKeyName)
    Else
        LogOnly "Value not found. Cannot delete value: " & HiveString(hDefKey) & "\" & sSubKeyName & sName
        Exit Sub
    End If

    ' prevent unintentional, unsafe REG_MULTI_SZ delete
    If RegReadValue(hDefKey, sDelKeyName, sName, sValue, "REG_MULTI_SZ") AND NOT fRegMultiSZ Then
        LogOnly "Disallowing unsafe delete of REG_MULTI_SZ: " & HiveString(hDefKey) & "\" & sDelKeyName & sName
        Exit Sub
    End If
    
    ' execute delete operation
    If Not fDetectOnly Then 
        LogOnly "Delete registry value: " & HiveString(hDefKey) & "\" & sDelKeyName & " -> " & sName
        iRetVal = 0
        iRetVal = oReg.DeleteValue(hDefKey, sDelKeyName, sName)
        CheckError "RegDeleteValue"
        If NOT (iRetVal = 0) Then
            LogOnly "     Delete failed. Return value: " & iRetVal
            SetError ERROR_STAGE2
        End If
    Else
        LogOnly "Preview mode. Disallowing delete registry value: " & HiveString(hDefKey) & "\" & sDelKeyName & " -> " & sName
    End If
    On Error Goto 0

End Sub 'RegDeleteValue

'-------------------------------------------------------------------------------
'   RegDeleteKey
'
'   Wrappper around RegDeleteKeyEx to handle 64bit
'-------------------------------------------------------------------------------
Sub RegDeleteKey(hDefKey, sSubKeyName)
    Dim sDelKeyName
    Dim fKeep
    
    ' ensure trailing "\"
    sSubKeyName = sSubKeyName & "\"
    While InStr(sSubKeyName, "\\") > 0
        sSubKeyName = Replace(sSubKeyName, "\\", "\")
    Wend

    fKeep = dicKeepReg.Exists(LCase(sSubKeyName))
    If (NOT fKeep AND f64) Then fKeep = dicKeepReg.Exists(LCase(Wow64Key(hDefKey, sSubKeyName)))
    If fKeep Then
        LogOnly "Disallowing the delete of still required keypath element: " & HiveString(hDefKey) & "\" & sSubKeyName
        If NOT fForce Then Exit Sub
    End If
    
    ' check on forced delete
    If fKeep Then
        LogOnly "Enforced delete of still required keypath element: " & HiveString(hDefKey) & "\" & sSubKeyName
        LogOnly "   Remaining applications will need a repair!"
    End If
    
    If Len(sSubKeyName) > 1 Then
        'Strip of trailing "\"
        sSubKeyName = Left(sSubKeyName, Len(sSubKeyName) - 1)
    End If
    
    ' ensure key exists
    If RegKeyExists(hDefKey, sSubKeyName) Then
        sDelKeyName = sSubKeyName
    ElseIf f64 AND RegKeyExists(hDefKey, Wow64Key(hDefKey, sSubKeyName)) Then
        sDelKeyName = Wow64Key(hDefKey, sSubKeyName)
    Else
        LogOnly "Key not found. Cannot delete key: " & HiveString(hDefKey) & "\" & sSubKeyName
        Exit Sub
    End If

    ' execute delete
    If Not fDetectOnly Then
        LogOnly "Delete registry key: " & HiveString(hDefKey) & "\" & sDelKeyName
        On Error Resume Next
        RegDeleteKeyEx hDefKey, sDelKeyName
        On Error Goto 0
    Else
        LogOnly "Preview mode. Disallowing delete of registry key: " & HiveString(hDefKey) & "\" & sSubKeyName
    End If
End Sub 'RegDeleteKey

'-------------------------------------------------------------------------------
'   RegDeleteKeyEx
'
'   Recursively delete a registry structure
'-------------------------------------------------------------------------------
Sub RegDeleteKeyEx(hDefKey, sSubKeyName) 
    Dim arrSubkeys
    Dim sSubkey
    Dim iRetVal

    'Strip of trailing "\"
    If Len(sSubKeyName) > 1 Then
        If Right(sSubKeyName, 1) = "\" Then sSubKeyName = Left(sSubKeyName, Len(sSubKeyName) - 1)
    End If
    On Error Resume Next

    ' exception handler
    If (hDefKey = HKLM) AND (sSubKeyName = "SOFTWARE\Microsoft\Office\15.0\ClickToRun") Then
        iRetVal = oWShell.Run("reg delete HKLM\SOFTWARE\Microsoft\Office\15.0\ClickToRun /f", 0, True)
        Exit Sub
    End If

    ' regular recursion
    oReg.EnumKey hDefKey, sSubKeyName, arrSubkeys
    If IsArray(arrSubkeys) Then 
        For Each sSubkey In arrSubkeys 
            RegDeleteKeyEx hDefKey, sSubKeyName & "\" & sSubkey 
        Next 
    End If 
    If Not fDetectOnly Then 
        iRetVal = 0
        iRetVal = oReg.DeleteKey(hDefKey, sSubKeyName)
        If NOT (iRetVal = 0) Then LogOnly "     Delete failed. Return value: "&iRetVal
    End If
    On Error Goto 0
End Sub 'RegDeleteKeyEx

'-------------------------------------------------------------------------------
'   Wow64Key
'
'   Return the 32bit regkey location on a 64bit environment
'-------------------------------------------------------------------------------
Function Wow64Key(hDefKey, sSubKeyName)
    Dim iPos

    Select Case hDefKey
    Case HKCU
        If Left(sSubKeyName, 17) = "Software\Classes\" Then
            Wow64Key = Left(sSubKeyName, 17) & "Wow6432Node\" & Right(sSubKeyName, Len(sSubKeyName) - 17)
        Else
            iPos = InStr(sSubKeyName, "\")
            Wow64Key = Left(sSubKeyName, iPos) & "Wow6432Node\" & Right(sSubKeyName, Len(sSubKeyName) - iPos)
        End If
    Case HKLM
        If Left(sSubKeyName, 17) = "Software\Classes\" Then
            Wow64Key = Left(sSubKeyName, 17) & "Wow6432Node\" & Right(sSubKeyName, Len(sSubKeyName) - 17)
        Else
            iPos = InStr(sSubKeyName, "\")
            Wow64Key = Left(sSubKeyName, iPos) & "Wow6432Node\" & Right(sSubKeyName, Len(sSubKeyName) - iPos)
        End If
    Case Else
        Wow64Key = "Wow6432Node\" & sSubKeyName
    End Select 'hDefKey
End Function 'Wow64Key

'-------------------------------------------------------------------------------
'   RemoveDuplicates
'
'   Remove duplicate entries from a one dimensional array
'-------------------------------------------------------------------------------
Function RemoveDuplicates(Array)
    Dim Item
    Dim dicNoDupes
    
    Set dicNoDupes = CreateObject("Scripting.Dictionary")
    For Each Item in Array
        If Not dicNoDupes.Exists(Item) Then dicNoDupes.Add Item,Item
    Next 'Item
    RemoveDuplicates = dicNoDupes.Keys
End Function 'RemoveDuplicates

'-------------------------------------------------------------------------------
'   CheckError
'
'   Checks the status of 'Err' and logs the error details if <> 0
'-------------------------------------------------------------------------------
Sub CheckError(sModule)
    If Err <> 0 Then 
        LogOnly "   Error: " & sModule & " - Source: " & Err.Source & "; Err# (Hex): " & Hex( Err ) & _
               "; Err# (Dec): " & Err & "; Description : " & Err.Description
    End If 'Err = 0
    Err.Clear
End Sub

'-------------------------------------------------------------------------------
'   LogH
'
'   Write a header log string to the log file
'-------------------------------------------------------------------------------
Sub LogH (sLog)
    LogStream.WriteLine ""
    sLog = sLog & vbCrLf & String(Len(sLog), "=")
    If NOT fQuiet AND fCScript Then wscript.echo ""
    If NOT fQuiet AND fCScript Then wscript.echo sLog
    LogStream.WriteLine sLog
End Sub 'Logh

'-------------------------------------------------------------------------------
'   LogH1
'
'   Write a header log string to the log file
'-------------------------------------------------------------------------------
Sub LogH1 (sLog)
    LogStream.WriteLine ""
    sLog = sLog & vbCrLf & String(Len(sLog), "-")
    If NOT fQuiet AND fCScript Then wscript.echo ""
    If NOT fQuiet AND fCScript Then wscript.echo sLog
    LogStream.WriteLine sLog
End Sub 'LogH1

'-------------------------------------------------------------------------------
'   LogH2
'
'   Write w/o indent Cmd window and the log file
'-------------------------------------------------------------------------------
Sub LogH2 (sLog)
    If NOT fQuiet AND fCScript Then wscript.echo sLog
    LogStream.WriteLine ""
    LogStream.WriteLine sLog
End Sub 'LogH2

'-------------------------------------------------------------------------------
'   Log
'
'   Echos the log string to the Cmd window and the log file
'-------------------------------------------------------------------------------
Sub Log (sLog)
    If NOT fQuiet AND fCScript Then wscript.echo sLog
    If sLog = "" Then
        LogStream.WriteLine
    Else
        LogStream.WriteLine "   " & Time & ": " & sLog
    End If
End Sub 'Log

'-------------------------------------------------------------------------------
'   LogOnly
'
'   Commits the log string to the log file
'-------------------------------------------------------------------------------
Sub LogOnly (sLog)
    If sLog = "" Then
        LogStream.WriteLine
    Else
        LogStream.WriteLine "   " & Time & ": " & sLog
    End If
End Sub 'Log

'-------------------------------------------------------------------------------
'   InScope
'
'   Check if ProductCode is in scope for removal
'-------------------------------------------------------------------------------
'Check if ProductCode is in scope
Function InScope(sProductCode)
    Dim fInScope
    Dim sProd
	
	Const OFFICEID = "0000000FF1CE}"
	
	On Error Resume Next

    fInScope = False
    'LogOnly "Now checking scope of: " & sProductCode
    If Len(sProductCode) = 38 Then
        'LogOnly "GUID length validated to be 38 characters"
        sProd = UCase(sProductCode)
        If Right(sProd, PRODLEN) = OFFICEID Then
        	'LogOnly "Pattern matches " & OFFICEID
        	If CInt(Mid(sProd, 4, 2)) > 14 Then 
	            If Err <> 0 Then
	            	Err.Clear
	            	Exit Function
	            End If
	            'LogOnly "VersionMajor confirmed to be > 14" 
	            Select Case Mid(sProd, 11, 4)
	            Case "007E", "008F", "008C", "24E1", "237A", "00DD"
	                'LogOnly "SKUFilter matches scope"
	                fInScope = True
	            Case Else
	            	'LogOnly "SKU " & Mid(sProd, 11, 4) & " doesn't match known integration products scope"
	            End Select
            End If
        End If
        ' Microsoft Online Services Sign-in Assistant (x64 ship and x86 ship)
        If sProd = "{6C1ADE97-24E1-4AE4-AEDD-86D3A209CE60}" Then fInScope = True
        If sProd = "{9520DDEB-237A-41DB-AA20-F2EF2360DCEB}" Then fInScope = True
        If sProd = UCase(sPackageGuid) Then fInScope = True
        If sProd = UCase("{9AC08E99-230B-47e8-9721-4577B7F124EA}") Then fInScope = True
    End If '38

    InScope = fInScope
End Function 'InScope

'-------------------------------------------------------------------------------
'   CheckDelete
'
'   Check a ProductCode is known to stay installed
'-------------------------------------------------------------------------------
Function CheckDelete(sProductCode)

    CheckDelete = False
    ' ensure valid GUID length
    If NOT Len(sProductCode) = 38 Then Exit Function
    ' only care if it's in the expected ProductCode pattern 
    If NOT InScope(sProductCode) Then Exit Function
    ' check if it's a known product that should be kept
    If dicKeepSku.Exists(UCase(sProductCode)) Then Exit Function
    
    CheckDelete = True
End Function 'CheckDelete

'-------------------------------------------------------------------------------
'   DeleteService
'
'   Delete a service
'-------------------------------------------------------------------------------
'Delete a service
Sub DeleteService(sName)
    Dim Services, srvc, Processes, process
    Dim sQuery, sStates, sProcessName, sCmd
    Dim iRet
    
    On Error Resume Next
    
    sStates = "STARTED;RUNNING"
    sQuery = "Select * From Win32_Service Where Name='" & sName & "'"
    Set Services = oWmiLocal.Execquery(sQuery)
    
    ' stop and delete the service
    For Each srvc in Services
        Log "   Found service " & sName & " (" & srvc.DisplayName & ") in state " & srvc.State
        ' get the process name
        sProcessName = Trim(Replace(Mid(srvc.PathName, InStrRev(srvc.PathName,"\") + 1), chr(34), ""))
        ' stop the service
        If InStr(sStates, UCase(srvc.State)) > 0 Then
            iRet = srvc.StopService()
            LogOnly " attempt to stop service " & sName & " returned: " & iRet
        End If
        ' ensure no more instances of the service are running
        Set Processes = oWmiLocal.ExecQuery("Select * From Win32_Process Where Name='" & sProcessName & "'")
        For Each process in Processes
            iRet = process.Terminate()
        Next 'Process
        If fDetectOnly Then 
            Log "   Not deleting service " & sName & " in preview mode"
            Exit Sub
        End If
        iRet = srvc.Delete()
        Log "   Delete service " & sName & " returned: " & iRet
    Next 'srvc

    ' check if service got deleted
    Set Services = oWmiLocal.Execquery(sQuery)
    For Each srvc in Services
        ' failed to delete service. retry with 'sc' command
        sLog "Delete service " & sName & " failed."
        sLog "Retry delete using 'SC' command"
        sCmd = "sc delete " & sName
        iRet = oWShell.Run(sCmd, 0, True)
    Next 'srvc

    Set Services = Nothing
    Err.Clear
    On Error Goto 0
End Sub 'DeleteService


'-------------------------------------------------------------------------------
'   SetupRetVal
'
'   Translation for known uninstall return values
'-------------------------------------------------------------------------------
Function SetupRetVal(RetVal)
    Select Case RetVal
        Case 0 : SetupRetVal = "Success"
        'msiexec return values
        Case 1259 : SetupRetVal = "APPHELP_BLOCK"
        Case 1601 : SetupRetVal = "INSTALL_SERVICE_FAILURE"
        Case 1602 : SetupRetVal = "INSTALL_USEREXIT"
        Case 1603 : SetupRetVal = "INSTALL_FAILURE"
        Case 1604 : SetupRetVal = "INSTALL_SUSPEND"
        Case 1605 : SetupRetVal = "UNKNOWN_PRODUCT"
        Case 1606 : SetupRetVal = "UNKNOWN_FEATURE"
        Case 1607 : SetupRetVal = "UNKNOWN_COMPONENT"
        Case 1608 : SetupRetVal = "UNKNOWN_PROPERTY"
        Case 1609 : SetupRetVal = "INVALID_HANDLE_STATE"
        Case 1610 : SetupRetVal = "BAD_CONFIGURATION"
        Case 1611 : SetupRetVal = "INDEX_ABSENT"
        Case 1612 : SetupRetVal = "INSTALL_SOURCE_ABSENT"
        Case 1613 : SetupRetVal = "INSTALL_PACKAGE_VERSION"
        Case 1614 : SetupRetVal = "PRODUCT_UNINSTALLED"
        Case 1615 : SetupRetVal = "BAD_QUERY_SYNTAX"
        Case 1616 : SetupRetVal = "INVALID_FIELD"
        Case 1618 : SetupRetVal = "INSTALL_ALREADY_RUNNING"
        Case 1619 : SetupRetVal = "INSTALL_PACKAGE_OPEN_FAILED"
        Case 1620 : SetupRetVal = "INSTALL_PACKAGE_INVALID"
        Case 1621 : SetupRetVal = "INSTALL_UI_FAILURE"
        Case 1622 : SetupRetVal = "INSTALL_LOG_FAILURE"
        Case 1623 : SetupRetVal = "INSTALL_LANGUAGE_UNSUPPORTED"
        Case 1624 : SetupRetVal = "INSTALL_TRANSFORM_FAILURE"
        Case 1625 : SetupRetVal = "INSTALL_PACKAGE_REJECTED"
        Case 1626 : SetupRetVal = "FUNCTION_NOT_CALLED"
        Case 1627 : SetupRetVal = "FUNCTION_FAILED"
        Case 1628 : SetupRetVal = "INVALID_TABLE"
        Case 1629 : SetupRetVal = "DATATYPE_MISMATCH"
        Case 1630 : SetupRetVal = "UNSUPPORTED_TYPE"
        Case 1631 : SetupRetVal = "CREATE_FAILED"
        Case 1632 : SetupRetVal = "INSTALL_TEMP_UNWRITABLE"
        Case 1633 : SetupRetVal = "INSTALL_PLATFORM_UNSUPPORTED"
        Case 1634 : SetupRetVal = "INSTALL_NOTUSED"
        Case 1635 : SetupRetVal = "PATCH_PACKAGE_OPEN_FAILED"
        Case 1636 : SetupRetVal = "PATCH_PACKAGE_INVALID"
        Case 1637 : SetupRetVal = "PATCH_PACKAGE_UNSUPPORTED"
        Case 1638 : SetupRetVal = "PRODUCT_VERSION"
        Case 1639 : SetupRetVal = "INVALID_COMMAND_LINE"
        Case 1640 : SetupRetVal = "INSTALL_REMOTE_DISALLOWED"
        Case 1641 : SetupRetVal = "SUCCESS_REBOOT_INITIATED"
        Case 1642 : SetupRetVal = "PATCH_TARGET_NOT_FOUND"
        Case 1643 : SetupRetVal = "PATCH_PACKAGE_REJECTED"
        Case 1644 : SetupRetVal = "INSTALL_TRANSFORM_REJECTED"
        Case 1645 : SetupRetVal = "INSTALL_REMOTE_PROHIBITED"
        Case 1646 : SetupRetVal = "PATCH_REMOVAL_UNSUPPORTED"
        Case 1647 : SetupRetVal = "UNKNOWN_PATCH"
        Case 1648 : SetupRetVal = "PATCH_NO_SEQUENCE"
        Case 1649 : SetupRetVal = "PATCH_REMOVAL_DISALLOWED"
        Case 1650 : SetupRetVal = "INVALID_PATCH_XML"
        Case 3010 : SetupRetVal = "SUCCESS_REBOOT_REQUIRED"
        Case Else : SetupRetVal = "Unknown Return Value"
    End Select
End Function 'SetupRetVal

'-------------------------------------------------------------------------------
'   DeleteFile
'
'   Wrapper to delete a file
'-------------------------------------------------------------------------------
Sub DeleteFile(sFile)
    Dim File, attr
    Dim sDelFile, sFileName, sNewPath
    Dim fKeep
    
    On Error Resume Next

    fKeep = dicKeepFolder.Exists(LCase(sFile))
    If (NOT fKeep AND f64) Then fKeep = dicKeepFolder.Exists(LCase(Wow64Folder(sFile)))
    If fKeep Then
        LogOnly "Disallowing the delete of still required keypath element: " & sFile
        If NOT fForce Then Exit Sub
    End If

    ' check on forced delete
    If fKeep Then
        LogOnly "Enforced delete of still required keypath element: " & sFile
        LogOnly "   Remaining applications will need a repair!"
    End If

    If oFso.FileExists(sFile) Then
        sDelFile = sFile
    ElseIf f64 AND oFso.FileExists(Wow64Folder(sFile)) Then
        sDelFile = Wow64Folder(sFile)
    Else
        LogOnly "Path not found. Cannot not delete folder: " & sFile
        Exit Sub
    End If
    If Not fDetectOnly Then 
        LogOnly "Delete file: " & sDelFile
		Set File = oFso.GetFile(sDelFile)
        ' ensure read-only flag is not set
        attr =  File.Attributes
        If CBool(attr AND 1) Then File.Attributes = attr AND (attr - 1)
        ' add folder to empty folder cleanup list
        If NOT dicDelFolder.Exists(File.ParentFolder.Path) Then dicDelFolder.Add File.ParentFolder.Path, File.ParentFolder.Path
        ' delete the file
        sFile = File.Path
        File.Delete True
        Set File = Nothing
        If Err <> 0 Then
            CheckError "DeleteFile"
            ' schedule file for delete on next reboot
            ScheduleDeleteFile sFile
        End If 'Err <> 0
    Else
        LogOnly "Preview mode. Disallowing delete for folder: " & sDelFile
    End If
    On Error Goto 0
End Sub 'DeleteFile

'-------------------------------------------------------------------------------
'   DeleteFolder
'
'   Wrapper to delete a folder
'-------------------------------------------------------------------------------
Sub DeleteFolder(sFolder)
    Dim Folder, fld, attr
    Dim sDelFolder, sFolderName, sNewPath, sCmd
    Dim fKeep
    
    ' ensure trailing "\"
    ' trailing \ is required for dicKeepFolder comparisons
    sFolder = sFolder & "\"
    While InStr(sFolder,"\\")>0
        sFolder = Replace(sFolder,"\\","\")
    Wend

    ' prevent delete of folders that are known to be still required
    fKeep = dicKeepFolder.Exists(LCase(sFolder))
    If (NOT fKeep AND f64) Then fKeep = dicKeepFolder.Exists(LCase(Wow64Folder(sFolder)))
    If fKeep Then
        LogOnly "Disallowing the delete of still required keypath element: " & sFolder
        If NOT fForce Then Exit Sub
    End If

    ' check on forced delete
    If fKeep Then
        LogOnly "Enforced delete of still required keypath element: " & sFolder
        LogOnly "   Remaining applications will need a repair!"
    End If
    
    ' strip trailing "\"
    If Len(sFolder) > 1 Then
        sFolder = Left(sFolder, Len(sFolder) - 1)
    End If

    On Error Resume Next
    If oFso.FolderExists(sFolder) Then 
        sDelFolder = sFolder
    ElseIf f64 AND oFso.FolderExists(Wow64Folder(sFolder)) Then 
        sDelFolder = Wow64Folder(sFolder)
    Else
        LogOnly "Path not found. Cannot not delete folder: " & sFolder
        Exit Sub
    End If
    If Not fDetectOnly Then 
        LogOnly "Delete folder: " & sDelFolder
        Set Folder = oFso.GetFolder(sDelFolder)
        ' ensure to remove read only flag
        attr =  Folder.Attributes
        If CBool(attr AND 1) Then Folder.Attributes = attr AND (attr - 1)
        ' add to empty folder cleanup list
        If NOT dicDelFolder.Exists(Folder.Path) Then dicDelFolder.Add Folder.Path, Folder.Path
        ' delete the folder
        ' for performance reasons try 'rd' first
        Set Folder = Nothing
        sCmd = "cmd.exe /c rd /s " & chr(34) & sDelFolder & chr(34) & " /q"
        oWShell.Run sCmd, 0, True
        If NOT oFso.FolderExists(sDelFolder) Then Exit Sub
        
        ' rd didn't work check with FileSystemObject
        Set Folder = oFso.GetFolder(sDelFolder)
        Folder.Delete True
        Set Folder = Nothing
        
        ' error handling
        If Err <> 0 Then
            Select Case Err
            Case 70
                ' Access Denied
                ' Retry after closing running processes
                CheckError "DeleteFolder"
                If NOT fRerun Then
                    CloseOfficeApps
                    ' attempt 'rd' command
                    LogOnly "   Attempt to remove with 'rd' command"
                    sCmd = "cmd.exe /c rd /s " & chr(34) & sDelFolder & chr(34) & " /q"
                    oWShell.Run sCmd, 0, True
                    If NOT oFso.FolderExists(sDelFolder) Then Exit Sub
                End If

            Case 76 
                ' check on invalid path lengt issues Err 76 (0x4C) "Path not found"
                ' attempt 'rd' command
                CheckError "DeleteFolder"
                LogOnly "   Attempt to remove with 'rd' command"
                sCmd = "cmd.exe /c rd /s " & chr(34) & sDelFolder & chr(34) & " /q"
                oWShell.Run sCmd, 0, True
                If NOT oFso.FolderExists(sDelFolder) Then Exit Sub
            End Select
            
            ' stil failed!
            Log "   Failed to delete folder: " & sDelFolder
            CheckError "DeleteFolder"

            ' try to delete as many folder contents as possible
            ' before the recursive error handling is called
            Set Folder = oFso.GetFolder(sDelFolder)
            For Each fld in Folder.Subfolders
                sCmd = "cmd.exe /c rd /s " & chr(34) & fld.Path & chr(34) & " /q"
                oWShell.Run sCmd, 0, True
            Next 'fld
            sCmd = "cmd.exe /c del " & chr(34) & fld.Path & "\*.*" & chr(34)
            oWShell.Run sCmd, 0, True
            Set Folder = Nothing

            ' schedule an additional run of the tool after reboot
            If NOT fRerun Then Rerun

            ' schedule folder for delete on next reboot
            ScheduleDeleteFolder sDelFolder
        End If 'Err <> 0
    Else
        LogOnly "Preview mode. Disallowing delete of folder: " & sDelFolder
    End If
    On Error Goto 0
End Sub 'DeleteFolder

Sub DeleteFolder_WMI (sFolder)
    Dim Folder, Folders
    Dim sWqlFolder
    Dim iRet

    sWqlFolder = Replace(sFolder, "\", "\\")
    Set Folders = oWmiLocal.ExecQuery ("Select * from Win32_Directory where name = '" & sWqlFolder & "'")
    For Each Folder in Folders
        iRet = Folder.Delete
    Next 'Folder
    LogOnly "   Delete (wmi) for folder " & sFolder & " returned: " & iRet
End Sub

'-------------------------------------------------------------------------------
'   Wow64Folder
'
'   Returns the WOW folder structure to handle folder-path operations on
'   64 bit environments
'-------------------------------------------------------------------------------
Function Wow64Folder(sFolder)
    If LCase(Left(sFolder, Len(sWinDir & "\System32"))) = LCase(sWinDir & "\System32") Then 
        Wow64Folder = sWinDir & "\syswow64" & Right(sFolder, Len(sFolder) - Len(sWinDir & "\System32"))
    ElseIf LCase(Left(sFolder, Len(sProgramFiles))) = LCase(sProgramFiles) Then 
        Wow64Folder = sProgramFilesX86 & Right(sFolder, Len(sFolder) - Len(sProgramFiles))
    Else
        Wow64Folder = "?" 'Return invalid string to ensure the folder cannot exist
    End If
End Function 'Wow64Folder

'-------------------------------------------------------------------------------
'   ScheduleDeleteFile
'
'   Adds a file to the list of items to delete on reboot
'-------------------------------------------------------------------------------
Sub ScheduleDeleteFile (sFile)
    If NOT dicDelInUse.Exists(sFile) Then dicDelInUse.Add sFile, sFile Else Exit Sub
    LogOnly "Add file in use for delete on reboot: " & sFile
    fRebootRequired = True
    SetError ERROR_REBOOT_REQUIRED
End Sub 'ScheduleDeleteFile

'-------------------------------------------------------------------------------
'   ScheduleDeleteFolder
'
'   Recursively adds a folder and its contents to the list of 
'   items to delete on reboot
'-------------------------------------------------------------------------------
Sub ScheduleDeleteFolder (sFolder)
    Dim oFolder, fld, file, attr

	Set oFolder = oFso.GetFolder(sFolder)
	' exclude hidden system  folders
    attr = oFolder.Attributes
    If CBool(attr AND 6) Then Exit Sub

	For Each fld In oFolder.SubFolders
		DeleteFolder fld.Path
	Next
	For Each file In oFolder.Files
		DeleteFile file.Path
	Next
	If NOT dicDelInUse.Exists(oFolder.Path) Then dicDelInUse.Add oFolder.Path, "" Else Exit Sub
    LogOnly "Add folder for delete on reboot: " & oFolder.Path
    fRebootRequired = True
    SetError ERROR_REBOOT_REQUIRED
End Sub 'ScheduleDeleteFile


'-------------------------------------------------------------------------------
'   ScheduleDeleteEx
'
'   Schedules the delete of files/folders in use on next reboot by adding
'   affected files/folders to the PendingFileRenameOperations registry entry
'-------------------------------------------------------------------------------
Sub ScheduleDeleteEx ()
    Dim key, hDefKey, sKeyName, sValueName
    Dim i
    Dim arrData

    hDefKey = HKLM
    sKeyName = "SYSTEM\CurrentControlSet\Control\Session Manager"
    sValueName = "PendingFileRenameOperations"
    
    LogH2 "Add " & dicDelInUse.Count & " PendingFileRenameOperations"
    If NOT RegValExists(hDefKey, sKeyName, sValueName) Then
        ReDim arrData(-1)
    Else
        oReg.GetMultiStringValue hDefKey, sKeyName, sValueName, arrData
    End If
    i = UBound(arrData) + 1
    ReDim Preserve arrData(UBound(arrData) + (dicDelInUse.Count * 2))
    For Each key in dicDelInUse.Keys
        LogOnly "   " & key
        arrData(i) = "\??\" & key
        arrData(i + 1) = ""
        i = i + 2
    Next 'key
    oReg.SetMultiStringValue hDefKey, sKeyName, sValueName, arrData
End Sub 'ScheduleDeleteEx

'-------------------------------------------------------------------------------
'   DeleteEmptyFolders
'
'   Deletes an individual folder structure if empty
'-------------------------------------------------------------------------------
Sub DeleteEmptyFolder (sFolder)
    Dim Folder
    
    ' cosmetic' task don't fail on error
    On Error Resume Next
    If oFso.FolderExists(sFolder) Then
        Set Folder = oFso.GetFolder(sFolder)
        If (Folder.Subfolders.Count = 0) AND (Folder.Files.Count = 0) Then 
            Set Folder = Nothing
            SmartDeleteFolder sFolder
        End If
    End If
    CheckError "DeleteEmptyFolder"
    On Error Goto 0
End Sub 'DeleteEmptyFolders

'-------------------------------------------------------------------------------
'   DeleteEmptyFolders
'
'   Delete an empty folder structure
'-------------------------------------------------------------------------------
Sub DeleteEmptyFolders
    Dim Folder
    Dim sFolder
    
    ' cosmetic' task don't fail on error
    On Error Resume Next
    DeleteEmptyFolder sCommonProgramFiles & "\Microsoft Shared\Office15"
    DeleteEmptyFolder sCommonProgramFiles & "\Microsoft Shared\Office16"
    DeleteEmptyFolder sCommonProgramFiles & "\Microsoft Shared\" 
    DeleteEmptyFolder sProgramFiles & "\Microsoft Office\Office15"
    DeleteEmptyFolder sProgramFiles & "\Microsoft Office\Office16"
    
    For Each sFolder in dicDelFolder.Keys
        If oFso.FolderExists(sFolder) Then
            Set Folder = oFso.GetFolder(sFolder)
            If (Folder.Subfolders.Count = 0) AND (Folder.Files.Count = 0) Then 
                Set Folder = Nothing
                SmartDeleteFolder sFolder
            End If
        End If
    Next 'sFolder
    CheckError "DeleteEmptyFolders"
    On Error Goto 0
End Sub 'DeleteEmptyFolders

'-------------------------------------------------------------------------------
'   SmartDeleteFolder
'
'   Wrapper to delete a folder and the empty parent folder structure
'-------------------------------------------------------------------------------
Sub SmartDeleteFolder(sFolder)
    Dim sDelFolder

    If oFso.FolderExists(sFolder) Then
        sDelFolder = sFolder
    ElseIf f64 AND oFso.FolderExists(Wow64Folder(sFolder)) Then
        sDelFolder = Wow64Folder(sFolder)
    Else
        Exit Sub
    End If

    If Not fDetectOnly Then
        LogOnly "Request SmartDelete for folder: " & sDelFolder
        SmartDeleteFolderEx sDelFolder
    Else
        LogOnly "Preview mode. Disallowing SmartDelete request for folder: " & sDelFolder
    End If
End Sub 'SmartDeleteFolder

'-------------------------------------------------------------------------------
'   SmartDeleteFolderEx
'
'   Executes the folder delete operation(s)
'-------------------------------------------------------------------------------
Sub SmartDeleteFolderEx(sFolder)
    Dim Folder
    
    On Error Resume Next
    DeleteFolder sFolder : CheckError "SmartDeleteFolderEx"
    On Error Goto 0
    Set Folder = oFso.GetFolder(oFso.GetParentFolderName(sFolder))
    If (Folder.Subfolders.Count = 0) AND (Folder.Files.Count = 0) Then SmartDeleteFolderEx(Folder.Path)
End Sub 'SmartDeleteFolderEx

'-------------------------------------------------------------------------------
'   RestoreExplorer
'
'   Ensure Windows Explorer is restarted if needed
'-------------------------------------------------------------------------------
Sub RestoreExplorer
    Dim Processes, Result, oAT, DateTime, JobID
    Dim sCmd
    
    'Non critical routine. Don't fail on error
    On Error Resume Next
    wscript.sleep 1000
    Set Processes = oWmiLocal.ExecQuery("Select * From Win32_Process Where Name='explorer.exe'")
    If Processes.Count < 1 Then 
        oWShell.Run "explorer.exe"
        'To handle this in case of System context, schedule and run as interactive task
        oWShell.Run "SCHTASKS /Create /TN OffScrEx /TR explorer /SC ONCE /ST 12:00 /IT", 0, True
        oWShell.Run "SCHTASKS /Run /TN OffScrEx", 0, True
        oWShell.Run "SCHTASKS /Delete /TN OffScrEx /F", 0, False
    End If
    On Error Goto 0
End Sub 'RestoreExploer

'-------------------------------------------------------------------------------
'   MyJoin
'
'   Replacement function to the internal Join function to prevent failures
'   that were seen in some instances
'-------------------------------------------------------------------------------
Function MyJoin(arrToJoin, sSeparator)
    Dim sJoined
    Dim i

    sJoined = ""
    If IsArray(arrToJoin) Then
        For i = 0 To UBound(arrToJoin)
            sJoined = sJoined & arrToJoin(i) & sSeparator
        Next 'i
    End If
    If Len(sJoined) > 1 Then sJoined = Left(sJoined, Len(sJoined) - 1)
    MyJoin = sJoined
End Function

'-------------------------------------------------------------------------------
'   Rerun
'
'   Flag need for reboot and schedule autorun to run the tool again on reboot.
'-------------------------------------------------------------------------------
Sub Rerun ()
    Dim sValue

    ' check if Rerun has already been called
    If fRerun Then Exit Sub

    ' set Rerun flag
    fRerun = True

    ' check if the previous run already initiated the Rerun
    If RegReadValue(HKCU, "SOFTWARE\Microsoft\Office\15.0\CleanC2R", "Rerun", sValue, "REG_DWORD") Then
        ' Rerun has already been tried
        LogH2 "Error: Removal failed"
        SetError ERROR_DCAF_FAILURE
        Exit Sub
    End If

    fRebootRequired = True
    SetError ERROR_REBOOT_REQUIRED
    SetError ERROR_INCOMPLETE

    ' cache the script to the local scrub folder
    oFso.CopyFile WScript.scriptFullName, sScrubDir & "\" & SCRIPTFILE

    oReg.CreateKey HKLM, "SOFTWARE"
    oReg.CreateKey HKLM, "SOFTWARE\Microsoft"
    oReg.CreateKey HKLM, "SOFTWARE\Microsoft\Office"
    oReg.CreateKey HKLM, "SOFTWARE\Microsoft\Office\15.0"
    oReg.CreateKey HKLM, "SOFTWARE\Microsoft\Office\15.0\CleanC2R"
    oReg.SetDWordValue HKLM, "SOFTWARE\Microsoft\Office\15.0\CleanC2R", "Rerun", 1

    fSetRunOnce = True
'    oReg.CreateKey HKCU, "SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce"
'    oReg.SetStringValue HKCU, "SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce", "CleanC2R", "cscript.exe " & chr(34) & sScrubDir & "\" & SCRIPTFILE & chr(34)
End Sub

'-------------------------------------------------------------------------------
'   SetRunOnce
'
'   Create a RunOnce entry to resume setup after a reboot
'-------------------------------------------------------------------------------
Sub SetRunOnce
    Dim sValue

    oReg.CreateKey HKLM, "SOFTWARE\Microsoft\Windows\CurrentVersion"
    oReg.CreateKey HKLM, "SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce"
    sValue = "cscript.exe " & chr(34) &  sScrubDir & "\" & SCRIPTFILE & chr(34) & " /NoElevate /Relaunched"
    oReg.SetStringValue HKLM, "SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce", "O15CleanUp", sValue

End Sub 'SetRunOnce

Always make sure to test everything in a development environment prior to implementing anything into production. The information in this article is provided “As Is” without warranty of any kind.

Понравилась статья? Поделить с друзьями:
0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest

0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии
  • Windows visio for windows 7
  • Не отображается сетевой диск windows 10
  • Как очистить историю сетевых подключений в windows 10
  • Windows phone мой телефон
  • Как сделать кастомную панель задач в windows 10