We are using a powershell script cobbled together from other entries here / spiceworks. After moving this to a newer server, theres some difference somewhere we cannot find and the get timespan line is resulting in the following error:
New-TimeSpan : Cannot bind parameter 'End'. Cannot convert the "60.00:00:00" value of type "System.TimeSpan" to type "System.DateTime".
At C:\ExpirationScript\PasswordChangeNotification.ps1:61 char:54
+ $daystoexpire = (New-TimeSpan -Start $today -End $Expireson).Days
+ ~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [New-TimeSpan], ParameterBindingException
+ FullyQualifiedErrorId : CannotConvertArgumentNoMessage,Microsoft.PowerShell.Commands.NewTimeSpanCommand
Tried a few different ideas found on stackoverflow to replace this variable without success:
$daystoexpire = (New-TimeSpan -Start $today -End $Expireson).Days`
Any ideas? Thank you in advance.
Script being used:
# Please Configure the following variables....
$smtpServer="localhost"
$expireindays = 7
$from = "[email protected]"
$logging = "Enabled" # Set to Disabled to Disable Logging
$logFile = "c:\pathtoscripting\ADpasscheck.csv" # ie. c:\mylog.csv
$testing = "Disabled" # Set to Disabled to Email Users
$testRecipient = "[email protected]"
$nullRecipient = "[email protected]"
$date = Get-Date -format ddMMyyyy
$exemptUsers = "Administrator"
#
############################################################################
# Check Logging Settings
if (($logging) -eq "Enabled")
{
# Test Log File Path
$logfilePath = (Test-Path $logFile)
if (($logFilePath) -ne "True")
{
# Create CSV File and Headers
New-Item $logfile -ItemType File
Add-Content $logfile "Date,Name,EmailAddress,DaystoExpire,ExpiresOn"
}
} # End Logging Check
# Get Users From AD who are Enabled, Passwords Expire and are Not Currently Expired #Enabled was missing from this line so disabled accounts were being found
Import-Module ActiveDirectory
$users = get-aduser -filter 'Enabled -eq $true' -properties Name, PasswordNeverExpires, PasswordExpired, PasswordLastSet, EmailAddress
$maxPasswordAge = (Get-ADDefaultDomainPasswordPolicy).MaxPasswordAge
# Process Each User for Password Expiry
foreach ($user in $users)
{
If ($exemptUsers -contains $user.SamAccountName) { Continue; }
$Name = (Get-ADUser $user | foreach { $_.Name})
$emailaddress = $user.emailaddress
$passwordSetDate = (get-aduser $user -properties * | foreach { $_.PasswordLastSet })
$PasswordPol = (Get-AduserResultantPasswordPolicy $user)
# Check for Fine Grained Password
if (($PasswordPol) -ne $null)
{
$maxPasswordAge = ($PasswordPol).MaxPasswordAge
}
$expireson = $passwordsetdate + $maxPasswordAge
$today = (get-date)
$daystoexpire = (New-TimeSpan -Start $today -End $Expireson).Days
# Set Greeting based on Number of Days to Expiry.
# Check Number of Days to Expiry
$messageDays = $daystoexpire
if (($messageDays) -ge "1")
{
$messageDays = "in " + "$daystoexpire" + " days."
}
else
{
$messageDays = "today."
}
}
Tried reworking line to use other idea found here (date time object) but could not incorporate properly: New-TimeSpan cmdlet in powershell
You're expecting $expireson
to be a [datetime]
instance, but it is a [timespan]
instance, which is why the call to New-TimeSpan
fails (the -Start
and -End
arguments must be [datetime]
instaces, i.e. points in time).
Given how you set the value of $expireson
:
$expireson = $passwordsetdate + $maxPasswordAge
the implication is that $passwordsetdate
is $null
- which, in effect, makes the assignment equivalent to $expireson = $maxPasswordAge
, i.e. stores the [timespan]
value contained in $maxPasswordAge
in $expireson
.
Only if $passwordsetdate
contained a [datetime]
instance would the +
operation work as intended, i.e. it would add the [timespan]
value to the [datetime]
instance to yield a new [datetime]
instance.
Simple examples:
# OK: Adds the timespan to the date and returns the resulting date,
# i.e. [datetime] '1970/01/02'
[datetime] '1970/01/01' + [timespan]::FromDays(1)
# !! BROKEN: because $allegedDate is $null, the timespan is used as-is.
$allegedDate = $null
$allegedDate + [timespan]::FromDays(1)
Therefore:
You must ensure that $passwordsetdate
contains the intended [datetime]
value.
$null
, but based on this ServerFault post, two factors may be at play:
$null
may be returned if the user will have to change their password on next login.You can then simply directly subtract your two [datetime]
instances from each other - no need for New-TimeSpan
:
$daystoexpire = ($expireson - $today).Days