PowerShell Workflows have been a bit of an underachiever in terms of their adoption and use.
Something I read prompted the thought that there are a number of activities when working with Active Directory where you have to interrogate a number of machines to get the result.
That’s something that workflows are good at.
A common problem is when did that user last logon. Using the Microsoft cmdlets you get this:
£> Get-ADUser -Identity Richard -Properties * -Server server02 | fl lastlogon* lastLogon : 130677233108205070
LastLogonDate : 30/01/2015 14:05:58
lastLogonTimestamp : 130671003582718505
£> Get-ADUser -Identity Richard -Properties * -Server W12R2SCDC01 | fl lastlogon*
lastLogon : 130671225126188854
LastLogonDate : 30/01/2015 14:05:58
lastLogonTimestamp : 130671003582718505
Lastlogontimestamp is the identical across the 2 DCs because it’s replicated – however its not always up to date. It can be up to 14 days out.
Now the lastlogon and lastlogontimestamp are not in a readable format – so need a bit of work on that
$dc = "server02"
Get-ADUser -Identity Richard -Properties lastLogon, LastLogonDate, lastLogonTimestamp -Server $dc |
select Name, LastLogondate,
@{N=’LastLogon’; E={[datetime]::FromFileTime([int64]::Parse($_.lastlogon))}},
@{N=’LastLogonTimestamp’; E={[datetime]::FromFileTime([int64]::Parse($_.lastlogonTimestamp))}},
@{N= ‘Domain Controller’; E={$dc}}
Name : Richard
LastLogondate : 30/01/2015 14:05:58
LastLogon : 06/02/2015 19:08:30
LastLogonTimestamp : 30/01/2015 14:05:58
Domain Controller : server02
You can see that the lastlogondate (Introduced with Windows 2008 R2) is the lastlogontimestamp in a readable format. Notoce the difference between the lastlogon and the lastlogontimestamp.
The calculation to get the date is relatively straightforward. Start by converting the property to a int64
[int64]::Parse($_.lastlogonTimestamp)
Then treat that as a filetime and convert to a datetime
[datetime]::FromFileTime([int64]::Parse($_.lastlogonTimestamp))
Now lets look at getting that data from multiple machines in parallel
workflow get-lastlogon {
param (
[string[]]$computername
)
foreach -parallel ($dc in $computername) {
Get-ADUser -Identity Richard -Properties lastLogon, LastLogonDate, lastLogonTimestamp -Server $dc |
Select-Object -Property Name, LastLogondate,
@{N=’LastLogon’; E={[datetime]::FromFileTime([int64]::Parse($_.lastlogon))}},
@{N=’LastLogonTimestamp’; E={[datetime]::FromFileTime([int64]::Parse($_.lastlogonTimestamp))}} |
Add-Member -MemberType NoteProperty -Name ‘DomainController’ -Value $dc -PassThru
}
}
get-lastlogon -computername (Get-ADDomainController -Filter * | select -ExpandProperty Name)
The workflow accepts an array of computer names. A foreach –parallel loop is use do run the Get-Aduser command.
One oddity was setting the Domain Controller name into the output object. It wouldn’t accept the value when I used a select calculated field but I could use Add-Member.
if I figure out what’s going on I post the information