PowerShell

Write output to file within a PowerShell foreach loop

Share
  • This topic has 18 replies, 2 voices, and was last updated 2 weeks ago by IQ.
Viewing 17 reply threads
  • Author
    Posts
    • #1556895
      IQ
      Participant
      • Topics: 4
      • Replies: 17
      Post count: 2
      Member Points: 661
      Rank: Level 2

      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 .

      1+
    • #1556910
      IQ
      Participant
      • Topics: 4
      • Replies: 17
      Post count: 2
      Member Points: 661
      Rank: Level 2

      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
    • #1556937
      David Figueroa
      Participant
      • Topics: 5
      • Replies: 41
      Post count: 13
      Member Points: 3,132
      Rank: Level 3

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

      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..

      0
    • #1556969
      IQ
      Participant
      • Topics: 4
      • Replies: 17
      Post count: 2
      Member Points: 661
      Rank: Level 2

      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

      ——————————————————–

      • This reply was modified 1 month ago by IQ.
      0
    • #1556971
      David Figueroa
      Participant
      • Topics: 5
      • Replies: 41
      Post count: 13
      Member Points: 3,132
      Rank: Level 3

      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.

      Good luck!

       

      David F.

      0
      • #1556999
        IQ
        Participant
        • Topics: 4
        • Replies: 17
        Post count: 2
        Member Points: 661
        Rank: Level 2

        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.

        Line 13 of the code is

        • This reply was modified 1 month ago by IQ.
        Attachments:
        You must be logged in to view attached files.
        0
    • #1557002
      IQ
      Participant
      • Topics: 4
      • Replies: 17
      Post count: 2
      Member Points: 661
      Rank: Level 2

      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
    • #1557003
      David Figueroa
      Participant
      • Topics: 5
      • Replies: 41
      Post count: 13
      Member Points: 3,132
      Rank: Level 3

      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
    • #1557066
      IQ
      Participant
      • Topics: 4
      • Replies: 17
      Post count: 2
      Member Points: 661
      Rank: Level 2

      Hi David,

      If I use this command I am seeing the passwd last set values under AccountExprationDate , what is the difference between this and the previous command. Also is there a way I can substitute the nulls in AccountExprationDate   with a sysdate ?

      Get-ADUser -Filter ‘enabled -eq $true’ -Properties AccountExpirationDate |
      Select sAMAccountName, distinguishedName, AccountExpirationDate

      0
    • #1557067
      IQ
      Participant
      • Topics: 4
      • Replies: 17
      Post count: 2
      Member Points: 661
      Rank: Level 2

      I  have modified the code to look like this but I am getting errors , Code I am using is below the errors.

      —————————————–

      Code I am using is shown below

      ———————————-

      0
    • #1557068
      David Figueroa
      Participant
      • Topics: 5
      • Replies: 41
      Post count: 13
      Member Points: 3,132
      Rank: Level 3

      The two attributes are completely unrelated.  PwdLastSet is the last time the user set their password, and the AccountExpirationDate is literally that – it is the date & time when the account will expire, and be automatically disabled.  For most accounts at most places, it’s not set.  It’s normally only set for contractors, visitors, etc.

      Based on your errors, it looks like the AccountExpirationDate is returning as a DateTime instead of a FileTime type that PwdLastSet uses.

      Can you get a single user account and export all the properties and show it here (sanitized of course)?

      David F.

      0
    • #1557086
      IQ
      Participant
      • Topics: 4
      • Replies: 17
      Post count: 2
      Member Points: 661
      Rank: Level 2

      Hi David,Thanks for your reply, how can I fix this error ?

      Also For one of the accounts the properties are shown below as you requested

      0
    • #1557108
      David Figueroa
      Participant
      • Topics: 5
      • Replies: 41
      Post count: 13
      Member Points: 3,132
      Rank: Level 3

      That’s definitely not the full property list.. I want to see the basic list of all the properties (and as I mentioned, sanitized is fine).

      In specific, I want to see the AccountExpirationDate (which you did get), the PwdLastSet field, and any other numeric/time date fields, preferably with screenshots of the data types.  My thought was an ADSIEdit view, but even a PS is fine.

       

      David F.

      0
    • #1557130
      IQ
      Participant
      • Topics: 4
      • Replies: 17
      Post count: 2
      Member Points: 661
      Rank: Level 2

      Hi David,

      How do I get the full property list ? Also what do you mean by “sanitized is fine” ?

      Thanks

      IQ

      0
    • #1557131
      David Figueroa
      Participant
      • Topics: 5
      • Replies: 41
      Post count: 13
      Member Points: 3,132
      Rank: Level 3

      Sanitized:  you can change names, and any proprietary information and sub in some generic value.  i.e. don’t need the real domain, the real SID, real GUID’s etc.  whatever you are not comfortable sharing.

      I just want to see you do a get-aduser and output one user into | format-list, so given what we’ve already seen..

      get-aduser -ldapfilter ‘(&(objectclass=user)(samaccountname=cpenic))’ -properties * | format-list (to get the actual values)

      get-aduser -ldaptfilter ‘(&(objectclass=user)(samaccountname=cpenic))’ -properties * | get-member  (to get the data types of each attribute)

      That should provide everything.

      David F.

      0
    • #1557149
      IQ
      Participant
      • Topics: 4
      • Replies: 17
      Post count: 2
      Member Points: 661
      Rank: Level 2
      0
    • #1557150
      IQ
      Participant
      • Topics: 4
      • Replies: 17
      Post count: 2
      Member Points: 661
      Rank: Level 2
      0
    • #1557232
      David Figueroa
      Participant
      • Topics: 5
      • Replies: 41
      Post count: 13
      Member Points: 3,132
      Rank: Level 3

      My apologies, I’ve been pretty tied up.  The user dump you put out is perfect.  The most important thing I see is that PwdLastSet *is* visible, and it is a FileTime like I figured.  I couldn’t figure out any way you could have it not be visible and actually be usable.  Now.. the password expiration date is going to be a calculated value based on what AD has set in the password policy.  i.e. if the password policy says expire in 90 days, the pwdlastset date is compared to the current time, and if it’s greater than 90 days, it will flag it as expired.

      Now… looking back, at my original rewrite, I believe the problem is probably line 9 in building the $GetADParameters hashtable.

      Try this:

      I’m not 100% sure, but I think the PasswordLastSet is some “syntactic sugar” that the AD module uses, and calculates when you return the user object, so it may not be usable for comparison purposes?

      David F.

      0
    • #1557244
      IQ
      Participant
      • Topics: 4
      • Replies: 17
      Post count: 2
      Member Points: 661
      Rank: Level 2

      Hi David,
      Since the code did not work, I have modified the way this could be done, my new code is given below,
      however I cannot seem to see the output within the foreach statement, is there anything wrong I am doing here

      Import-Module ActiveDirectory

      #Set the number of days within expiration. This will start to send the email x number of days before it is expired.
      $DaysWithinExpiration = 90

      #Set the days where the password is already expired and needs to change. — Do Not Modify —
      $MaxPwdAge = (Get-ADDefaultDomainPasswordPolicy).MaxPasswordAge.Days
      $expiredDate = (Get-Date).addDays(-$MaxPwdAge)

      #Set the number of days until you would like to begin notifing the users. — Do Not Modify —
      $emailDate = (Get-Date).addDays(-($MaxPwdAge – $DaysWithinExpiration))

      #Filters for all users who’s password is within $date of expiration.
      $ExpiredUsers = Get-ADUser -Filter {(PasswordLastSet -lt $emailDate) -and (PasswordLastSet -gt $expiredDate) -and (PasswordNeverExpires -eq $false) -and (Enabled -eq $true)} -Properties PasswordNeverExpires, PasswordLastSet, Mail -SearchBase “OU=Service Accounts,OU=SG1,OU=WAT,DC=cit,DC=ad,DC=cit,DC=cc” | select samaccountname, PasswordLastSet, @{name = “DaysUntilExpired”; Expression = {$_.PasswordLastSet – $ExpiredDate | select -ExpandProperty Days}}, @{name = “EmailAddress”; Expression = {$_.mail}} | Sort-Object PasswordLastSet
      $ExpiredUsers

      Foreach ($User in $ExpiredUsers) {

      $Message = ‘User has a password expiration date ‘ + $ExpiredUsers.samaaccountname + $PasswordLastSet
      Add-Content -Path C:\Temp\PasswordExpList.txt -Value $Message

      0
Viewing 17 reply threads
  • You must be logged in to reply to this topic.
© 4sysops 2006 - 2020

CONTACT US

Please ask IT administration questions in the forums. Any other messages are welcome.

Sending

Log in with your credentials

or    

Forgot your details?

Create Account