Google
 
Main Page
 The gatekeeper of reality is
 quantified imagination.

Stay notified when site changes by adding your email address:

Your Email:

Bookmark and Share
The Ultimate Candle
Email Notification
Powershell: User logon/logoff
Octagon Beeswax Glyph Candles
  Using Windows Powershell you can track when users logon and logoff computers on Windows Vista/7/Server 2008. A simple Powershell script and batch file is all that is needed to start out. Two scheduled tasks on the computer are setup which call the batch file (the batch file then invokes the Powershell script).


While you could easily change the way in which the Powershell script logs the data it detects, in this scenario we actually have the script send the data over https. This allows a receiver (a server-side webpage that processes a query string) on a website to take the data and put it into XML files (the XML files could then be read by a different webpage).

(1) Ensure Powershell scripts will run on the computer that users logon/logoff

STEP 1

(Enlarge)
  1. Open regedit.
  2. Navigate to HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell.
  3. Select new string value.
STEP 2

(Enlarge)
  1. Set the value to "ExecutionPolicy".
STEP 3

(Enlarge)
  1. Right-click on "ExecutionPolicy" and select "Modify".
STEP 4

(Enlarge)
  1. Under "Value data" enter "RemoteSigned".
STEP 5

(Enlarge)
  1. This is what the modification should look like when completed.


(2) Create a new rtask.bat file (notepad) below and place it at C:\Program Files\Common Files\Services\

powershell.exe -command "& 'c:\Program Files\Common Files\Services\psmontsk.ps1' -noninteractive -windowstyle hidden Set-ExecutionPolicy RemoteSigned"


(2) Create a new psmontsk.ps1 file (notepad) below and place it at C:\Program Files\Common Files\Services\
NOTE: You will need to change $wcTarget to reflect your website containing the receiver.

<#
.SYNOPSIS
Retrieve current listing of logged on users. Integrate on target machine as a scheduled task/job that periodically runs this script.
This script functions the same on Windows XP as well as Windows 7 workstations AND Windows Server 2008 R2 machines.
.NOTES
Name: SystemStatusTracker
Author: Joe McCormack
DateCreated: 1/1/2011
.LINK
http://www.virtualsecrets.com
.EXAMPLE
Call from Command-Line: powershell.exe -command "& 'c:\Program Files\Common Files\Services\psmontsk.ps1' -noninteractive -windowstyle hidden Set-ExecutionPolicy RemoteSigned"
#>

# Start Customization
$nameAction = "flagname"
$wcTarget = "https://www.yoursite.com/Receiver.asp" # Target URL to pass data to for processing
$requestUserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2;)+SystemStatusTracker" # Agent signature
# End Customization
$results = ""

# Get Current Date
$nameDate = Get-Date -format g

# Get Computer Name
$nameComputer = $env:computername

# Get Current User
$nameUser = $env:username

# Get IP of Computer
$rawData = gwmi Win32_NetworkAdapterConfiguration -computer $nameComputer
$ipStep = 0
$nameIP = ""
ForEach ($segData in $rawData) {
If ($segData.IPAddress) {
$tmpIP = $segData.IPAddress
$tmpIPBlocks = $tmpIP -split " "
ForEach ($segment in $tmpIPBlocks) {
if ($ipStep -eq 0) {
$nameIP = $segment
$ipStep = 1
}
}
}
}

# Get All Currently Logged-on Users
# While "query session /server:$nameComputer" works on Windows 7 and Windows XP workstations it does not work on Windows Server 2008 R2
# by default beyond listing the current user's session. To keep things simple, use win32_process.
ForEach($c in $nameComputer) {
$userEntry = gwmi win32_process -computer $c -Filter "Name = 'explorer.exe'"
ForEach ($user in $userEntry) {
if($results -ne '') { $results += "::" }
$tmpComputer = $c
$tmpUser = ($user.GetOwner()).User
$tmpDomain = ($user.GetOwner()).Domain
$results += "$tmpDomain|$tmpComputer|$tmpUser"
}
}

# Prepend Current User Information
$results = "$nameAction|$nameDate|$nameComputer|$nameUser|$nameIP||$results"

# Assemble
$sndData = new-object System.Collections.Specialized.NameValueCollection
$sndData.Add("cd", $results)

# Run Transaction
$wc = New-Object System.Net.WebClient
$wc.Headers.Add("user-agent", $requestUserAgent)
$wc.QueryString = $sndData
$wcTargetSnd = $wc.DownloadData($wcTarget)
$wcTargetRec = [System.Text.Encoding]::ASCII.GetString($wcTargetSnd)

# Print out $wcTarget Response for Testing
# "Web Transaction Response = $wcTargetRec"


(3) Create the two scheduled tasks

STEP 1

(Enlarge)
  1. The first scheduled task that will be created will run under the SYSTEM account once every 5 minutes indefinitely. The purpose of this task is to (1) let you know of a possible connection issue if the timestamp is older than 5 minutes, and, (2) report who is currently logged in; method to deduce who may have logged off.
  2. Under Control Panel go to Administrative Tools.
STEP 2

(Enlarge)
  1. Open task scheduler.
STEP 3

(Enlarge)
  1. Under "Action" select "Create Task...".
STEP 4

(Enlarge)
  1. Under the General tab, for the name specify "psmontsk".
  2. Enter a description such as Activity monitor.
  3. Under "Security options" click on the button "Change User or Group..." and change the account to SYSTEM.
STEP 5

(Enlarge)
  1. Under the Trigger tab, for "Begin this task:" specify "On a schedule".
  2. Under "Settings" check Daily.
  3. Under "Advanced settings" check "Repeat task every:". For the first drop-down select "5 minutes" and for "for a duration of:" select "Indefinitely".
STEP 6

(Enlarge)
  1. Under the Actions tab, for "Action:" specify "Start a program".
  2. Under "Settings" enter the Program/script path as C:\Program Files\Common Files\Services\rtask.bat.
STEP 7

(Enlarge)
  1. Under the Conditions tab, for the Power section check "Start the task only if the computer is on AC power" and "Wake the computer to run this task".
  2. Under "Network" check "Start only if the following network connection is available:" and select "Any Connection".
STEP 8

(Enlarge)
  1. Under the Settings tab, check "Allow task to be run on demand", "Run task as soon as possible after a scheduled start is missed", "Stop the task if it runs longer than:" and "If the running task does not end when requested, force it to stop".
  2. Click the "OK" button and the task will be created and started.
STEP 9

(Enlarge)
  1. Under Task Status of the summary pane you will see that "psmontsk" has been added.
STEP 10
  1. The second task to create should be called "uloon" and run when a user logon is detected. Otherwise this task is largely the same as the first scheduled task "psmontsk" that was created.


(4) Setting up the receiver on a website
NOTE: Remember, the receiver (a server-side script) takes data being sent from the Powershell script (on a computer) and does something with it. In this tutorial the receiver will be a simple ASP webpage that creates or updates XML files (the name of each XML file cooresponds to the name of a computer). Those XML files could then be read by a self-updating webpage to show users logged onto a computer.

<%
' SystemStatusTracker: Receives secure data from "flagname" machines.
' Author: Joe McCormack, 1/1/2011, www.virtualsecrets.com

Dim receiveAction : receiveAction = "" ' Request action; should always be "flagname"
Dim receiveDate : receiveDate = "" ' Date of request; example: 2/1/2011 9:15 AM
Dim receiveMachine : receiveMachine = "" ' Machine name making request; example: COMPUTERNAME
Dim receiveUser : receiveUser = "" ' "Username" making request; example: COMPUTERNAME$ or YOURLOGON
Dim receiveIP : receiveIP = "" ' IP Address of the computer
Dim respErrors : respErrors = 0 ' 0 - don't show detailed error messages, 1 - show detailed error messages
Dim allowProcessing : allowProcessing = 0
Dim tmpCount : tmpCount = -1
Dim rawReceive : rawReceive = ""
Dim userRawData : userRawData = ""
Dim compRawData : compRawData = ""
Dim tmpDomain : tmpDomain = ""
Dim tmpMachine : tmpMachine = ""
Dim tmpUser : tmpUser = ""
Dim collection : collection = ""
Dim msgNote : msgNote = "[0] Data Received"

' DEFINE ACTION/PATH LOOKUP MAPPINGS
Dim actionMap()
Redim Preserve actionMap(1) : actionMap(0) = "flagname,ComputerData" ' When receiveAction = "flagname" resolve that to the "ComputerData" folder

' DEFINE FIRST TWO ALLOWED OCTETS
Dim allowedOctets()
Redim Preserve allowedOctets(1) : allowedOctets(0) = "333.444" ' External facing IP range to allow for the computer network is on

' GET IP ADDRESS AND EVALUATE OCTETS
Dim sourceIPOctets : sourceIPOctets = ""
Dim sourceIP : sourceIP = Request.ServerVariables("REMOTE_ADDR")
if Len(sourceIP) = 0 Then : sourceIP = Request.ServerVariables("HTTP_X_FORWARDED_FOR") : End if
if Len(sourceIP) > 0 Then
sourceIPOctets = Split(sourceIP, ".")(0) & "." & Split(sourceIP, ".")(1)
allowProcessing = 0
For S = 0 TO UBound(allowedOctets) - 1
if allowedOctets(S) = sourceIPOctets Then : allowProcessing = 1 : End if
Next
Else
allowProcessing = 0
if respErrors = 0 Then
msgNote = "[1] Error"
Else
msgNote = "[1] Error. The IP address value of """ & sourceIP & """ was not found in allowedOctets()."
End if
End if

' FILTER
if allowProcessing = 1 Then
rawReceive = CStr(Request.QueryString("cd"))
Dim blockSequences()
Redim Preserve blockSequences(1) : blockSequences(0) = "<"
Redim Preserve blockSequences(2) : blockSequences(1) = ">"
Redim Preserve blockSequences(3) : blockSequences(2) = "#"
Redim Preserve blockSequences(4) : blockSequences(3) = """"
Redim Preserve blockSequences(5) : blockSequences(4) = "'"
Redim Preserve blockSequences(6) : blockSequences(5) = "="
Redim Preserve blockSequences(7) : blockSequences(6) = "./"
Redim Preserve blockSequences(8) : blockSequences(7) = "\"
Redim Preserve blockSequences(9) : blockSequences(8) = "&"
Redim Preserve blockSequences(10) : blockSequences(9) = "--"
Redim Preserve blockSequences(11) : blockSequences(10) = "("
Redim Preserve blockSequences(12) : blockSequences(11) = ")"
Redim Preserve blockSequences(13) : blockSequences(12) = "%"
Redim Preserve blockSequences(14) : blockSequences(13) = "+"
Redim Preserve blockSequences(15) : blockSequences(14) = ";"
For F = 0 TO UBound(blockSequences) - 1
if InStr(rawReceive, blockSequences(F)) Then
allowProcessing = 0
if respErrors = 0 Then
msgNote = "[2] Error"
Else
msgNote = "[2] Error. Possible malicious script detected."
End if
End if
Next
End if

' CHECK MINIMUM DATA SIZE
if allowProcessing = 1 Then
if InStr(rawReceive, "||") Then
Dim tmpRawReceive : tmpRawReceive = ""
tmpRawReceive = Split(rawReceive, "||")(0) & Split(rawReceive, "||")(1)
if InStr(tmpRawReceive, "|") Then
Dim pipeNumber : pipeNumber = UBound(Split(tmpRawReceive, "|"))
if pipeNumber < 3 Then : allowProcessing = 0 : End if
Else
allowProcessing = 0
End if
Else
allowProcessing = 0
End if
if allowProcessing = 0 Then
if respErrors = 0 Then
msgNote = "[3] Error"
Else
msgNote = "[3] Error. The data is not formatted correctly."
End if
End if
End if

' HANDLE REQUEST
if allowProcessing = 1 Then
userRawData = Split(rawReceive, "||")(0)
compRawData = Split(rawReceive, "||")(1)
receiveAction = Split(userRawData, "|")(0) ' Request action
receiveDate = Split(userRawData, "|")(1) ' Date of request
receiveMachine = Split(userRawData, "|")(2) ' Machine name making request
receiveUser = Split(userRawData, "|")(3) ' "Username" making request
receiveIP = Split(userRawData, "|")(4) ' IP Address of the computer
' DETERMINE SAVE LOCATION
Dim strPath : strPath = ""
Dim pathCustom: pathCustom = ""
strPath = Server.MapPath(".")
For P = 0 TO UBound(actionMap) - 1
Dim receiveActionValue : receiveActionValue = Split(actionMap(P), ",")(0)
Dim folderUse : folderUse = Split(actionMap(P), ",")(1)
if LCase(receiveAction) = LCase(receiveActionValue) Then
pathCustom = folderUse
End if
Next
if Len(pathCustom) = 0 Then
allowProcessing = 0
if respErrors = 0 Then
msgNote = "[4] Error"
Else
msgNote = "[4] Error. The term """ & receiveAction & """ was not found in the mapping defined by actionMap()."
End if
Else
Set folderFSO = Server.CreateObject("Scripting.FileSystemObject")
if folderFSO.FolderExists(strPath & "\" & pathCustom) <> True Then
allowProcessing = 0
if respErrors = 0 Then
msgNote = "[5] Error"
Else
msgNote = "[5] Error. The term """ & receiveAction & """ was found in the mapping defined by actionMap() but the physical folder """ & pathCustom & """ was not detected."
End if
End if
Set folderFSO = Nothing
End if
if allowProcessing = 1 Then
if InStr(compRawData, "::") Then
' More than one user - YOUR-DOMAIN|COMPUTERNAME|USERNAME::YOUR-DOMAIN|COMPUTERNAME|USERNAME
Dim tmpMultiples : tmpMultiples = Split(compRawData, "::")
For X = 0 TO UBound(tmpMultiples)
tmpCount = tmpCount + 1
tmpDomain = Split(tmpMultiples(X), "|")(0)
tmpMachine = Split(tmpMultiples(X), "|")(1)
tmpUser = Split(tmpMultiples(X), "|")(2)
ReDim Preserve userEntryDomain(tmpCount) : userEntryDomain(tmpCount) = tmpDomain
ReDim Preserve userEntryMachine(tmpCount) : userEntryMachine(tmpCount) = tmpMachine
ReDim Preserve userEntryUser(tmpCount) : userEntryUser(tmpCount) = tmpUser
Next
Else
' One or less users - YOUR-DOMAIN|COMPUTERNAME|USERNAME --OR-- |COMPUTERNAME|
tmpCount = tmpCount + 1
tmpDomain = Split(compRawData, "|")(0)
tmpMachine = Split(compRawData, "|")(1)
tmpUser = Split(compRawData, "|")(2)
ReDim Preserve userEntryDomain(tmpCount) : userEntryDomain(tmpCount) = tmpDomain
ReDim Preserve userEntryMachine(tmpCount) : userEntryMachine(tmpCount) = tmpMachine
ReDim Preserve userEntryUser(tmpCount) : userEntryUser(tmpCount) = tmpUser
End if
tmpDomain = "" : tmpMachine = "" : tmpUser = ""
' GENERATE CONTENT
For Y = 0 TO UBound(userEntryDomain)
tmpDomain = userEntryDomain(Y)
tmpMachine = userEntryMachine(Y)
tmpUser = userEntryUser(Y)
collection = collection & " <activity>" & vbcrlf
collection = collection & " <lastdate>" & Replace(Server.HTMLEncode(receiveDate), "&", "&amp;") & "</lastdate>" & vbcrlf
collection = collection & " <host>" & Replace(Server.HTMLEncode(receiveMachine), "&", "&amp;") & "</host>" & vbcrlf
collection = collection & " <entity>" & Replace(Server.HTMLEncode(receiveUser), "&", "&amp;") & "</entity>" & vbcrlf
collection = collection & " <domain>" & Replace(Server.HTMLEncode(tmpDomain), "&", "&amp;") & "</domain>" & vbcrlf
collection = collection & " <machine>" & Replace(Server.HTMLEncode(tmpMachine), "&", "&amp;") & "</machine>" & vbcrlf
collection = collection & " <name>" & Replace(Server.HTMLEncode(tmpUser), "&", "&amp;") & "</name>" & vbcrlf
collection = collection & " <source>" & Replace(Server.HTMLEncode(receiveIP), "&", "&amp;") & "</source>" & vbcrlf
collection = collection & " </activity>" & vbcrlf
Next
tmpDomain = "" : tmpMachine = "" : tmpUser = ""
' FORMAT CONTENT
collection = "<" & "?" & "xml version=""1.0"" encoding=""utf-8""" & "?" & ">" & vbcrlf & "<parameters>" & vbcrlf & collection & "</parameters>"
' SAVE CONTENT
Set objFSO = Server.CreateObject("Scripting.FilesystemObject")
if objFSO.fileExists(strPath & "\" & pathCustom & "\" & receiveMachine & ".xml") = True Then
' Set augment = objFSO.OpenTextFile(strPath & "\" & pathCustom & "\" & receiveMachine & ".xml")
Set augment = objFSO.createTextFile(strPath & "\" & pathCustom & "\" & receiveMachine & ".xml")
augment.writeLine(collection)
augment.Close
Set augment = Nothing
Else
Set make = objFSO.createTextFile(strPath & "\" & pathCustom & "\" & receiveMachine & ".xml")
make.writeLine(collection)
make.Close
Set make = Nothing
End if
Set objFSO = Nothing : collection = ""
End if
strPath = ""
End if

' GENERATE OUTPUT
Response.Write "<html><head><title>" & msgNote & "</title></head><body></body></html>"
%>
About Joe