Auditing the VMware UEM Configuration Share
I want to start this blog post by saying that the content of this post is based upon great solutions and work by others. A special thanks and appreciation goes out to Boe Prox for providing his PowerShell function New-FileSystemWatcher and to Mike Bijl for providing the configuration steps and his PowerShell script for looking up file/folder changes and user name and machine name lookup.
Introduction
VMware User Environment Manager (UEM) does not have auditing build in. However, VMware UEM is all file/folder based, and therefore a solution that audits files and folders should normally be sufficient. In this blog post I want to describe a solution which is easy to implement and which can easily be adjusted to your own needs. The solution is built using
- A Group Policy Object (GPO)
- A PowerShell script
- A scheduled task
One important thing to mention: This solution only works using a Windows file server (share) that hosts the VMware UEM configuration.
Auditing GPO
A GPO that audits the file system and file share is required for being able to look up the user name that made the change and for looking up the system name from which the change happened.
Use the following steps for creating the Auditing GPO.
Open Group Policy Management and create a new GPO and apply it to your file server hosting the VMware UEM Configuration Share.
In this example my domain controller (INFRA01) is also the server hosting the VMware UEM Configuration Share. |
|
Edit the GPO and browse to Computer Configuration –> Policies –> Windows Settings –> Security Settings –>Advanced Audit Policy Configuration –> Audit Policies –> Object Access
Configure the following Subcategories and enable the Audit Events for Success – Audit Detailed File Share |
|
Applying the above GPO to the server hosting the VMware UEM Configuration Share results in events in the Security event log as pictured. |
Audit VMware UEM Configuration Share PowerShell Script
The Audit VMware UEM Configuration Share PowerShell Script is the actual brain in this solution. It uses the FileSystemWatcher class for setting up a listener that watches predefined folders and/or files. The following script is an example of how I implemented it in my LAB environment and it does the following (high level).
- Creates an event log for VMware UEM Configuration Share auditing (VMware UEM)
- “Listens” for changes in the specified local path (C:\Shares\UEM_Config –> INFRA01.lab.localUEM_Config)
- Creates events for changes in the specified local path in the specified event log (VMware UEM)
This is the actual content of my script.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
$EventLogName = "VMware UEM" $EventSource = "VMware UEM Configuration" $UEMConfigPath = "C:\Shares\UEM_Config" $logFileExists = Get-EventLog -list | Where-Object {$_.logdisplayname -eq $EventLogName} if (! $logFileExists) { New-EventLog -LogName $EventLogName -Source $EventSource } # # Credits go to Boe Prox for this part --> https://mcpmag.com/articles/2015/09/24/changes-to-a-folder-using-powershell.aspx # Function Start-FileSystemWatcher { [cmdletbinding()] Param ( [parameter()] [string]$Path, [parameter()] [ValidateSet('Changed','Created','Deleted','Renamed')] [string[]]$EventName, [parameter()] [string]$Filter, [parameter()] [System.IO.NotifyFilters]$NotifyFilter, [parameter()] [switch]$Recurse, [parameter()] [scriptblock]$Action ) #region Build FileSystemWatcher $FileSystemWatcher = New-Object System.IO.FileSystemWatcher If (-NOT $PSBoundParameters.ContainsKey('Path')){ $Path = $PWD } $FileSystemWatcher.Path = $Path If ($PSBoundParameters.ContainsKey('Filter')) { $FileSystemWatcher.Filter = $Filter } If ($PSBoundParameters.ContainsKey('NotifyFilter')) { $FileSystemWatcher.NotifyFilter = $NotifyFilter } If ($PSBoundParameters.ContainsKey('Recurse')) { $FileSystemWatcher.IncludeSubdirectories = $True } If (-NOT $PSBoundParameters.ContainsKey('EventName')){ $EventName = 'Changed','Created','Deleted','Renamed' } If (-NOT $PSBoundParameters.ContainsKey('Action')){ $Action = { Switch ($Event.SourceEventArgs.ChangeType) { 'Renamed' { $Object = "{0} was {1} to {2} at {3}" -f $Event.SourceArgs[-1].OldFullPath, $Event.SourceEventArgs.ChangeType, $Event.SourceArgs[-1].FullPath, $Event.TimeGenerated } Default { $Object = "{0} was {1} at {2}" -f $Event.SourceEventArgs.FullPath, $Event.SourceEventArgs.ChangeType, $Event.TimeGenerated } } $WriteHostParams = @{ ForegroundColor = 'Green' BackgroundColor = 'Black' Object = $Object } Write-Host @WriteHostParams } } #endregion Build FileSystemWatcher #region Initiate Jobs for FileSystemWatcher $ObjectEventParams = @{ InputObject = $FileSystemWatcher Action = $Action } ForEach ($Item in $EventName) { $ObjectEventParams.EventName = $Item $ObjectEventParams.SourceIdentifier = "File.$($Item)" Write-Verbose "Starting watcher for Event: $($Item)" $Null = Register-ObjectEvent @ObjectEventParams } #endregion Initiate Jobs for FileSystemWatcher } Start-FileSystemWatcher -Path $UEMConfigPath -Recurse -Action { # # Credits go to Mike Bijl for this part --> https://www.linkedin.com/in/mikebijl/ # $name = $Event.SourceEventArgs.Name $changeType = $Event.SourceEventArgs.ChangeType $timeStamp = $Event.TimeGenerated $after = $timeStamp.addSeconds(-2) $before = $timeStamp.addSeconds(+2) start-sleep -Seconds 2 $evententries = @(Get-WinEvent -FilterHashtable @{logname="Security"; starttime=$after;endtime=$before; ID = 5145 } -MaxEvents 10 ) foreach($evententry in $evententries) { $user = "" $null = $($evententry.Message) -match '.*AccountsName:s*(?.*)x0D' $user = $($matches['content']) $null = $($evententry.Message) -match '.*SourcesAddress:s*(?.*)x0D' $machine = $($matches['content']) + " `($([system.net.dns]::gethostentry("$($matches['content'])").HostName)`)" If ($user -ne "") {break} } $Object = "{0} was {1} at {2} by {3} on {4}" -f $Event.SourceEventArgs.FullPath, ($Event.SourceEventArgs.ChangeType | Out-String).ToUpper(), $Event.TimeGenerated, $user.ToUpper(), $machine.ToUpper() $WriteHostParams = @{ ForegroundColor = 'Green' BackgroundColor = 'Black' Object = $Object } Write-Host @WriteHostParams Write-EventLog -LogName "VMware UEM" -Source "VMware UEM Configuration" -EntryType "Information" -EventId "1001" -Message $Object } |
You can download the script and change it to your own needs.
Scheduled Task Configuration
Follow the next steps for creating the scheduled task that runs the PowerShell script.
Start Task Scheduler and create a new Task (not a Basic Task) | |
On the General tab, give the task a name and use the SYSTEM account for running the task and select Run with highest privileges | |
On the Triggers tab, create a new trigger and select At startup for Begin the task
Select Delay task for 1 minute Select Repeat task every 1 hour for a duration of Indefinitely Select Enabled |
|
On the Actions tab, create a new action and select Start a program for Action
For Program/script enter C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe For Add arguments (optional) enter -noexit -executionpolicy bypass -file “D:\Audit\VMware UEM Configuration Share.ps1” Change the path to the script when needed. |
|
Select Run task as soon as possible after a scheduled start is missed | |
That’s all for creating the scheduled task. |
End Results
When I now create/edit/delete configurations in the VMware UEM Management Console it will be picked up by the PowerShell script that’s running (scheduled task) and it will create events in the event log, specifying the file/folder, action (Create/Delete/Change), date/time, user name and source computer name.