Powershell - Disable expired users - powershell

I need to run a command that disables users who have an account expiration date 7 days BEFORE the current date.
At the moment I have only been able to find code that looks at users who are expiring in the future
Search-ADAccount -AccountExpiring -TimeSpan "7"
or have simply already expired (can't specify date)

You can try this:
$date = (Get-Date) - (New-TimeSpan -Days 7)
Search-ADAccount -AccountExpiring | ? { $_.AccountExpirationDate -le $date }
It'll return any accounts where the expiration date is less than the date seven days ago.

Related

Powershell Query does not calculate correct Date

HelloThere,
we get AD-Users from an import script that runs daily and if a user was found in a csv we write the current date in the extensionattribute1 in format "dd-MM-yyyy".
Now we want to calculate if a AD user has a different date in the extensionattribute1 (minus 90 days) then we want to inform their managers what should happen to those accounts.
Interesting is, with my query we get correct Users and some Users between 30 and 90 Days. I don't know what is wrong in my code or with the syntax - can someone pls help? Thanks
sorry, i am not a PowerShell Pro by now but working on it :D
Greetings
# get date -90 Days
$date = (Get-Date).AddDays(-90).ToString("dd-MM-yyyy")
$date
# it gets "27-08-2022" -> so the script should only show users less than this date
# query for extensionattribute1 less than 90 days
get-aduser -properties ExtensionAttribute1 -filter {(enabled -eq "true") -and (extensionAttribute1 -gt $date)}
# here the output is partial correct, we get users with an extensionattribute1 from
# 31-05-2022
# 30-06-2022
# 29-07-2022
# but also some Users with a date from between 30 and 90 days what is incorrect =/
# 30-09-2022
# 31-10-2022
You should not compare date strings against eachother, especially not when you use date format "dd-MM-yyyy", since that is a non-sortable date format. (you might get away with it if you would have used format 'yyyy-MM-dd'..)
Instead, convert the value found in the ExtensionAttribute1 to a DateTime object first and compare that to a real reference DateTime object.
Try
# get date -90 Days
$date = (Get-Date).AddDays(-90).Date # set to midnight with time part '00:00:00'
# query for extensionattribute1 less than 90 days
Get-ADUser -Properties ExtensionAttribute1 -Filter 'Enabled -eq $true -and ExtensionAttribute1 -like "*"' |
Where-Object {[datetime]::ParseExact($_.ExtensionAttribute1, 'dd-MM-yyyy', $null) -gt $date}

powershell to get exact date for passwordlastset

I'm working on scripts which send emails to users 14, 10, 7, 3 days before password expiring.
Password expires in 60 days.
If I set like below it works for accounts with 3 and less days to expiring. I don't want accounts with 2 days, 1 day, etc.
$ExpiringUsers = $AdUsers | where PasswordLastSet -lt (get-date).AddDays(-57)
If I set like below it doesn't work at all
$ExpiringUsers = $AdUsers | where PasswordLastSet -eq (get-date).AddDays(-57)
How to set equal 3 days not more not less.
Thanks!
You need to define and filter by a time range, for example, set equal 3 days not more not less would be like this:
$start = [datetime].AddDays(-3) # => April 2 at 12:00 AM
$finish = [datetime].AddDays(-2) # => April 3 at 12:00 AM
# Note `-lt $finish` instead of `-le $finish`
$AdUsers | Where-Object { $_.PasswordLastSet -ge $start -and $_.PasswordLastSet -lt $finish }
A better approach is to use msDS-UserPasswordExpiryTimeComputed for checking how long until the account credential expires:
$serviceAccounts =
'acct1#domain.tld',
'acct2#domain.tld
$daysLeft = 20
$expiringAccounts = ( $serviceAccounts | Foreach-Object {
Get-AdUser -Filter "(UserPrincipalName -eq '$_' -Or sAMAccountName -eq '$_' ) -And ( PasswordNeverExpires -eq 'false' )" -Properties msDS-UserPasswordExpiryTimeComputed |
Where-Object { ( New-TimeSpan -Start $currentDate -End ( [DateTime]::FromFileTime( $_.'msDS-UserPasswordExpiryTimeComputed' ) ) ).Days -le $daysLeft }
} )
As written, this code will gather the accounts expiring within 20 days. Adjust $daysLeft to control the remaining threshold until expiry.
Note that [DateTime]::FromFileTime is required to transpose the value ofmsDS-UserPasswordExpiryTimeComputed from the file-time format it is stored in AD as to a workable DateTime object.
You can define the account as a sAMAccountName or in Universal Principal Name (UPN) format.
This also exemplifies using AD filters in order to have AD return only the objects you need for this query, minimizing the local processing performed with Where-Object.
The notable exception is msDS-UserPasswordExpiryTimeComputed; because it is a Constructed Attribute within Active Directory, neither AD filters or LDAP filters can evaluate it and so this must be done via additional local processing.
Here is an answer I have also written which goes into deeper detail on using the AD filter syntax.
What is wrong with PasswordLastSet for checking credential expiration if you know the account's lifecycle?
The problem with checking PasswordLastSet is that, while it works, if the threshold until expiry changes on the Active Directory side, your script will need to be updated or it will incorrectly identify accounts whose credential is set to expire soon. It also becomes more difficult to track which accounts are beholden to different lifecycles in environments where not all accounts are beholden to the same security policies.

Powershell notify when certificate almost expires

In Powershell I want to notify specific users when a certificate in a domain controller is gonna expire 24hour before hand. I already found a code then displays the start and expiry date and also the days remaining. But how can i get notified (through email) when the certificate expires.
Get-ChildItem Cert:\LocalMachine\My `
| Select #{N='StartDate';E={$_.NotBefore}},
#{N='EndDate';E={$_.NotAfter}},
#{N='DaysRemaining';E={($_.NotAfter - (Get-Date)).Days}}
I'd suggest adding some more properties to the objects you select for better recognition later and add a Where-Object{} clause to it, to filter for certificates that have 1 day or less left before expiring:
$certs = Get-ChildItem -Path 'Cert:\LocalMachine\My' |
Select-Object Thumbprint, Issuer,
#{N='StartDate';E={$_.NotBefore}},
#{N='EndDate';E={$_.NotAfter}},
#{N='DaysRemaining';E={($_.NotAfter - (Get-Date).Date).Days}} |
Where-Object { $_.DaysRemaining -le 1 }
if ($certs) {
# send an email to yourself
$mailSplat = #{
To = 'me#mycompany.com'
From = 'me#mycompany.com'
SmtpServer = 'MySmtpServer'
Subject = 'Expiring certificates'
Body = $certs | Format-List | Out-String
# other params can go here
}
# send the email
Send-MailMessage #mailSplat
}
(Get-Date).Date takes today's date as of midnight, not at the current time of day you run the script

The months difference between dates using PowerShell

I need to have AD User Account Expiration Date and now how many months and date its remain until will be disabled.
I tried the code under but I am getting in the months 1 and I have less than one month I would like to have answer like 0 month and 27 days
$StartDate (DateNow)
2019-08-29 00:00:00
AccountExpirationDate
---------------------
2019-09-26 00:00:00
$ExpirDate = Get-ADUser test111 -Properties AccountExpirationDate | select AccountExpirationDate
AccountExpirationDate
---------------------
2019-09-26 00:00:00
$EndDate= $ExpirDate.AccountExpirationDate
2019-09-26 00:00:00
$StartDate = (GET-DATE)
2019-08-29 00:00:00
NEW-TIMESPAN –Start $StartDate –End $EndDate
Days : 27
Hours : 10
Minutes : 29
Seconds : 56
$monthdiff = $EndDate.month - $StartDate.month + (($EndDate.Year - $StartDate.year) * 12)
1
(Here I got the number 1 but I have less than one month)
I found no easy way to do this in PowerShell (as TimeSpan doesn't support month counting), hence I ended up with the following. Starting with the years of the two dates, take their difference and course correct if the start day hasn't passed in the current year. Then do the same with the months:
$StartDate = [DateTime]'2021-01-23'
$today = Get-Date
$daydiff = New-TimeSpan -Start $StartDate -End $today
$yeardiff = $today.year - $StartDate.year
If($yeardiff -gt 0 -And $StartDate.month -gt $today.month
-And $StartDate.day -gt $today.day) {
$yeardiff = $yeardiff -1
}
$monthdiff = $today.month - $StartDate.month + ($yeardiff * 12)
If($StartDate.day -gt $today.day) { $monthdiff = $monthdiff -1 }
Write-Host "$($daydiff.days) days | $($monthdiff) months"
Simplest solution I could work out.
I get the number of months between the start date and the monthly anniversary day in the current month. Then adjust:
$start_date = Get-Date '2022-02-27 21:00'
$end_date = Get-Date
# get the monthly anniversary of the $start_date in the current month
$this_month_anniversary = Get-Date ('{0}-{1}-{2} {3:d2}:{4:d2}' -f $end_date.Year, $end_date.Month, $start_date.Day, $start_date.Hour, $start_date.Minute)
# get the number days in the month, so we can get a denominator when figuring the percent of the way we are towards the next anniversay.
# Which month? If we're past this month's anniversary use the current month. If we haven't reached it yet, use the previous month
if ($end_date -gt $this_month_anniversary) {
$days_in_month = [DateTime]::DaysInMonth($end_date.Year, $end_date.Month)
} else {
$last_month = (Get-Date ('{0}-{1}-01' -f $end_date.Year, $end_date.Month)).AddDays(-1)
$days_in_month = [DateTime]::DaysInMonth($last_month.Year, $last_month.Month)
}
# get months between the start date and this month's anniversay, then
# adjust for the current month, this will be negative if the anniversay hasn't occured yet, otherwise positive
($this_month_anniversary.Month - $start_date.month + (($this_month_anniversary.Year - $start_date.year) * 12) +
(New-TimeSpan -Start $this_month_anniversary -End $end_date).TotalDays / $days_in_month)
I believe this is what you want, or can be tweaked to achieve it relatively easily.
$today = Get-Date;
$endOfYearDate = "12/31/$($today.Year)";
$endOfYear = Get-Date($endOfYearDate);
$monthsLeftInTheYear = ($endOfYear.Month - $today.Month);
$daysLeftInTheYear = ($endOfYear - $today);
$daysLefInTheYear.Days;
You can just do normal arithmetic on dates, but if there are no months, it will return $null not 0.
$today - date
$ExpirDate = Get-ADUser test111 -Properties AccountExpirationDate | select AccountExpirationDate
$diffday = $today - $expirDate
$diffday.days
$diffday.months
if ($diffday.months -eq $null)
{
$Diffday.months =0
}

Year wrong using Powershell script to pull dates from AD

I am using Powershell to pull simple data from AD. The script pulls usernames from a text file and is similar to:
Import-Module ActiveDirectory
Get-Content c:\temp\userlist.txt | Foreach-Object {
$user = $_
$fullname = (Get-ADuser -identity $user | foreach {$_.Name})
$email = (Get-ADUser -identity $user -properties * | foreach {$_.mail})
$lastlog = (Get-ADUser -identity $user -properties * | foreach {$_.lastLogon})
$lastlogstr = (Get-Date -format "yyyy MMM d" $lastlog)
"$user,$fullname,$email,$lastlog,$lastlogstr"
}
When I run this, all the correct data is pulled, and I'll see (for example)
XXXXX,John Smith,jsmith#company.com,130252373811789928,0413 Oct 2
When I check Active directory, and use the Attribute editor to view "lastLogon", I see
10/2/2013 8:29:41PM Central Daylight Time
and if I click to View that field, I see 130252373811789928 as shown above.
But for absolutely every user I query, and no matter how I format the date (i.e. as above, using D, etc.) it -always- puts in 0413 instead of 2013. Similarly, it shows 0411 for 2011, etc.
I cannot imagine why this is happening. Powershell is being run from a Windows 7 system, and I have tried using both the ISE and the powershell command.
Can you try :
$date = [datetime]::fromfiletime($lastlog)
$date.ToString("yyyy MMM d")
or
$date = [datetime]::FromFileTimeUtc($lastlog)
$date.ToString("yyyy MMM d")
In ActiveDirectory Microsoft specifics attibuts that deal with time are stored as a Windows file time. It's a 64-bit value that represents the number of 100-nanosecond intervals that have elapsed since 12:00 midnight, January 1, 1601 A.D. (C.E.) Coordinated Universal Time (UTC).