Script help

Hello, this script does exactly what I need, except in my environment I need to use the invoke-command with credentials. However when I edit the script for it, it breaks. Can someone help?

Param (
[string]$Computer = (Read-Host Remote computer name),
[int]$Days = 1
)
$events = @()
$events += Get-WinEvent -ComputerName $Computer -FilterHashtable @{
LogName='Security'
Id=@(529,4634,4647,4800,4801,4624,540)
StartTime=(Get-Date).AddDays(-$Days)
}
$events += Get-WinEvent -ComputerName $Computer -FilterHashtable @{
LogName='System'
Id=@(7001,7002)
StartTime=(Get-Date).AddDays(-$Days)
}

$type_lu = @{
7001 = 'Logon'
7002 = 'Logoff'
4800 = 'Lock'
4801 = 'UnLock'
529 = 'Logon Failure'
540 = 'Successful Network Logon'
4634 = 'An account was logged off'
4624 = 'An account was successfully logged on'
4647 = 'User initiated logoff'
4608 = 'Windows is starting up'
4609 = 'Windows is shutting down'
}

$ns = @{'ns'='http://schemas.microsoft.com/win/2004/08/events/event'}
$target_xpath = "//ns:Data[@Name='TargetUserName']"
$usersid_xpath = "//ns:Data[@Name='UserSid']"

If($events) {
$results = ForEach($event in $events) {
$xml = $event.ToXml()
Switch -Regex ($event.Id) {
'4...' {
$user = (
Select-Xml -Content $xml -Namespace $ns -XPath $target_xpath
).Node.'#text'
Break
}
'7...' {
$sid = (
Select-Xml -Content $xml -Namespace $ns -XPath $usersid_xpath
).Node.'#text'
$user = (
New-Object -TypeName 'System.Security.Principal.SecurityIdentifier' -ArgumentList $sid
).Translate([System.Security.Principal.NTAccount]).Value
Break
}
}
New-Object -TypeName PSObject -Property @{
Time = $event.TimeCreated
Id = $event.Id
Type = $type_lu[$event.Id]
User = $user

}
}
If($results) {
#$results
$Results | Sort Time -Descending | Out-GridView
}
}

<#Logon types possible:

Logon Type- Description

2- Interactive (logon at keyboard and screen of system) Windows 2000 records Terminal Services logon as this type rather than Type 10.
3- Network (i.e. connection to shared folder on this computer from elsewhere on network or IIS logon - Never logged by 528 on W2k and forward. See event 540)
4- Batch (i.e. scheduled task)
5- Service (Service startup)
7- Unlock (i.e. unnattended workstation with password protected screen saver)
8- NetworkCleartext (Logon with credentials sent in the clear text. Most often indicates a logon to IIS with “basic authentication”)
9- NewCredentials
10- RemoteInteractive (Terminal Services, Remote Desktop or Remote Assistance)
11- CachedInteractive (logon with cached domain credentials such as when logging on to a laptop when away from the network)
#>

Can you post the script that breaks along with the error message?

Get-WinEvent accepts credentials:

Get-WinEvent
   [[-LogName] <String[]>]
   [-MaxEvents <Int64>]
   [-ComputerName <String>]
   [-Credential <PSCredential>]
   [-FilterXPath <String>]
   [-Force]
   [-Oldest]
   [<CommonParameters>]

Just add credentials:

param (
    [string]$Computer = (Read-Host Remote computer name),
    [pscredential]$Credential = (Get-Credential),
    [int]$Days = 1
)
$events = @()
$events += Get-WinEvent -ComputerName $Computer -Credential $Credential -FilterHashtable @{
LogName='Security'
Id=@(529,4634,4647,4800,4801,4624,540)
StartTime=(Get-Date).AddDays(-$Days)
}

Another advantage to Mr. Simmers approach is that Invoke-Command requires Remote PowerShell enabled on the remote systems. His solution does not. Remote Powershell is not enabled by default for security reasons and getting it all worked out on a lot of systems (GPO or otherwise) can get ugly.

My $.02

Thank you Mr Simmers, this is exactly what I was looking / hoping for.

 

Tony- The reason I needed that method is we will not enable RPC or Remote PS enablement on our machines as you pointed out.

[quote quote=278478]Thank you Mr Simmers, this is exactly what I was looking / hoping for.

Tony- The reason I needed that method is we will not enable RPC or Remote PS enablement on our machines as you pointed out.

[/quote]
How are you remoting without RPC or WinRM (PS standard remoting)? Cmdlets that have a computername parameter but no session parameter use RPC for connection.

A lot of the commands that provide credentials are WMI wrappers. My assumption is that Get-WinEvent is using DCOM or WSMan to get information, which uses the underlying RPC protocol. WSMAN would require to be enabled to run Invoke-Command or create sessions. Regardless, if you are remotely connecting you would be using RPC or WSMAN to make that connection.

Mike R, in my environment, we either disable the Windows firewall(s) to allow for both Get-WinEvent and Get-WmiObject to work on remote systems, or we enable the following firewall rules if turning off the Windows Firewall is not an option. Keep in mind, we are also running McAfee as well which requires no changes.

Enable-NetFireWallRule -DisplayName “Remote Event Log Management (RPC)” -PolicyStore “PersistentStore”
Enable-NetFireWallRule -DisplayName “Remote Event Log Management (RPC-EPMAP)” -PolicyStore “PersistentStore”
Enable-NetFireWallRule -DisplayName “Windows Management Instrumentation (WMI-In)” -PolicyStore “PersistentStore”
Enable-NetFireWallRule -DisplayName “Netlogon Service (NP-In)” -PolicyStore “PersistentStore”

This works now except I am unable to grab the unlock/lock/screensaver logs (auditing is enabled in GPO)

param (
[string]$Computer = (Read-Host Remote computer name),
[pscredential]$Credential = (Get-Credential),
[int]$Days = 30
)
$events = @()

$events += Get-WinEvent -ComputerName $Computer -Credential $Credential -FilterHashtable @{
LogName='Security'
Id=@(540,4634,4800,4801,4624,4608,4609,4778,4779,4802,4803)
StartTime=(Get-Date).AddDays(-$Days)
}
$events += Get-WinEvent -ComputerName $Computer -Credential $Credential -FilterHashtable @{
LogName='System'
Id=@(7001,7002)
StartTime=(Get-Date).AddDays(-$Days)
}

$type_lu = @{
7001 = 'Logon'
7002 = 'Logoff'
4800 = 'Computer was Locked'
4801 = 'Comupter was UnLocked'
529 = 'Logon Failed'
540 = 'Successful Network Logon'
4634 = 'An account was logged out'
4624 = 'An account was successfully logged in'
4647 = 'User initiated logoff'
4608 = 'Windows started up'
4609 = 'Windows shutting down'
4778 = 'A remote desktop session was reconnected'
4779 = 'A remote desktop session was disconnected'
4802 = 'screensaver started'
4803 = 'screensaver stopped'
}

$ns = @{'ns'='http://schemas.microsoft.com/win/2004/08/events/event'}
$target_xpath = "//ns:Data[@Name='TargetUserName']"
$usersid_xpath = "//ns:Data[@Name='UserSid']"

If($events) {
$results = ForEach($event in $events) {
$xml = $event.ToXml()
Switch -Regex ($event.Id) {
'4...' {
$user = (
Select-Xml -Content $xml -Namespace $ns -XPath $target_xpath
).Node.'#text'
Break
}
'7...' {
$sid = (
Select-Xml -Content $xml -Namespace $ns -XPath $usersid_xpath
).Node.'#text'
$user = (
New-Object -TypeName 'System.Security.Principal.SecurityIdentifier' -ArgumentList $sid
).Translate([System.Security.Principal.NTAccount]).Value
Break
}
}
New-Object -TypeName PSObject -Property @{
Time = $event.TimeCreated
Id = $event.Id
Type = $type_lu[$event.Id]
User = $user

}
}
If($results) {
#$results
$Results | Sort Time -Descending | Out-GridView
}
}
<#Logon types possible:

Logon Type- Description

2- Interactive (logon at keyboard and screen of system) Windows 2000 records Terminal Services logon as this type rather than Type 10.
3- Network (i.e. connection to shared folder on this computer from elsewhere on network or IIS logon - Never logged by 528 on W2k and forward. See event 540)
4- Batch (i.e. scheduled task)
5- Service (Service startup)
7- Unlock (i.e. unnattended workstation with password protected screen saver)
8- NetworkCleartext (Logon with credentials sent in the clear text. Most often indicates a logon to IIS with "basic authentication")
9- NewCredentials
10- RemoteInteractive (Terminal Services, Remote Desktop or Remote Assistance)
11- CachedInteractive (logon with cached domain credentials such as when logging on to a laptop when away from the network)
#>

 

ERROR:

PS C:\pstools> C:\PScripts\Audit.ps1
Remote computer name:
cmdlet Get-Credential at command pipeline position 1
Supply values for the following parameters:
New-Object : Constructor not found. Cannot find an appropriate constructor for type System.Security.Principal.SecurityIdentifier.
At C:\PScripts\Audit.ps1:57 char:21

  • New-Object -TypeName 'System.Security.Principal.SecurityIden …
  • CategoryInfo : ObjectNotFound: (:slight_smile: [New-Object], PSArgumentException
  • FullyQualifiedErrorId : CannotFindAppropriateCtor,Microsoft.PowerShell.Commands.NewObjectCommand

Your formatting is a tad funky, but I do believe -ArugmentList is your issue. Here is what I use:

$UserIDFromSID = (New-Object System.Security.Principal.SecurityIdentifier($sid)).Translate([System.Security.Principal.NTAccount]).Value

Using your suggestion yielded same results:



If($events) {
$results = ForEach($event in $events) {
$xml = $event.ToXml()
Switch -Regex ($event.Id) {
'4...' {
$user = (
Select-Xml -Content $xml -Namespace $ns -XPath $target_xpath
).Node.'#text'
Break
}
'7...' {
$sid = (
Select-Xml -Content $xml -Namespace $ns -XPath $usersid_xpath
).Node.'#text'
$user = (New-Object System.Security.Principal.SecurityIdentifier($sid)).Translate([System.Security.Principal.NTAccount]).Value
Break
}
}
New-Object -TypeName PSObject -Property @{
Time = $event.TimeCreated
Id = $event.Id
Type = $type_lu[$event.Id]
User = $user

}
}


PS C:\pstools> C:\PScripts\Audit.ps1
Remote computer name:
cmdlet Get-Credential at command pipeline position 1
Supply values for the following parameters:
New-Object : Constructor not found. Cannot find an appropriate constructor for type System.Security.Principal.SecurityIdentifier.
At C:\PScripts\Audit.ps1:56 char:26

  • $user = (New-Object System.Security.Principal.SecurityIdentifier …
  • CategoryInfo : ObjectNotFound: (:slight_smile: [New-Object], PSArgumentException
  • FullyQualifiedErrorId : CannotFindAppropriateCtor,Microsoft.PowerShell.Commands.NewObjectCommand

Somehow when I post code on here its formatting it incorrectly.

If($events) {
    $results = ForEach($event in $events) {
        $xml = $event.ToXml()
        Switch -Regex ($event.Id) {
            '4...' {
                $user = (
                    Select-Xml -Content $xml -Namespace $ns -XPath $target_xpath
                ).Node.'#text'
                Break            
            }
            '7...' {
                $sid = (
                    Select-Xml -Content $xml -Namespace $ns -XPath $usersid_xpath
                ).Node.'#text'
                $user = (New-Object System.Security.Principal.SecurityIdentifier($sid)).Translate([System.Security.Principal.NTAccount]).Value
                Break
            }
        }
        New-Object -TypeName PSObject -Property @{
            Time = $event.TimeCreated
            Id = $event.Id
            Type = $type_lu[$event.Id]
            User = $user
                        
        }
    }

What happens if you try:

$usersid_xpath = “//ns:Data[@Name=‘SubjectUserSid’]”

or

$usersid_xpath = “//ns:Data[@Name=‘TargetUserSid’]”

You search includes a fair number of event ID’s and M$ is not consistent in the XML properties for their event ID’s.

That is my theory anyway :slight_smile:

Hi Tony,

Thanks, I tried those yesterday and they yielded the same results. I did also narrow down to one EID per Security and System and retrieved the same error.

If anyone has a better way to pull Lock/Unlock/Login/Logoff status into an xml, I would be open to hearing it. This was the best I could come up with for our needs.

This is what I use for Successful Logins. Does NOT include logoff. $System needs to be defined as the host you want to query.

$XPath = “(Event[System[EventID=4624 or EventID=4648]]) and (Event[EventData[Data[@Name=‘LogonType’] = ‘2’]] or Event[EventData[Data[@Name=‘LogonType’] = ‘3’]] or Event[EventData[Data[@Name=‘LogonType’] = ‘7’]] or Event[EventData[Data[@Name=‘LogonType’] = ‘10’]] or Event[EventData[Data[@Name=‘LogonType’] = ‘11’]]) and (Event[EventData[Data[@Name=‘SubjectUserSid’] != ‘S-1-0-0’]])”

$AuditData = Get-WinEvent -LogName ‘Security’ -ComputerName $System -FilterXPath $XPath -ErrorAction Stop

Add your additional IDs as needed.

Thanks Tony,

That would work for logon, the primary need for my script is the Lock / Unlock (as they do not count as logon’s and will not show in that list. We have users that never log off, but do lock (via gpo enforcement timeout) and have to unlock to resume using the machine. We need an audit log of those events. 4800 4801

Have you tried as I suggested to update the IDs as needed ??

Change this: (Event[System[EventID=4624 or EventID=4648]])

to this: (Event[System[EventID=4624 or EventID=4648 or EventID=4800 or EventID=4801]])

Hi Tony,

Yes, it failed. The 4800/4801 is in Security and not System. I changed that also and it did not return any values.

OK, I finally decided to actually do some testing :slight_smile:

This should work (at least it did for me). And I am sure you know that unless you enable “Other Logon Events” in your advanced audit policy, 4800 and 4801 will not be logged. Again, adjust the EventID to include what you want. I added the exclusion TargetUserSid to reduce some of the noise. You should fine tune the results to get rid of more noise as there is a ton of it when you enable Other Logon Events.

$XPath = “Event[System[EventID=4624 or EventID=4648 0r EventID=4800 or EventID=4801]]) and (Event[EventData[Data[@Name=‘LogonType’] = ‘2’]]) -and (Event[EventData[Data[@Name=‘TargetUserSid’] != ‘S-1-5-18’]])”

$AuditData = Get-WinEvent -LogName ‘Security’ -ComputerName $System -FilterXPath $XPath

Sorry for not actually testing before posting.