• I'm not sure how you could manage passwords without PwdLastSet - that's a value automatically written by AD when you set your password.  Now -- they modified the security on that attribute, then the queries would fail, and basically turn up nothing.  There isn't any other way I know of to obtain that piece of information directly.  If you can't see PwdLastSet, then adding a year won't make a difference, unless you mess with the clock and figure out bit by bit when it expires, but that's messy and certainly not easy or stable.

    I can't figure out why in the world someone would block security on that attribute? It's certainly not an easy thing to do.  I can think of numerous circumstances where that would break things?

    Anyway.. if you have a Domain Admin or Enterprise Admin account, you could use PSexec to launch a process as the System account on the Domain Controller and basically give yourself true full control of the AD database.  But, if you have that AD level permission, it wouldn't/shouldn't block you from seeing PwdLastSet.

    But, you made it sound like you *can* get it for the output? or not get it?

     

    David F.

    0
  • Hi David,

    I was able to fix the issue I had described in my reply and the code is now working, I am able to output username , PwdLastSet values to the output file, I will look into the email stub part later.

    I have a problem though, looks like the PwdLastSet column is always null as they have not stored this information,  as I mentioned earlier, I was using PwdLastSet and adding a year to it to get the password expiry date information as our AD was not letting us retrieve this information , so is there any other way for me to get the password expiry information ?

     

    Thanks

    IQ

     

    0
  • Another powershell statement uses this command

    Stop-Process -Name notepad

     

    But want to provide 'L' as the answer and continue to the next statement. Is it possible to select 'L' ?

    0
  • Thanks David, for taking time to look into this piece of code for me.

    Please ignore the $File pieces in the code , I was just playing with the syntax to familiarise myself.

    With regards to PassWdEXp being one year + PasswordLastSet , we are using this as our AD prevents us from querying for Password expired info. and as a rule all our passwords are set to expire one year from the time they were last set. So to get PasswdExp we are adding one year to PasswordLastSet

    I have tried to run your modified code but I am getting the error  at line 13 of the code as shown below,  Attached is the code as an attachment, please note I have commented the email stub portion of the code  for now as I am only focussing on generating an output file for now.

    Get-ADUser : Error parsing query: '{ Enabled -eq $True -and PasswordLastSet -gt 0 }' Error Message: 'syntax error' at position: '1'.
    At C:UsersDesktopPower_Shell_Script_For Expired_accountstst_op.ps1:13 char:10
    + $users = Get-ADUser @GetADParams |
    +          ~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ParserError: (:) [Get-ADUser], ADFilterParsingException
    + FullyQualifiedErrorId : ActiveDirectoryCmdlet:Microsoft.ActiveDirectory.Management.ADFilterParsingException,Microsoft.ActiveDi
    rectory.Management.Commands.GetADUser

    Line 13 of the code is

    $users = Get-ADUser @GetADParams |
    Select-Object -Property 'Name', 'PwdLastSet' |
    sort-object -property 'PwdLastSet'
    0
  • Ok, I sat down and took some time with this, and changed a bunch.

    I think your main failure is the attribute name being incorrect - it should be 'PwdLastSet'.
    I'm not sure what you were looking for with the $File pieces?
    Your Set-Contents would have overwritten it every time because you didn't have a -append attached to it.
    And I don't understand why you are adding a year to the one date?  Your dates would never match with that.
    I changed the date matching -- you're dealing with the PwdLastSet attribute, which is a FileTime type attribute, which is a measure of 100 nanosecond intervals, and the chances of that ever actually being equal is basically zero.

    $OneDayWarnDate     = [datetime]::Today.AddDays(1)
    $SevenWarnDate      = [datetime]::Today.AddDays(7)
    $FifteenDayWarnDate = [datetime]::Today.AddDays(15)
    $ThirtyDayWarnDate  = [datetime]::Today.AddDays(30)
    
    #Find accounts that are enabled and have expiring passwords
    
    $GetADParams = @{
        Filter     = '{ Enabled -eq $True -and PasswordLastSet -gt 0 }'
        Properties = 'Name', 'PwdLastSet'  # <- attribute name was wrong; I feel this is probably why you weren't getting anything
        SearchBase = 'Service Accounts,OU=SG1,OU=WAT,DC=wt,DC=ad,DC=cit,DC=cc'
    }
    $users = Get-ADUser @GetADParams | 
        Select-Object -Property 'Name', 'PwdLastSet' |
        sort-object -property 'PwdLastSet'
    
    #$PasswordExp = $users.PasswordLastSet.Addyears(1)  I don't think this is really what you are looking for; adding a year means they will never match
    
    $MailParams = @{
        To          = $users.name
        From        = 'iq@mail.cit.cc'
        SMTPServer  = 'mail.cit.cc'
        Subject     = 'Password Expiration warning'
    }
    
    $AdminMailParams = @{
        To          = 'domainadmins@mail.cit.cc'
        From        = 'iq@mail.cit.cc'
        SMTPServer  = 'mail.cit.cc'
        Subject     = 'Password Expiration warning list'
        Attachments = 'C:TempPasswordExpList.txt'
    }
    
    foreach ($user in $Users) {
        #Thinking about this part - because you are using -eq comparisons, this setup forcibly returns the midnight stamp, just like the initial warning variables do; 
        #otherwise, you're dealing with 100 nanosecond ticks, and that would be virtually impossible to be equal
        #I'm also assuming you are defining the Email stubs somewhere else
        $PasswordExp = [datetime]::parse([datetime]::FromFileTime($user.PwdLastSet).ToString('yyyy-MM-dd')) 
        $username = $user.name 
        $Message = 'User ({0}) has a password expiration date of {0}' -f $username, $PasswordExp.ToLongDateString()
        Add-Content -Path C:TempPasswordExpList.txt -Value $Message
    
        switch ($PasswordExp) {
            ($PasswordExp -eq $OneDayWarnDate) {
                $WarningDays = '1'
                $WarningDate = $OneDayWarnDate
                # You are overwriting your own variable here with the $file statements, this does not make sense?
                $VerboseMessage = 'The password expiration for user {0} is within the OneDayWarnBlock' -f $username
                break
            }
            ($PasswordExp -eq $SevenWarnDate) {
                $WarningDays = '7'
                $WarningDate = $SevenDayWarnDate
                $VerboseMessage = 'The password expiration for user {0} is within the SevenDayWarnBlock' -f $username
                break
            }
            ($PasswordExp -eq $FifteenDayWarnDate) {
                $WarningDays = '15'
                $WarningDate = $FifteenDayWarnDate
                $VerboseMessage = 'The password expiration for user {0} is within the FifteenDayWarnBlock' -f $username
                break
            }
            ($PasswordExp -eq $ThirtyDayWarnDate) {
                $WarningDays = '30'
                $WarningDate = $ThirtyDayWarnDate
                $VerboseMessage =  'The password expiration for user {0} is within the ThirtyDayWarnBlock' -f $username
                break
            }
        }
        Write-Verbose -Message $VerboseMessage
        $MailParams.Add('Body', ($EmailStub1, $users.name, $EmailStub2, $WarningDays, $EmailStub3, $WarningDate.ToString('yyyy-MM-dd'), $EmailStub4 -join ' ')) )
        Send-MailMessage $MailParams
    }
    Send-MailMessage @AdminMailParams
    

    Good luck!

     

    David F.

    0
  • Hello David,

    Thanks for your suggestions, I have tried to use this code as shown below to output the message to a file based on the number of days to expiry of the password, but somehow I think I am still missing something, I dont see any output getting generated. Where could I be going wrong ? Thanks for your help.

    IQ

    --------------------------------------------------------

    $SevenWarnDate = (get-date).adddays(7).ToLongDateString()
    $OneDayWarnDate = (get-date).adddays(1).ToLongDateString()
    
    #Find accounts that are enabled and have expiring passwords
    
    $users = Get-ADUser -filter {Enabled -eq $True -and PasswordLastSet -gt 0 } `
    -SearchBase "OU=Service Accounts,OU=SG1,OU=WAT,DC=wt,DC=ad,DC=cit,DC=cc" `
    -Properties "Name", PasswordLastSet | Select-Object -Property "Name", "PasswordLastSet" |`
    sort-object -property PasswordLastSet
    $PasswordExp = $users.PasswordLastSet.Addyears(1)
    $MailParams = @{
    To = $users.name
    From = 'iq@mail.cit.cc'
    SMTPServer = 'mail.cit.cc' #$SMTPServer
    Subject = 'Test' #$Subject
    }
    switch ($PasswordExp)
    {
    ($PasswordExp -eq $OneDayWarnDate) {
    $null = $MailParams.Add('Body', ( Body = ($EmailStub1, $users.name, $EmailStub2, $days, $EmailStub3, $SevenDayWarnDate, $EmailStub4 -join ' ')))
    $file = get-content test.txt -Raw
    $file = get-content test.txt
    set-content -Path test.txt -value $file
    get-content test.txt
    break
    }
    ($PasswordExp -eq $SevenWarnDate) {
    $null = $MailParams.Add('Body', ( Body = ($EmailStub1, $users.name, $EmailStub2, $days, $EmailStub3, $ThreeDayWarnDate, $EmailStub4 -join ' ')))
    $file = get-content test.txt -Raw
    $file = get-content test.txt
    set-content -Path test.txt -value $file
    get-content test.txt
    break
    break
    }
    ($PasswordExp -eq $FifteenDayWarnDate) {
    $null = $MailParams.Add('Body', ( Body = ($EmailStub1, $users.name, $EmailStub2, $days, $EmailStub3, $OneDayWarnDate, $EmailStub4 -join ' ')))
    $file = get-content test.txt -Raw
    $file = get-content test.txt
    set-content -Path test.txt -value $file
    get-content test.txt
    break
    }
    ($PasswordExp -eq $ThirtyDayWarnDate) {
    $null = $MailParams.Add('Body', ( Body = ($EmailStub1, $users.name, $EmailStub2, $days, $EmailStub3, $OneDayWarnDate, $EmailStub4 -join ' ')))
    $file = get-content test.txt -Raw
    $file = get-content test.txt
    set-content -Path test.txt -value $file
    get-content test.txt
    break
    }
    }
    0
  • 1+
    avatar
  • I'm having the same issue as Lukas

    0
  • Then based on what you have there, I would insert a new line 19 (between the current 18 & 19).

    Add-Content -Path C:test.txt -value ('{0},{1}' -f $user.samaccountname,[datetime]::FromFileTime($PasswordExp).ToString() )
    

    But, the way it's written, I don't think it is going to work?  You have this line for $PasswordExp:
    $PasswordExp = $users.PasswordLastSet.Addyears(1)

    That would be trying to gather all the users' PasswordLastSet value, and then you are adding a full year to it? Your previous statements are getting the current date, so the warnings will never trigger, because they are always a year ahead of the current date.

    You should extract the PasswordLastSet inside the loop for the single user, and don't add a year to it, and then you can compare it to your warning dates. I would put all of those statements into a single switch statement..

    $MailParams = @{
       To = $user.name
       From = $MailSender
       SMTPServer = $SMTPServer
       Subject = $Subject
    }
    switch ($PasswordExp)
    {
        ($PasswordExp -eq $OneDayWarnDate) {
            $null = $MailParams.Add('Body', (   Body = ($EmailStub1, $user.name, $EmailStub2, $days, $EmailStub3, $SevenDayWarnDate, $EmailStub4 -join ' ')
            break     
        }
        ($PasswordExp -eq $SevenWarnDate) {
            $null = $MailParams.Add('Body', (   Body = ($EmailStub1, $user.name, $EmailStub2, $days, $EmailStub3, $ThreeDayWarnDate, $EmailStub4 -join ' ')
            break     
        }
        ($PasswordExp -eq $FifteenDayWarnDate) {
            $null = $MailParams.Add('Body', (   Body = ($EmailStub1, $user.name, $EmailStub2, $days, $EmailStub3, $OneDayWarnDate, $EmailStub4 -join ' ')
            break     
        }
        ($PasswordExp -eq $ThirtyDayWarnDate) {
            $null = $MailParams.Add('Body', (   Body = ($EmailStub1, $user.name, $EmailStub2, $days, $EmailStub3, $OneDayWarnDate, $EmailStub4 -join ' ')
            break     
        }
    }
    Send-MailMessage @MailParams
    0
  • 0
  • There is an enterprise level tool called Gytpol Validator which does this on all endpoints in an organization

    0
  • Hello,

    How do you take the Subscription level Tags and a specific tags associated in all the subscriptions. 

    0
  • In case you don't want to specify the destination filename:

    If filename is part of the url, you could use

    $filename = [System.Uri]::UnescapeDataString((Split-Path -Leaf $strDownloadURL))

    (e.g. "Test%20123.pdf" --> "Test 123.pdf")

    If it's not: Use function "Get-RedirectedUrl" from https://stackoverflow.com/questions/25125818/powershell-invoke-webrequest-how-to-automatically-use-original-file-name/25127597#25127597

    0
  • I tried doing this but i get this error!

     

    At line:3 char:8
    + foreach($obj in $InstalledSoftware){write-host $obj.GetValue('Display ...
    +        ~
    Missing '=' operator after key in hash literal.
    At line:3 char:8
    + foreach($obj in $InstalledSoftware){write-host $obj.GetValue('Display ...
    +        ~
    The hash literal was incomplete.
        + CategoryInfo          : ParserError: (:) [], ParentContainsErrorRecordException
        + FullyQualifiedErrorId : MissingEqualsInHashLiteral

     

     

    I need to do this Please create a PowerShell script to fetch the list of installed software through Registry keys. And create a Hash table to hold the information (DisplayName & DisplayVersion).

    0
  • I have tried using   Set-Content -Path C:test.txt -Value 'foo'   to write the output to a file basically I need the UserId, PasswordExp written to the test file.  This did not work,  Is there a different command to be used to write to a file ?

    Please let me know.

     

    Thanks

    IQ

     

    0
  • Hi Paul,

    the last link you posted is correct. It is called Audit Directory Service Access option in  GPO. I have not tried yesterday, but withou this audit turned on, a query to AD will do nothing in seclog. I can try later today to turn this on and let you know what happened.

    However, if you alreaydy have this setting on, you already got a ton of logs generated just by normal usage of the environment.

    According to CIS you should not have the "Shutdown server if it cant record the audit message" on. This can lead to DoS attacks. Important logs should be forwarded somewhere and backed up.

    Cheers

    L

    0
  • Hello,

    I am trying to modify the following PowerShell code to write to a file within the foreach loop's if statement. So instead of  Send-MailMessage -To $user.EmailAddress -From $MailSender -SmtpServer $SMTPServer -Subject $Subject `
    -Body $EmailBody

    I would like to write to a file, later this file will be emailed to the Domain Admins.

    Please let me know how I can output the Send Mail message line of code into a file .

    #Import AD Module
    Import-Module ActiveDirectory
    
    #Create warning dates for future password expiration
    $ThirtyDayWarnDate = (get-date).adddays(30).ToLongDateString()
    $FifteenDayWarnDate = (get-date).adddays(15).ToLongDateString()
    $SevenWarnDate = (get-date).adddays(7).ToLongDateString()
    $OneDayWarnDate = (get-date).adddays(1).ToLongDateString()
    
    #Find accounts that are enabled and have expiring passwords
    
    $users = Get-ADUser -filter {Enabled -eq $True -and PasswordLastSet -gt 0 } `
    -SearchBase "OU=Service Accounts,OU=SG1,OU=WAT,DC=wt,DC=ad,DC=ed,DC=cn" `
    -Properties "Name", PasswordLastSet | Select-Object -Property "Name", "PasswordLastSet" |`
    sort-object -property PasswordLastSet
    $PasswordExp = $users.PasswordLastSet.Addyears(1)
    
    foreach ($user in $users) {
    if ($PasswordExp -eq $OneDayWarnDate) {
    $days = 1
    $EmailBody = $EmailStub1, $user.name, $EmailStub2, $days, $EmailStub3, $SevenDayWarnDate, $EmailStub4 -join ' '
    
    Send-MailMessage -To $user.EmailAddress -From $MailSender -SmtpServer $SMTPServer -Subject $Subject -Body $EmailBody
    }
    elseif ($PasswordExp -eq $SevenWarnDate) {
    $days = 7
    $EmailBody = $EmailStub1, $user.name, $EmailStub2, $days, $EmailStub3, $ThreeDayWarnDate, $EmailStub4 -join ' '
    
    Send-MailMessage -To $user.EmailAddress -From $MailSender -SmtpServer $SMTPServer -Subject $Subject `
    -Body $EmailBody
    }
    elseif ($PasswordExp -eq $FifteenDayWarnDate) {
    $days = 15
    $EmailBody = $EmailStub1, $user.name, $EmailStub2, $days, $EmailStub3, $OneDayWarnDate, $EmailStub4 -join ' '
    
    Send-MailMessage -To $user.EmailAddress -From $MailSender -SmtpServer $SMTPServer -Subject $Subject -Body $EmailBody
    }
    elseif ($PasswordExp -eq $ThirtyDayWarnDate) {
    $days = 30
    $EmailBody = $EmailStub1, $user.name, $EmailStub2, $days, $EmailStub3, $OneDayWarnDate, $EmailStub4 -join ' '
    
    Send-MailMessage -To $user.EmailAddress -From $MailSender -SmtpServer $SMTPServer -Subject $Subject -Body $EmailBody
    }
    else {}
    }
    0
  • Still the same. Modules aren't there.

    0
  • Don't you hate it when you get to the office and discover you lost your house keys? You go desperately through all your pockets, but they are nowhere to be found. With a sigh, you are about to go digging through all the lost crannies in your bag when the boss pops in and reminds you that those application servers need their public-facing NICs moved to a new address space.

    0
  • Hi Leos,

    We are having some trouble connecting to our mail server, so we would like to first develop this pseudo code and later integrate it with email server

    Get Service_Account_List Order by PasswordExpireDate Decending
    Loop Service_Account in Service_Account List
    Is Expire_Date < 1 ?
    Message := Service_Account + "Account Password Expired"**
    Else Is Expire_Date <= 7?**
    Message := Service_Account + "Account Password Will Expire within in 7 Days"**
    Else Is Expire_Date <= 15?**
    Message := Service_Account + "Account Password Will Expire within in 15 Days"**
    Else Is Expire_Date <= 30?**
    Message := Service_Account + "Account Password Will Expire within in 30 Days"
    End Is
    
    Store Message in file
    End Loop

    What is the best way to do this basically put all Accounts with the criteria given in a file and then loop through that file ?

    0
  • Load More