Scripting

Set-FileOwnership and Set-FilePermissions Powershell function

Here are two separate Powershell functions that will configure file ownership and file permissions. I had to create them, since I was having to reuse the same code multiple times in my upcoming Creators Update 1703 cleanup script. Enjoy!

Set-FileOwnership

Function Set-FileOwnership {
    <#
    .SYNOPSIS
    Sets File Ownership
 
    .PARAMETER File
    Provide file path
 
    .PARAMETER User
    Provide a username or group that requires file ownership
 
    .EXAMPLE
    Set-FileOwnership -File "C:\windows\web\Wallpaper\Windows\img0.jpg" -User Users
 
    .EXAMPLE
    Set-FileOwnership -File "C:\windows\web\Wallpaper\Windows\img0.jpg" -User Administrators
    #>
    param (
     [parameter(Mandatory=$true)]
     [ValidateNotNullOrEmpty()]$File,
     [parameter(Mandatory=$true)]
     [ValidateNotNullOrEmpty()]$User
    )

    $ACL = Get-ACL "$File"
    $Group = New-Object System.Security.Principal.NTAccount("$User")
    $ACL.SetOwner($Group)
    Set-Acl -Path "$File" -AclObject $ACL

}

Set-FilePermissions

Function Set-FilePermissions {
    <#
    .SYNOPSIS
    Sets File Permissions
 
    .PARAMETER File
    Provide file path
 
    .PARAMETER User
    Provide a username or group that requires permissions configured

    .PARAMETER Control
    Provide file system rights (Ex: FullControl, Modify, ReadAndExecute, etc)
 
    .PARAMETER Access
    Provide file system access rule (Ex: Allow or Deny)
 
    .EXAMPLE
    Set-FilePermissions -File "C:\windows\web\Wallpaper\Windows\img0.jpg" -User Users -Control FullControl -Access Allow
 
    .EXAMPLE
    Set-FilePermissions -File "C:\windows\web\Wallpaper\Windows\img0.jpg" -User Administrators -Control ReadAndExecute -Access Allow
    #>
    param (
     [parameter(Mandatory=$true)]
     [ValidateNotNullOrEmpty()]$File,
     [parameter(Mandatory=$true)]
     [ValidateNotNullOrEmpty()]$User,
     [parameter(Mandatory=$true)]
     [ValidateNotNullOrEmpty()]$Control,
     [parameter(Mandatory=$true)]
     [ValidateNotNullOrEmpty()]$Access
    )

    $ACL = Get-ACL "$File"
    Set-Acl -Path "$File" -AclObject $ACL
    $Permission = New-Object  system.security.accesscontrol.filesystemaccessrule("$User","$Control","$Access")
    $Acl.SetAccessRule($Permission)
    Set-Acl -Path "$File" -AclObject $ACL

}

How to run a post script after a Windows 10 feature upgrade with SetupConfig.ini

If you are planning on upgrading your Windows 10 OS from 1607 to 1703 you may have noticed that a few apps have reappeared. Luckily for us, Microsoft has provided a way to add parameters to upgrades with the SetupConfig.ini file.

For example, you can create a Setupconfig.ini with the following:
Note that the header [SetupConfig] is required.

[SetupConfig]
NoReboot
ShowOobe=None
Telemetry=Enable

This is equivalent to the following command line:

Setup.exe /NoReboot /ShowOobe None /Telemetry Enable

How does the upgrade use the SetupConfig.ini file?
If the update is delivered through Windows Update, Windows Setup searches in a default location for a setupconfig file. You can include the setupconfig file here:
“%systemdrive%\Users\Default\AppData\Local\Microsoft\Windows\WSUS\SetupConfig.ini”

How do you run a post script?
You can easily add a post script by adding the PostOOBE parameter to the SetupConfig file as shown below:

[SetupConfig]
PostOOBE=C:\SetupComplete.cmd

How do you run a Powershell script?
The only way that I have been able to run a Powershell script is by running it from the .cmd file that I have called using the PostOOBE parameter.

Inside of the cmd file, you would have to add the following command to launch a Powershell script:

Powershell.exe -ExecutionPolicy Unrestricted -File "C:\Scripts\Remove-Apps-1703.ps1" -WindowStyle Hidden

I hope this post helps you understand the power of this ini file. Feel free to leave any questions in the comments and stay tuned for the cleanup script that I am currently working on!

How to remove the Contact Support app in Windows 10 1607 and above

The Contact Support app can now officially be removed but the process is a little different than how you would normally remove a Windows app with Powershell. Luckily it isn’t too difficult and it can be done with a one liner!

Get-WindowsCapability -online | ? {$_.Name -like ‘*ContactSupport*’} | Remove-WindowsCapability –online

How to silently install LexisNexis InterAction 6.21.21

I recently had some issues specifying server data for my LexisNexis Interaction silent install. For some reason, the server information that I used was not applying during the install. After a few failed attempts, I decided to review the MSIEXEC logs and found the following lines:

Action start 15:13:52: SetDataDirDef.
MSI (s) (F0:68) [15:13:52:542]: Doing action: SetDBServerSRCH
Action ended 15:13:52: SetDataDirDef. Return value 1.
MSI (s) (F0:68) [15:13:52:542]: Transforming table CustomAction.

MSI (s) (F0:68) [15:13:52:542]: PROPERTY CHANGE: Deleting IADBSERVER property. Its current value is ‘SQLSERVER’.

According to the logs, it looks like the server information that I added was getting deleted because of the SetDBServerSRCH action.

Now that I found what was causing the server information to be removed, I decide to review the InterAction MSI table and search for the SetDBServerSRCH action. Once I found the action, I was able to locate the condition that was forcing the action to run.
Condtion:
IANETINSTALL=0 and UILevel<5
Conditions

After a few tests, I verified that you can specify server information if you make the condition false. So all you have to do is add the following to your MSIEXEC command:
IANETINSTALL=2

And for anyone lazy enough to not read everything, here is the entire silent install command for InterAction.
MSIEXEC /I InterAction Desktop Applications.msi IADBSERVER=”DB SERVER” IADBNAME=”DB NAME” IAPORT=”PORT HERE” NETAPPSERVER=”APPSERVER” IANETINSTALL=2 /qn

I hope this helps someone!

Test-RegValue Function

Powershell has a great CMDLET called Test-Path that can check to see if a registry key exists but unfortunately it does not have the ability to check for registry values. In order to get around this, I created the following function to check to see if a registry value exists. This can be extremely useful when you are using a registry key to verify if a script has already executed in the past.

Examples:
Test-RegValue -Key “HKCU:\Control Panel\Desktop” -Value WallPaper
Test-RegValue -Key “HKLM:\SOFTWARE\Custom” -Value Test

Function Test-RegValue {
    <#
    .SYNOPSIS
    Determine if a registry value exists

    .PARAMETER Key
    Provide registry key path

    .PARAMETER Value
    Provide registry value that you would like to test

    .EXAMPLE
    Test-RegValue -Key "HKCU:\Control Panel\Desktop" -Value WallPaper

    .EXAMPLE
    Test-RegValue -Key "HKLM:\SOFTWARE\Custom" -Value Test
    #>
    param (
     [parameter(Mandatory=$true)]
     [ValidateNotNullOrEmpty()]$Value,
     [parameter(Mandatory=$true)]
     [ValidateNotNullOrEmpty()]$Key
    )

    
    Try {
        Get-ItemProperty "$Key" -ErrorAction Stop| Select-Object -ExpandProperty $Value -ErrorAction Stop | Out-Null
        Return $True
    }
    Catch [System.Management.Automation.ItemNotFoundException] {
        Write-Host "Please verify the registry key exists" -ForegroundColor Red 
        Return $False
    }
    Catch {
        Return $False
    }
}

Read more

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)


<#  

.SYNOPSIS  
    Run a report to find who is in Outlook Cache Mode

.NOTES  
    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 = [system.security.principal.securityidentIfier]$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!

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.

<#  

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

.NOTES  
    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) { 
            10.101.1.1 {"Orlando"} 
            10.102.1.1 {"Miami"} 
            10.103.1.1 {"Atlanta"} 
            10.104.1.1 {"New York City"}
            10.105.1.1 {"Denver"}
            10.106.1.1 {"Austin"}
            10.107.1.1 {"Los Angeles"}
            10.108.1.1 {"Las Vegas"}
            10.109.1.1 {"Seattle"} 
    }

    # 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

    }
}

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:
$Group = YOUR AD GROUP
$Shortcut = “THE SHORTCUT NAME WITH THE EXTENSION”
$Location = “THE SHORTCUT’S LOCATION”

# Variables that need to be set
$Group = "YOUR AD GROUP HERE"
$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")
    $file.InvokeVerb('pintostartscreen')  
}

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:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\sk\Parameters.

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
Older Posts »
Page 1 of 5