Script to featch lastlogon userid and date, time from the list of servers.

This topic contains 9 replies, has 3 voices, and was last updated by  Keshav Prasad 2 years ago.

  • Author
    Posts
  • #29422

    Keshav Prasad
    Participant

    Hello All,
    i need a script where i can featch lastlogon userid and date , time from the list of servers. and export it to csv.

    i have one which works as function.
    if i pipe it to export to csv. it will stop running.

    #>

    [CmdletBinding()]
    param(
    [Parameter(Position=0,ValueFromPipeline=$true)]
    [Alias("CN","Computer")]
    [String[]]$ComputerName="$env:COMPUTERNAME",
    [String]$FilterSID,
    [String]$WQLFilter="NOT SID = 'S-1-5-18' AND NOT SID = 'S-1-5-19' AND NOT SID = 'S-1-5-20'"
    )

    Begin
    {
    #Adjusting ErrorActionPreference to stop on all errors
    $TempErrAct = $ErrorActionPreference
    $ErrorActionPreference = "Stop"
    #Exclude Local System, Local Service & Network Service
    }#End Begin Script Block

    Process
    {
    Foreach ($Computer in $ComputerName)
    {
    $Computer = $Computer.ToUpper().Trim()
    Try
    {
    #Querying Windows version to determine how to proceed.
    $Win32OS = Get-WmiObject -Class Win32_OperatingSystem -ComputerName $Computer
    $Build = $Win32OS.BuildNumber

    #Win32_UserProfile exist on Windows Vista and above
    If ($Build -ge 6001)
    {
    If ($FilterSID)
    {
    $WQLFilter = $WQLFilter + " AND NOT SID = `'$FilterSID`'"
    }#End If ($FilterSID)
    $Win32User = Get-WmiObject -Class Win32_UserProfile -Filter $WQLFilter -ComputerName $Computer
    $LastUser = $Win32User | Sort-Object -Property LastUseTime -Descending | Select-Object -First 1
    $Loaded = $LastUser.Loaded
    $Script:Time = ([WMI]").ConvertToDateTime($LastUser.LastUseTime)

    #Convert SID to Account for friendly display
    $Script:UserSID = New-Object System.Security.Principal.SecurityIdentifier($LastUser.SID)
    $User = $Script:UserSID.Translate([System.Security.Principal.NTAccount])
    }#End If ($Build -ge 6001)

    If ($Build -le 6000)
    {
    If ($Build -eq 2195)
    {
    $SysDrv = $Win32OS.SystemDirectory.ToCharArray()[0] + ":"
    }#End If ($Build -eq 2195)
    Else
    {
    $SysDrv = $Win32OS.SystemDrive
    }#End Else
    $SysDrv = $SysDrv.Replace(":","$")
    $Script:ProfLoc = "\\$Computer\$SysDrv\Documents and Settings"
    $Profiles = Get-ChildItem -Path $Script:ProfLoc
    $Script:NTUserDatLog = $Profiles | ForEach-Object -Process {$_.GetFiles("ntuser.dat.LOG")}

    #Function to grab last profile data, used for allowing -FilterSID to function properly.
    function GetLastProfData ($InstanceNumber)
    {
    $Script:LastProf = ($Script:NTUserDatLog | Sort-Object -Property LastWriteTime -Descending)[$InstanceNumber]
    $Script:UserName = $Script:LastProf.DirectoryName.Replace("$Script:ProfLoc","").Trim("\").ToUpper()
    $Script:Time = $Script:LastProf.LastAccessTime

    #Getting the SID of the user from the file ACE to compare
    $Script:Sddl = $Script:LastProf.GetAccessControl().Sddl
    $Script:Sddl = $Script:Sddl.split("(") | Select-String -Pattern "[0-9]\)$" | Select-Object -First 1
    #Formatting SID, assuming the 6th entry will be the users SID.
    $Script:Sddl = $Script:Sddl.ToString().Split(";")[5].Trim(")")

    #Convert Account to SID to detect if profile is loaded via the remote registry
    $Script:TranSID = New-Object System.Security.Principal.NTAccount($Script:UserName)
    $Script:UserSID = $Script:TranSID.Translate([System.Security.Principal.SecurityIdentifier])
    }#End function GetLastProfData
    GetLastProfData -InstanceNumber 0

    #If the FilterSID equals the UserSID, rerun GetLastProfData and select the next instance
    If ($Script:UserSID -eq $FilterSID)
    {
    GetLastProfData -InstanceNumber 1
    }#End If ($Script:UserSID -eq $FilterSID)

    #If the detected SID via Sddl matches the UserSID, then connect to the registry to detect currently loggedon.
    If ($Script:Sddl -eq $Script:UserSID)
    {
    $Reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey([Microsoft.Win32.RegistryHive]"Users",$Computer)
    $Loaded = $Reg.GetSubKeyNames() -contains $Script:UserSID.Value
    #Convert SID to Account for friendly display
    $Script:UserSID = New-Object System.Security.Principal.SecurityIdentifier($Script:UserSID)
    $User = $Script:UserSID.Translate([System.Security.Principal.NTAccount])
    }#End If ($Script:Sddl -eq $Script:UserSID)
    Else
    {
    $User = $Script:UserName
    $Loaded = "Unknown"
    }#End Else

    }#End If ($Build -le 6000)

    #Creating Custom PSObject For Output
    New-Object -TypeName PSObject -Property @{
    Computer=$Computer
    User=$User
    SID=$Script:UserSID
    Time=$Script:Time
    CurrentlyLoggedOn=$Loaded
    } | Select-Object Computer, User, SID, Time, CurrentlyLoggedOn | Export-Csv c:\t.csv -NoTypeInformation
    N
    }#End Try

    Catch
    {
    If ($_.Exception.Message -Like "*Some or all identity references could not be translated*")
    {
    Write-Warning "Unable to Translate $Script:UserSID, try filtering the SID `nby using the -FilterSID parameter."
    Write-Warning "It may be that $Script:UserSID is local to $Computer, Unable to translate remote SID"
    }
    Else
    {
    Write-Warning $_
    }
    }#End Catch

    }#End Foreach ($Computer in $ComputerName)

    }#End Process

    End
    {
    #Resetting ErrorActionPref
    $ErrorActionPreference = $TempErrAct
    }#End End

    }# End Function Get-LastLogon

    Any this is missing, please suggest.

    Thanks in Advance

  • #29424

    Don Jones
    Keymaster

    Your script accepts -computername as [string[]] from the pipeline ByValue; what Import-CSV produces _looks_ like a string, so it'll try and bind to it, but it isn't a useful string, which is probably why it's failing.

    However, because you haven't formatted your code (instructions are listed above the posting text box; we prefer you to store your code as a Gist in GitHub and just paste the Gist URL here), it's difficult to completely follow the code. I would start by adding some Verbose output. E.g:

    Foreach ($Computer in $ComputerName)
    {
    $Computer = $Computer.ToUpper().Trim()
    Write-Verbose "Computer is $Computer"
    ...
    

    And then running your command with the -Verbose parameter to enable that output. MOST PowerShell bugs are the result of a variable not containing what you thought it did, so the goal of debugging is to MAKE SURE you know what your variables contain by displaying their contents.

  • #29425

    Don Jones
    Keymaster

    Also, I should point out that you're not really handling errors in the preferred way ($ErrorActionPreference vs. -ErrorAction), and there's no reason to "reset" $ErrorActionPreference as it, like all variables, is scoped to your script once you change it there. Read, "The Big Book of PowerShell Error Handling" (free, Resources menu here) for details on preferred error handling methods.

  • #29426

    Keshav Prasad
    Participant

    Thanks Jones,

    i need csv in below format,
    Computer User Time CurrentlyLoggedOn

    code is in below link
    https://gist.github.com/f1594cf36d79ac1cac48.git

  • #29428

    Don Jones
    Keymaster

    Actually, it's "Don." We put our surname last and given first :). Or "Mr. Jones" but there's no need to be formal here! 🙂

    Since your CSV has a Computer column, the easy fix would be to add:

    ValueFromPipelineByPropertyName=$True

    To your -ComputerName parameter. Then, also add the following right after its [Parameter()]

    [Alias('computer')]

    That will let it bind the Computer column from the pipeline.

  • #29429

    Don Jones
    Keymaster

    By the way, that's an extremely useful function. If you get it working, I hope you consider writing it in an article and submitting it via email to webmaster@. We would love to publish it and offer it to others as your contribution to the community!

  • #29430

    Keshav Prasad
    Participant

    HI Don (is it sound good) 🙂
    changed below lines, getting error as below

    [CmdletBinding()]
    param(
    [Parameter(Position=0,ValueFromPipelineByPropertyName=$True)]
    [Alias("CN","Computer")][Parameter()][Alias('computer')]
    [String[]]$ComputerName="$env:COMPUTERNAME",
    [String]$FilterSID,
    [String]$WQLFilter="NOT SID = 'S-1-5-18' AND NOT SID = 'S-1-5-19' AND NOT SID = 'S-1-5-20'"
    )

    Getting below Error
    The parameter "ComputerName" is declared in parameter-set "__AllParameterSets" multiple times.
    At line:1 char:1
    + get-lastlogon -computername $servername
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : MetadataError: (:) [], MetadataException
    + FullyQualifiedErrorId : ParameterDeclaredInParameterSetMultipleTimes

  • #29431

    Don Jones
    Keymaster

    Sorry – you can't have two [Parameter()]. It should be:

    [Parameter=ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$True)]

    I think you already had the Alias definition, now that I look back.

  • #29432

    Daniel Krebs
    Moderator

    The script/function posted here seems to be copied from the TechNet Script Center.

    https://gallery.technet.microsoft.com/scriptcenter/Get-LastLogon-Determining-283f98ae

  • #29463

    Keshav Prasad
    Participant

    it's the same script,i am not the Author (Author: Brian C. Wilhite) i should thank him for the code. i am customizing it for my environment
    i need the data out put to csv. i did that but it will stuck with single entry. it will not move further.

    if i remove | to csv then it will work fine.

    Thanks Mr. Don and Krebs for the support, still i am learning scripting.

You must be logged in to reply to this topic.