Monitoring Windows Shares with Splunk and PowerShell

I sometimes get emails after blog posts. One of the (fair) criticisms is that I sometimes do something in PowerShell that can be quite legitimately done via another data input like WMI. While this is true for simple cases, it’s not always true. Take the request, for example, of monitoring network shares. There are three parts to this. Firstly, producing a monitor of the share itself; secondly, producing a monitor of the permissions on the share; and finally, monitoring the file accesses utilizing that share. I’ve already blogged about the last one. Let’s take a look at the first two.

You can actually monitor the share itself using WMI. Network Shares are exposed via a WMI class Win32_Share. However, I wanted to go a little further – I wanted to show that we can expose the shares in a way that allows us to monitor changes to the shares. As is most often the case, I’m going to use the SA-ModularInput-PowerShell data input for this purpose. This modular input has a key feature we are going to use – the ability to save state between script executions.

Let’s take a look at the code for getting the data first. It’s relatively simple:

Gwmi Win32_Share | Where Type –eq 0 | Select Name,Path,Status,MaximumAllowed,AllowMaximum

The Share Type 0 is a “standard Windows share” and not something else (like an admin connection or a printer share). If we were doing a WMI connection, then we could construct this to allow us to output this with a WMI query and it would be logged every X minutes. However, we want to go further – we want to show off changes as well. To do this, we utilize the LocalStorage module that is distributed with the SA-ModularInput-PowerShell addon. The basics are simple. First, we set up a LocalStorage hash to use:

$State = Import-LocalStorage ‘Win32_Share.xml’ –DefaultValue (NewObject PSObject –Property @{ S = @{}})

Note the default value – we are setting up a hash that will be persistently stored on each server and will be used to store the current settings. At the end of our script, we want to ensure that we store any updates we made:

$State | Export-LocalStorage ‘Win32_Share.xml’

In between these statements we can handle all the stuff we need. Here is the complete script:

$State = Import-LocalStorage "Win32_Share.xml" -DefaultValue (New-Object PSObject -Property @{ S = @{} })

$shares = (Get-WmiObject -Class Win32_Share | Where-Object Type -eq 0 | Select-Object Name,Path,Status,MaximumAllowed,AllowMaximum)
foreach ($share in $shares) {
    $Emit = $false

    if (-not $State.S.ContainsKey($share.Name)) {
        $Emit = $true
    } else {
        $cache = $State.S.Get_Item($share.Name)
        if (($cache.Path -ne $share.Path) -or 
            ($cache.Status -ne $share.Status) -or
            ($cache.MaximumAllowed -ne $share.MaximumAllowed) -or
            ($cache.AllowMaximum -ne $share.AllowMaximum)) {
            $Emit = $true

    if ($Emit -eq $true) {
        Write-Output $share
        $State.S.Set_Item($share.Name, $share)

$State | Export-LocalStorage "Win32_Share.xml"

What we are basically doing here is saying “if the share does not exist in our cache or anything has changed about the share compared to the cache, then output the share to the pipeline and store the new share in the cache. To run this, you will need to add a stanza to inputs.conf. I’ve added this script to my script repository in TA-windows-local/bin, so here is my stanza from that same app:

script = . “$SplunkHome\etc\apps\TA-windows-local\bin\win32_share.ps1”
schedule = 0 0/5 * ? * *
index = win
sourcetype = Windows:Win32_Share

The output looks like this:


There are a couple of improvements we could do to this script. Firstly, adding a “last emitted time” to the event and storing that in the cache would allow us to add a condition that states “if the share has not been emitted in the last 24 hours, then emit the event”. This allows us to restrict the search parameters we use when utilizing this data source to the last 24 hours. Secondly, we can do a second pass – over the cache instead of the shares – and see if any cache entries are not in the share list. This allows us to detect share deletions as well.

Next week, I will cover the second part of this problem – getting the permissions for each share. Until then, keep those ideas for Windows data inputs coming!

Posted by


Join the Discussion