20 February 2017

Cisco Jabber Conversation Secure Delete Cleanup

Here is a script that will delete Cisco Jabber conversations. If you are in an environment where you do not want these conversations to be saved and recoverable, this tool with taking care of it.

I wrote this tool so that it will kill the CiscoJabber process first and then deletes the appropriate file that stores the conversation. It will then restart Jabber. We set this up to execute when a user logs on and logs off. We have the script setup to make three passes of deletion.

We chose to use SDelete after reading this article on how much better SDelete is at cleaning up files on both SSD and HDD drives. You can download SDelete from here. The script is set up to execute SDelete.exe when it resides in the same location as the script.

Here is a video I took of the script executing. You can see the script closes jabber, deletes the associated .DB file, and then reopens Jabber. It must shut down Jabber to unlock the .DB file for deletion.



I have included examples of executing the script in the script documentation. As you can see in the script, I have set the SecureDeletePasses to 3, which can either be changed or overridden by defining it in the parameter at the time the script is executed.

UPDATE 1:

I came back and updated this script so that it will now parse through all user profiles and securely delete the appropriate files. Another change made is with the sdelete.exe file. A GPO is now used to do the following:

  • Push the sdelete.exe or sdelete64.exe file to all systems in the %WINDIR%\System32 directory. I use a GPO to push this file to the %Windir%\System32 directory so that it is available everywhere on the system in the event I want to do a secure delete on anything else.
  • Push the .PS1 script to the designated directory on the computer so it can be executed locally without network connectivity. I also use the same GPO to push this file down. 
  • Create a scheduled task to execute the .PS1 file on the system at the designated interval. This is also created by a GPO.
You can download the script from my GitHub site located here.

UPDATE 2:

I updated this script to function as a one-liner in case you want to run this as the end-user at logon, logoff, etc, which is what I have ended up doing. I also split this off into two one-liners. One is for a secured delete using sdelete64.exe and the other uses Remove-Item.

Secured Delete One-Liner:
 powershell.exe -command "&{$Deletes='3';Get-Process -Name CiscoJabber -ErrorAction SilentlyContinue | Stop-Process;Do {$Process = Get-Process -Name CiscoJabber -ErrorAction SilentlyContinue} While ($Process -ne $null);Get-childItem -Path $Env:LOCALAPPDATA'\Cisco\Unified Communications\Jabber\CSF\History' -Filter *.db | ForEach-Object {$arguments='-accepteula'+[char]32+'-p'+[char]32+$Deletes+[char]32+[char]34+$_.FullName+[char]34;Start-Process -FilePath $env:windir'\System32\sdelete64.exe' -ArgumentList $Arguments -WindowStyle Hidden};Get-Item -Path $env:USERPROFILE'\Documents\MyJabberFiles' -ErrorAction SilentlyContinue | Where-Object {$arguments='-accepteula'+[char]32+'-p'+[char]32+$Deletes+[char]32+[char]34+$_.FullName+[char]34;Start-Process -FilePath $env:windir'\System32\sdelete64.exe' -ArgumentList $Arguments -WindowStyle Hidden};Start-Process -FilePath (Get-ChildItem -Path $env:ProgramFiles,${env:ProgramFiles(x86)} -Filter CiscoJabber.exe -Recurse -ErrorAction SilentlyContinue).FullName}"  

Unsecured Delete One-Liner
 powershell.exe -command "&{Get-Process -Name CiscoJabber -ErrorAction SilentlyContinue | Stop-Process;Do {$Process = Get-Process -Name CiscoJabber -ErrorAction SilentlyContinue} While ($Process -ne $null);Get-childItem -Path $Env:LOCALAPPDATA'\Cisco\Unified Communications\Jabber\CSF\History' -Filter *.db | ForEach-Object { Remove-Item -Path $_.FullName -Force };Get-Item -Path $env:USERPROFILE'\Documents\MyJabberFiles' -ErrorAction SilentlyContinue | Remove-Item -Recurse -Force;Start-Process -FilePath (Get-ChildItem -Path $env:ProgramFiles,${env:ProgramFiles(x86)} -Filter CiscoJabber.exe -Recurse -ErrorAction SilentlyContinue).FullName}"  


Main Script:
 <#  
      .SYNOPSIS  
           Delete Cisco Jabber Chat History  
        
      .DESCRIPTION  
           Deletes the files and folder that contain the Cisco Jabber chat history  
        
      .PARAMETER SecureDelete  
           Implement Secure Deletion of files and folders  
        
      .PARAMETER SecureDeletePasses  
           Number of secure delete passes  
        
      .EXAMPLE  
           Delete Cisco Jabber chat without secure delete  
                powershell.exe -file CiscoJabberChatCleanup.ps1  
   
           Delete Cisco Jabber chate with secure delete  
                powershell.exe -file CiscoJabberChatCleanup.ps1 -SecureDelete -SecureDeletePasses 3  
   
      .NOTES  
           ===========================================================================  
           Created with:      SAPIEN Technologies, Inc., PowerShell Studio 2016 v5.3.131  
           Created on:       12/13/2016 12:20 PM  
           Updated on:     12/27/2018 3:34 PM  
           Created by:       Mick Pletcher  
           Filename:          CiscoJabberChatCleanup.ps1  
           ===========================================================================  
 #>  
 [CmdletBinding()]  
 param  
 (  
      [switch]$SecureDelete,  
      [string]$SecureDeletePasses = '3'  
 )  
   
 function Close-Process {  
 <#  
      .SYNOPSIS  
           Stop ProcessName  
        
      .DESCRIPTION  
           Kills a ProcessName and verifies it was stopped while reporting it back to the screen.  
        
      .PARAMETER ProcessName  
           Name of ProcessName to kill  
        
      .EXAMPLE  
           PS C:\> Close-ProcessName -ProcessName 'Value1'  
        
      .NOTES  
           Additional information about the function.  
 #>  
        
      [CmdletBinding()][OutputType([boolean])]  
      param  
      (  
           [ValidateNotNullOrEmpty()][string]$ProcessName  
      )  
        
      $Process = Get-Process -Name $ProcessName -ErrorAction SilentlyContinue  
      If ($Process -ne $null) {  
           $Output = "Stopping " + $Process.Name + " process....."  
           Stop-Process -Name $Process.Name -Force -ErrorAction SilentlyContinue  
           Start-Sleep -Seconds 1  
           $TestProcess = Get-Process $ProcessName -ErrorAction SilentlyContinue  
           If ($TestProcess -eq $null) {  
                $Output += "Success"  
                Write-Host $Output  
                Return $true  
           } else {  
                $Output += "Failed"  
                Write-Host $Output  
                Return $false  
           }  
      } else {  
           Return $true  
      }  
 }  
   
 function Get-Architecture {  
 <#  
      .SYNOPSIS  
           Get-Architecture  
        
      .DESCRIPTION  
           Returns whether the system architecture is 32-bit or 64-bit  
        
      .EXAMPLE  
           Get-Architecture  
        
      .NOTES  
           Additional information about the function.  
 #>  
        
      [CmdletBinding()][OutputType([string])]  
      param ()  
        
      $OSArchitecture = Get-WmiObject -Class Win32_OperatingSystem | Select-Object OSArchitecture  
      $OSArchitecture = $OSArchitecture.OSArchitecture  
      Return $OSArchitecture  
      #Returns 32-bit or 64-bit  
 }  
   
 function Get-RelativePath {  
 <#  
      .SYNOPSIS  
           Get the relative path  
        
      .DESCRIPTION  
           Returns the location of the currently running PowerShell script  
        
      .NOTES  
           Additional information about the function.  
 #>  
        
      [CmdletBinding()][OutputType([string])]  
      param ()  
        
      $Path = (split-path $SCRIPT:MyInvocation.MyCommand.Path -parent) + "\"  
      Return $Path  
 }  
   
 function Open-Application {  
 <#  
      .SYNOPSIS  
           Open Application  
        
      .DESCRIPTION  
           Opens an applications  
        
      .PARAMETER Executable  
           A description of the Executable parameter.  
        
      .PARAMETER ApplicationName  
           Display Name of the application  
        
      .PARAMETER Process  
           Application Process Name  
        
      .EXAMPLE  
           PS C:\> Open-Application -Executable 'Value1'  
        
      .NOTES  
           Additional information about the function.  
 #>  
        
      [CmdletBinding()]  
      param  
      (  
           [string]$Executable,  
           [ValidateNotNullOrEmpty()][string]$ApplicationName  
      )  
        
      $Architecture = Get-Architecture  
      $Uninstall = Get-ChildItem -Path REGISTRY::"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall"  
      If ($Architecture -eq "64-bit") {  
           $Uninstall += Get-ChildItem -Path REGISTRY::"HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall"  
      }  
      $InstallLocation = ($Uninstall | ForEach-Object {     Get-ItemProperty $_.PsPath } | Where-Object { $_.DisplayName -eq $ApplicationName }).InstallLocation  
      If ($InstallLocation[$InstallLocation.Length - 1] -ne "\") {  
           $InstallLocation += "\"  
      }  
      $Process = ($Executable.Split("."))[0]  
      $Output = "Opening $ApplicationName....."  
      Start-Process -FilePath $InstallLocation$Executable -ErrorAction SilentlyContinue  
      Start-Sleep -Seconds 5  
      $NewProcess = Get-Process $Process -ErrorAction SilentlyContinue  
      If ($NewProcess -ne $null) {  
           $Output += "Success"  
      } else {  
           $Output += "Failed"  
      }  
      Write-Output $Output  
 }  
   
 function Remove-ChatFiles {  
 <#  
      .SYNOPSIS  
           Delete Jabber Chat Files  
        
      .DESCRIPTION  
           Deletes Jabber chat files located at %USERNAME%\AppData\Local\Cisco\Unified Communications\Jabber\CSF\History and verifies they were deleted  
        
      .EXAMPLE  
           PS C:\> Remove-ChatFiles  
        
      .NOTES  
           Additional information about the function.  
 #>  
        
      [CmdletBinding()]  
      param ()  
        
      $Users = Get-ChildItem -Path $env:HOMEDRIVE"\users" -Exclude 'Administrator', 'public', 'iCreateService', 'sccmadmin', 'Default'  
      foreach ($User in $Users) {  
           #Get Jabber Chat history files  
           $History = $User.FullName + '\AppData\Local\Cisco\Unified Communications\Jabber\CSF\History'  
           $ChatHistoryFiles = Get-ChildItem -Path $History -Filter *.db  
           If ($ChatHistoryFiles -ne $null) {  
                foreach ($File in $ChatHistoryFiles) {  
                     $Output = "Deleting " + $File.Name + "....."  
                     If ($SecureDelete.IsPresent) {  
                          $RelativePath = Get-RelativePath  
                          $sDelete = [char]34 + $env:windir + "\system32\" + "sdelete64.exe" + [char]34  
                          $Switches = "-accepteula -p" + [char]32 + $SecureDeletePasses + [char]32 + "-q" + [char]32 + [char]34 + $File.FullName + [char]34  
                          $ErrCode = (Start-Process -FilePath $sDelete -ArgumentList $Switches -Wait -PassThru).ExitCode  
                          If (($ErrCode -eq 0) -and ((Test-Path $File.FullName) -eq $false)) {  
                               $Output += "Success"  
                          } else {  
                               $Output += "Failed"  
                          }  
                     } else {  
                          Remove-Item -Path $File.FullName -Force | Out-Null  
                          If ((Test-Path $File.FullName) -eq $false) {  
                               $Output += "Success"  
                          } else {  
                               $Output += "Failed"  
                          }  
                     }  
                     Write-Output $Output  
                }  
           } else {  
                $Output = "No Chat History Present"  
                Write-Output $Output  
           }  
      }  
 }  
   
 function Remove-MyJabberFilesFolder {  
 <#  
      .SYNOPSIS  
           Delete MyJabberFiles Folder  
        
      .DESCRIPTION  
           Delete the MyJabberFiles folder stores under %USERNAME%\documents and verifies it was deleted.  
        
      .EXAMPLE  
           PS C:\> Remove-MyJabberFilesFolder  
        
      .NOTES  
           Additional information about the function.  
 #>  
        
      [CmdletBinding()]  
      param ()  
        
      $Users = Get-ChildItem -Path $env:HOMEDRIVE"\users" -Exclude 'Administrator', 'public', 'iCreateService', 'sccmadmin', 'Default'  
      foreach ($User in $Users) {  
           $Folder = $User.FullName + '\Documents\MyJabberFiles'  
           $MyJabberFilesFolder = Get-Item $Folder -ErrorAction SilentlyContinue  
           If ($MyJabberFilesFolder -ne $null) {  
                $Output = "Deleting " + $MyJabberFilesFolder.Name + "....."  
                Remove-Item -Path $MyJabberFilesFolder -Recurse -Force | Out-Null  
                If ((Test-Path $MyJabberFilesFolder.FullName) -eq $false) {  
                     $Output += "Success"  
                } else {  
                     $Output += "Failed"  
                }  
                Write-Output $Output  
           } else {  
                $Output = "No MyJabberFiles folder present"  
                Write-Output $Output  
           }  
      }  
 }  
   
 Clear-Host  
 #Kill Cisco Jabber Process  
 $JabberClosed = Close-Process -ProcessName CiscoJabber  
 #Delete .DB files from each %USERNAME%\AppData\Local\Cisco\Unified Communications\Jabber\CSF\History  
 Remove-ChatFiles  
 #Delete each %USERNAME%\documents\MyJabberFiles directory  
 Remove-MyJabberFilesFolder  
 #Reopen Jabber if it was open  
 If ($JabberClosed -eq $true) {  
      Open-Application -ApplicationName "Cisco Jabber" -Executable CiscoJabber.exe  
 }  
   

2 comments:

  1. Great Post! Another handy trick is, once the database is deleted and the file recreated on launch, mark the file as "read-only". This will prevent future conversations from being logged.

    ReplyDelete
  2. Hi Charles and Mick,

    Nice post. Congratulations for help.

    ReplyDelete