Remote Outlook 2016 Caching Report

I was recently asked to figure out a way to determine which users had cache mode enabled in Outlook 2016 and the end result is the script below.

In order to run the script, you will need to specify the following variables:
$Directory = Insert the exact path of where you would like to save your report ( EX: C:\Reports)
$File = Insert the file name of your report (EX: MyReport.csv)
$ComputerList = Insert the full path of your computer list (EX: C:\Computerlist.txt)


    Run a report to find who is in Outlook Cache Mode

    File Name  : OutlookCachingReport.ps1  
    Author     : Jose Espitia
    Requires   : PowerShell V5
    Version    : Version 1.00


# Specify where to save the report
$Directory = "C:\Reports"
$File = "MyReport.csv"

# Computer list
$ComputerList = "C:\ComputerList"
$Computers = Get-Content "$ComputerList"

ForEach($Computer in $Computers) {
    Try { 
        # Test connection with computer
        Test-Connection -ComputerName $Computer -ErrorAction Stop
        # Query remote machines
        $HKEY_Users = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey("Users",$Computer)
        # Get list of SIDs
        $SIDs = $HKEY_Users.GetSubKeyNames() | Where-Object { ($_ -like "S-1-5-21*") -and ($_ -notlike "*_Classes") }

        # Associate SID with Username
        $TotalSIDs = ForEach ($SID in $SIDS) {
            Try {
                $SID = []$SID
                $user = $SID.Translate([System.Security.Principal.NTAccount])
                New-Object PSObject -Property @{
                    Name = $User.value
                    SID = $SID.value
            Catch {
                Write-Warning ("Unable to translate {0}.`n{1}" -f $UserName,$_.Exception.Message)
        $UserList = $TotalSIDs 

        # Loop through users to determine If they are in cache mode
        ForEach($User in $UserList) {
            # Get SID
            $UserSID = $User.SID
            # Get list of Outlook profiles
            $OutlookProfiles = $HKEY_Users.OpenSubKey("$UserSID\SOFTWARE\Microsoft\Office\16.0\Outlook\Profiles\Outlook\")
            # Loop through Outlook profiles to find caching key
            ForEach($Profile in ($OutlookProfiles.GetSubKeyNames())) {
                $ProfileKey = $HKEY_Users.OpenSubKey("$UserSID\SOFTWARE\Microsoft\Office\16.0\Outlook\Profiles\Outlook\$Profile")
                # Locate cache key
                If(($ProfileKey.GetValueNames() -contains "00036601") -eq $True) {
                    $Result = $ProfileKey.GetValue("00036601")
                    # Convert value to HEX
                    $Result = [System.BitConverter]::ToString($Result)
                    # Determine if cache mode is enabled
                    If($Result -like "8*") {
                        $CacheMode = "Enabled"
                    Else {
                        $CacheMode = "Disabled"
                    # Create custom table
                    $Table = New-Object PSObject -Property @{
                        Username = $User.Name
                        SID = $User.SID
                        "Computer Name" = $Computer
                        "Cache Mode" = $CacheMode
                        "Registry Key Value" = $Result

                    } | Select-Object Username, SID, "Computer Name", "Cache mode", "Registry Key Value"
                    # Export table to CSV
                    $Table | Export-Csv -NoTypeInformation -Append -Path "$directory\$file"
    Catch {
        # Create custom table
        $Table = New-Object PSObject -Property @{
            Username = "N/A"
            SID = "N/A"
            "Computer Name" = $Computer
            "Cache Mode" = "N/A"
            "Registry Key Value" = "N/A"

        } | Select-Object Username, SID, "Computer Name", "Cache mode", "Registry Key Value"
        # Export table to CSV
        $Table | Export-Csv -NoTypeInformation -Append -Path "$directory\$file"

Feel free to leave questions in the comments!

Add a wireless profile to your MDT task sequence

First you will need to export the configuration for the wireless profile that you would like to add to your task sequence.
Note: You will need to connect to the wireless profile before you can export it.


The export should have copied an XML file to your desktop. In order to keep this simple, go ahead and rename the XML file WirelessProfile.xml. Now, copy WirelessProfile.xml and place it inside of your Deployment Share.
For this example, I will be copying the XML file into a folder called Custom, inside of your scripts folder.

Now go ahead and open up your task sequence and add a “Run Command Line” task inside of the State Restore group.

You can name the task anything you would like but in this example I have named it “Add Wireless Profile”.

Last but not least, you will need to add the following in the Command Line field:


Now you will have a pre-configured Wireless profile!

Enable or Disable Outlook caching based on the user’s location

The following script will use the user’s AD city and the default gateway to determine if a user is in their home office or visiting an office. If the script determines that the user is not in their home office, it will automatically disable Outlook caching and vice versa for a user that is in their home office.

In order for the script to work, you will need to use the cities listed in AD for your $CurrentLocation switch. Similar to the example below, you will also have to copy your default gateways inside of the switch.


    Caches a user's mailbox based on machine type or location  

    File Name  : OutlookCaching.ps1  
    Author     : Jose Espitia
    Requires   : PowerShell V5
    Version    : Version 1.00

if($env:COMPUTERNAME -like "*-D") {    
    # Get Default Gateway
    $CurrentDefaultGateway = (Get-WmiObject Win32_NetworkAdapterConfiguration) | foreach { $_.DefaultIPGateway }

    # Find Machine's Location
    $CurrentLocation = switch ($CurrentDefaultGateway) { 
   {"New York City"}
   {"Los Angeles"}
   {"Las Vegas"}

    # Get User's Info
    $objSearcher = New-Object System.DirectoryServices.DirectorySearcher
    $objSearcher.SearchRoot = New-Object System.DirectoryServices.DirectoryEntry
    $objSearcher.Filter = "(&(objectCategory=User)(SAMAccountName=$env:USERNAME))"
    $objSearcher.SearchScope = "Subtree"
    $obj = $objSearcher.FindOne()
    $UsersHome = $obj.Properties["l"]

    # Determine if user is in their home office
    if($UsersHome -match $CurrentLocation) {
        cmd /c REG ADD "HKEY_CURRENT_USER\Software\Policies\Microsoft\Office\16.0\Outlook\Cached Mode" /v Enable /t REG_DWORD /d 1 /f
    else {
        cmd /c REG ADD "HKEY_CURRENT_USER\Software\Policies\Microsoft\Office\16.0\Outlook\Cached Mode" /v Enable /t REG_DWORD /d 0 /f


Registry Keys for Windows 10 Privacy Settings

The following registry keys in this post control the privacy settings in Windows 10 1607. These settings can be found in the GUI by going to SETTINGS\PRIVACY.
Read more

Pin shortcuts to a user in a specific Active Directory group.

The following Powershell script will pin the Chrome shortcut to the Windows 10 start menu for anyone inside of a specific Active Directory group. In order to pin to the start menu, you will need to verify if your shortcut can be pinned through the GUI. To check this, you can right click your shortcut and see if you have “Pin to Start” available in your context menu. If you do not see this, then you may want to try copying the shortcut to:
%PROGRAMDATA%\Microsoft\Windows\Start Menu\Programs

In order to configure the script, you will need to provide values for the following variables:

# Variables that need to be set
$Shortcut = "Google Chrome.lnk"
$Location = "C:\ProgramData\Microsoft\Windows\Start Menu\Programs"

# Get User's Info
$objSearcher = New-Object System.DirectoryServices.DirectorySearcher
$objSearcher.SearchRoot = New-Object System.DirectoryServices.DirectoryEntry
$objSearcher.Filter = "(&(objectCategory=User)(SAMAccountName=$env:USERNAME))"
$objSearcher.SearchScope = "Subtree"
$obj = $objSearcher.FindOne()
$User = $obj.Properties["distinguishedname"]

# Get Group Info
$objSearcher.Filter = "(&(objectCategory=group)(SamAccountname=$Group))"
$objSearcher.SearchScope = "Subtree"
$obj = $objSearcher.FindOne()
[String[]]$Members = $obj.Properties["member"]

If ($Members -contains $User) { 
    $object= New-Object -ComObject shell.application
    $folder = $object.Namespace("$Location")
    $file= $folder.parsename("$Shortcut")

How to remove “Scan with Windows Defender” from the Context Menu

The following short batch script will automatically remove “Scan with Windows Defender” from the context menu for files, folders and drives in Windows 10.

:: Removes Windows Defender from the Context Menu for Files
REG DELETE HKEY_CLASSES_ROOT\*\shellex\ContextMenuHandlers\EPP /F
:: Removes Windows Defender from the Context Menu for Folders
REG DELETE HKEY_CLASSES_ROOT\Directory\shellex\ContextMenuHandlers\EPP /F
:: Removes Windows Defender from the Context Menu for Drives
REG DELETE HKEY_CLASSES_ROOT\Drive\shellex\ContextMenuHandlers\EPP /F

How to exclude specific applications with Lumension Endpoint Security

Open the Windows Registry Editor on the client machine.
Navigate to:

Create a new DWORD (32-bit) value.
The NAME is the file path to the driver \application that you want to exclude, for example if you are excluding the Skype application:
For 64 bit: C:\Program Files (x86)\Skype\Phone\Skype.exe
For 32 bit: C:\Program Files\Skype\Phone\Skype.exe

The Value data is 0 (zero)
Restarting the application or the machine may be required for the change to take effect.
The application specified in the registry entry name will be excluded from protection by Lumension Endpoint Security.

You can of course automate this task by running something like this:

:: Set the file you would like to exclude
SET EXCLUSION="C:\Program Files\Skype\Phone\Skype.exe"

REG ADD "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\sk\Parameters" /v %EXCLUSION% /t REG_DWORD /d 0 /f

Automate your BIOS update in MDT

This universal script will automate your BIOS updates in MDT. In order for this script to work, you will need to configure your MDT deployment share with the following folder structure:

Inside of the BIOS folder, you will need a folder for each model that you are supporting in your deployment. The folder names must match the model name that MDT queries with ZTIGather.
You can run wmic computersystem get model to get this value.

Folder Structure Example:
DeploymentShare$\Scripts\Custom\BIOS\HP EliteBook 8560w

Inside of these folders, you will need to place all the files needed to install your BIOS update. You will also need to create custom files needed to silently install and determine the latest BIOS version.

1st File: BIOS.txt
In this txt file, you will place the BIOS version of the update. This is used to compare the BIOS version installed on the machine and the latest update version.

2nd File: UpgradeBIOS.cmd
In this file you will add all the commands needed to silently install your BIOS update.

REM Setting Current Directory
cd "%~dp0"
WINUPTP.exe -s

Once you have the the folder structure completed, you will want to add a Reboot task to your Task Sequence. With this task, you will need to add an if statement with the following configuration:

Reboot Task Configuration

And now for the actual Powershell script!

# Load MDT Task Sequence Environment and Logs
$TSenv = New-Object -COMObject Microsoft.SMS.TSEnvironment
$logPath = $tsenv.Value("LogPath") 
$logFile = "$logPath\BIOS_Update.log"

# Start the logging 

Write-Output "Logging to $logFile." > $logFile

# Collect data
Write-Output "Collecting Data" >> $logFile
$ScriptRoot = $tsenv.Value("ScriptRoot")
$Model = $TSenv.Value("Model")
$CompBiosVersion = (Get-WmiObject WIN32_BIOS).SMBIOSBIOSVersion
$CurrentBiosVersion = Get-Content "$ScriptRoot\Scripts\Custom\BIOS\$Model\BIOS.txt"
$Installer = "UpgradeBIOS.cmd"

try { 
    Test-Path $CurrentBiosVersion -ErrorAction Stop
catch {
    Write-Output "$CurrentBiosVersion does not exist" >> $logFile

# Checking for BIOS update
if($CompBiosVersion.replace(' ' , '') -eq $CurrentBiosVersion.replace(' ' , '')) {
    Write-Output "BIOS is up to date." >> $logFile
else {
    Write-Output "Updating BIOS $CompBiosVersion to $CurrentBiosVersion." >> $logFile
    Start-Process "cmd.exe" "/c $ScriptRoot\Deploy\Scripts\Custom\BIOS\$Model\$Installer" -Wait
    $tsenv.Value("NeedReboot") = "YES"
    Write-Output "Update has been completed successfully." >> $logFile

How to enable used space encryption using Invoke-MbamClientDeployment.ps1

First and foremost, if you have not had a chance to read the latest Technet article on how to enable BitLocker by using MBAM, please do so here!

It is an excellent guide that explains how to configure MBAM and Bitlocker inside of MDT. Unfortunately the guide does not explain how to enable used space encryption when you are not pre-provisioning your drive. It’s actually pretty simple and can be done by just modifying the registry.

Now I’m assuming that you have Invoke-MbamClientDeployment.ps1 in your task sequence but if you have not set everything up, please read the Technet article that I referenced earlier.

In your task sequence, please navigate to the step that calls Invoke-MbamClientDeployment.ps1. If you followed the Technet guide, the task name should be “Configure BitLocker for MBAM”. Now go ahead and add a Run Command Line step before the “Configure BitLocker for MBAM” step. Let’s name this step “Enable Used Space Encryption”.

In the command line field, you will want to enter the following command:

reg.exe add HKLM\SOFTWARE\Policies\Microsoft\FVE /v OSEncryptionType /t REG_DWORD /d 2 /f

And.. That’s it!

How to configure your Windows 10 default file associations in MDT

You will first need to configure all your file associations on a test machine. Once this has been done, you will want to run the following command to export your file associations:

Dism.exe /Online /Export-DefaultAppAssociations:%USERPROFILE%\Documents\DefaultAppAssociations.xml

The XML file will be exported to your Documents folder

Now you will want to place the XML file that we just exported into your Scripts folder inside of your MDT Deployment Share.

Once that is done, launch MDT and open your deployment task sequence. Locate the PostInstall folder and add a command line task above the Inject Drivers task.

Set File Associations
Set File Associations - 2

Lets go ahead and name the task Set File Associations. In the command line field, insert the following command:

Dism.exe /Image:%OSDisk%\ /Import-DefaultAppAssociations:%SCRIPTROOT%\DefaultAppAssociations.xml

Now you’re all set!