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
Email Notification
Powershell: User logon/logoff
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