Author Posts

June 28, 2016 at 4:52 pm

I am using the following code and it works great to retrieve users that have profiles on a system and then uses Get-WinEvent and looks for only 4642 events that user has created and then it uses Get-ADUser to see if that user is in Active Directory, so it filters out any locally created custom account.

The problem with this script is that it gets multiple users and all I want is for it to retrieve the most current last logged on user from the list of users the Get-WmiObject Win32_UserProfile -ComputerName $Computer -Filter 'Special=False').LocalPath -replace 'C:\\users\\'," gets.

I have no idea how to go about doing this and any help here would be MUCH appreciated.

Thank you all

Here is the code:

$Computers = 'Computer1', 'Computer2', 'Computer3'

Foreach ($Computer in $Computers)
{   
    $Users = (Get-WmiObject Win32_UserProfile -ComputerName $Computer -Filter 'Special=False').LocalPath -replace 'C:\\users\\','' 

    $ADComputerProps = Get-ADComputer -Identity $Computer -Properties * -ErrorAction SilentlyContinue

    Foreach ($User in $Users)
    {
        $UserLastLogonEvent = Get-WinEvent -Computer $Computer -FilterHashtable @{Logname='Security';ID='4624';Data=$User;} -MaxEvents 1 -ErrorAction SilentlyContinue
                
        If ($UserLastLogonEvent)
        {
            $SID = '{0}' -f $UserLastLogonEvent.Properties[4].Value,$UserLastLogonEvent.Properties[5].Value,$UserLastLogonEvent.Properties[6].Value 

            $User = '{1}' -f $UserLastLogonEvent.Properties[4].Value,$UserLastLogonEvent.Properties[5].Value,$UserLastLogonEvent.Properties[6].Value

            $Domain = '{2}' -f $UserLastLogonEvent.Properties[4].Value,$UserLastLogonEvent.Properties[5].Value,$UserLastLogonEvent.Properties[6].Value

            $ADUserProps = Get-ADUser -Identity $User -Properties * -ErrorAction SilentlyContinue

            If ($ADComputerProps) 
            {
                If ($ADUserProps)
                {
                    [pscustomobject]@{
            
                        'ComputerDistinguishedName' = $ADComputerProps.DistinguishedName
                        'ComputerName' = $Computer
                        'ComputerIPV4Address' = $ADComputerProps.IPv4Address
                        'ComputerLastADLogonDate' = $ADComputerProps.LastLogonDate
                        'ComputerOperatingSystem' = $ADComputerProps.OperatingSystem
                        'ComputerServerReferenceBL' = $ADComputerProps.serverReferenceBL 
                        'UserDomain' = $Domain
                        'UserDisplayName' = $ADUserProps.DisplayName
                        'UserDepartment' = $ADUserProps.Department
                        'UserDescription' = $ADUserProps.Description
                        'UserEmailAddress' = $ADUserProps.EmailAddress
                        'UserLastADLogonDate' = $ADUserProps.LastLogonDate
                        'UserLastComputerLogOnDate' = $UserLastLogonEvent.TimeCreated
                        'UserLastLoggedOn' = $User
                        'UserName' = $ADUserProps.Name
                        'UserOffice' = $ADUserProps.Office
                        'UserOfficePhone' = $ADUserProps.OfficePhone
                        'UsewrOrganization' = $ADUserProps.Organization
                        'UserSamAccountName' = $ADUserProps.SamAccountName
                        'UserSID' = $SID
                    }
                }
            }
        }
    }
}

June 28, 2016 at 5:33 pm

If you look at all of the properties of the Win32_UserProfile class, you'll see there is a property LastUseTime. This datetime value is stored as WMI datetime, which appears to be sortable. If we get the profile data, sort it descending on the LastUseTime property and then Select -First 1, we should get the last user that logged in, something like this:

Get-WmiObject Win32_UserProfile -Filter "Special=False" | 
Sort-Object -Property LastUseTime -Descending |
Select LocalPath, LastUseTime, @{Name="Test";Expression={[System.Management.ManagementDateTimeConverter]::ToDateTime($_.LastUseTime)}} -First 1

June 28, 2016 at 11:31 pm

Thanks, but the only problem with relying on the LastUseTime is that it can be a task ran within the context of the user and what I want is the actual logon time, which is why I was using Event ID 4624 and filtering out special logons. Basically any event that takes place that was created under a user account will run and that will force the NTUser.dat file to be written to which will be recorded as the LastUseTime and that is not exactly what I am looking for.

I could be completely wrong about this, but I have researched fairly thoroughly and this is the conclusion that I have come to.

June 29, 2016 at 5:03 am

Using the code you've already got, just collect your events up into a variable, sort the events by your time (descending), then select the first event. I would probably turn this into an advanced function to use the pscustom object with the pipeline, but this is functional.

$Computers = 'Computer1', 'Computer2', 'Computer3'

Foreach ($Computer in $Computers)
{   
    $Users = (Get-WmiObject Win32_UserProfile -ComputerName $Computer -Filter 'Special=False').LocalPath -replace 'C:\\users\\','' 

    $ADComputerProps = Get-ADComputer -Identity $Computer -Properties * -ErrorAction SilentlyContinue

    Foreach ($User in $Users)
    {
        $UserLastLogonEvent = Get-WinEvent -Computer $Computer -FilterHashtable @{Logname='Security';ID='4624';Data=$User;} -MaxEvents 1 -ErrorAction SilentlyContinue
                
        If ($UserLastLogonEvent)
        {
            $SID = '{0}' -f $UserLastLogonEvent.Properties[4].Value,$UserLastLogonEvent.Properties[5].Value,$UserLastLogonEvent.Properties[6].Value 

            $User = '{1}' -f $UserLastLogonEvent.Properties[4].Value,$UserLastLogonEvent.Properties[5].Value,$UserLastLogonEvent.Properties[6].Value

            $Domain = '{2}' -f $UserLastLogonEvent.Properties[4].Value,$UserLastLogonEvent.Properties[5].Value,$UserLastLogonEvent.Properties[6].Value

            $ADUserProps = Get-ADUser -Identity $User -Properties * -ErrorAction SilentlyContinue

            If ($ADComputerProps) 
            {
                If ($ADUserProps)
                {
                    $colevents += @([pscustomobject]@{
            
                        'ComputerDistinguishedName' = $ADComputerProps.DistinguishedName
                        'ComputerName' = $Computer
                        'ComputerIPV4Address' = $ADComputerProps.IPv4Address
                        'ComputerLastADLogonDate' = $ADComputerProps.LastLogonDate
                        'ComputerOperatingSystem' = $ADComputerProps.OperatingSystem
                        'ComputerServerReferenceBL' = $ADComputerProps.serverReferenceBL 
                        'UserDomain' = $Domain
                        'UserDisplayName' = $ADUserProps.DisplayName
                        'UserDepartment' = $ADUserProps.Department
                        'UserDescription' = $ADUserProps.Description
                        'UserEmailAddress' = $ADUserProps.EmailAddress
                        'UserLastADLogonDate' = $ADUserProps.LastLogonDate
                        'UserLastComputerLogOnDate' = $UserLastLogonEvent.TimeCreated
                        'UserLastLoggedOn' = $User
                        'UserName' = $ADUserProps.Name
                        'UserOffice' = $ADUserProps.Office
                        'UserOfficePhone' = $ADUserProps.OfficePhone
                        'UsewrOrganization' = $ADUserProps.Organization
                        'UserSamAccountName' = $ADUserProps.SamAccountName
                        'UserSID' = $SID
                    })
                }
            }
        }
    }
}

$colevents | Sort-Object UserLastComputerLogOnDate -Descending | Select-Object -First 1
Remove-Variable colevents
  • This reply was modified 2 years, 3 months ago by  Curtis Smith.

June 29, 2016 at 5:17 am

CURTIS!!

That did it.

I could kiss that beautiful bald head of yours.

Actually, this code was just a snippet of a much larger script that is already an advanced function.

Thanks a bunch man, I love you.

June 29, 2016 at 5:22 am

BTW, is there a reason to remove the ColEvents variable at the end there, or is that just some common practice that you like to do?

Thanks

June 29, 2016 at 5:26 am

GOD I LOVE PowerShell.org!!

You guys are a life saver man.

June 29, 2016 at 1:27 pm

The remove is there because when I was testing the script I initially just added the PSCustomObject to the variable without enclosing it in an array first.

IE.

$colevents += [pscustomobject]@{
            
                        'ComputerDistinguishedName' = $ADComputerProps.DistinguishedName
                        'ComputerName' = $Computer
                        'ComputerIPV4Address' = $ADComputerProps.IPv4Address
                        etc. etc. etc.
}

This created $colevents as an object type variable rather than an array, which also meant that it only had the last event found, not the whole collection. Since I was using the ISE, the $colevents stayed around between runs. When I enclosed the [pscustomobject] in and array @(), the same result happened because the variable $colevents had already been created as an object. I added remove-variable so that it would be unset at the end and then recreated on the next run.

Technically it is not required since running in a console, rather than ISE would terminate the variables at the end of the run, but in programming it is good practice to clean up your variables when you no longer need their value so that subsequent uses of the variable name or new data assignment does not contain unexpected results. Happens with loops a lot. But anyway, that's why it's there. You can remove it if you like.

June 29, 2016 at 5:45 pm

Great info!

Thanks again man.

Appreciate your help.