Author Posts

September 7, 2015 at 5:31 am

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

September 7, 2015 at 5:44 am

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.

September 7, 2015 at 5:46 am

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.

September 7, 2015 at 6:34 am

Thanks Jones,

i need csv in below format,
Computer User Time CurrentlyLoggedOn

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

September 7, 2015 at 6:55 am

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.

September 7, 2015 at 7:04 am

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!

September 7, 2015 at 7:17 am

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

September 7, 2015 at 7:21 am

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.

September 7, 2015 at 8:52 am

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

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

September 8, 2015 at 6:42 am

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.