Windows 10 Notification Database

Notifications are a feature added in Windows 8 and 10, displaying text and images either in the start menu tiles or on the right side of the screen. These notifications can hold interesting data such as popup messages or text snippets from applications. This may allow you to recover data even when its source has been deleted. The notification database storing this information is located here:

%APPDATA%\Local\Microsoft\Windows\Notifications\wpndatabase.db

Related pictures are stored in this subfolder:

%APPDATA%\Local\Microsoft\Windows\Notifications\wpnidm\

On current Windows versions the database is in an SQLite format and can be inspected by any SQLite tool. For the Windows 10 notification database prior to Windows 10 build 1607 (Aug. 2016) have a look at Yogesh Khatri’s blog post.

The database contains several tables from which the Notification and NotificationHandler seems to be the most interesting:

Notification table:

  • HandlerId: That’s the reference to the RecordId NotificationHandler table. Allows to look up the application which created the notification.
  • Payload: This is the actual content of the notification. Here you might find interesting information.
  • ArrivalTime: The time when the notification was received.
  • ExpiryTime: The time when the notification will be deleted from the database.

The time stamps in this notification table are in the Windows filetime format. You can use this CyberChef recipe to convert them to a human readable format.

NotificationHandler table:

  • PrimaryId: References via RecordId to the HandlerId of the Notification table. Shows the application name which created a notification.

Convert to CSV

Sometimes it’s useful to use a tool like Excel to inspect and sort the data. The following is a small script which takes a wpndatabase.db as input and returns a tab-separated file with the most important information.

#!/usr/bin/env python3

import sqlite3
import csv
import sys


def generateCSV(csr, outputfilename):
    csr.execute("""SELECT n.'Order', n.Id, n.Type, nh.PrimaryId AS HandlerPrimaryId, nh.CreatedTime AS HandlerCreatedTime, nh.ModifiedTime AS HandlerModifiedTime, n.Payload,
                          CASE WHEN n.ExpiryTime != 0 THEN datetime((n.ExpiryTime/10000000)-11644473600, 'unixepoch') ELSE n.ExpiryTime END AS ExpiryTime,
                          CASE WHEN n.ArrivalTime != 0 THEN datetime((n.ArrivalTime/10000000)-11644473600, 'unixepoch') ELSE n.ArrivalTime END AS ArrivalTime
                   FROM Notification n
                   INNER JOIN NotificationHandler nh ON n.HandlerID = nh.RecordID""")

    result = csr.fetchall()
    with open(outputfilename, "w", newline='', encoding="utf-8") as f:
        writer = csv.writer(f, delimiter='\t')
        writer.writerow(list(map(lambda x: x[0], csr.description)))
        for line in result:
            lst = list(line)
            # In case the payload should be a string, uncomment the next line
            #lst[-3] = str(lst[-3], "UTF-8")
            lst[-2] = "" if lst[-2] == 0 else lst[-2]
            lst[-1] = "" if lst[-1] == 0 else lst[-1]
            writer.writerow(lst)


def printMetainfo(csr):
    csr.execute("SELECT * FROM Metadata")
    result = csr.fetchall()
    print("""\n            
        Notifications - Metadata
        ------------------------
        """)
    for line in result:
        print("\t" + line[0] + ":  " + str(line[1]))
    print()


if __name__ == "__main__":
    if len(sys.argv) == 3:
        conn = sqlite3.connect(sys.argv[1])
        csr = conn.cursor()
        printMetainfo(csr)
        generateCSV(csr, sys.argv[2])

    else:
        print("""\n            
        Windows 10 Notifications to CSV 
        -------------------------------
        This script processes the wpndatabase.db notifications database from Windows 10 
        and gives a truncated, tab-delimited file as output.
        File location:  %APPDATA%\Local\Microsoft\Windows\\Notifications\wpndatabase.db
            
        Usage: 
        WPNtoCSV.py   inputDB   outputCSV 
            
        Example:
        WPNtoCSV.py   wpndatabase.db  notifications.csv
        """)