• From your description seems that your issue is with the task scheduler and powershell.

    Please check:

    • User or Service Account that will be used for running that script.
    • that the action “start a program” contains powershell.exe
    • Pay attention to execution policies, maybe adding “-ExecutionPolicy Bypass” in your case is required on that box. Check with Get-ExecutionPolicy
    •  “add argument” field should contain your script with the absolute path.
    • the flag Run whether user is logged on or not should be checked.

    Last but not least task scheduler expects an exit (int) value for your script or the report of the last execution will be always wrong.

    I also suggest you to add few lines for logging. Just in case you’re using write-host on your script, replace it with Write-OutPut.


  • Paolo Frigo liked comment of Paolo Frigo on A password expiration reminder script in PowerShell. (So far, Paolo Frigo has 1 likes for this comment.) 4 years, 8 months ago

  • Nice article Don! Well done!

    I’m not confused by your article by the way! 🙂

    Can I suggest few way of improving your script?

    I’ve created similar scripts in almost a compact script format (almost a one-liner) using JSON file for storing my variables, so the script can be signed once after being tested (with pester and simple unit-tests) an can be safely executed knowing that the code wasn’t altered after being  deployed, meeting the needs of more restricting execution policies.

    So my first suggestion is decouple where possible settings from the script itself, so is easier to re-use in different environments.

    Second is using require statements, if you’re script depends from a module or running as an administrator will it make easier to read and debug.

    #Requires –Modules ActiveDirectory

    Third is stick with the DRY approach (Don’t Repeat Yourself). You’re design implicitly has some different warning dates (1,3,7), but they are Hard-Coded, if you wan’t to remove or add dates you need to alter many lines of code. That is key on preserving your code for a long time without any need to change. Focus some effort on refactoring.

    $WarningDates = 1,3,7

    Use a foreach and a define a function send warning and look how more readable your code will be:

    #check password expiration date and send email on match
    $WarningDays = 1,3,7
    foreach ($user in $users) {
    foreach($WarnDay in $WarningDays){
    if($user.PasswordExpiry -eq (get-date).adddays($WarnDay).ToLongDateString()) {
    $EmailBody=$EmailStub1,$user.name,$EmailStub2,$WarnDay,$EmailStub3,$SevenDayWarnDate,$EmailStub4-join’ ‘
    Send-MailMessage-To $user.EmailAddress-From$MailSender-SmtpServer $SMTPServer-Subject $Subject`
    -Body $EmailBody

    Forth… joinin strings is a good strategy, but not the best in this case because the content of the email is not easy to read.  Why don’t you create a simple $EmailBody variable?

    $email_body = “Hi $($user.name), … some text”

    Or my favourite is create different body templates (so I can eventually choose it according to the user or day)  and replacing a string “-USERNAME-“. Similar to this

    $email_body = “Hi -USERNAME-, … some text”.Replace(“-USERNAME-“, $user.name))

    And you can also concatenate replace methods if needed.

    Fifth if you’re going to schedule this task you need to provide exit values for knowing from task scheduler when script is executed correctly.

    Sixth, try to avoid comments. Yes, I’ve said it… Comments are less useful than you think, personally I try to write code is easy to read for everybody.. even a novice of programming.

    Seven, review your code and try to make it shorter and simpler. Refactoring your own code will make you a better developer.

    Sorry if I wrote too much, I really think that your article is good, I thought that with some small steps can be even simpler and efficient and make it great.


  • Line 4 of the first code block I think is just a normal line of text.
    So the code block should close at line 3 and another one should be open on line 5.

    It’s a good article by the way!

  • Personally I agree that using core at the same time with 6 as version number was not the best choice.

    In software development different versions of the same product first should imply backward compatibility and foremost an increase of the number of features available.

    My opinion is that powershell core goal at this stage is not meant to replace  powershell 5.1, but just working side-by-side. Otherwise the default choice should be an in-place upgrade or a windows update release.

    Try this one-liner

    get-command | measure

    It will show you at glance that powershell core has almost 10 times less cmdlets 425 vs 4009 ( your result my vary by the number of module loaded). Similar comparison for the get-module.

  • Paolo Frigo's profile was updated 4 years, 9 months ago

  • Paolo Frigo's profile was updated 4 years, 9 months ago

  • Paolo Frigo became a registered member 4 years, 9 months ago

  • Paolo Frigo changed their profile picture 4 years, 9 months ago

© 4sysops 2006 - 2022


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


Log in with your credentials


Forgot your details?

Create Account