none
need help with Get-LastLogon.ps1 script

    Question

  • I have been using the script the Brian Wilhite created at this link:  http://gallery.technet.microsoft.com/scriptcenter/Get-LastLogon-Determining-283f98ae

    for the last month and a half... it has been working without any issues... until recently. For some reason I am not able to load the Get-LastLogon.ps1 script into PS. I have tried many ways to load it..               . .\  ,  .\ , & "C:\(path) , and others... I get nothing in return

    I have tried both Set-executionpolicy of unrestricted and remotesigned in both PS 64 and 32... I still cant get the ps1 script to load. If I remember correctly I was supposed to see some kind of confirmation that the script loaded... but I am no longer seeing it... I have tried using both my domain admin and using the run as admin in all ps 32 and 64 and also the AD module... Any one have an idea of what I am doing wrong or how to trouble shoot this? 

    Thursday, December 06, 2012 6:38 PM

Answers

  • Did you follow the author's instructions that are listed explicitly with the script's entry in the gallery?

    You must load this "script" as a "function" by "dot sourcing" the .ps1 file, as in the following example:
    PS C:\> . .\Get-LastLogon.ps1
    This example assumes the path to the Get-LastLogon.ps1 file is relative to the current directory.
    Then the Function can be run:
    PS C:\> Get-LastLogon -ComputerName WKS01, WKS02, SVR01, SVR02

    Note that the first command starts with a dot, a space, then '.\Get-LastLogon.ps1' after it.

    Bill

    Thursday, December 06, 2012 8:32 PM

All replies

  • When you say that something didn't work, you have to say how it didn't work.

    Specifically: What does "I am not able to load" mean?

    Please copy and paste the exact command you are running and the exact error message(s).

    Bill

    Thursday, December 06, 2012 6:48 PM
  • I have the Get-LastLogon.ps1 located on the Root of C: and I am trying to load the ps1 file so I can execute it. I am typing at the PS C:\ promt    .\Get-LastLogn.ps1

    I used to get a message that the ps1 script loaded after runing the .\Get-LastLogon.ps1

    all that shows up is PS C:\

    I am not actually getting any error message... Then I try to run the script..

    $Servers = Get-Content "C:\computerlist.txt"  ***I have a text file that contains the computer names***

    Get-LastLogon -ComputerName $Servers

    and I get this error:

    The term 'Get-LastLogon1' is not recognized as the name of a cmdlet, function, script file, or operable program. Check
    the spelling of the name, or if a path was included, verify that the path is correct and try again.
    At line:1 char:15
    + Get-LastLogon1 <<<<  -ComputerName $Servers
        + CategoryInfo          : ObjectNotFound: (Get-LastLogon1:String) [], CommandNotFoundException
        + FullyQualifiedErrorId : CommandNotFoundException

    Suggestion [3,General]: The command Get-LastLogon was not found, but does exist in the current location. Windows PowerShell doesn't load Commands from the furrent location by default. If you trust this command, instead type ".\Get-LastLogon". See "get-help abount_Command_Precendence" for more details.


    Todd Ilk Network Systems Analyst

    Thursday, December 06, 2012 7:09 PM
  • Try

    c:\GetLastLogin.ps1

    Or try

    cd c:\
    .\GetLastLogin.ps1


    ¯\_(ツ)_/¯

    Thursday, December 06, 2012 7:14 PM
  • Pay close attention to the last part of the error message:

    Suggestion [3,General]: The command Get-LastLogon was not found, but does exist in the current location. Windows PowerShell doesn't load Commands from the furrent location by default. If you trust this command, instead type ".\Get-LastLogon". See "get-help abount_Command_Precendence" for more details.

    I highlighted the part of the error message that actually tells you precisely what to do.


    PS C:\> .\Get-LastLogon.ps1

    Bill

    Thursday, December 06, 2012 7:20 PM
  • original ps1 file was named Get-LastLogon.ps1

    Renamed file to GetLastLogon.ps1

    Tried both options posted and it still displays nothing... goes right back to the PS C:\  prompt


    Todd Ilk Network Systems Analyst

    Thursday, December 06, 2012 7:20 PM
  • I have read that over and over... I have tried both .\Get-LastLogon.ps1 and .\GetLastLogon.ps1 and they both just return to the ps prompt


    Todd Ilk Network Systems Analyst

    Thursday, December 06, 2012 7:24 PM
  • I have read that over and over... I have tried both .\Get-LastLogon.ps1 and .\GetLastLogon.ps1 and they both just return to the ps prompt


    Todd Ilk Network Systems Analyst

    What is in Get-LastLogon ?

    You have not used the fullpath so you may be getting a different file that is empty

    To check the file yu are specifying do this:

    cat .\Get-LastLogon.ps1

    This will display the contents of the file.


    ¯\_(ツ)_/¯

    Thursday, December 06, 2012 7:29 PM
  • Ran the Cat command and it shows the entire code that is in the Get-LastLogon.ps1 file

    Todd Ilk Network Systems Analyst

    Thursday, December 06, 2012 7:31 PM
  • Ran the Cat command and it shows the entire code that is in the Get-LastLogon.ps1 file

    Todd Ilk Network Systems Analyst

    We cannot see that code.  It is likely a function. Correct?


    ¯\_(ツ)_/¯

    Thursday, December 06, 2012 8:19 PM
  • yes it is... I have the link to the page on my first post but just in case here is the code...

    ****just to note... it is the same code I was using last month without error... I renamed the original file to keep it and compared it with a new copy I got today****

    Function Get-LastLogon
    {
    <#

    .SYNOPSIS
      This function will list the last user logged on or logged in.

    .DESCRIPTION
      This function will list the last user logged on or logged in.  It will detect if the user is currently logged on
      via WMI or the Registry, depending on what version of Windows is running on the target.  There is some "guess" work
      to determine what Domain the user truly belongs to if run against Vista NON SP1 and below, since the function
      is using the profile name initially to detect the user name.  It then compares the profile name and the Security
      Entries (ACE-SDDL) to see if they are equal to determine Domain and if the profile is loaded via the Registry.

    .PARAMETER ComputerName
      A single Computer or an array of computer names.  The default is localhost ($env:COMPUTERNAME).

    .PARAMETER FilterSID
      Filters a single SID from the results.  For use if there is a service account commonly used.
     
    .PARAMETER WQLFilter
      Default WQLFilter defined for the Win32_UserProfile query, it is best to leave this alone, unless you know what
      you are doing.
      Default Value = "NOT SID = 'S-1-5-18' AND NOT SID = 'S-1-5-19' AND NOT SID = 'S-1-5-20'"
     
    .EXAMPLE
      $Servers = Get-Content "C:\ServerList.txt"
      Get-LastLogon -ComputerName $Servers

      This example will return the last logon information from all the servers in the C:\ServerList.txt file.

      Computer          : SVR01
      User              : WILHITE\BRIAN
      SID               : S-1-5-21-012345678-0123456789-012345678-012345
      Time              : 9/20/2012 1:07:58 PM
      CurrentlyLoggedOn : False

      Computer          : SVR02
      User              : WILIHTE\BRIAN
      SID               : S-1-5-21-012345678-0123456789-012345678-012345
      Time              : 9/20/2012 12:46:48 PM
      CurrentlyLoggedOn : True
     
    .EXAMPLE
      Get-LastLogon -ComputerName svr01, svr02 -FilterSID S-1-5-21-012345678-0123456789-012345678-012345

      This example will return the last logon information from all the servers in the C:\ServerList.txt file.

      Computer          : SVR01
      User              : WILHITE\ADMIN
      SID               : S-1-5-21-012345678-0123456789-012345678-543210
      Time              : 9/20/2012 1:07:58 PM
      CurrentlyLoggedOn : False

      Computer          : SVR02
      User              : WILIHTE\ADMIN
      SID               : S-1-5-21-012345678-0123456789-012345678-543210
      Time              : 9/20/2012 12:46:48 PM
      CurrentlyLoggedOn : True

    .LINK
      http://msdn.microsoft.com/en-us/library/windows/desktop/ee886409(v=vs.85).aspx
      http://msdn.microsoft.com/en-us/library/system.security.principal.securityidentifier.aspx

    .NOTES
      Author:   Brian C. Wilhite
      Email:   bwilhite1@carolina.rr.com
      Date:    "09/20/2012"
      Updates: Added FilterSID Parameter
               Cleaned Up Code, defined fewer variables when creating PSObjects
      ToDo:    Clean up the UserSID Translation, to continue even if the SID is local
    #>

    [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
                 
              }#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


    Todd Ilk Network Systems Analyst

    Thursday, December 06, 2012 8:25 PM
  • Did you follow the author's instructions that are listed explicitly with the script's entry in the gallery?

    You must load this "script" as a "function" by "dot sourcing" the .ps1 file, as in the following example:
    PS C:\> . .\Get-LastLogon.ps1
    This example assumes the path to the Get-LastLogon.ps1 file is relative to the current directory.
    Then the Function can be run:
    PS C:\> Get-LastLogon -ComputerName WKS01, WKS02, SVR01, SVR02

    Note that the first command starts with a dot, a space, then '.\Get-LastLogon.ps1' after it.

    Bill

    Thursday, December 06, 2012 8:32 PM
  • yes I have tried it all already. I have tried with and without the space between the dots...

    Todd Ilk Network Systems Analyst

    Thursday, December 06, 2012 8:34 PM
  • Sorry; then you're doing something wrong that I can't see. I recommend learning PowerShell fundamentals so that you will quickly be more able to identify the problem. A forum is not really a good place to teach basic fundamentals because it's just not well suited for interactive help.

    Bill

    Thursday, December 06, 2012 8:37 PM
  • For your information I do know fundamentals of powershell. I have had it working fine for 2 months. I have been troubleshooting this script for this entire week. I came here hoping someone would have an alternate idea I havent already tried. Saying "I don't know" is a much better answer than the one you just provided. Some moderator... instead of saying you are not sure... you resort to demeaning comments towards people ligitamately seeking help after they have exhausted all other avenues of research.


    Todd Ilk Network Systems Analyst

    Thursday, December 06, 2012 8:55 PM
  • The function in the file is what is the issue.  You cannot execute a function in a file by running the file.  YOu must load teh function into memory to execute it.

    Thisis a common error when first learning PowerShell.  Try using teh dor operator to load the function into memory then call the function by name.

    Example:

    Create a file (Test-Call.ps1) with this in it:

    Write-Host "Hello from outside of the function."

    function Test-Call{
        Write-Host " Hello from inside the function in file"
    }

    Now run this file as you did above above -> .\Test-Call.ps1


    ¯\_(ツ)_/¯


    • Edited by jrv Thursday, December 06, 2012 9:01 PM
    Thursday, December 06, 2012 9:00 PM
  • ptoad - Bill is noting that you are stuck on what to look at next.  It is an issue of fundamentals.  Believe me.  I have seen maany who have used POwerShell for more than a year and still do not know some important fundamentals.

    On fundamental is dot sourcing.  The descritpoion of dor-sourcing is trapped in a help file somewhere.  It is likely the cause of your issues.

    Try the code I posted.  I think it will help you to see what you are missing assuming the file contents you posted are actually correct and complete.


    ¯\_(ツ)_/¯

    Thursday, December 06, 2012 9:28 PM
  • Hi,

    No offense intended. I do believe that the problem is you're not dot-sourcing the ps1 file correctly (dot-sourcing makes the function available in the current PowerShell session). As jrv noted, this is covered in the PowerShell help:


    PS C:\> help about_Scripts

    Bill

    Thursday, December 06, 2012 11:02 PM