30 November 2015

Local Administrator Report

The firm I work at does not give users local administrator access for several reasons. We did an audit of our systems and found out several users had local administrator privileges that should not have. In order to keep track of all systems all of the time, I wrote the following two PowerShell scripts to report systems in which a user is part of the administrators group.

This is a two step process, using SCCM Application deployment. The first step is to use a custom detection method written in PowerShell. The detection script queries the local administrator group of the system it is being executed on. It excludes members in the $MemberExclusions and systems in the $SystemExclusions arrays. I hard coded the exclusions in the detection script so that I can go right in there and directly add users and systems as needed. When you add a system to the application detection method, you also need to add the system to the exclusions.txt file. If there are no users in the administrators group, then the application detection script will return an "installed" status back to SCCM. If there are additional users in the group, besides the excluded, then the script will return a "not installed" message back to SCCM.

The only portion of the LocalAdministratorsDetection.ps1 file you need to modify are lines 19, 26, and 27. 

When a "not installed" message is returned back, which is an exit code 0, SCCM will now execute the LocalAdministrators.ps1 script to "install" the application. I wanted to have emails generated when this script executes, so I had to find a way to execute the script with a domain account, instead of the normal system account. This was achieved by placing a copy of psexec.exe in the same folder as the localadministrators.ps1 file exists. Now the way to set this up is to create a normal application deployment in SCCM 2012. As you setup the deployment types, under the Programs tab, you will need to use the following command line:

psexec.exe \\%COMPUTERNAME% -u <domain>\<domain account> -p <password> -h cmd.exe /c "echo . | powershell.exe -executionpolicy bypass -file \\<Directory>\LocalAdministrators.ps1"

The only parts of the psexec.exe command line you need to customize for your environment will be those highlighted in bold. This command line executes the powershell script using the specified domain account. The %COMPUTERNAME% grabs the computer name of the system it is being executed on.

The LocalAdministrators.ps1 script will now get a list of all users in the administrators group that are not excluded in the exclusions.txt file, which also exists in the same directory as the .ps1 file. You will need to create a file called EmailAddresses.txt, which will have a list of email addresses that you want to be emailed a report. You also need to create an exclusions.txt file. This will have a list of systems to exclude from the query. The only parts of the localadministrators.ps1 file you need to customize are Lines 27, 28, 77, and 83. At the end of the script, it will send out an email to all addresses in the EmailAddresses.txt file. Finally, it renames the file LocalAdministrators.log to LocalAdministrators_Emailed.log. When the application detection is rerun, it will see the _Emailed in the filename and return a success if there are extra users in the local administrator group. If there are no extra users in the group and that file exists, then the application detection method will delete the .log file. 

You can download the LocalAdministrators.ps1 script from here.
You can download the LocalAdministratorsDetection.ps1 script from here.

1:  <#       
2:       .NOTES  
3:       ===========================================================================  
4:        Created with:      SAPIEN Technologies, Inc., PowerShell Studio 2015 v4.2.98  
5:        Created on:       11/23/2015 1:14 PM  
6:        Created by:       Mick Pletcher  
7:        Organization:         
8:        Filename:        LocalAdministrators.ps1  
9:       ===========================================================================  
10:       .DESCRIPTION  
11:            This script will open query the local administrators group. It generates  
12:            a log file if there are users in the local administrators group that are  
13:            not in the exclusions group. A .log file is written to the local HDD. The  
14:            script then returns a error code 0 back to SCCM, which will initiate a   
15:            software deployment. At that point, the secondary script will email  
16:            the .log file to the appropriate users. That script then deletes the  
17:            .log file which will then create a successful   
18:  #>  
20:  #Declare Global Variables  
21:  Set-Variable -Name Body -Force  
22:  Set-Variable -Name EmailAddress -Force  
23:  Set-Variable -Name EmailAddresses -Force  
24:  Set-Variable -Name Exclusions -Force  
25:  Set-Variable -Name LocalAdmin -Force  
26:  Set-Variable -Name LocalAdmins -Force  
27:  Set-Variable -Name LogFile -Value $env:windir"\Logs\LocalAdministrators.log" -Force  
28:  Set-Variable -Name LogFileEmailed -Value $env:windir"\Logs\LocalAdministrators_Emailed.log" -Force  
29:  Set-Variable -Name Member -Force  
30:  Set-Variable -Name Members -Force  
31:  Set-Variable -Name Output -Force  
32:  Set-Variable -Name Prof -Force  
33:  Set-Variable -Name Profiles -Force  
34:  Set-Variable -Name RelativePath -Force  
36:  cls  
37:  $RelativePath = (split-path $SCRIPT:MyInvocation.MyCommand.Path -parent) + "\"  
38:  $Body = "Local Administrator(s)" + [char]13 + "---------------------------" + [char]13  
39:  $EmailAddresses = @()  
40:  $EmailAddresses = Get-Content -Path $RelativePath"EmailAddresses.txt"  
41:  $LocalAdmins = @()  
42:  $Members = net localgroup administrators | where { $_ -AND $_ -notmatch "command completed successfully" } | select -skip 4  
43:  $Profiles = Get-ChildItem -Path $env:SystemDrive"\users" -Force  
44:  $Exclusions = Get-Content -Path $RelativePath"Exclusions.txt"  
45:  Foreach ($Member in $Members) {  
46:       $Member = $Member.Split("\")  
47:       If ($Member.Count -gt 1) {  
48:            [string]$Member = $Member[1]  
49:            If ($Member -notin $Exclusions) {  
50:                 Foreach ($Prof in $Profiles) {  
51:                      If ($Member -eq $Prof) {  
52:                           $LocalAdmins += $Member  
53:                      }  
54:                 }  
55:            }  
56:       }  
57:       Remove-Variable -Name Member  
58:  }  
59:  if ((Test-Path $LogFileEmailed) -eq $true) {  
60:       Remove-Item -Path $LogFileEmailed -Force  
61:  }  
62:  if ((Test-Path $LogFile) -eq $true) {  
63:       Remove-Item -Path $LogFile -Force  
64:  }  
65:  if ($LocalAdmins.Count -gt 0) {  
66:       if ((Test-Path $LogFile) -eq $false) {  
67:            New-Item -Path $LogFile -ItemType file -Force  
68:       }  
69:       foreach ($LocalAdmin in $LocalAdmins) {  
70:            Add-Content -Path $LogFile -Value $LocalAdmin -Force  
71:            $Body = $Body + $LocalAdmin + [char]13  
72:       }  
73:  }  
74:  If ($LocalAdmins.count -eq 1) {  
75:       $Output = $LocalAdmin + [char]32 + "is a local administrator on" + [char]32 + $env:COMPUTERNAME  
76:       foreach ($EmailAddress in $EmailAddresses) {  
77:            Send-MailMessage -To $EmailAddress -From "IT@acme.com" -Subject "Local Administrator Report" -Body $Output -SmtpServer "smtp.acme.com"  
78:       }  
79:       Rename-Item -Path $LogFile -NewName $LogFileEmailed -Force  
80:  } else {  
81:       $Output = "The attached file lists all local administrators on" + [char]32 + $env:COMPUTERNAME  
82:       foreach ($EmailAddress in $EmailAddresses) {  
83:            Send-MailMessage -To $EmailAddress -From "IT@acme.com" -Subject "Local Administrator Report" -Body $Output -Attachments $LogFile -SmtpServer "smtp.acme.com"  
84:       }  
85:       Rename-Item -Path $LogFile -NewName $LogFileEmailed -Force  
86:  }  
87:  $LocalAdmins = $null  
89:  #Cleanup Global Variables  
90:  Remove-Variable -Name Body -Force  
91:  Remove-Variable -Name EmailAddress -Force  
92:  Remove-Variable -Name EmailAddresses -Force  
93:  Remove-Variable -Name Exclusions -Force  
94:  Remove-Variable -Name LocalAdmin -Force  
95:  Remove-Variable -Name LocalAdmins -Force  
96:  Remove-Variable -Name LogFile -Force  
97:  Remove-Variable -Name LogFileEmailed -Force  
98:  Remove-Variable -Name Members -Force  
99:  Remove-Variable -Name Output -Force  
100:  Remove-Variable -Name Prof -Force  
101:  Remove-Variable -Name Profiles -Force  

1:  <#       
2:       .NOTES  
3:       ===========================================================================  
4:        Created with:      SAPIEN Technologies, Inc., PowerShell Studio 2015 v4.2.98  
5:        Created on:       11/23/2015 1:14 PM  
6:        Created by:       Mick Pletcher  
7:        Organization:         
8:        Filename:        LocalAdministratorsDetectionMethod.ps1  
9:       ===========================================================================  
10:       .DESCRIPTION  
11:            This script will query the local administrators group. It will return a  
12:            success to SCCM if there are no members in the local administrators   
13:            group or if a system is in the SystemExclusions array or a user is   
14:            in the MemberExclusions variable.   
15:  #>  
17:  #Declare Global Variables  
18:  Set-Variable -Name LocalAdmins -Force  
19:  Set-Variable -Name LogFile -Value $env:windir"\Logs\LocalAdministrators_Emailed.log" -Force  
20:  Set-Variable -Name Member -Force  
21:  Set-Variable -Name MemberExclusions -Force  
22:  Set-Variable -Name Members -Force  
23:  Set-Variable -Name SystemExclusions -Force  
25:  cls  
26:  $MemberExclusions = @("Domain Admins","Workstation Admins")  
27:  $SystemExclusions = @("SYSTEM01")  
28:  $LocalAdmins = @()  
29:  $Members = net localgroup administrators | where { $_ -AND $_ -notmatch "command completed successfully" } | select -skip 4  
30:  $Profiles = Get-ChildItem -Path $env:SystemDrive"\users" -Force  
31:  Foreach ($Member in $Members) {  
32:       $Member = $Member.Split("\")  
33:       If ($Member.Count -gt 1) {  
34:            [string]$Member = $Member[1]  
35:            If ($Member -notin $MemberExclusions) {  
36:                 $LocalAdmins += $Member  
37:            }  
38:       }  
39:       Remove-Variable -Name Member  
40:  }  
41:  if (($LocalAdmins.Count -eq 0) -and ((Test-Path -Path $LogFile) -eq $true)) {  
42:       Remove-Item -Path $LogFile -Force  
43:  }  
44:  if (($LocalAdmins.Count -gt 0) -and ($env:COMPUTERNAME -notin $SystemExclusions) -and ((Test-Path -Path $LogFile) -eq $false )) {  
45:       Start-Sleep -Seconds 5  
46:       exit 0  
47:  } else {  
48:       Write-Host "No Local Administrators"  
49:       Start-Sleep -Seconds 5  
50:       exit 0  
51:  }  
52:  $LocalAdmins = $null  
54:  #Cleanup Global Variables  
55:  Remove-Variable -Name LocalAdmins -Force  
56:  Remove-Variable -Name LogFile -Force  
57:  Remove-Variable -Name Member -Force  
58:  Remove-Variable -Name MemberExclusions -Force  
59:  Remove-Variable -Name Members -Force  
60:  Remove-Variable -Name SystemExclusions -Force  

20 November 2015

Automating Microsoft Endpoint Full System Scan upon Infection

While helping to manage Microsoft Endpoint, a former colleague suggested that I setup Endpoint to automatically run a full system scan each time an infection is detected. I googled the blog posting on it and although it is a great post, I figured I could streamline it even more by just using SCCM alone to achieve the same outcome. It is nice when you are out of the office and your backup might not have the time to keep an eye on the antivirus infections.

I decided to use the SCCM custom application detection to scan a system and see if a full system scan has been performed. I first started out by writing a powershell script that would perform a WMI query on the SCCM server for the status of the system the application detection was being run on. The problem I ran across was that the application is being run under system credentials, which would require me to pass network credentials within the script. Instead of having to do this, I decided to query the event viewer logs on the local machine to look for the last infection date/time, which is event 1116. I queried all machines in my firm to find another event log that was unused, and 1118 happened to be just the one.

Here is how the process works:
  1. SCCM deploys the package to the system.
  2. The application detection queries the event viewer logs for the last 1116 ID (infection).
  3. The application detection queries the event viewer logs for the last 1118 ID.
  4. If a system 1118 ID  does not exist since the last infection, or there is no 1116 ID detected, the custom detection method will exit out as a failure.
  5. If the custom detection failed, the antivirusscan.ps1 file will be executed on the machine.
  6. Once the scan is complete, a machine policy update is initiated to update the SCCM server with the status of the system.
  7. The application detection is initiated again to confirm the scan occurred. 

This is setup in SCCM as a normal application deployment. The only thing that differs from a standard deployment is the application detection method. That script is imported in for the detection method. The antivirusscan.ps1 file is setup as the installation program. I have mine entered like this:
powershell.exe -executionpolicy bypass -file antivirusscan.ps1

One more thing is that I have the application hidden from the software center. There really isn't a need for it to be there. 
Click here to download the Application Virus Detection Method.
Click here to download the Antivirus Scan script.

Antivirus Scan Script
1:  <#       
2:       .NOTES  
3:       ===========================================================================  
4:        Created with:      SAPIEN Technologies, Inc., PowerShell Studio 2015 v4.2.98  
5:        Created on:       11/19/2015 3:26 PM  
6:        Created by:       Mick Pletcher  
7:        Filename:        AntiVirusScan.ps1  
8:       ===========================================================================  
9:       .DESCRIPTION  
10:            This script will initiate a full or quick scan, whichever one is uncommented  
11:            out below. It will then write a log to the event viewer logs showing the   
12:            scan was executed. The final step is to execute a machine policy update so  
13:            the SCCM server is updated on the status of the system.  
14:  #>  
16:  Import-Module $env:ProgramFiles"\Microsoft Security Client\MpProvider"  
17:  <#Full Scan#>  
18:  Start-MProtScan -ScanType "FullScan"  
19:  New-EventLog –LogName System –Source "Antimalware Full Scan"  
20:  Write-EventLog -LogName System -Source "Antimalware Full Scan" -EntryType Information -EventId 1118 -Message "Antimalware full system scan was performed" -Category ""  
22:  <#Quick Scan  
23:  Start-MProtScan -ScanType "QuickScan"  
24:  New-EventLog –LogName System –Source "Antimalware Quick Scan"  
25:  Write-EventLog -LogName System -Source "Antimalware Quick Scan" -EntryType Information -EventId 1118 -Message "Antimalware quick system scan was performed" -Category ""  
26:  #>  
28:  $WMIPath = "\\" + $env:COMPUTERNAME + "\root\ccm:SMS_Client"  
29:  $SMSwmi = [wmiclass]$WMIPath  
30:  $strAction = "{00000000-0000-0000-0000-000000000021}"  
31:  [Void]$SMSwmi.TriggerSchedule($strAction)  
32:  Exit 0  

Application Virus Detection Method
1:  $LastInfection = get-winevent -filterhashtable @{ logname = 'system'; ID = 1116 } -maxevents 1 -ErrorAction SilentlyContinue  
2:  $LastFullScan = get-winevent -filterhashtable @{ logname = 'system'; ID = 1118 } -maxevents 1 -ErrorAction SilentlyContinue  
3:  If (($LastFullScan.TimeCreated -lt $LastInfection.TimeCreated) -or ($LastInfection -eq $null)) {  
4:       Start-Sleep -Seconds 5  
5:       exit 0  
6:  } else {  
7:       Write-Host "No Infection"  
8:       Start-Sleep -Seconds 5  
9:       exit 0  
10:  }  

05 November 2015

Deploying Microsoft Endpoint

I recently converted my firm to Microsoft Endpoint. Part of the process is including endpoint in the golden image. I wrote this powershell script that will install endpoint and then remove the necessary registry keys so it will set itself back up when the reference image is laid down on a new machine. The script also allows you to visually see if the application is installed correctly by returning a success/failure by checking to see if MsMpEng.exe is running. You may wonder why I have an uninstall first. I do this in all of my installation scripts in the event something is wrong with the currently installed app and it needs to be reinstalled. You can easily comment out that line if you do not want that to occur.

I execute this script using psexec so that it is run under the local system context. I use the following:
psexec.exe \\%computername% -s -h cmd.exe /c "echo . | powershell.exe -executionpolicy bypass -file install_build.ps1"

You can download the script from here.

1:  <#       
2:       .NOTES  
3:       ===========================================================================  
4:        Created with:      SAPIEN Technologies, Inc., PowerShell Studio 2015 v4.2.98  
5:        Created on:       05 November 2015 10:37 AM  
6:        Created by:       Mick Pletcher  
7:        Organization:        
8:        Filename:        installEndPoint_build.ps1  
9:       ===========================================================================  
10:       .DESCRIPTION  
11:            Install endpoint during the generation of a golden image. This will  
12:            also remove all necessary registry keys required in preparation of   
13:            generating a golden image.  
14:  #>  
16:  #Declare Global Memory  
17:  $Global:RelativePath = (split-path $SCRIPT:MyInvocation.MyCommand.Path -parent) + "\"  
19:  Function Wait-ProcessEnd {  
20:       <#  
21:       .SYNOPSIS  
22:            Wait-Process  
23:       .DESCRIPTION  
24:            Waits for a Process to end before continuing.  
25:       #>  
27:       Param ([String]$Process)  
28:       $Proc = Get-Process $Process -ErrorAction SilentlyContinue  
29:       If ($Proc -ne $null) {  
30:            Do {  
31:                 Start-Sleep -Seconds 5  
32:                 $Proc = Get-Process $Process -ErrorAction SilentlyContinue  
33:            } While ($Proc -ne $null)  
34:       }  
35:  }  
37:  Function Install-EXE {  
38:       <#  
39:       .SYNOPSIS  
40:            Install-EXE  
41:       .DESCRIPTION  
42:            Installs an EXE file  
43:       #>  
45:       Param ([String]$DisplayName,  
46:            [String]$Executable,  
47:            [String]$Switches)  
48:       Write-Host "Install"$DisplayName"....." -NoNewline  
49:       If ((Test-Path $Executable) -eq $true) {  
50:            Start-Process -FilePath $Executable -ArgumentList $Switches  
51:            Wait-ProcessEnd -Process "scepinstall"  
52:       } else {  
53:            $ErrCode = 1  
54:       }  
55:       $Process = Get-Process -ProcessName MsMpEng -ErrorAction SilentlyContinue  
56:       If ($Process.ProcessName -eq "MsMpEng") {  
57:            Write-Host "Success" -ForegroundColor Yellow  
58:       } else {  
59:            Write-Host "Failed" -ForegroundColor Red  
60:       }  
61:  }  
63:  Function Uninstall-EXE {  
64:       <#  
65:       .SYNOPSIS  
66:            Uninstall-EXE  
67:       .DESCRIPTION  
68:            Uninstalls an EXE file  
69:       #>  
71:       Param ([String]$DisplayName,  
72:            [String]$Executable,  
73:            [String]$Switches)  
74:       Write-Host "Uninstall"$DisplayName"....." -NoNewline  
75:       If ((Test-Path $Executable) -eq $true) {  
76:            Start-Process -FilePath $Executable -ArgumentList $Switches  
77:            Wait-ProcessEnd -Process "scepinstall"  
78:       }  
79:       $Process = Get-Process -ProcessName MsMpEng -ErrorAction SilentlyContinue  
80:       If ($Process -eq $null) {  
81:            Write-Host "Success" -ForegroundColor Yellow  
82:       } else {  
83:            Write-Host "Failed" -ForegroundColor Red  
84:       }  
85:  }  
87:  Function Remove-RegistryValue {  
88:       <#  
89:       .SYNOPSIS  
90:            Remove-RegistryValue  
91:       .DESCRIPTION  
92:            Deletes a specific registry value  
93:       .EXAMPLE  
94:            Remove-RegistryValue "HKEY_LOCAL_MACHINE\SOFTWARE\Hummingbird"  
95:       #>  
97:       Param ([String]$RegistryKey,  
98:            [String]$Value)  
99:       $tempdrive = New-PSDrive -Name HKCR -PSProvider Registry -Root HKEY_CLASSES_ROOT  
100:       $RegistryKey1 = $RegistryKey.split("\")  
101:       switch ($RegistryKey1[0]) {  
102:            "HKEY_CLASSES_ROOT" { $RegistryKey1[0] = "HKCR" }  
103:            "HKEY_CURRENT_USER" { $RegistryKey1[0] = "HKCU" }  
104:            "HKEY_LOCAL_MACHINE" { $RegistryKey1[0] = "HKLM" }  
105:            "HKEY_USERS" { $RegistryKey1[0] = "HKU" }  
106:            "HKEY_CURRENT_CONFIG" { $RegistryKey1[0] = "HKCC" }  
107:       }  
108:       For ($i = 0; $i -lt $RegistryKey1.Count; $i++) {  
109:            $RegKey = $RegKey + $RegistryKey1[$i]  
110:            If ($i -eq 0) {  
111:                 $RegKey = $RegKey + ":\"  
112:            } elseif ($i -ne $RegistryKey1.Count - 1) {  
113:                 $RegKey = $RegKey + "\"  
114:            } else {  
115:                 $RegKey = $RegKey  
116:            }  
117:       }  
118:       Write-Host "Delete"$RegKey"\"$Value"....." -NoNewline  
119:       $exists = Get-ItemProperty -Path $RegKey -Name $Value -ErrorAction SilentlyContinue  
120:       If (($exists -ne $null) -and ($exists.Length -ne 0)) {  
121:            Remove-ItemProperty -Path $RegKey -Name $Value -Force  
122:       }  
123:       $exists = Get-ItemProperty -Path $RegKey -Name $Value -ErrorAction SilentlyContinue  
124:       If ($exists -eq $null) {  
125:            Write-Host "Success" -ForegroundColor Yellow  
126:       } else {  
127:            Write-Host "Failed" -ForegroundColor Yellow  
128:       }  
129:  }  
131:  cls  
132:  Uninstall-EXE -DisplayName "Microsoft Endpoint" -Executable $global:RelativePath"scepinstall.exe" -Switches "/u /s"  
133:  $Parameters = "/s /policy " + $global:RelativePath + "EndpointPolicies.xml"  
134:  Install-EXE -DisplayName "Microsoft Endpoint" -Executable $global:RelativePath"scepinstall.exe" -Switches $Parameters  
135:  Remove-RegistryValue -RegistryKey "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft Antimalware" -Value "InstallTime"  
136:  Remove-RegistryValue -RegistryKey "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft Antimalware\Scan" -Value "LastScanRun"  
137:  Remove-RegistryValue -RegistryKey "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft Antimalware\Scan" -Value "LastScanType"  
138:  Remove-RegistryValue -RegistryKey "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft Antimalware\Scan" -Value "LastQuickScanID"  
139:  Remove-RegistryValue -RegistryKey "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft Antimalware\Scan" -Value "LastFullScanID"  
140:  Remove-RegistryValue -RegistryKey "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\RemovalTools\MRT" -Value "GUID"  

04 November 2015

.Net Framework 4.5.x Error 0x80004005

Recently, I had to deploy .Net Framework 4.5.2 to all systems, as it was a requirement for a software update. I first deployed it through software updates in SCCM 2012. The status showed up as compliant. I thought nothing more of it. I went to deploy the application and it failed on many machines. SCCM was reporting back false data, which is part of my other blog posting. I had verified the powershell script I had written to install the app was working when running it from the software center and/or a command line. I was perplexed. I then kicked off an install after rebooting a machine through a machine policy update from the SCCM console. It stuck on the NDP452-KB2901907-x86-x64-AllOS-ENU.exe execution. I finally found the log file for this located at c:\windows\temp\dd_NDP452-KB2901907-x86-x64-AllOS-ENU_decompression_log.txt. In the log were these last three lines:

[11/4/2015, 14:4:24] Extracting files to: C:\4ace42dcab1cf4386b698f\
[11/4/2015, 14:4:24] Error 0x80004005: Failed to extract all files out of box container #0.
[11/4/2015, 14:4:24] Error 0x80004005: Failed to extract

I then tried another step by checking off the Run installation and uninstall program as 32-bit process on 64-bit clients. This did no good. Since it would successfully execute from a command line and/or manual execution through software center, I decided to add it as package and run it directly from the network share instead of a distribution point. This worked. It is now installing with no problems. When creating the package, there will be no source files. Instead, you will put the network share of where the installation files exist in the Start in field. This should allow you to now install 4.5.2. 

03 November 2015

Packaging EverMap Redaction for Adobe Acrobat XI

To easily deploy Redaction for Adobe Acrobat XI, I created an MSI file using the AppDeploy Repackager. There are a total of 8 files it packages up. My firm has an enterprise license, which gets written to the AutoRedact.LIC file. To properly package this up, you can download the attached XML file I have made available that will generate the MSI using AppDeploy Repackager. You will need to install the EverMap application using your enterprise key on the same machine as Adobe Acrobat Standard XI and the repackager are installed on.

Another thing you can do is to pre-configure the preferences in the Redacting plugin. To do this, open Acrobat up, click Plug-Ins-->Redacting-->Preferences. Make whatever changes that are needed for all users. Click the Exemption Codes tab. Click Create New. You can lable the Group Title anything you prefer. I left it at Default. Click Add Code. I used REDACTED under Use this code for redacting. In the description field, I used Redaction. Click OK. Click OK. Click OK. This will create three CFS files located %APPDATA%\EverMap\AutoRedact. Create a GPO that will push these three files out to all systems with the Redaction app installed using a user policy. I limited this in the GPO via MSI GUID.

You can download the XML from here.

Here is what the XML looks like. The unins000.xxx files are forced to be created by AppDeploy.

 <?xml version="1.0" encoding="UTF-16"?>  
      <ProjectFile Version="1.1">  
      <Repackager Version="1.2">  
           <ProductInformation ApplicationName="AutoRedact Plug-In" Version="" CompanyName="EverMap Company, LLC.">  
                     <Directory Name="%PROGRAMFILES%\Adobe\Acrobat 11.0\Acrobat\plug_ins\AutoRedact">  
                          <File Name="unins000.exe">  
                          <File Name="unins000.dat">  
                          <File Name="LanguageTable.lan">  
                          <File Name="AutoRedactManual.pdf">  
                          <File Name="AutoRedactIntro.pdf">  
                          <File Name="AutoRedact.api">  
                          <File Name="AutoRedact.LIC">  
                          <File Name="AUTOREDACT_RegExp.txt">  
                          <File Name="AUTOREDACTDict.CFS">  
                          <File Name="AUTOREDACTCodes.CFS">  
                     <File Name="%PROGRAMFILES%\AppDeploy\Repackager\AppDeployRepackager.ini">  
                          <Section Name="SnapshotDetails" Key="IsSnapshotTaken" Value="1">  
           <Shortcut Name="unins000" ExeName="unins000.exe" Directory="ProgramMenuFolder" Icon="%PROGRAMFILES%\Adobe\Acrobat 11.0\Acrobat\plug_ins\AutoRedact\unins000.exe" IconIndex="0">