none
Usuarios que não se logam por X dias RRS feed

  • Pergunta

  • Pessoal sugiru uma duvida minha.

    Preciso de um script que localizam os usuarios que não se logam por mais de 90 dias

    Sei que pelo Saved Queries do AD eu consigo localizar os usuarios que não se logam por mais de X dias.

    Mais essa consulta traz todos os tipos de autenticação do AD.

    Quero desativar os usuarios que não se logam por mais de 90 mais quero ter certeza que eles não estão utilizando nenhum recurso da Empresa, EX: webmail, OCS, VPN etc.

    Ou algum script que me traga isso.


    O mundo é uma "janela" de oportunidades


    segunda-feira, 20 de agosto de 2012 12:54

Respostas

  • Pedro,

    Segue versão nova versão, acho que encontrei o erro, estava errado na parte que faz a comparação com a data do DC que eu já peguei com a data do DC atual, por isso acabava prevalecendo a primeira informação que ele pegou.

    $FileOut = "C:\temp\lastlogon.csv"
    
    $strFilter = "(&(objectCategory=person)(objectClass=user)(sAMAccountName=384177498))"
    
    #Empty Hash
    $hash = @{}
    
    
    # List each Domain Controller
    $StrDCs = [System.DirectoryServices.ActiveDirectory.Domain]::getcurrentdomain() | foreach{$_.DomainControllers| foreach{$_.Name}}
    
    $StrDCs | foreach-object {
    #Reseta Variaveis
        $dtLogon=get-date "01/01/1600"
        
        $StrEachDC = "LDAP://"+$_.split(".")[0]
    
        $objDomain = New-Object System.DirectoryServices.DirectoryEntry $StrEachDC
    
        $objSearcher = New-Object System.DirectoryServices.DirectorySearcher
        $objSearcher.SearchRoot = $objDomain
        $objSearcher.PageSize = 1000
        $objSearcher.Filter = $strFilter
        $objSearcher.SearchScope = "Subtree"
    
        $colProplist = "name","sAMAccountName","lastlogon","whenCreated"
        foreach ($i in $colPropList){$objSearcher.PropertiesToLoad.Add($i)}
    
        $colResults = $objSearcher.FindAll()
    
        foreach ($objResult in $colResults){
            $User  = $objResult.Properties;
    	[string]$lastLogonInterval = $User.lastlogon
            $dtLogon  =  [System.DateTime]::FromFileTime($lastLogonInterval)
            $dtCreated= $User.whenCreated
            $Account=$User.samaccountname[0]
            "$StrEachDC :  $Account : $dtLogon"
            
            #Array
            $arrTmp = $User.name[0],$dtCreated,$dtLogon
            
            if (-not $Hash.ContainsKey($Account)) {
                $hash.Add($Account, $arrTmp)
            }
            else {
    	    
                if ($dtLogon -gt $hash.item($Account)[2]){$hash[$Account] = $arrTmp}
            }
    
        }
    }
    
    #Write File
    "Conta;Nome;Criação;Ultimo Logon" | out-file -filepath $FileOut
    
    foreach ($key in $hash.keys){ 
        
        if ($hash.item($key)[2].year -eq 1600){
            #Nunca logou
        }else{
        
            $a = New-TimeSpan $hash.item($key)[2].date $(Get-Date).date 
            if ($a.days -gt 90){
                $Line = $key+";"+$hash.item($key)[0]+";"+$hash.item($key)[1]+";"+$hash.item($key)[2] 
                $Line | out-file -filepath $FileOut  -append 
            }
        }
    
    } 


    Fábio de Paula Junior

    terça-feira, 4 de setembro de 2012 15:21
    Moderador

Todas as Respostas

  • Pessoal sei que no OCS tem o lastlogon e replica no AD agora o exchange existe tb mais não replica no AD

    O mundo é uma "janela" de oportunidades

    segunda-feira, 20 de agosto de 2012 15:00
  • Agora minha duvida é usar o lastlogon que não é replicado nos Dc's ou utilizar o lastlogon timestamp que só atualiza a cada 14 dias.


    O mundo é uma "janela" de oportunidades

    segunda-feira, 20 de agosto de 2012 15:04
  • Preciso de um script que localize em todos os DC's o lastlogon dos usuarios que não se logam por mais de 90 dias.

    O mundo é uma "janela" de oportunidades

    segunda-feira, 20 de agosto de 2012 21:04
  • Pedro,

    Fui procurar o link mas parece que você já passou por lá.

    Último Login (sem utilizar módulos)

    http://gallery.technet.microsoft.com/scriptcenter/ltimo-Login-sem-utilizar-549cacd1/view/Discussions#content


    Fábio de Paula Junior

    segunda-feira, 20 de agosto de 2012 21:37
    Moderador
  • Fabio,

    Como ficaria o script para gerar o arquivo apenas dos usuarios que não logam por mais de 90 dias?


    O mundo é uma "janela" de oportunidades

    terça-feira, 21 de agosto de 2012 11:30
  • Amigo, tenta isso no powershell
    Import-Module activedirectory
    Get-ADUser -Properties * -Filter * | ?{$_.LastLogonDate -lt (Get-Date).adddays(-90)}|%{$_.SamAccountName}

    Ajudei? Marca como útil, aproveita e visita meu blog :) HowToServer.com

    terça-feira, 21 de agosto de 2012 16:08
  • Amigo, tenta isso no powershell
    Import-Module activedirectory
    Get-ADUser -Properties * -Filter * | ?{$_.LastLogonDate -lt (Get-Date).adddays(-90)}|%{$_.SamAccountName}

    Ajudei? Marca como útil, aproveita e visita meu blog :) HowToServer.com

    Matheus esse comando verifica em todos os DC's a data mais recente do lastlogon?

    Pois o lastlogon não é replicado.


    O mundo é uma "janela" de oportunidades

    terça-feira, 21 de agosto de 2012 17:27
  • Você quer só usuários que estejam sem logar a 90 dias em todos dcs?

    Ajudei? Marca como útil, aproveita e visita meu blog :) HowToServer.com

    terça-feira, 21 de agosto de 2012 18:42
  • Isso mesmo.

    O mundo é uma "janela" de oportunidades

    terça-feira, 21 de agosto de 2012 19:42
  • Amigo tenta isso:

    Import-Module activedirectory
    Function ListaLastLogon($dias){
        $DCs = $null
        $date = (Get-Date).AddDays(-$dias)
        $DCs = Get-ADGroup -Filter {(name -like "Domain Controllers")} | Get-ADGroupMember | %{$_.Name}
        $i = 0
        $listas = $null
        foreach($DC in $DCS){
            $Lista = New-Object System.Object
            $Lista | add-member -membertype noteproperty -name usuarios -value (Get-ADUser -Properties * -Filter {(LastLogonDate -lt $date)} -Server $DC | %{$_.SamAccountName})
            $Lista | add-member -membertype noteproperty -name index -value $i
            $i++
            $Listas +=,$lista
        }
        $Comando = $null
        foreach($lista in $listas){
            if($lista.index -eq 0){
                $a = $lista.index
                $Comando = "`$listas[$a].usuarios"
            } else {
                $a = $lista.index
                $Comando += " | ?{`$listas[$a].usuarios -contains `$_ }"
            }
        }
        Return Invoke-Expression $Comando
    }
    

    Para usar isso é so copiar isso no console ou no script e rodar ListaLastLogon -dias 90 , se quiser ver melhor como usar uma função no powershell da uma olhada no meu blog

    http://howtoserver.com/adicionar-funcoes-a-sessao-powershell/


    Ajudei? Marca como útil, aproveita e visita meu blog :) HowToServer.com

    terça-feira, 21 de agosto de 2012 20:41
  • Alteração  do script que está na galeria.

    Altere o foreach do final do script para este:

    foreach ($key in $hash.keys){ 
        
        if ($hash.item($key)[2].year -eq 1600){
            #Nunca logou
        }else{
        
            $a = New-TimeSpan $hash.item($key)[2].date $(Get-Date).date 
            if ($a.days -gt 90){
                $Line = $key+";"+$hash.item($key)[0]+";"+$hash.item($key)[1]+";"+$hash.item($key)[2] 
                $Line | out-file -filepath $FileOut  -append 
            }
        }
    } 

    Veja que tem um IF que verifica usuários que nunca logaram (que aparecem com uma data de logon de 1600).


    Fábio de Paula Junior


    quarta-feira, 22 de agosto de 2012 02:09
    Moderador
  • Fabio esta com erro,

    Sabe dizer o que pode ser? (At line:14 char:72)

    Exception calling "Parse" with "1" argument(s): "Input string was not in a correct format."
    At line:14 char:72
    +         $dtLogon  = $lastlogon =[DateTime]::FromFileTime([Int64]::Parse <<<< ($User.lastlogon))
        + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
        + FullyQualifiedErrorId : DotNetMethodException


    O mundo é uma "janela" de oportunidades


    quarta-feira, 22 de agosto de 2012 14:23
  • Chegou a testar o meu?

    Ajudei? Marca como útil, aproveita e visita meu blog :) HowToServer.com Gosta de powershell? entra no grupo do facebook Powershell Brasil

    quarta-feira, 22 de agosto de 2012 14:25
  • Chegou a testar o meu?

    Ajudei? Marca como útil, aproveita e visita meu blog :) HowToServer.com Gosta de powershell? entra no grupo do facebook Powershell Brasil


    Matheus o ListaLastLogon -dias 90 eu devo rodar no final do comando? ou edito o atributo ($date = (Get-Date).AddDays(-$dias)
    ) para $date = (Get-Date).AddDays(-90)

    O mundo é uma "janela" de oportunidades

    quarta-feira, 22 de agosto de 2012 14:35
  • Amigo, assim eu criei uma Função chamada ListaLastLogon , ela recebe como paremetro o numero de dias sem logon por exemplo você quer 90 dias correto você vai executar ListaLastLogon -dias 90, mas antes de executar isso você tem que adicionar a função a sua sessão powershell, pode so copiar todo codigo da linha function até a ultima } no powershell e depois executar ListaLastLogon -dias 90

    obs tem que ter os modulos do ad importados (Import-Module activedirectory)

    Amigo eu fiz um post sobre funções no powershell se quiser dar uma olhada.
    http://howtoserver.com/adicionar-funcoes-a-sessao-powershell/


    Ajudei? Marca como útil, aproveita e visita meu blog :) HowToServer.com Gosta de powershell? entra no grupo do facebook Powershell Brasil


    quarta-feira, 22 de agosto de 2012 15:39
  • Amigo, assim eu criei uma Função chamada ListaLastLogon , ela recebe como paremetro o numero de dias sem logon por exemplo você quer 90 dias correto você vai executar ListaLastLogon -dias 90, mas antes de executar isso você tem que adicionar a função a sua sessão powershell, pode so copiar todo codigo da linha function até a ultima } no powershell e depois executar ListaLastLogon -dias 90

    obs tem que ter os modulos do ad importados (Import-Module activedirectory)

    Amigo eu fiz um post sobre funções no powershell se quiser dar uma olhada.
    http://howtoserver.com/adicionar-funcoes-a-sessao-powershell/


    Ajudei? Marca como útil, aproveita e visita meu blog :) HowToServer.com Gosta de powershell? entra no grupo do facebook Powershell Brasil



    Matheus segue o erro apresentado,

     


    O mundo é uma "janela" de oportunidades

    quarta-feira, 22 de agosto de 2012 17:26
  • Amigo execute só isso e me mande saída, 

    $date = (get-date).adddays(-90)
    $DCs
    = Get-ADGroup -Filter {(name -like "Domain Controllers")} | Get-ADGroupMember | %{$_.Name}
    $DCs
    Get-ADUser -Properties * -Filter {(LastLogonDate -lt $date)} -Server $DCs[0] | %{$_.SamAccountName}


    Ajudei? Marca como útil, aproveita e visita meu blog :) HowToServer.com Gosta de powershell? entra no grupo do facebook Powershell Brasil

    quarta-feira, 22 de agosto de 2012 19:16
  • Subindo.

    Fábio de Paula Junior

    segunda-feira, 27 de agosto de 2012 15:18
    Moderador
  • Matheus segue saida com erro


    O mundo é uma "janela" de oportunidades

    quarta-feira, 29 de agosto de 2012 17:30
  • Sres,

    Alguem pode ajudar?


    O mundo é uma "janela" de oportunidades

    sexta-feira, 31 de agosto de 2012 19:00
  • Pedro,

    Teste este:

    # ============================================================================================== 
    #  
    # AUTOR: Fábio de Paula Junior 
    # DATA : 11/07/2011
    #  
    #        Este script lê o atributo lastlogon de todos os DCs do dominio 
    #  (o atributo lastlogon não é replicado entre os DCs) e gera um CSV contendo sAMAccountName, 
    #  Name, when created e lastlogon (o verdadeiro, a data mais recente encontrada entre todos os DCs).
    #
    #        Eu não utilizei módulos de terceiros, ele foi feito em puro PowerShell.
    #  
    # ============================================================================================== 
    
    
    $FileOut = "C:\temp\lastlogon.csv"
    
    $strFilter = "(&(objectCategory=person)(objectClass=user))"
    
    #Empty Hash
    $hash = @{}
    
    
    # List each Domain Controller
    $StrDCs = [System.DirectoryServices.ActiveDirectory.Domain]::getcurrentdomain() | foreach{$_.DomainControllers| foreach{$_.Name}}
    
    $StrDCs | foreach-object {
        
        $StrEachDC = "LDAP://"+$_.split(".")[0]
    
        $objDomain = New-Object System.DirectoryServices.DirectoryEntry $StrEachDC
    
        $objSearcher = New-Object System.DirectoryServices.DirectorySearcher
        $objSearcher.SearchRoot = $objDomain
        $objSearcher.PageSize = 1000
        $objSearcher.Filter = $strFilter
        $objSearcher.SearchScope = "Subtree"
    
        $colProplist = "name","sAMAccountName","lastlogon","whenCreated"
        foreach ($i in $colPropList){$objSearcher.PropertiesToLoad.Add($i)}
    
        $colResults = $objSearcher.FindAll()
    
        foreach ($objResult in $colResults){
            $User  = $objResult.Properties;
    	[string]$lastLogonInterval = $User.lastlogon
            $dtLogon  =  [System.DateTime]::FromFileTime($lastLogonInterval)
            $dtCreated= $User.whenCreated
            $Account=$User.samaccountname[0]
            
            #Array
            $arrTmp = $User.name[0],$dtCreated,$dtLogon
            
            if (-not $Hash.ContainsKey($Account)) {
                $hash.Add($Account, $arrTmp)
            }
            else {
                if ($dt -gt $hash[$Account]){$hash[$Account] = $arrTmp}
            }
    
        }
    }
    
    #Write File
    "Conta;Nome;Criação;Ultimo Logon" | out-file -filepath $FileOut
    
    foreach ($key in $hash.keys){ 
        
        if ($hash.item($key)[2].year -eq 1600){
            #Nunca logou
        }else{
        
            $a = New-TimeSpan $hash.item($key)[2].date $(Get-Date).date 
            if ($a.days -gt 90){
                $Line = $key+";"+$hash.item($key)[0]+";"+$hash.item($key)[1]+";"+$hash.item($key)[2] 
                $Line | out-file -filepath $FileOut  -append 
            }
        }
    } 
    

    Veja o IF no final, só vai para o arquivo os com 90 dias ou mais.


    Fábio de Paula Junior

    sexta-feira, 31 de agosto de 2012 19:34
    Moderador
  • Pedro,

    Teste este:

    # ============================================================================================== 
    #  
    # AUTOR: Fábio de Paula Junior 
    # DATA : 11/07/2011
    #  
    #        Este script lê o atributo lastlogon de todos os DCs do dominio 
    #  (o atributo lastlogon não é replicado entre os DCs) e gera um CSV contendo sAMAccountName, 
    #  Name, when created e lastlogon (o verdadeiro, a data mais recente encontrada entre todos os DCs).
    #
    #        Eu não utilizei módulos de terceiros, ele foi feito em puro PowerShell.
    #  
    # ============================================================================================== 
    
    
    $FileOut = "C:\temp\lastlogon.csv"
    
    $strFilter = "(&(objectCategory=person)(objectClass=user))"
    
    #Empty Hash
    $hash = @{}
    
    
    # List each Domain Controller
    $StrDCs = [System.DirectoryServices.ActiveDirectory.Domain]::getcurrentdomain() | foreach{$_.DomainControllers| foreach{$_.Name}}
    
    $StrDCs | foreach-object {
        
        $StrEachDC = "LDAP://"+$_.split(".")[0]
    
        $objDomain = New-Object System.DirectoryServices.DirectoryEntry $StrEachDC
    
        $objSearcher = New-Object System.DirectoryServices.DirectorySearcher
        $objSearcher.SearchRoot = $objDomain
        $objSearcher.PageSize = 1000
        $objSearcher.Filter = $strFilter
        $objSearcher.SearchScope = "Subtree"
    
        $colProplist = "name","sAMAccountName","lastlogon","whenCreated"
        foreach ($i in $colPropList){$objSearcher.PropertiesToLoad.Add($i)}
    
        $colResults = $objSearcher.FindAll()
    
        foreach ($objResult in $colResults){
            $User  = $objResult.Properties;
    	[string]$lastLogonInterval = $User.lastlogon
            $dtLogon  =  [System.DateTime]::FromFileTime($lastLogonInterval)
            $dtCreated= $User.whenCreated
            $Account=$User.samaccountname[0]
            
            #Array
            $arrTmp = $User.name[0],$dtCreated,$dtLogon
            
            if (-not $Hash.ContainsKey($Account)) {
                $hash.Add($Account, $arrTmp)
            }
            else {
                if ($dt -gt $hash[$Account]){$hash[$Account] = $arrTmp}
            }
    
        }
    }
    
    #Write File
    "Conta;Nome;Criação;Ultimo Logon" | out-file -filepath $FileOut
    
    foreach ($key in $hash.keys){ 
        
        if ($hash.item($key)[2].year -eq 1600){
            #Nunca logou
        }else{
        
            $a = New-TimeSpan $hash.item($key)[2].date $(Get-Date).date 
            if ($a.days -gt 90){
                $Line = $key+";"+$hash.item($key)[0]+";"+$hash.item($key)[1]+";"+$hash.item($key)[2] 
                $Line | out-file -filepath $FileOut  -append 
            }
        }
    } 

    Veja o IF no final, só vai para o arquivo os com 90 dias ou mais.


    Fábio de Paula Junior

    Fabio, bom dia.

    O script funcionou, mas o estranho é que ele me trouxe usuarios que eu tenho certeza que se logou recentimente, pq são colegas de trabalho.

    Tem algum outro parametro que eu possa testar?


    O mundo é uma "janela" de oportunidades

    segunda-feira, 3 de setembro de 2012 14:01
  • Pedro,

    Você pode fazer duas alterações para ajudar a debugar;

    Primeira

    trocar 

    $strFilter = "(&(objectCategory=person)(objectClass=user))"


    por

    $strFilter = "(&(objectCategory=person)(objectClass=user)(sAMAccountName=fabiojr))"

    Isto vai fazer um filtro para que apenas o usuário com login fabiojr seja pesquisado, troque pelo usuário que vc acha estar com problema.

    Segundo:

    Após a linha

     $Account=$User.samaccountname[0]

    adicione

    "$StrEachDC :  $Account : $dtLogon"

    Isto vai fazer com que seja mostrado na tela a informação da data do usuário fabiojr em cada DC.

    Veja um exemplo da saida

    LDAP://SVDC01 :  fabiojr : 03/09/1600 12:01:29
    LDAP://SVDC02 :  fabiojr : 12/31/1600 21:00:00

    Neste exemplo indicou que fabiojr logou pela ultima vez no SVDC01 (é a data mais recente), e a propósito nunca logou no SVDC02 (ano de 1600?)


    Fábio de Paula Junior

    segunda-feira, 3 de setembro de 2012 16:00
    Moderador
  • Em qual sistema operacional você está executando este script?

    Fábio de Paula Junior

    segunda-feira, 3 de setembro de 2012 16:01
    Moderador
  • Em qual sistema operacional você está executando este script?

    Fábio de Paula Junior

    Fábio, eu estou executando no Windows Server 2008R2 Standart, S.O Virtual em Hyper-V.

    Testarie suas alterações e logo estarei postando.

    Obrigado, pela ajuda.


    O mundo é uma "janela" de oportunidades

    segunda-feira, 3 de setembro de 2012 17:01
  • Em qual sistema operacional você está executando este script?


    Fábio de Paula Junior

    Fábio, eu estou executando no Windows Server 2008R2 Standart, S.O Virtual em Hyper-V.

    Testarie suas alterações e logo estarei postando.

    Obrigado, pela ajuda.


    O mundo é uma "janela" de oportunidades

    Fabio em alugns momentos deu erro, segue a saida.

    Desculpa por não te informar anteriormente mais quando eu rodei o primeiro sem o filtrar por um usuario expecifico

    tb deu o mesmo erro, deve ter sido isso a causa da consulta não ter saido 100%.

    O erro é o msm nos dois tipos de consulta.

    

    PS C:\Users\pcampos.DEDIC-BR> $FileOut = "C:\temp\lastlogon.csv"
    PS C:\Users\pcampos.DEDIC-BR>
    PS C:\Users\pcampos.DEDIC-BR> $strFilter = "(&(objectCategory=person)(objectClass=user)(sAMAccountName=384177498))"
    PS C:\Users\pcampos.DEDIC-BR>
    PS C:\Users\pcampos.DEDIC-BR> #Empty Hash
    PS C:\Users\pcampos.DEDIC-BR> $hash = @{}
    PS C:\Users\pcampos.DEDIC-BR>
    PS C:\Users\pcampos.DEDIC-BR>
    PS C:\Users\pcampos.DEDIC-BR> # List each Domain Controller
    PS C:\Users\pcampos.DEDIC-BR> $StrDCs = [System.DirectoryServices.ActiveDirectory.Domain]::getcurrentdomain() | foreach{
    $_.DomainControllers| foreach{$_.Name}}
    PS C:\Users\pcampos.DEDIC-BR>
    PS C:\Users\pcampos.DEDIC-BR> $StrDCs | foreach-object {
    >>
    >>     $StrEachDC = "LDAP://"+$_.split(".")[0]
    >>
    >>     $objDomain = New-Object System.DirectoryServices.DirectoryEntry $StrEachDC
    >>
    >>     $objSearcher = New-Object System.DirectoryServices.DirectorySearcher
    >>     $objSearcher.SearchRoot = $objDomain
    >>     $objSearcher.PageSize = 1000
    >>     $objSearcher.Filter = $strFilter
    >>     $objSearcher.SearchScope = "Subtree"
    >>
    >>     $colProplist = "name","sAMAccountName","lastlogon","whenCreated"
    >>     foreach ($i in $colPropList){$objSearcher.PropertiesToLoad.Add($i)}
    >>
    >>     $colResults = $objSearcher.FindAll()
    >>
    >>     foreach ($objResult in $colResults){
    >>         $User  = $objResult.Properties;
    >>     [string]$lastLogonInterval = $User.lastlogon
    >>         $dtLogon  =  [System.DateTime]::FromFileTime($lastLogonInterval)
    >>         $dtCreated= $User.whenCreated
    >>         $Account=$User.samaccountname[0]
    >>         "$StrEachDC :  $Account : $dtLogon"
    >>
    >>         #Array
    >>         $arrTmp = $User.name[0],$dtCreated,$dtLogon
    >>
    >>         if (-not $Hash.ContainsKey($Account)) {
    >>             $hash.Add($Account, $arrTmp)
    >>         }
    >>         else {
    >>             if ($dt -gt $hash[$Account]){$hash[$Account] = $arrTmp}
    >>         }
    >>
    >>     }
    >> }
    >>
    0
    1
    2
    3
    LDAP://BRSPOQS001 :  384177498 : 08/08/2011 11:56:21
    0
    1
    2
    3
    Exception calling "FindAll" with "0" argument(s): "The server is not operational.
    "
    At line:11 char:39
    +     $colResults = $objSearcher.FindAll <<<< ()
        + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
        + FullyQualifiedErrorId : DotNetMethodException

    LDAP://BRSPOAN002 :  384177498 : 08/08/2011 11:56:21
    0
    1
    2
    3
    LDAP://BRSPODC002 :  384177498 : 08/05/2012 15:57:38
    0
    1
    2
    3
    LDAP://BRLDALA002 :  384177498 : 12/31/1600 22:00:00
    0
    1
    2
    3
    LDAP://BRLDALA001 :  384177498 : 12/31/1600 22:00:00
    0
    1
    2
    3
    LDAP://BRBRACN001 :  384177498 : 12/31/1600 22:00:00
    0
    1
    2
    3
    LDAP://BRSPOBC001 :  384177498 : 09/17/2011 09:09:38
    0
    1
    2
    3
    LDAP://BRCASQC001 :  384177498 : 08/16/2012 13:38:08
    0
    1
    2
    3
    LDAP://BRCASEH001 :  384177498 : 12/31/1600 22:00:00
    0
    1
    2
    3
    LDAP://BRSPOBL002 :  384177498 : 12/31/1600 22:00:00
    0
    1
    2
    3
    Exception calling "FindAll" with "0" argument(s): "The server is not operational.
    "
    At line:11 char:39
    +     $colResults = $objSearcher.FindAll <<<< ()
        + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
        + FullyQualifiedErrorId : DotNetMethodException

    LDAP://BRSPOAN001 :  384177498 : 12/31/1600 22:00:00
    0
    1
    2
    3
    LDAP://BRCASCT001 :  384177498 : 12/31/1600 22:00:00
    0
    1
    2
    3
    LDAP://BRBRACN002 :  384177498 : 12/31/1600 22:00:00
    0
    1
    2
    3
    LDAP://BRSPOEG001 :  384177498 : 03/30/2012 09:50:36
    0
    1
    2
    3
    LDAP://brcaseh002 :  384177498 : 12/31/1600 22:00:00
    0
    1
    2
    3
    LDAP://BRSPOPL001 :  384177498 : 08/17/2012 09:25:15
    0
    1
    2
    3
    LDAP://BRSPOBL001 :  384177498 : 12/31/1600 22:00:00
    0
    1
    2
    3
    LDAP://BRJOIPJ001 :  384177498 : 12/31/1600 22:00:00
    0
    1
    2
    3
    LDAP://BRJOIPJ002 :  384177498 : 12/31/1600 22:00:00
    0
    1
    2
    3
    LDAP://BRSPODC001 :  384177498 : 08/16/2012 13:21:22
    0
    1
    2
    3
    LDAP://BRCASQC002 :  384177498 : 08/18/2012 00:01:27
    0
    1
    2
    3
    LDAP://BRSPOEG002 :  384177498 : 12/31/1600 22:00:00
    0
    1
    2
    3
    LDAP://BRSPOPL002 :  384177498 : 08/17/2012 15:32:19
    PS C:\Users\pcampos.DEDIC-BR> #Write File
    PS C:\Users\pcampos.DEDIC-BR> "Conta;Nome;Criaçao;Ultimo Logon" | out-file -filepath $FileOut
    PS C:\Users\pcampos.DEDIC-BR>
    PS C:\Users\pcampos.DEDIC-BR> foreach ($key in $hash.keys){
    >>
    >>     if ($hash.item($key)[2].year -eq 1600){
    >>         #Nunca logou
    >>     }else{
    >>
    >>         $a = New-TimeSpan $hash.item($key)[2].date $(Get-Date).date
    >>         if ($a.days -gt 90){
    >>             $Line = $key+";"+$hash.item($key)[0]+";"+$hash.item($key)[1]+";"+$hash.item($key)[2]
    >>             $Line | out-file -filepath $FileOut  -append
    >>         }
    >>     }
    >> }
    >>
    PS C:\Users\pcampos.DEDIC-BR>


    O mundo é uma "janela" de oportunidades

    segunda-feira, 3 de setembro de 2012 17:31

  • No erro The server is not operational. parece que você tem um problema com alguns DCs (LDAP://BRSPOAN002 e LDAP://BRSPOAN001)

    E agora? Qual o resultado você esperava e qual resultado efetivo do script (dentro do arquivo gerado?)

    Se olhei certo o resultado correto (ultimo logon) seria: LDAP://BRCASQC002 :  384177498 : 08/18/2012 00:01:27

    Foi isso que apareceu escrito no arquivo de resultado?


    Fábio de Paula Junior

    segunda-feira, 3 de setembro de 2012 17:56
    Moderador
  • Em qual sistema operacional você está executando este script?


    Fábio de Paula Junior

    Fábio, eu estou executando no Windows Server 2008R2 Standart, S.O Virtual em Hyper-V.

    Testarie suas alterações e logo estarei postando.

    Obrigado, pela ajuda.


    O mundo é uma "janela" de oportunidades

    Fabio em alugns momentos deu erro, segue a saida.

    Desculpa por não te informar anteriormente mais quando eu rodei o primeiro sem o filtrar por um usuario expecifico

    tb deu o mesmo erro, deve ter sido isso a causa da consulta não ter saido 100%.

    O erro é o msm nos dois tipos de consulta.

    

    PS C:\Users\pcampos.DEDIC-BR> $FileOut = "C:\temp\lastlogon.csv"
    PS C:\Users\pcampos.DEDIC-BR>
    PS C:\Users\pcampos.DEDIC-BR> $strFilter = "(&(objectCategory=person)(objectClass=user)(sAMAccountName=384177498))"
    PS C:\Users\pcampos.DEDIC-BR>
    PS C:\Users\pcampos.DEDIC-BR> #Empty Hash
    PS C:\Users\pcampos.DEDIC-BR> $hash = @{}
    PS C:\Users\pcampos.DEDIC-BR>
    PS C:\Users\pcampos.DEDIC-BR>
    PS C:\Users\pcampos.DEDIC-BR> # List each Domain Controller
    PS C:\Users\pcampos.DEDIC-BR> $StrDCs = [System.DirectoryServices.ActiveDirectory.Domain]::getcurrentdomain() | foreach{
    $_.DomainControllers| foreach{$_.Name}}
    PS C:\Users\pcampos.DEDIC-BR>
    PS C:\Users\pcampos.DEDIC-BR> $StrDCs | foreach-object {
    >>
    >>     $StrEachDC = "LDAP://"+$_.split(".")[0]
    >>
    >>     $objDomain = New-Object System.DirectoryServices.DirectoryEntry $StrEachDC
    >>
    >>     $objSearcher = New-Object System.DirectoryServices.DirectorySearcher
    >>     $objSearcher.SearchRoot = $objDomain
    >>     $objSearcher.PageSize = 1000
    >>     $objSearcher.Filter = $strFilter
    >>     $objSearcher.SearchScope = "Subtree"
    >>
    >>     $colProplist = "name","sAMAccountName","lastlogon","whenCreated"
    >>     foreach ($i in $colPropList){$objSearcher.PropertiesToLoad.Add($i)}
    >>
    >>     $colResults = $objSearcher.FindAll()
    >>
    >>     foreach ($objResult in $colResults){
    >>         $User  = $objResult.Properties;
    >>     [string]$lastLogonInterval = $User.lastlogon
    >>         $dtLogon  =  [System.DateTime]::FromFileTime($lastLogonInterval)
    >>         $dtCreated= $User.whenCreated
    >>         $Account=$User.samaccountname[0]
    >>         "$StrEachDC :  $Account : $dtLogon"
    >>
    >>         #Array
    >>         $arrTmp = $User.name[0],$dtCreated,$dtLogon
    >>
    >>         if (-not $Hash.ContainsKey($Account)) {
    >>             $hash.Add($Account, $arrTmp)
    >>         }
    >>         else {
    >>             if ($dt -gt $hash[$Account]){$hash[$Account] = $arrTmp}
    >>         }
    >>
    >>     }
    >> }
    >>
    0
    1
    2
    3
    LDAP://BRSPOQS001 :  384177498 : 08/08/2011 11:56:21
    0
    1
    2
    3
    Exception calling "FindAll" with "0" argument(s): "The server is not operational.
    "
    At line:11 char:39
    +     $colResults = $objSearcher.FindAll <<<< ()
        + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
        + FullyQualifiedErrorId : DotNetMethodException

    LDAP://BRSPOAN002 :  384177498 : 08/08/2011 11:56:21
    0
    1
    2
    3
    LDAP://BRSPODC002 :  384177498 : 08/05/2012 15:57:38
    0
    1
    2
    3
    LDAP://BRLDALA002 :  384177498 : 12/31/1600 22:00:00
    0
    1
    2
    3
    LDAP://BRLDALA001 :  384177498 : 12/31/1600 22:00:00
    0
    1
    2
    3
    LDAP://BRBRACN001 :  384177498 : 12/31/1600 22:00:00
    0
    1
    2
    3
    LDAP://BRSPOBC001 :  384177498 : 09/17/2011 09:09:38
    0
    1
    2
    3
    LDAP://BRCASQC001 :  384177498 : 08/16/2012 13:38:08
    0
    1
    2
    3
    LDAP://BRCASEH001 :  384177498 : 12/31/1600 22:00:00
    0
    1
    2
    3
    LDAP://BRSPOBL002 :  384177498 : 12/31/1600 22:00:00
    0
    1
    2
    3
    Exception calling "FindAll" with "0" argument(s): "The server is not operational.
    "
    At line:11 char:39
    +     $colResults = $objSearcher.FindAll <<<< ()
        + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
        + FullyQualifiedErrorId : DotNetMethodException

    LDAP://BRSPOAN001 :  384177498 : 12/31/1600 22:00:00
    0
    1
    2
    3
    LDAP://BRCASCT001 :  384177498 : 12/31/1600 22:00:00
    0
    1
    2
    3
    LDAP://BRBRACN002 :  384177498 : 12/31/1600 22:00:00
    0
    1
    2
    3
    LDAP://BRSPOEG001 :  384177498 : 03/30/2012 09:50:36
    0
    1
    2
    3
    LDAP://brcaseh002 :  384177498 : 12/31/1600 22:00:00
    0
    1
    2
    3
    LDAP://BRSPOPL001 :  384177498 : 08/17/2012 09:25:15
    0
    1
    2
    3
    LDAP://BRSPOBL001 :  384177498 : 12/31/1600 22:00:00
    0
    1
    2
    3
    LDAP://BRJOIPJ001 :  384177498 : 12/31/1600 22:00:00
    0
    1
    2
    3
    LDAP://BRJOIPJ002 :  384177498 : 12/31/1600 22:00:00
    0
    1
    2
    3
    LDAP://BRSPODC001 :  384177498 : 08/16/2012 13:21:22
    0
    1
    2
    3
    LDAP://BRCASQC002 :  384177498 : 08/18/2012 00:01:27
    0
    1
    2
    3
    LDAP://BRSPOEG002 :  384177498 : 12/31/1600 22:00:00
    0
    1
    2
    3
    LDAP://BRSPOPL002 :  384177498 : 08/17/2012 15:32:19
    PS C:\Users\pcampos.DEDIC-BR> #Write File
    PS C:\Users\pcampos.DEDIC-BR> "Conta;Nome;Criaçao;Ultimo Logon" | out-file -filepath $FileOut
    PS C:\Users\pcampos.DEDIC-BR>
    PS C:\Users\pcampos.DEDIC-BR> foreach ($key in $hash.keys){
    >>
    >>     if ($hash.item($key)[2].year -eq 1600){
    >>         #Nunca logou
    >>     }else{
    >>
    >>         $a = New-TimeSpan $hash.item($key)[2].date $(Get-Date).date
    >>         if ($a.days -gt 90){
    >>             $Line = $key+";"+$hash.item($key)[0]+";"+$hash.item($key)[1]+";"+$hash.item($key)[2]
    >>             $Line | out-file -filepath $FileOut  -append
    >>         }
    >>     }
    >> }
    >>
    PS C:\Users\pcampos.DEDIC-BR>


    O mundo é uma "janela" de oportunidades


    Fabio, tenho 23 DC's o que me parece ele não consegue "chegar" em dois, teria algum motivo?

    O mundo é uma "janela" de oportunidades

    segunda-feira, 3 de setembro de 2012 17:57
  • Acabei encontrando um erro no script, quando ele não consegue ler o DC ele mantem os dados do DC anterior.

    Segue o novo, veja se consegue identificar a alteração

    $StrDCs | foreach-object {
    
        #Reseta Variaveis
        $dtLogon=get-date "01/01/1600"
        
        
        $StrEachDC = "LDAP://"+$_.split(".")[0]

    Entre a linha que começa com $strDCs |... e a $strEachDC =... eu adicionei um comentário (#Reseta Variaveis) e a próxima faz com que dtLogon receba 01/01/1600.

    Quanto as DCs, não faço a minima idéia. Pode ser firewall habilitado pelo caminho.

    Vc não me disse qual o valor foi parar no arquivo, isto é, o resultado final.


    Fábio de Paula Junior

    segunda-feira, 3 de setembro de 2012 20:46
    Moderador
  • Prezado,

    O lastlogon não replica para todos os ADs. Se você tiver mais de um AD na sua rede, em localidades remotas a informação do parametro lastloogn não é replicada. O correto é utilizar o parametro lastlogontimestamp que é replicado para todos os ADs da rede. Segue um pequeno script retirado do próprio Windows da ferramenta Central Administrativa do AD, que é instalado com o RSAT.

    Apenas para 90 dias: (&(objectCategory=person)(objectClass=user)(!userAccountControl:1.2.840.113556.1.4.803:=2)(|(lastLogonTimestamp<=129833388000000000)))

    Para 90 dias e quen nunca fez logon: (&(objectCategory=person)(objectClass=user)(!userAccountControl:1.2.840.113556.1.4.803:=2)(|(lastLogonTimestamp<=129833388000000000)(!lastLogonTimestamp=*)))

    Basta colar nas querys do AD e testar.

    segunda-feira, 3 de setembro de 2012 22:35
  • Elton,

    Vc está correto em parte, realmente lastlogon não replica para os outros DCs, por isso o script passa por todos os DCs para saber qual é o valor do lastlogon mais recente entre todos os DC.

    Mas aí vc pergunta: Pra que isso se o lastlogontimestamp é replicado? Bastaria pesquisar em um.

    Porém esta replicação não é realtime então o DC que você pesquisar pode estar com uma diferença de dias em relação ao valor real(considero valor real o lastlogon mais recente entre todos os DCs).

    “The LastLogonTimeStamp Attribute” – “What it was designed for and how it works”

    http://blogs.technet.com/b/askds/archive/2009/04/15/the-lastlogontimestamp-attribute-what-it-was-designed-for-and-how-it-works.aspx


    Fábio de Paula Junior


    terça-feira, 4 de setembro de 2012 11:37
    Moderador
  • Acabei encontrando um erro no script, quando ele não consegue ler o DC ele mantem os dados do DC anterior.

    Segue o novo, veja se consegue identificar a alteração

    $StrDCs | foreach-object {
    
        #Reseta Variaveis
        $dtLogon=get-date "01/01/1600"
        
        
        $StrEachDC = "LDAP://"+$_.split(".")[0]

    Entre a linha que começa com $strDCs |... e a $strEachDC =... eu adicionei um comentário (#Reseta Variaveis) e a próxima faz com que dtLogon receba 01/01/1600.

    Quanto as DCs, não faço a minima idéia. Pode ser firewall habilitado pelo caminho.

    Vc não me disse qual o valor foi parar no arquivo, isto é, o resultado final.


    Fábio de Paula Junior

    Fábio, bom dia.

    No arquivo a saida foi:

    Conta;Nome;Criação;ultimo Logon

    384177498;Acsa da Silva Gomes;;08/08/2011 11:56:21

    Porem quando o script foi executado apareceu data mais recente

    
    
    
    

    O mundo é uma "janela" de oportunidades

    terça-feira, 4 de setembro de 2012 12:02
  • Passa o log todo, todas as datas como vc fez antes.

    Fábio de Paula Junior

    terça-feira, 4 de setembro de 2012 12:26
    Moderador
  • 
    
    
    
    
    
    
    

    Fábio vamos lá.

    Saida do power shell.

    Retirei os 0 1 2 3 entre os DC's para diminuir o espaço

    A saida o txt é a msm que te informei acima

    
    

    

    O mundo é uma "janela" de oportunidades

    terça-feira, 4 de setembro de 2012 13:26
  • Pedro,

    Por favor passa também o script completo que você está usando.


    Fábio de Paula Junior

    terça-feira, 4 de setembro de 2012 13:29
    Moderador
  • Pedro,

    Por favor passa também o script completo que você está usando.


    Fábio de Paula Junior


    $FileOut = "C:\temp\lastlogon.csv"
    
    $strFilter = "(&(objectCategory=person)(objectClass=user)(sAMAccountName=384177498))"
    
    #Empty Hash
    $hash = @{}
    
    
    # List each Domain Controller
    $StrDCs = [System.DirectoryServices.ActiveDirectory.Domain]::getcurrentdomain() | foreach{$_.DomainControllers| foreach{$_.Name}}
    
    $StrDCs | foreach-object {
    #Reseta Variaveis
        $dtLogon=get-date "01/01/1600"
        
        $StrEachDC = "LDAP://"+$_.split(".")[0]
    
        $objDomain = New-Object System.DirectoryServices.DirectoryEntry $StrEachDC
    
        $objSearcher = New-Object System.DirectoryServices.DirectorySearcher
        $objSearcher.SearchRoot = $objDomain
        $objSearcher.PageSize = 1000
        $objSearcher.Filter = $strFilter
        $objSearcher.SearchScope = "Subtree"
    
        $colProplist = "name","sAMAccountName","lastlogon","whenCreated"
        foreach ($i in $colPropList){$objSearcher.PropertiesToLoad.Add($i)}
    
        $colResults = $objSearcher.FindAll()
    
        foreach ($objResult in $colResults){
            $User  = $objResult.Properties;
    	[string]$lastLogonInterval = $User.lastlogon
            $dtLogon  =  [System.DateTime]::FromFileTime($lastLogonInterval)
            $dtCreated= $User.whenCreated
            $Account=$User.samaccountname[0]
            "$StrEachDC :  $Account : $dtLogon"
            
            #Array
            $arrTmp = $User.name[0],$dtCreated,$dtLogon
            
            if (-not $Hash.ContainsKey($Account)) {
                $hash.Add($Account, $arrTmp)
            }
            else {
                if ($dt -gt $hash[$Account]){$hash[$Account] = $arrTmp}
            }
    
        }
    }
    
    #Write File
    "Conta;Nome;Criação;Ultimo Logon" | out-file -filepath $FileOut
    
    foreach ($key in $hash.keys){ 
        
        if ($hash.item($key)[2].year -eq 1600){
            #Nunca logou
        }else{
        
            $a = New-TimeSpan $hash.item($key)[2].date $(Get-Date).date 
            if ($a.days -gt 90){
                $Line = $key+";"+$hash.item($key)[0]+";"+$hash.item($key)[1]+";"+$hash.item($key)[2] 
                $Line | out-file -filepath $FileOut  -append 
            }
        }
    } 


    O mundo é uma "janela" de oportunidades

    terça-feira, 4 de setembro de 2012 14:02
  • Elton,

    Vc está correto em parte, realmente lastlogon não replica para os outros DCs, por isso o script passa por todos os DCs para saber qual é o valor do lastlogon mais recente entre todos os DC.

    Mas aí vc pergunta: Pra que isso se o lastlogontimestamp é replicado? Bastaria pesquisar em um.

    Porém esta replicação não é realtime então o DC que você pesquisar pode estar com uma diferença de dias em relação ao valor real(considero valor real o lastlogon mais recente entre todos os DCs).

    “The LastLogonTimeStamp Attribute” – “What it was designed for and how it works”

    http://blogs.technet.com/b/askds/archive/2009/04/15/the-lastlogontimestamp-attribute-what-it-was-designed-for-and-how-it-works.aspx


    Fábio de Paula Junior


    Fábio,

    PERFEITO. Li o artigo que você me enviou. Havia lido somente que as informações do LastLogonTimeStamp era replicada para todos os DC´s, porém vi agora que ela pode estar com dias de atraso.

    Abraço.

    terça-feira, 4 de setembro de 2012 15:01
  • Pedro,

    Segue versão nova versão, acho que encontrei o erro, estava errado na parte que faz a comparação com a data do DC que eu já peguei com a data do DC atual, por isso acabava prevalecendo a primeira informação que ele pegou.

    $FileOut = "C:\temp\lastlogon.csv"
    
    $strFilter = "(&(objectCategory=person)(objectClass=user)(sAMAccountName=384177498))"
    
    #Empty Hash
    $hash = @{}
    
    
    # List each Domain Controller
    $StrDCs = [System.DirectoryServices.ActiveDirectory.Domain]::getcurrentdomain() | foreach{$_.DomainControllers| foreach{$_.Name}}
    
    $StrDCs | foreach-object {
    #Reseta Variaveis
        $dtLogon=get-date "01/01/1600"
        
        $StrEachDC = "LDAP://"+$_.split(".")[0]
    
        $objDomain = New-Object System.DirectoryServices.DirectoryEntry $StrEachDC
    
        $objSearcher = New-Object System.DirectoryServices.DirectorySearcher
        $objSearcher.SearchRoot = $objDomain
        $objSearcher.PageSize = 1000
        $objSearcher.Filter = $strFilter
        $objSearcher.SearchScope = "Subtree"
    
        $colProplist = "name","sAMAccountName","lastlogon","whenCreated"
        foreach ($i in $colPropList){$objSearcher.PropertiesToLoad.Add($i)}
    
        $colResults = $objSearcher.FindAll()
    
        foreach ($objResult in $colResults){
            $User  = $objResult.Properties;
    	[string]$lastLogonInterval = $User.lastlogon
            $dtLogon  =  [System.DateTime]::FromFileTime($lastLogonInterval)
            $dtCreated= $User.whenCreated
            $Account=$User.samaccountname[0]
            "$StrEachDC :  $Account : $dtLogon"
            
            #Array
            $arrTmp = $User.name[0],$dtCreated,$dtLogon
            
            if (-not $Hash.ContainsKey($Account)) {
                $hash.Add($Account, $arrTmp)
            }
            else {
    	    
                if ($dtLogon -gt $hash.item($Account)[2]){$hash[$Account] = $arrTmp}
            }
    
        }
    }
    
    #Write File
    "Conta;Nome;Criação;Ultimo Logon" | out-file -filepath $FileOut
    
    foreach ($key in $hash.keys){ 
        
        if ($hash.item($key)[2].year -eq 1600){
            #Nunca logou
        }else{
        
            $a = New-TimeSpan $hash.item($key)[2].date $(Get-Date).date 
            if ($a.days -gt 90){
                $Line = $key+";"+$hash.item($key)[0]+";"+$hash.item($key)[1]+";"+$hash.item($key)[2] 
                $Line | out-file -filepath $FileOut  -append 
            }
        }
    
    } 


    Fábio de Paula Junior

    terça-feira, 4 de setembro de 2012 15:21
    Moderador
  • Fábio, eu testei e agora me parece OK.

    Uma duvida posso trocar o (if ($a.days -gt 900}) por qualquer data?

    

    O mundo é uma "janela" de oportunidades

    terça-feira, 4 de setembro de 2012 17:59
  • Obrigado pela ajuda e dedicação para resolver o problema


    O mundo é uma "janela" de oportunidades

    terça-feira, 4 de setembro de 2012 18:01
  • Pedro,

    Obrigado a você por ter testado o script, vou atualizar a galeria .


    Fábio de Paula Junior

    terça-feira, 4 de setembro de 2012 18:29
    Moderador