Windows Vista Forums

Working with arrays

  1. #1


    Jobbsy Guest

    Working with arrays

    I have having the following problem:

    I have an array say $events
    i obtained from get-eventlog (which say returns a number of events matching
    the criteria set)

    when displayed it will give something like

    {passwordlastset: 15\12\70 callerusername: administrator}

    I am basically trying to write only where the passwordlastchanged criteria
    match and the user did not change the password himself from similar code to
    below:

    foreach ($objuser in $AD)
    {
    foreach ($event in $events)
    {
    $P = $event.passwordlastset
    $N = $event.callerusername
    IF ($passwordlastsetobtainedfromADSI -eq $P) -and ($N -ine
    $usersnameobtainedfromADSI)
    {
    write-host "$N" + " was the last person to change the password of " +
    "$usersnameobtainedfromADSI"
    }
    }
    }
    The problem I have is it will hit the first person who meets the criteria
    and write as expected but also the same info for each and every user
    thereafter - any help would be much appreciated as I have tried a number of
    things all to no avail
    --
    jobbsy@xxxxxx



      My System SpecsSystem Spec

  2. #2


    Shay Levi Guest

    Re: Working with arrays

    It's hard to say just from viewing the code sample. You can try to assign
    the variables to $null or "" in each iteration.

    BTW, -ine (case-insensitive comparison) is the same as -ne.
    Also, if $N and $usersnameobtainedfromADSI are strings then you don't need
    to concatenate the variables:

    write-host "$N" + " was the last person to change the password of " + "$usersnameobtainedfromADSI"

    You can simply write:

    write-host "$N was the last person to change the password of $usersnameobtainedfromADSI"



    -----
    Shay Levi
    $cript Fanatic
    http://scriptolog.blogspot.com



    > I have having the following problem:
    >
    > I have an array say $events
    > i obtained from get-eventlog (which say returns a number of events
    > matching
    > the criteria set)
    > when displayed it will give something like
    >
    > {passwordlastset: 15\12\70 callerusername: administrator}
    >
    > I am basically trying to write only where the passwordlastchanged
    > criteria match and the user did not change the password himself from
    > similar code to below:
    >
    > foreach ($objuser in $AD)
    > {
    > foreach ($event in $events)
    > {
    > $P = $event.passwordlastset
    > $N = $event.callerusername
    > IF ($passwordlastsetobtainedfromADSI -eq $P) -and ($N -ine
    > $usersnameobtainedfromADSI)
    > {
    > write-host "$N" + " was the last person to change the password of "
    > +
    > "$usersnameobtainedfromADSI"
    > }
    > }
    > }
    > The problem I have is it will hit the first person who meets the
    > criteria and write as expected but also the same info for each and
    > every user thereafter - any help would be much appreciated as I have
    > tried a number of things all to no avail
    >


      My System SpecsSystem Spec

  3. #3


    Jobbsy Guest

    Re: Working with arrays

    Thanks Shay there's nothing else I believe coming into the second loop that
    would effect it - I hav tried with both $null and "" and the code works fine
    until there is an earlier entry picked up - I test this by changing the
    password of same user in quickish succesion and running against a certain
    -newest no of eventlog entries knowing I will pick them both up - therefore
    the earlier one shouldnn't match the passwordlastset adsi value, although it
    would match -ne to username).

    Yes thanks for the write-host and -ieq tip.




    --
    jobbsy@xxxxxx


    "Shay Levi" wrote:

    > It's hard to say just from viewing the code sample. You can try to assign
    > the variables to $null or "" in each iteration.
    >
    > BTW, -ine (case-insensitive comparison) is the same as -ne.
    > Also, if $N and $usersnameobtainedfromADSI are strings then you don't need
    > to concatenate the variables:
    >
    > write-host "$N" + " was the last person to change the password of " + "$usersnameobtainedfromADSI"
    >
    > You can simply write:
    >
    > write-host "$N was the last person to change the password of $usersnameobtainedfromADSI"
    >
    >
    >
    > -----
    > Shay Levi
    > $cript Fanatic
    > http://scriptolog.blogspot.com
    >
    >
    >

    > > I have having the following problem:
    > >
    > > I have an array say $events
    > > i obtained from get-eventlog (which say returns a number of events
    > > matching
    > > the criteria set)
    > > when displayed it will give something like
    > >
    > > {passwordlastset: 15\12\70 callerusername: administrator}
    > >
    > > I am basically trying to write only where the passwordlastchanged
    > > criteria match and the user did not change the password himself from
    > > similar code to below:
    > >
    > > foreach ($objuser in $AD)
    > > {
    > > foreach ($event in $events)
    > > {
    > > $P = $event.passwordlastset
    > > $N = $event.callerusername
    > > IF ($passwordlastsetobtainedfromADSI -eq $P) -and ($N -ine
    > > $usersnameobtainedfromADSI)
    > > {
    > > write-host "$N" + " was the last person to change the password of "
    > > +
    > > "$usersnameobtainedfromADSI"
    > > }
    > > }
    > > }
    > > The problem I have is it will hit the first person who meets the
    > > criteria and write as expected but also the same info for each and
    > > every user thereafter - any help would be much appreciated as I have
    > > tried a number of things all to no avail
    > >
    >
    >
    >

      My System SpecsSystem Spec

  4. #4


    Shay Levi Guest

    Re: Working with arrays

    What are the types of $N, $P, etc? (e.g $N.gettype())


    Doe's the same happens when you run:

    $N=@{name="CallerUserName";expression={$_.callerusername}}
    $P=@{name="PasswordLastSet";expression={$_.passwordlastset}}
    $ADSIUser =@{name="ADSIUserName";expression={$usersnameobtainedfromADSI}}

    $events | select $N,$P,$ADSIUser | format-table -auto


    -----
    Shay Levi
    $cript Fanatic
    http://scriptolog.blogspot.com



    > Thanks Shay there's nothing else I believe coming into the second loop
    > that would effect it - I hav tried with both $null and "" and the code
    > works fine until there is an earlier entry picked up - I test this by
    > changing the password of same user in quickish succesion and running
    > against a certain -newest no of eventlog entries knowing I will pick
    > them both up - therefore the earlier one shouldnn't match the
    > passwordlastset adsi value, although it would match -ne to username).
    >
    > Yes thanks for the write-host and -ieq tip.
    >
    > "Shay Levi" wrote:
    >

    >> It's hard to say just from viewing the code sample. You can try to
    >> assign the variables to $null or "" in each iteration.
    >>
    >> BTW, -ine (case-insensitive comparison) is the same as -ne. Also, if
    >> $N and $usersnameobtainedfromADSI are strings then you don't need to
    >> concatenate the variables:
    >>
    >> write-host "$N" + " was the last person to change the password of " +
    >> "$usersnameobtainedfromADSI"
    >>
    >> You can simply write:
    >>
    >> write-host "$N was the last person to change the password of
    >> $usersnameobtainedfromADSI"
    >>
    >> -----
    >> Shay Levi
    >> $cript Fanatic
    >> http://scriptolog.blogspot.com

    >>> I have having the following problem:
    >>>
    >>> I have an array say $events
    >>> i obtained from get-eventlog (which say returns a number of events
    >>> matching
    >>> the criteria set)
    >>> when displayed it will give something like
    >>> {passwordlastset: 15\12\70 callerusername: administrator}
    >>>
    >>> I am basically trying to write only where the passwordlastchanged
    >>> criteria match and the user did not change the password himself from
    >>> similar code to below:
    >>>
    >>> foreach ($objuser in $AD)
    >>> {
    >>> foreach ($event in $events)
    >>> {
    >>> $P = $event.passwordlastset
    >>> $N = $event.callerusername
    >>> IF ($passwordlastsetobtainedfromADSI -eq $P) -and ($N -ine
    >>> $usersnameobtainedfromADSI)
    >>> {
    >>> write-host "$N" + " was the last person to change the password of "
    >>> +
    >>> "$usersnameobtainedfromADSI"
    >>> }
    >>> }
    >>> }
    >>> The problem I have is it will hit the first person who meets the
    >>> criteria and write as expected but also the same info for each and
    >>> every user thereafter - any help would be much appreciated as I have
    >>> tried a number of things all to no avail


      My System SpecsSystem Spec

  5. #5


    Jobbsy Guest

    Re: Working with arrays

    Thanks for your help Shay I was able to figure it out (I needed the 5thField
    outside of the events loop from my finished code below - you were right
    without seeing all the code you could not have troubleshooted that - but
    appreciated your input - I'm sure this is not the most professional code ever
    but it works! - Thanks again


    #INITIALISATION SECTION
    #----------------------

    #Clear the Windows command console screen
    Clear-Host

    #CONSTANTS SECTION
    #-----------------

    $strDate = get-date -uformat "%Y-%m-%d"
    $CSVFilePath = 'c:\Documents and Settings\All
    Users\Desktop\SwapClearITD_users_'+$strDate+'.csv'

    #Delete previous file if exists
    $RetVal = Test-Path 'c:\Documents and Settings\All Users\Desktop\' |
    where-object {$_.name -like "*.CSV"}
    If ($RetVal = 'True')
    {
    Remove-Item 'c:\Documents and Settings\All Users\Desktop\*.CSV'
    }

    #Creates new dated file and specifies header for CSV.
    $strOutputString = "User,Member Of Group,Account Created,Password last
    changed"
    $strOutputString | out-file -Width 2147483647 -filepath $CSVFilePath
    -encoding ascii

    #Retrieve Events for Administrator Password Changes

    [regex]$regEx = ('\:\s+')
    $events = @()
    get-eventlog Security -newest 2000 |
    where {$_.eventID -eq '642'} |
    % {
    $obj = new-object psObject
    switch -regex ($_.message.split("`n")) {
    '^\s*Password Last Set\:' {
    add-member NoteProperty -name PasswordLastSet `
    -value $($regEx.split($_)[1]).trim() -in $obj
    }
    '^\s*Caller User Name\:' {
    add-member NoteProperty -name CallerUserName `
    -value $($regEx.split($_)[1]).trim() -in $obj
    }
    }
    $events += $obj
    }



    #FUNCTIONS & FILTERS SECTION
    #----------------------------



    #MAIN PROCESSING SECTION
    #-----------------------

    $Dom = 'LDAP://OU=test,DC=vmware,DC=vm'
    $Root = New-Object DirectoryServices.DirectoryEntry $Dom
    $i=0

    # Create a selector and start searching from the Root of AD
    $selector = New-Object DirectoryServices.DirectorySearcher
    $selector.SearchRoot = $root
    $selector.pagesize = 1000
    $adobj= $selector.findall() |`
    where {$_.properties.objectcategory -match "CN=Person"}


    foreach ($person in $adobj) {
    $prop=$person.properties
    $i++

    $1stField = "$($prop.name)" + ","


    # $2nd Field - Member Of
    #---------------------------------------------------------
    IF ("$($prop.memberof)" -match "CN=*") {
    #Remove the "CN=, OU=TEST," etc & just keep name of group at front of DN
    $s = "$($prop.memberof)"
    $firstdivofDN,$seconddivofDN,$thirddivofDN =
    ([regex]'=(.+?),').matches($s) | foreach {$_.Groups[1].Value}
    $2ndField = "$firstdivofDN" + ","
    } ELSE {
    $2ndField = "****NOT A MEMBER OF A GROUP****" + ","
    }
    # $3rd Field - date When account was created
    #------------------------------------------
    $AC = $($prop.whencreated)
    $AccountCreated = "{00:dd}/{00:MM}/{0000:yyyy} {0:hh}:{0:mm}:{0:ss}" -f($AC)

    $3rdField = "$AccountCreated" + ","

    # $4th Field - Password Last Set
    #----------------------------------------------------------
    #Convert the large Integer format into a readable date

    $LI = [datetime]::FromFileTimeUTC( $($prop.pwdlastset[0]) )
    $PWLSet = "{00:dd}/{00:MM}/{0000:yyyy} {0:hh}:{0:mm}:{0:ss}" -f ($LI)

    $4thField = "$PWLSet" + ","

    # $5th Field - Was Administrator last person to change Password?
    #--------------------------------------------------------------

    $5thField = ""

    IF ("$AccountCreated" -match "$PWLSet") {
    $5thField = "****PASSWORD NOT CHANGED SINCE ACCOUNT SETUP****" + ","
    } ELSE {
    Foreach($event in $events) { # from constants section at start

    $E = $event.PasswordLastSet

    $N = $event.CallerUserName

    IF (("$E" -match "$PWLSet") -and ("$N" -ne "$($prop.name)")) {
    $5thField = "****PASSWORD last Changed by " + "$N" + "****" + ","
    }
    }
    }


    $strOutputString = "$1stField" + "$2ndField" + "$3rdField" + "$4thField" +
    "$5thField"

    $strOutputString | out-file -filepath $CSVFilePath -encoding ascii -append

    }




    --
    jobbsy@xxxxxx


    "Shay Levi" wrote:

    > What are the types of $N, $P, etc? (e.g $N.gettype())
    >
    >
    > Doe's the same happens when you run:
    >
    > $N=@{name="CallerUserName";expression={$_.callerusername}}
    > $P=@{name="PasswordLastSet";expression={$_.passwordlastset}}
    > $ADSIUser =@{name="ADSIUserName";expression={$usersnameobtainedfromADSI}}
    >
    > $events | select $N,$P,$ADSIUser | format-table -auto
    >
    >
    > -----
    > Shay Levi
    > $cript Fanatic
    > http://scriptolog.blogspot.com
    >
    >
    >

    > > Thanks Shay there's nothing else I believe coming into the second loop
    > > that would effect it - I hav tried with both $null and "" and the code
    > > works fine until there is an earlier entry picked up - I test this by
    > > changing the password of same user in quickish succesion and running
    > > against a certain -newest no of eventlog entries knowing I will pick
    > > them both up - therefore the earlier one shouldnn't match the
    > > passwordlastset adsi value, although it would match -ne to username).
    > >
    > > Yes thanks for the write-host and -ieq tip.
    > >
    > > "Shay Levi" wrote:
    > >

    > >> It's hard to say just from viewing the code sample. You can try to
    > >> assign the variables to $null or "" in each iteration.
    > >>
    > >> BTW, -ine (case-insensitive comparison) is the same as -ne. Also, if
    > >> $N and $usersnameobtainedfromADSI are strings then you don't need to
    > >> concatenate the variables:
    > >>
    > >> write-host "$N" + " was the last person to change the password of " +
    > >> "$usersnameobtainedfromADSI"
    > >>
    > >> You can simply write:
    > >>
    > >> write-host "$N was the last person to change the password of
    > >> $usersnameobtainedfromADSI"
    > >>
    > >> -----
    > >> Shay Levi
    > >> $cript Fanatic
    > >> http://scriptolog.blogspot.com
    > >>> I have having the following problem:
    > >>>
    > >>> I have an array say $events
    > >>> i obtained from get-eventlog (which say returns a number of events
    > >>> matching
    > >>> the criteria set)
    > >>> when displayed it will give something like
    > >>> {passwordlastset: 15\12\70 callerusername: administrator}
    > >>>
    > >>> I am basically trying to write only where the passwordlastchanged
    > >>> criteria match and the user did not change the password himself from
    > >>> similar code to below:
    > >>>
    > >>> foreach ($objuser in $AD)
    > >>> {
    > >>> foreach ($event in $events)
    > >>> {
    > >>> $P = $event.passwordlastset
    > >>> $N = $event.callerusername
    > >>> IF ($passwordlastsetobtainedfromADSI -eq $P) -and ($N -ine
    > >>> $usersnameobtainedfromADSI)
    > >>> {
    > >>> write-host "$N" + " was the last person to change the password of "
    > >>> +
    > >>> "$usersnameobtainedfromADSI"
    > >>> }
    > >>> }
    > >>> }
    > >>> The problem I have is it will hit the first person who meets the
    > >>> criteria and write as expected but also the same info for each and
    > >>> every user thereafter - any help would be much appreciated as I have
    > >>> tried a number of things all to no avail
    >
    >
    >

      My System SpecsSystem Spec

  6. #6


    Shay Levi Guest

    Re: Working with arrays

    Hi Jobbsy,

    Glad you could resolve it :-)

    Generally, I would avoid keeping/running files from any desktop, the path
    is too deep any you may encounter permission errors.

    1. You can embed $strDate inside double quotes string and it will expand
    its value.
    $CSVFilePath = "C:\Documents and Settings\All Users\Desktop\SwapClearITD_users_$strDate.csv"

    2. Test-Path determines whether all elements of a path exist. It checks for
    one file/directory based on leaf/container value of -pathType parameter.
    It doesn't check for ALL (*.CSV) files. If you want to delete all CSV
    files before starting use 'get-childitem -filter *.csv | remove-item -force'

    To test for a file existence use:
    test-path -path c:\scripts\$strDate.csv -pathType leaf

    For directory:
    test-path -path c:\scripts -pathType Container

    Execute 'get-help test-path -full' to get full available help

    3. You can format dates easily with the -format operator, its much more concise
    then $AccountCreated assignment:
    PS > get-date -f "dd/MM/yyyy hh:mm:ss"
    19/11/2007 11:36:08

    The same can be applied when you retrieve events from a log file:
    PS > $e= get-eventlog application -new 1
    PS> $e.TimeWritten -f "dd/MM/yyyy hh:mm:ss"
    19/11/2007 11:36:08

    4. '$AC = $($prop.whencreated)' is the same as '$AC = $prop.whencreated'.
    Generally, You use the $($prop.member) subexpression expansion notation
    when you need to expand the variable inside of a string.

    You can't write this:
    PS > write-host "PowerShell current culture is: $Host.CurrentCulture"
    PowerShell current culture is: System.Management.Automation.Internal.Host.InternalHost.CurrentCulture

    This works:
    PS > write-host "Working directory path is $($Host.CurrentCulture)"
    PowerShell current culture is: he-IL




    HTH

    -----
    Shay Levi
    $cript Fanatic
    http://scriptolog.blogspot.com



    > Thanks for your help Shay I was able to figure it out (I needed the
    > 5thField outside of the events loop from my finished code below - you
    > were right without seeing all the code you could not have
    > troubleshooted that - but appreciated your input - I'm sure this is
    > not the most professional code ever but it works! - Thanks again
    >
    > #INITIALISATION SECTION
    > #----------------------
    > #Clear the Windows command console screen
    > Clear-Host
    > #CONSTANTS SECTION
    > #-----------------
    > $strDate = get-date -uformat "%Y-%m-%d"
    > $CSVFilePath = 'c:\Documents and Settings\All
    > Users\Desktop\SwapClearITD_users_'+$strDate+'.csv'
    > #Delete previous file if exists
    > $RetVal = Test-Path 'c:\Documents and Settings\All Users\Desktop\' |
    > where-object {$_.name -like "*.CSV"}
    > If ($RetVal = 'True')
    > {
    > Remove-Item 'c:\Documents and Settings\All Users\Desktop\*.CSV'
    > }
    > #Creates new dated file and specifies header for CSV.
    > $strOutputString = "User,Member Of Group,Account Created,Password last
    > changed"
    > $strOutputString | out-file -Width 2147483647 -filepath $CSVFilePath
    > -encoding ascii
    > #Retrieve Events for Administrator Password Changes
    >
    > [regex]$regEx = ('\:\s+')
    > $events = @()
    > get-eventlog Security -newest 2000 |
    > where {$_.eventID -eq '642'} |
    > % {
    > $obj = new-object psObject
    > switch -regex ($_.message.split("`n")) {
    > '^\s*Password Last Set\:' {
    > add-member NoteProperty -name PasswordLastSet `
    > -value $($regEx.split($_)[1]).trim() -in $obj
    > }
    > '^\s*Caller User Name\:' {
    > add-member NoteProperty -name CallerUserName `
    > -value $($regEx.split($_)[1]).trim() -in $obj
    > }
    > }
    > $events += $obj
    > }
    > #FUNCTIONS & FILTERS SECTION
    > #----------------------------
    > #MAIN PROCESSING SECTION
    > #-----------------------
    > $Dom = 'LDAP://OU=test,DC=vmware,DC=vm'
    > $Root = New-Object DirectoryServices.DirectoryEntry $Dom
    > $i=0
    > # Create a selector and start searching from the Root of AD
    > $selector = New-Object DirectoryServices.DirectorySearcher
    > $selector.SearchRoot = $root
    > $selector.pagesize = 1000
    > $adobj= $selector.findall() |`
    > where {$_.properties.objectcategory -match "CN=Person"}
    > foreach ($person in $adobj) {
    > $prop=$person.properties
    > $i++
    > $1stField = "$($prop.name)" + ","
    >
    > # $2nd Field - Member Of
    > #---------------------------------------------------------
    > IF ("$($prop.memberof)" -match "CN=*") {
    > #Remove the "CN=, OU=TEST," etc & just keep name of group at front of
    > DN
    > $s = "$($prop.memberof)"
    > $firstdivofDN,$seconddivofDN,$thirddivofDN =
    > ([regex]'=(.+?),').matches($s) | foreach {$_.Groups[1].Value}
    > $2ndField = "$firstdivofDN" + ","
    > } ELSE {
    > $2ndField = "****NOT A MEMBER OF A GROUP****" + ","
    > }
    > # $3rd Field - date When account was created
    > #------------------------------------------
    > $AC = $($prop.whencreated)
    > $AccountCreated = "{00:dd}/{00:MM}/{0000:yyyy} {0:hh}:{0:mm}:{0:ss}"
    > -f($AC)
    > $3rdField = "$AccountCreated" + ","
    >
    > # $4th Field - Password Last Set
    > #---------------------------------------------------------- #Convert
    > the large Integer format into a readable date
    >
    > $LI = [datetime]::FromFileTimeUTC( $($prop.pwdlastset[0]) )
    > $PWLSet = "{00:dd}/{00:MM}/{0000:yyyy} {0:hh}:{0:mm}:{0:ss}" -f
    > ($LI)
    > $4thField = "$PWLSet" + ","
    >
    > # $5th Field - Was Administrator last person to change Password?
    > #--------------------------------------------------------------
    >
    > $5thField = ""
    >
    > IF ("$AccountCreated" -match "$PWLSet") {
    > $5thField = "****PASSWORD NOT CHANGED SINCE ACCOUNT SETUP****" +
    > ","
    > } ELSE {
    > Foreach($event in $events) { # from constants section at start
    > $E = $event.PasswordLastSet
    >
    > $N = $event.CallerUserName
    >
    > IF (("$E" -match "$PWLSet") -and ("$N" -ne "$($prop.name)")) {
    > $5thField = "****PASSWORD last Changed by " + "$N" + "****" +
    > ","
    > }
    > }
    > }
    > $strOutputString = "$1stField" + "$2ndField" + "$3rdField" +
    > "$4thField" + "$5thField"
    >
    > $strOutputString | out-file -filepath $CSVFilePath -encoding ascii
    > -append
    >
    > }
    >
    > "Shay Levi" wrote:
    >

    >> What are the types of $N, $P, etc? (e.g $N.gettype())
    >>
    >> Doe's the same happens when you run:
    >>
    >> $N=@{name="CallerUserName";expression={$_.callerusername}}
    >> $P=@{name="PasswordLastSet";expression={$_.passwordlastset}}
    >> $ADSIUser
    >> =@{name="ADSIUserName";expression={$usersnameobtainedfromADSI}}
    >>
    >> $events | select $N,$P,$ADSIUser | format-table -auto
    >>
    >> -----
    >> Shay Levi
    >> $cript Fanatic
    >> http://scriptolog.blogspot.com

    >>> Thanks Shay there's nothing else I believe coming into the second
    >>> loop that would effect it - I hav tried with both $null and "" and
    >>> the code works fine until there is an earlier entry picked up - I
    >>> test this by changing the password of same user in quickish
    >>> succesion and running against a certain -newest no of eventlog
    >>> entries knowing I will pick them both up - therefore the earlier one
    >>> shouldnn't match the passwordlastset adsi value, although it would
    >>> match -ne to username).
    >>>
    >>> Yes thanks for the write-host and -ieq tip.
    >>>
    >>> "Shay Levi" wrote:
    >>>
    >>>> It's hard to say just from viewing the code sample. You can try to
    >>>> assign the variables to $null or "" in each iteration.
    >>>>
    >>>> BTW, -ine (case-insensitive comparison) is the same as -ne. Also,
    >>>> if $N and $usersnameobtainedfromADSI are strings then you don't
    >>>> need to concatenate the variables:
    >>>>
    >>>> write-host "$N" + " was the last person to change the password of "
    >>>> + "$usersnameobtainedfromADSI"
    >>>>
    >>>> You can simply write:
    >>>>
    >>>> write-host "$N was the last person to change the password of
    >>>> $usersnameobtainedfromADSI"
    >>>>
    >>>> -----
    >>>> Shay Levi
    >>>> $cript Fanatic
    >>>> http://scriptolog.blogspot.com
    >>>>> I have having the following problem:
    >>>>>
    >>>>> I have an array say $events
    >>>>> i obtained from get-eventlog (which say returns a number of events
    >>>>> matching
    >>>>> the criteria set)
    >>>>> when displayed it will give something like
    >>>>> {passwordlastset: 15\12\70 callerusername: administrator}
    >>>>> I am basically trying to write only where the passwordlastchanged
    >>>>> criteria match and the user did not change the password himself
    >>>>> from similar code to below:
    >>>>>
    >>>>> foreach ($objuser in $AD)
    >>>>> {
    >>>>> foreach ($event in $events)
    >>>>> {
    >>>>> $P = $event.passwordlastset
    >>>>> $N = $event.callerusername
    >>>>> IF ($passwordlastsetobtainedfromADSI -eq $P) -and ($N -ine
    >>>>> $usersnameobtainedfromADSI)
    >>>>> {
    >>>>> write-host "$N" + " was the last person to change the password of
    >>>>> "
    >>>>> +
    >>>>> "$usersnameobtainedfromADSI"
    >>>>> }
    >>>>> }
    >>>>> }
    >>>>> The problem I have is it will hit the first person who meets the
    >>>>> criteria and write as expected but also the same info for each and
    >>>>> every user thereafter - any help would be much appreciated as I
    >>>>> have
    >>>>> tried a number of things all to no avail


      My System SpecsSystem Spec

  7. #7


    Jobbsy Guest

    Re: Working with arrays

    Thanks Shay I will sit down and go through your tips and certainly take them
    onboard

    My next challenge is to interrogate 2 DCs in a Domain - this script runs
    happily against one dc in a test domain - also as the security event log is
    liable to being overwritten I will have to save the csv files and loop
    through a number of historical ones to make sure info is accurate - I reckon
    it will probably be easier to combine the two output files after running on
    each DC - all this will be scheduled to run daily - that should test my
    knowledge!


    --
    jobbsy@xxxxxx


    "Shay Levi" wrote:

    > Hi Jobbsy,
    >
    > Glad you could resolve it :-)
    >
    > Generally, I would avoid keeping/running files from any desktop, the path
    > is too deep any you may encounter permission errors.
    >
    > 1. You can embed $strDate inside double quotes string and it will expand
    > its value.
    > $CSVFilePath = "C:\Documents and Settings\All Users\Desktop\SwapClearITD_users_$strDate.csv"
    >
    > 2. Test-Path determines whether all elements of a path exist. It checks for
    > one file/directory based on leaf/container value of -pathType parameter.
    > It doesn't check for ALL (*.CSV) files. If you want to delete all CSV
    > files before starting use 'get-childitem -filter *.csv | remove-item -force'
    >
    > To test for a file existence use:
    > test-path -path c:\scripts\$strDate.csv -pathType leaf
    >
    > For directory:
    > test-path -path c:\scripts -pathType Container
    >
    > Execute 'get-help test-path -full' to get full available help
    >
    > 3. You can format dates easily with the -format operator, its much more concise
    > then $AccountCreated assignment:
    > PS > get-date -f "dd/MM/yyyy hh:mm:ss"
    > 19/11/2007 11:36:08
    >
    > The same can be applied when you retrieve events from a log file:
    > PS > $e= get-eventlog application -new 1
    > PS> $e.TimeWritten -f "dd/MM/yyyy hh:mm:ss"
    > 19/11/2007 11:36:08
    >
    > 4. '$AC = $($prop.whencreated)' is the same as '$AC = $prop.whencreated'.
    > Generally, You use the $($prop.member) subexpression expansion notation
    > when you need to expand the variable inside of a string.
    >
    > You can't write this:
    > PS > write-host "PowerShell current culture is: $Host.CurrentCulture"
    > PowerShell current culture is: System.Management.Automation.Internal.Host.InternalHost.CurrentCulture
    >
    > This works:
    > PS > write-host "Working directory path is $($Host.CurrentCulture)"
    > PowerShell current culture is: he-IL
    >
    >
    >
    >
    > HTH
    >
    > -----
    > Shay Levi
    > $cript Fanatic
    > http://scriptolog.blogspot.com
    >
    >
    >

    > > Thanks for your help Shay I was able to figure it out (I needed the
    > > 5thField outside of the events loop from my finished code below - you
    > > were right without seeing all the code you could not have
    > > troubleshooted that - but appreciated your input - I'm sure this is
    > > not the most professional code ever but it works! - Thanks again
    > >
    > > #INITIALISATION SECTION
    > > #----------------------
    > > #Clear the Windows command console screen
    > > Clear-Host
    > > #CONSTANTS SECTION
    > > #-----------------
    > > $strDate = get-date -uformat "%Y-%m-%d"
    > > $CSVFilePath = 'c:\Documents and Settings\All
    > > Users\Desktop\SwapClearITD_users_'+$strDate+'.csv'
    > > #Delete previous file if exists
    > > $RetVal = Test-Path 'c:\Documents and Settings\All Users\Desktop\' |
    > > where-object {$_.name -like "*.CSV"}
    > > If ($RetVal = 'True')
    > > {
    > > Remove-Item 'c:\Documents and Settings\All Users\Desktop\*.CSV'
    > > }
    > > #Creates new dated file and specifies header for CSV.
    > > $strOutputString = "User,Member Of Group,Account Created,Password last
    > > changed"
    > > $strOutputString | out-file -Width 2147483647 -filepath $CSVFilePath
    > > -encoding ascii
    > > #Retrieve Events for Administrator Password Changes
    > >
    > > [regex]$regEx = ('\:\s+')
    > > $events = @()
    > > get-eventlog Security -newest 2000 |
    > > where {$_.eventID -eq '642'} |
    > > % {
    > > $obj = new-object psObject
    > > switch -regex ($_.message.split("`n")) {
    > > '^\s*Password Last Set\:' {
    > > add-member NoteProperty -name PasswordLastSet `
    > > -value $($regEx.split($_)[1]).trim() -in $obj
    > > }
    > > '^\s*Caller User Name\:' {
    > > add-member NoteProperty -name CallerUserName `
    > > -value $($regEx.split($_)[1]).trim() -in $obj
    > > }
    > > }
    > > $events += $obj
    > > }
    > > #FUNCTIONS & FILTERS SECTION
    > > #----------------------------
    > > #MAIN PROCESSING SECTION
    > > #-----------------------
    > > $Dom = 'LDAP://OU=test,DC=vmware,DC=vm'
    > > $Root = New-Object DirectoryServices.DirectoryEntry $Dom
    > > $i=0
    > > # Create a selector and start searching from the Root of AD
    > > $selector = New-Object DirectoryServices.DirectorySearcher
    > > $selector.SearchRoot = $root
    > > $selector.pagesize = 1000
    > > $adobj= $selector.findall() |`
    > > where {$_.properties.objectcategory -match "CN=Person"}
    > > foreach ($person in $adobj) {
    > > $prop=$person.properties
    > > $i++
    > > $1stField = "$($prop.name)" + ","
    > >
    > > # $2nd Field - Member Of
    > > #---------------------------------------------------------
    > > IF ("$($prop.memberof)" -match "CN=*") {
    > > #Remove the "CN=, OU=TEST," etc & just keep name of group at front of
    > > DN
    > > $s = "$($prop.memberof)"
    > > $firstdivofDN,$seconddivofDN,$thirddivofDN =
    > > ([regex]'=(.+?),').matches($s) | foreach {$_.Groups[1].Value}
    > > $2ndField = "$firstdivofDN" + ","
    > > } ELSE {
    > > $2ndField = "****NOT A MEMBER OF A GROUP****" + ","
    > > }
    > > # $3rd Field - date When account was created
    > > #------------------------------------------
    > > $AC = $($prop.whencreated)
    > > $AccountCreated = "{00:dd}/{00:MM}/{0000:yyyy} {0:hh}:{0:mm}:{0:ss}"
    > > -f($AC)
    > > $3rdField = "$AccountCreated" + ","
    > >
    > > # $4th Field - Password Last Set
    > > #---------------------------------------------------------- #Convert
    > > the large Integer format into a readable date
    > >
    > > $LI = [datetime]::FromFileTimeUTC( $($prop.pwdlastset[0]) )
    > > $PWLSet = "{00:dd}/{00:MM}/{0000:yyyy} {0:hh}:{0:mm}:{0:ss}" -f
    > > ($LI)
    > > $4thField = "$PWLSet" + ","
    > >
    > > # $5th Field - Was Administrator last person to change Password?
    > > #--------------------------------------------------------------
    > >
    > > $5thField = ""
    > >
    > > IF ("$AccountCreated" -match "$PWLSet") {
    > > $5thField = "****PASSWORD NOT CHANGED SINCE ACCOUNT SETUP****" +
    > > ","
    > > } ELSE {
    > > Foreach($event in $events) { # from constants section at start
    > > $E = $event.PasswordLastSet
    > >
    > > $N = $event.CallerUserName
    > >
    > > IF (("$E" -match "$PWLSet") -and ("$N" -ne "$($prop.name)")) {
    > > $5thField = "****PASSWORD last Changed by " + "$N" + "****" +
    > > ","
    > > }
    > > }
    > > }
    > > $strOutputString = "$1stField" + "$2ndField" + "$3rdField" +
    > > "$4thField" + "$5thField"
    > >
    > > $strOutputString | out-file -filepath $CSVFilePath -encoding ascii
    > > -append
    > >
    > > }
    > >
    > > "Shay Levi" wrote:
    > >

    > >> What are the types of $N, $P, etc? (e.g $N.gettype())
    > >>
    > >> Doe's the same happens when you run:
    > >>
    > >> $N=@{name="CallerUserName";expression={$_.callerusername}}
    > >> $P=@{name="PasswordLastSet";expression={$_.passwordlastset}}
    > >> $ADSIUser
    > >> =@{name="ADSIUserName";expression={$usersnameobtainedfromADSI}}
    > >>
    > >> $events | select $N,$P,$ADSIUser | format-table -auto
    > >>
    > >> -----
    > >> Shay Levi
    > >> $cript Fanatic
    > >> http://scriptolog.blogspot.com
    > >>> Thanks Shay there's nothing else I believe coming into the second
    > >>> loop that would effect it - I hav tried with both $null and "" and
    > >>> the code works fine until there is an earlier entry picked up - I
    > >>> test this by changing the password of same user in quickish
    > >>> succesion and running against a certain -newest no of eventlog
    > >>> entries knowing I will pick them both up - therefore the earlier one
    > >>> shouldnn't match the passwordlastset adsi value, although it would
    > >>> match -ne to username).
    > >>>
    > >>> Yes thanks for the write-host and -ieq tip.
    > >>>
    > >>> "Shay Levi" wrote:
    > >>>
    > >>>> It's hard to say just from viewing the code sample. You can try to
    > >>>> assign the variables to $null or "" in each iteration.
    > >>>>
    > >>>> BTW, -ine (case-insensitive comparison) is the same as -ne. Also,
    > >>>> if $N and $usersnameobtainedfromADSI are strings then you don't
    > >>>> need to concatenate the variables:
    > >>>>
    > >>>> write-host "$N" + " was the last person to change the password of "
    > >>>> + "$usersnameobtainedfromADSI"
    > >>>>
    > >>>> You can simply write:
    > >>>>
    > >>>> write-host "$N was the last person to change the password of
    > >>>> $usersnameobtainedfromADSI"
    > >>>>
    > >>>> -----
    > >>>> Shay Levi
    > >>>> $cript Fanatic
    > >>>> http://scriptolog.blogspot.com
    > >>>>> I have having the following problem:
    > >>>>>
    > >>>>> I have an array say $events
    > >>>>> i obtained from get-eventlog (which say returns a number of events
    > >>>>> matching
    > >>>>> the criteria set)
    > >>>>> when displayed it will give something like
    > >>>>> {passwordlastset: 15\12\70 callerusername: administrator}
    > >>>>> I am basically trying to write only where the passwordlastchanged
    > >>>>> criteria match and the user did not change the password himself
    > >>>>> from similar code to below:
    > >>>>>
    > >>>>> foreach ($objuser in $AD)
    > >>>>> {
    > >>>>> foreach ($event in $events)
    > >>>>> {
    > >>>>> $P = $event.passwordlastset
    > >>>>> $N = $event.callerusername
    > >>>>> IF ($passwordlastsetobtainedfromADSI -eq $P) -and ($N -ine
    > >>>>> $usersnameobtainedfromADSI)
    > >>>>> {
    > >>>>> write-host "$N" + " was the last person to change the password of
    > >>>>> "
    > >>>>> +
    > >>>>> "$usersnameobtainedfromADSI"
    > >>>>> }
    > >>>>> }
    > >>>>> }
    > >>>>> The problem I have is it will hit the first person who meets the
    > >>>>> criteria and write as expected but also the same info for each and
    > >>>>> every user thereafter - any help would be much appreciated as I
    > >>>>> have
    > >>>>> tried a number of things all to no avail
    >
    >
    >

      My System SpecsSystem Spec

Working with arrays

Similar Threads
Thread Thread Starter Forum Replies Last Post
Re: Multidimensional Arrays Vadims Podans [MVP] PowerShell 3 02 Apr 2009
Arrays Jason Massie PowerShell 10 14 May 2008
Overwriting Arrays DavidLMeissner PowerShell 1 27 Dec 2007
Multidimensional arrays Jacob Saaby Nielsen PowerShell 6 27 Nov 2007
question about arrays Nicola Attico PowerShell 3 26 Aug 2006